In C++ how to call Windows "Disk Management" and wait until it is closed (completed)

I'm using Visual Studio 2019 Community.
I'm trying to call the Windows 10 program "Disk Management" (diskmgmt.msc) and wait for it to be closed before continuing with the next part of the program.
I have tried "diskmgmt.msc" from CreateProcessA, it will not start.
I have tried calling "cmd.exe /c C:\\Windows\\System32\\diskmgmt.msc" from CreateProcessA.
Disk Management will start but how can you wait for it to complete. I tried using the pi.dwProcessId and looking for it using Task Manager but it is gone by the time the Disk Management is open, I think the Process ID was that of cmd.exe that started the Disk Management.
I have tried using "system("diskmgmt.msc") it starts Disk Management but it doesn't wait until Disk Management is closed.

Below is my Test Code.

// This program tries to start "Disk Management" (diskmgmt.msc) and get the process ID so the program
// can wait for "Disk Management" to be closed before moving on.

// I know diskmgmt.msc can be started via cmd.exe via CreateProcessA but the process ID
// returned via pi.dwProcessId is not the pid for diskmgmt.msc (my guess it is for cmd.exe)

// diskmgmt.msc can also be started from system(diskmgmt.msc) BUT how can I get the process ID?

// Note: This program is compiled under Microsoft Visual Studio Community 2019 ver 16.2.3
// As a Console application no header files
// On Windows 10 home 64Bit
// ASUS Sabertooth Z77
// 16GB Ram


#include <iostream>
#include <shlwapi.h>

using namespace std;

int main(int argc, TCHAR* argv[])
{
STARTUPINFO si;
PROCESS_INFORMATION pi;

// Start the child process.
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));

string commandName, commandLine;
LPSTR commandName_LPSTR, commandLine_LPSTR;

commandName = "c:\\Windows\\System32\\diskmgmt.msc";
commandLine = commandName;
commandName_LPSTR = const_cast<char*>(commandName.c_str());
commandLine_LPSTR = const_cast<char*>(commandLine.c_str());

cout << "Try #1" << endl;
cout << "Trying to start \"Disk Management\" using call to \"c:\\Windows\\System32\\diskmgmt.msc\"" << endl;
cout << " Using \"CreateProcessA\"" << endl << endl;
cout << " Trying this way ALWAYS fails!!!" << endl;
cout << " Command Name := \"" << commandName_LPSTR << "\"" << endl;
cout << " Command Line := \"" << commandLine_LPSTR << "\"" << endl << endl;
if (!CreateProcessA(commandName_LPSTR, // Command Name
commandLine_LPSTR, // Command line
NULL, // Arguments to diskmgmt.msc
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
)
{
cout << "Try #1 " << commandLine << " failed " << GetLastError() << endl;
}
else
{
cout << "Process ID returned by CreateProcessA Try #1 was: " << pi.dwProcessId << endl;

WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}

// Try #2
// This process starts the program "Disk Management" but the process ID returns is not that of
// MMC.EXE (Microsoft Management Console) which is the started from diskmgmt.msc or any other running
// process
commandName = "c:\\Windows\\System32\\cmd.exe";
commandLine = commandName;
commandLine.append(" /c C:\\Windows\\System32\\diskmgmt.msc");
commandName_LPSTR = const_cast<char*>(commandName.c_str());
commandLine_LPSTR = const_cast<char*>(commandLine.c_str());

cout << endl << "Try #2" << endl;
cout << "Trying to start \"Disk Management\" using call to \"c:\\Windows\\System32\\cmd.exe\"" << endl;
cout << " with \" /c C:\\Windows\\System32\\diskmgmt.msc\" added to end of commandLine" << endl;
cout << " Using \"CreateProcessA\"" << endl << endl;
cout << " Command Name := \"" << commandName_LPSTR << "\"" << endl;
cout << " Command Line := \"" << commandLine_LPSTR << "\"" << endl << endl;
if (!CreateProcessA(commandName_LPSTR, // Command Name
commandLine_LPSTR, // Command line
NULL, // Arguments to diskmgmt.msc
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
)
{
cout << "CreateProcess #2 " << commandLine << " failed " << GetLastError() << endl;
}
else
{
// The ProcessId returned here is NOT the one for MMC.exe (diskmgmt.msc) I think it was for cmd.exe
cout << "Process ID returned by CreateProcessA was: " << pi.dwProcessId << endl;
cout << " This is NOT the process ID for MMC.exe (diskmgmt.msc)" << endl;

WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);

}

cout << endl << "Try #3" << endl;
cout << "Trying to start \"Disk Management\" using call to \"System(diskmgmt.msc)\"" << endl;
cout << "Start Disk Manager using \"System(diskmgmt.msc)\"" << endl;
system("diskmgmt.msc");
cout << "Disk Management was called, BUT Process ID is unknown" << endl;

// Is there a way to get the process ID from the system call??

// Prompt User to press any key
cout << "\n Press the \"ENTER\" key to Exit" << "\n";
cin.get();
}
Last edited on
see https://docs.microsoft.com/en-us/windows/win32/procthread/creating-processes
I think you need the
WaitForSingleObject( pi.hProcess, INFINITE );
part of it?
I added WaitForSingleObject( pi.hProcess, INFINITE ); as you suggested in the code in "Try #2" just after the CreateProcessA else.
WaitForSingleObject does NOT WAIT. The value of pi.hProcess is 0x00000104.
Did you add it into my code and test it? If you did and it worked could you show me just where you added it. Thanks
Maybe it looks better if I add indented code!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// This program tries to start "Disk Management" (diskmgmt.msc) and get the process ID so the program 
//		can wait for "Disk Management" to be closed before moving on.

//	I know diskmgmt.msc can be started via cmd.exe via CreateProcessA but the process ID 
//		returned via pi.dwProcessId is not the pid for diskmgmt.msc (my guess it is for cmd.exe)

//  diskmgmt.msc can also be started from system(diskmgmt.msc) BUT how can I get the process ID?

//  Note:	This program is compiled under Microsoft Visual Studio Community 2019 ver 16.2.3 
//			As a Console application no header files
//			On Windows 10 home 64Bit 
//			ASUS Sabertooth Z77
//			16GB Ram


#include <iostream>
#include <shlwapi.h>

using namespace std;

int main(int argc, TCHAR* argv[])
{
	STARTUPINFO si;
	PROCESS_INFORMATION pi;

	// Start the child process. 
	ZeroMemory(&si, sizeof(si));
	si.cb = sizeof(si);
	ZeroMemory(&pi, sizeof(pi));

	string	commandName, commandLine;
	LPSTR	commandName_LPSTR, commandLine_LPSTR;

	commandName = "c:\\Windows\\System32\\diskmgmt.msc";
	commandLine = commandName;
	commandName_LPSTR = const_cast<char*>(commandName.c_str());
	commandLine_LPSTR = const_cast<char*>(commandLine.c_str());

	cout << "Try #1" << endl;
	cout << "Trying to start \"Disk Management\" using call to \"c:\\Windows\\System32\\diskmgmt.msc\"" << endl;
	cout << "   Using \"CreateProcessA\"" << endl << endl;
	cout << "  Trying this way ALWAYS fails!!!" << endl;
	cout << "   Command Name := \"" << commandName_LPSTR << "\"" << endl;
	cout << "   Command Line := \"" << commandLine_LPSTR << "\"" << endl << endl;
	if (!CreateProcessA(commandName_LPSTR,	// Command Name
		commandLine_LPSTR,					// Command line
		NULL,				// Arguments to diskmgmt.msc
		NULL,				// Thread handle not inheritable
		FALSE,				// Set handle inheritance to FALSE
		0,					// No creation flags
		NULL,				// Use parent's environment block
		NULL,				// Use parent's starting directory 
		&si,				// Pointer to STARTUPINFO structure
		&pi)				// Pointer to PROCESS_INFORMATION structure
		)
	{
		cout << "Try #1 " << commandLine << " failed " << GetLastError() << endl;
	}
	else
	{
		cout << "Process ID returned by CreateProcessA Try #1 was: " << pi.dwProcessId << endl;
		
		WaitForSingleObject(pi.hProcess, INFINITE);
		CloseHandle(pi.hProcess);
		CloseHandle(pi.hThread);
	}

	//	Try #2
	//	This process starts the program "Disk Management" but the process ID returns is not that of 
	//	MMC.EXE (Microsoft Management Console) which is the started from diskmgmt.msc or any other running
	//	process
	commandName = "c:\\Windows\\System32\\cmd.exe";
	commandLine = commandName;
	commandLine.append(" /c C:\\Windows\\System32\\diskmgmt.msc");
	commandName_LPSTR = const_cast<char*>(commandName.c_str());
	commandLine_LPSTR = const_cast<char*>(commandLine.c_str());

	cout << endl << "Try #2" << endl;
	cout << "Trying to start \"Disk Management\" using call to \"c:\\Windows\\System32\\cmd.exe\"" << endl;
	cout << "  with \" /c C:\\Windows\\System32\\diskmgmt.msc\" added to end of commandLine" << endl;
	cout << "   Using \"CreateProcessA\"" << endl << endl;
	cout << "   Command Name := \"" << commandName_LPSTR << "\"" << endl;
	cout << "   Command Line := \"" << commandLine_LPSTR << "\"" << endl << endl;
	if (!CreateProcessA(commandName_LPSTR,		// Command Name
		commandLine_LPSTR,						// Command line
		NULL,				// Arguments to diskmgmt.msc
		NULL,				// Thread handle not inheritable
		FALSE,				// Set handle inheritance to FALSE
		0,					// No creation flags
		NULL,				// Use parent's environment block
		NULL,				// Use parent's starting directory 
		&si,				// Pointer to STARTUPINFO structure
		&pi)				// Pointer to PROCESS_INFORMATION structure
		)
	{
		cout << "CreateProcess #2 " << commandLine << " failed " << GetLastError() << endl;
	}
	else
	{
		WaitForSingleObject(pi.hProcess, INFINITE);
		// The ProcessId returned here is NOT the one for MMC.exe (diskmgmt.msc)  I think it was for cmd.exe
		cout << "Process ID returned by CreateProcessA was: " << pi.dwProcessId << endl;
		cout << "pi.hProcess returned was " << pi.hProcess << endl;
		cout << "   This is NOT the process ID for MMC.exe (diskmgmt.msc)" << endl;

		CloseHandle(pi.hProcess);
		CloseHandle(pi.hThread);

	}

	cout << endl << "Try #3" << endl;
	cout << "Trying to start \"Disk Management\" using call to \"System(diskmgmt.msc)\"" << endl;
	cout << "Start Disk Manager using \"System(diskmgmt.msc)\"" << endl;
	system("diskmgmt.msc");
	cout << "Disk Management was called,  BUT Process ID is unknown" << endl;

	// Is there a way to get the process ID from the system call??

		// Prompt User to press any key
	cout << "\n Press the \"ENTER\" key to Exit" << "\n";
	cin.get();
}
The command line
cmd /c start /wait diskmgmt.msc
will make the cmd process wait around until the diskmgmt has finished.
cmd /c start /wait diskmgmt.msc Works like I want it to from a DOS CMD.EXE windows, But NOT from within my C++ Program.
Within C++ using function CreateProcessA and
LPCSTR commandName = NULL;
LPSTR commandLine = const_cast<char*>("C:\\Windows\\System32\\CMD.EXE /c START /WAIT C:\\Windows\\System32\\diskmgmt.msc");
Disk Management starts BUT my the program executes the next instruction as if it closed immediately.

Note: in C++ I must use the FULL path for cmd.exe and diskmgmt.msc or I get an error 2 (file not found) from CreateProcessA.

What instructions do I need to use to get it to wait until "Disk Management" is closed???

I've no idea why start/wait works from an actual open console command line, where it doesn't work when invoked from within a program.

I tried investigating using procmon from https://docs.microsoft.com/en-us/sysinternals/
I used these filters to trace the process and thread start/exit events -> https://ibb.co/9cn06zr
And got these results -> https://ibb.co/ZSm7srZ

A couple of things seem odd.

1. Trying to execute the MSC file directly from program code results in

ERROR_BAD_EXE_FORMAT     193 (0xC1)
%1 is not a valid Win32 application.

https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-

Which is kinda odd, since you can just type in diskmgmt.msc at a command prompt and it works just fine.

2. diskmgmt.msc is in fact loaded by mmc.exe (as a process), which makes me wonder what the bad exe format thing is all about if you can't run a .msc directly.

3. Looking a bit closer at the procmon trace, it seems the actual process running diskmgmt.msc is a grandchild of your code. The actual child "mmc.exe" exits soon after, and satisfies the "wait", but the real grandchild becomes an orphan you know nothing about.

But then, how does start/wait from the command line know this?

All I can suggest is running tests to compare start/wait from an actual command line vs start/wait from program code.

Or perhaps figure out how wait for all grandchildren, even if they become orphaned.
can you call the exe with the .msc as a parameter?
that may be what you needed.

No, I cannot easily run your code, I don't have a windows development setup anymore. Ive been coding for unix at work for a while and my windows setup is a g++ right now, all commandline stuff, no gui dev.
Last edited on
NO

If you use "MMC.EXE diskmgmt.msc" as the commandLine value of CreateProcessA the value of pi.dwProcessId is not the processor ID that shoes up under Task Manager for any application.
also using "WaitForSingleObject(pi.hProcess, INFINITE);"
doesn't wait until "Disk Management" is closed.

Any other ideas?
tigerlcf wrote:
cmd /c start /wait diskmgmt.msc Works like I want it to from a DOS CMD.EXE windows, But NOT from within my C++ Program.

If I remember correctly, this might be a 32-bit vs 64-bit thing. Try seeing if compiling your program in 64-bit or vice-versa makes a difference.

I'm not sure if that will work, but I think it's worth a try.

I just skimmed the thread. If nothing else works you might have to enumerate all windows/mmc processes and then find the one that has Disk Management as the title.
Last edited on
Topic archived. No new replies allowed.