C++ - Array pointer as function parameter, filling out array and accessing it from UI thread
I haven't coded much in C++ since HS and I'm pretty rusty / not very experienced.
I want to find all the running processes on a machine and fill a listbox control with their names. I created a C++ win form application, and on the form load event handler I have the following code -
private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e) {
// Proccess monitor class
ProcessMonitor oMonitor;
// Array pointer
string* processes = NULL;
// Call method in process monitor class called get processes,
// pass int array pointer as parameter
oMonitor.GetProcesses(processes);
// Iterate through array
for (int i = 0; i < sizeof(processes) / sizeof(string); i++)
{
}
}
};
Hopefully the code / comments are straight forward enough.
This is what my GetProcesses method looks like -
void ProcessMonitor::GetProcesses(string processNames[])
{
// Array to hold process ID's
DWORD aProcesses[1024], cbNeeded, cProcesses;
// Iterator
unsigned int i;
// If no running processes can be detected exit function
if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) )
return;
// Get number of running processes
cProcesses = cbNeeded / sizeof(DWORD);
// Ins开发者_如何学运维tantiate array that was passed in
// ***NOTE*** I think this is where my problem lies,
// as I passed in a pointer to an array, not an actual array
processNames = new string[cProcesses];
// Iterate through array and initialize all indicies to an empty string
for ( int j = 0; j < sizeof(processNames) / sizeof(string); i++)
{
processNames[i] = "";
}
// Enumerate through processes and fill array with process names
for ( i = 0; i < cProcesses; i++ )
{
if( aProcesses[i] != 0 )
{
TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, aProcesses[i]);
if (NULL != hProcess )
{
HMODULE hMod;
DWORD cbNeeded;
/*Given a handle to a process, this returns all the modules running within the process.
The first module is the executable running the process,
and subsequent handles describe DLLs loaded into the process.*/
if ( EnumProcessModules( hProcess, &hMod, sizeof(hMod), &cbNeeded) )
{
//This function returns the short name for a module,
//typically the file name portion of the EXE or DLL
GetModuleBaseName( hProcess, hMod, szProcessName,
sizeof(szProcessName)/sizeof(TCHAR) );
processNames[i] = szProcessName;
}
}
CloseHandle( hProcess );
}
}
}
I believe the problem with my code is that I'm not instantiating my array until it is already inside the GetProcesses method. When the code returns to the calling windows form, the pointer to the array I passed in is null. I'm guessing what I have to do is instantiate the array before I pass it in to the function as a parameter. The problem is I don't know the size the array needs to be until I determine the number of running processes on the machine.
I realize I could break the GetProcesses function down into two calls, one to determine the size the array needs to be, and one to fill the array. The problem with that is if you examine the condition -
if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) )
return;
The call within that condition fills out the aProcesses array with all the process IDs. I don't want to have to do this twice.
Does anyone have any ideas as far as what I'm doing wrong?
Again if I'm really off here I apologize, I haven't programmed anything in C++ in a while.
ProcessMonitor::GetProcesses(string processNames[])
I think that you need to pass a pointer in to function
not too sure of the syntax
ProcessMonitor::GetProcesses(string *processNames[])
because processNames = new string[cProcesses]; will allocate it locally and it will not be returned back...
(Oh yes I think that managed C++ is the worst of all worlds. But that's my opinion.)
Strings and vectors are your friend in C++ :)
#include <string>
#include <vector>
typedef std::vector<std::string> StringVector;
StringVector ProcessMonitor::GetProcesses()
{
StringVector ret;
// Array to hold process ID's
DWORD aProcesses[1024], cbNeeded, cProcesses;
// Iterator
unsigned int i;
// If no running processes can be detected exit function
if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) )
return;
// Enumerate through processes and fill array with process names
for ( i = 0; i < cProcesses; i++ )
{
if( aProcesses[i] != 0 )
{
TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, aProcesses[i]);
if (NULL != hProcess )
{
HMODULE hMod;
DWORD cbNeeded;
/*Given a handle to a process, this returns all the modules running within the process.
The first module is the executable running the process,
and subsequent handles describe DLLs loaded into the process.*/
if ( EnumProcessModules( hProcess, &hMod, sizeof(hMod), &cbNeeded) )
{
//This function returns the short name for a module,
//typically the file name portion of the EXE or DLL
GetModuleBaseName( hProcess, hMod, szProcessName,
sizeof(szProcessName)/sizeof(TCHAR) );
// CHANGE HERE!!!
ret.push_back(szProcessName);
}
}
CloseHandle( hProcess );
}
}
return ret; // return vector back to caller.
}
Call like:
StringVector ret = monitor.GetProcesses();
精彩评论