digitalmars.D - Windows API: Strange behaviour after calling GetModuleFileNameExA
- Tobias Wassermann (67/67) Nov 26 2007 Hi all,
- Regan Heath (2/2) Nov 26 2007 How have you declared processFileName? Perhaps "char[]
- Tobias Wassermann (3/5) Nov 26 2007 Yes, it is declared just before the for-loop as:
- Regan Heath (6/14) Nov 27 2007 The thought I had was that perhaps GetModuleFileNameExA was overwriting
- Tobias Wassermann (43/51) Nov 27 2007 Hi,
- Regan Heath (81/81) Nov 27 2007 This is totally whacky... using the code posted below I get the
- Tobias Wassermann (38/64) Nov 27 2007 Could be an implib problem - I ported the code to C and compiled with DM...
- Joel Lucsy (8/14) Nov 27 2007 Ah, I would tend to think that EnumProcesses and GetModuleFileNameExA
- Regan Heath (21/32) Nov 27 2007 I thought the same thing but couldn't get it to link with
- Joel Lucsy (8/24) Nov 27 2007 Actually, the WINAPI is what sets STDCALL. I believe the extern "C" is
- Tobias Wassermann (6/32) Nov 27 2007 The problem is:
- Carlos Santander (4/17) Nov 28 2007 You could use a .def file to alias _EnumProcesses@12 to EnumProcesses.
- Tobias Wassermann (1/17) Nov 28 2007
- Carlos Santander (4/24) Nov 29 2007 Check http://www.digitalmars.com/ctg/ctgDefFiles.html#exports
Hi all, I have the following code, including some functions out of the psapi.dll (generated a lib with implib /noi /system psapi.lib C:\windows\system32\psapi.lib): extern (Windows) { HANDLE OpenProcess(uint dwDesiredAccess, BOOL bInheritHandle, uint dwProcessId); BOOL CloseHandle(HANDLE hHandle); } extern (C) { BOOL EnumProcesses(DWORD* pProcessIds, DWORD cb, DWORD* pBytesReturned); uint GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule, LPTSTR fileName, uint size); } void main(char[][] args) { ... uint[256] processIds; int ret = EnumProcesses(&processIds[0], processIds.length * uint.sizeof, &byteCount); ... for(uint i=0; i<processIds.length && i<byteCount/uint.sizeof; i++) { uint pid = processIds[i]; HANDLE hProcess = OpenProcess(0x410 /* QueryInformation | VMRead */, false, pid); if(cast(int)hProcess>0) CloseHandle(hProcess); } } Running this code works fine. I'll get a list like: ... But now I'll change the for-loop: for(uint i=0; i<processIds.length && i<byteCount/uint.sizeof; i++) { uint pid = processIds[i]; HANDLE hProcess = OpenProcess(0x410 /* QueryInformation | VMRead */, false, pid); if(cast(int)hProcess>0) { processFileName.length = 300; uint namelength = 0; namelength = GetModuleFileNameExA(hProcess, cast(HMODULE)null, processFileName.ptr, processFileName.length); CloseHandle(hProcess); } } With the call of GetModuleFileNameExA() my process id list will be corrupted, I'll get something like this: id doesn't exist, the next real id is 1288. I don't know why this happens, looking to the MSDN it gives me the following function header: DWORD GetModuleFileNameEx( HANDLE hProcess, HMODULE hModule, LPTSTR lpFilename, DWORD nSize ); So I think, my declaration within D should be correct: uint GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule, LPTSTR fileName, uint size); Do anybody have any suggestions? Thanks, Tobias
Nov 26 2007
How have you declared processFileName? Perhaps "char[] processFileName;"? Is it declared in main right next to processIds?
Nov 26 2007
Regan Heath Wrote:How have you declared processFileName? Perhaps "char[] processFileName;"? Is it declared in main right next to processIds?Yes, it is declared just before the for-loop as: char[] processFileName;
Nov 26 2007
Tobias Wassermann wrote:Regan Heath Wrote:The thought I had was that perhaps GetModuleFileNameExA was overwriting the wrong memory and corrupting the process list. Can you post a complete working piece of code which exhibits the bug, I'd like to help by debugging it locally. ReganHow have you declared processFileName? Perhaps "char[] processFileName;"? Is it declared in main right next to processIds?Yes, it is declared just before the for-loop as: char[] processFileName;
Nov 27 2007
Hi, here is the code: import std.stdio; import std.c.windows.windows; extern (Windows) HANDLE OpenProcess(uint dwDesiredAccess, BOOL bInheritHandle, uint dwProcessId); extern (C) { BOOL EnumProcesses(DWORD* pProcessIds, DWORD cb, DWORD* pBytesReturned); DWORD GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule, char* fileName, uint size); } void main(char[][] args) { uint[256] processIds; uint byteCount; char[] processFileName; int ret = EnumProcesses(processIds.ptr, processIds.length*uint.sizeof, &byteCount); if(ret!=0) { for(uint i=0; i<processIds.length && i<byteCount/uint.sizeof; i++) { if(processIds[i]==0) continue; uint pid = processIds[i]; HANDLE hProcess = OpenProcess(0x410 /* QueryInformation | VMRead */, false, pid); if(cast(int)hProcess>0) { processFileName.length = 300; uint namelength = 0; namelength = GetModuleFileNameExA(hProcess, cast(HMODULE)0, processFileName.ptr, processFileName.length); processFileName.length = namelength; writefln("=> %s", processFileName); CloseHandle(hProcess); } } } } If you comment out the namelength = GetModuleFileNameExA(hProcess, cast(HMODULE)0, processFileName.ptr, processFileName.length); line, all works fine. I also tried a char* allocated memory block with malloc() instead of the processFileName.ptr - so I thought about a bug between the communication between D and the Windows API, but the result is the same: a corrupted uint[] process-id-array. Bye Tobias Regan Heath Wrote:The thought I had was that perhaps GetModuleFileNameExA was overwriting the wrong memory and corrupting the process list. Can you post a complete working piece of code which exhibits the bug, I'd like to help by debugging it locally. Regan
Nov 27 2007
This is totally whacky... using the code posted below I get the following output: a 4 b 2000 c d e 883C00 300 f 883C00 300 g 883C00 300 h 884FF0 4296896 The output for both g and h are written with: writefln("h %p %d", processFileName.ptr, processFileName.length); The line between the two which causes this behaviour is processFileName = "Unknown".dup; PID of 4 is of course "System". Removing the call to GetModuleFileNameExA prevents the problem. My guess is that GetModuleFileNameExA is corrupting the stack somehow, perhaps the implib didn't correctly convert the dll to a lib. I used: implib /noi /system psapi.lib C:\windows\system32\psapi.dll The full code: import std.stdio; import std.c.windows.windows; extern (Windows) HANDLE OpenProcess(uint dwDesiredAccess, BOOL bInheritHandle, uint dwProcessId); extern (C) { BOOL EnumProcesses(DWORD* pProcessIds, DWORD cb, DWORD* pBytesReturned); DWORD GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule, char* fileName, uint size); } void main(char[][] args) { char[] processFileName; uint[] processIds; uint[] processIds2; uint byteCount; processIds.length = 256; int ret = EnumProcesses(processIds.ptr, processIds.length*uint.sizeof, &byteCount); if(ret!=0) { processIds.length = byteCount/uint.sizeof; processIds2 = processIds.dup; foreach(i, pid; processIds) { if(pid==0) continue; writefln("a %d", pid); HANDLE hProcess = OpenProcess(0x410 /* QueryInformation | VMRead */, false, pid); writefln("b %d", cast(int)hProcess); if(cast(int)hProcess>0) { writefln("c"); processFileName.length = 300; writefln("d"); uint namelength = 0; writefln("e %p %d", processFileName.ptr, processFileName.length); namelength = GetModuleFileNameExA(hProcess, cast(HMODULE)0, processFileName.ptr, processFileName.length); writefln("f %p %d", processFileName.ptr, processFileName.length); if (namelength == 0) { writefln("g %p %d", processFileName.ptr, processFileName.length); processFileName = "Unknown".dup; writefln("h %p %d", processFileName.ptr, processFileName.length); } else { writefln("i"); processFileName.length = namelength; writefln("j"); } break; writefln("%d. (%d) => %s", i, pid, processFileName); CloseHandle(hProcess); } } } }
Nov 27 2007
Could be an implib problem - I ported the code to C and compiled with DMC, the same thing. Used C-Code: #include <stdio.h> #include <windows.h> HANDLE OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId); CloseHandle(HANDLE hHandle); BOOL EnumProcesses(DWORD* pProcessIds, DWORD cb, DWORD* pBytesReturned); DWORD GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule, char* fileName, DWORD size); void main() { unsigned long processIds[256]; unsigned long byteCount; char processFileName[300]; int ret = EnumProcesses(&processIds[0], 256*sizeof(unsigned long), &byteCount); if(ret!=0) { for(DWORD i=0; i<256 && i<byteCount/sizeof(unsigned long); i++) { if(processIds[i]==0) continue; unsigned int pid = processIds[i]; HANDLE hProcess = OpenProcess(0x410, FALSE, pid); if((int)hProcess>0) { unsigned int namelength = GetModuleFileNameExA(hProcess, NULL, &processFileName[0], 300); printf("=> %s\r\n", processFileName); CloseHandle(hProcess); } } } } Compiled with: dmc -L/+psapi/noi ProcessFinderTest.c Uncomment the GetModuleFileNameExA-Call and all works fine - otherthise the array will be corrupted. Regan Heath Wrote:This is totally whacky... using the code posted below I get the following output: a 4 b 2000 c d e 883C00 300 f 883C00 300 g 883C00 300 h 884FF0 4296896 The output for both g and h are written with: writefln("h %p %d", processFileName.ptr, processFileName.length); The line between the two which causes this behaviour is processFileName = "Unknown".dup; PID of 4 is of course "System". Removing the call to GetModuleFileNameExA prevents the problem. My guess is that GetModuleFileNameExA is corrupting the stack somehow, perhaps the implib didn't correctly convert the dll to a lib. I used: implib /noi /system psapi.lib C:\windows\system32\psapi.dll
Nov 27 2007
Tobias Wassermann wrote:extern (Windows) HANDLE OpenProcess(uint dwDesiredAccess, BOOL bInheritHandle, uint dwProcessId); extern (C) { BOOL EnumProcesses(DWORD* pProcessIds, DWORD cb, DWORD* pBytesReturned); DWORD GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule, char* fileName, uint size); }Ah, I would tend to think that EnumProcesses and GetModuleFileNameExA should be extern(Windows) as well. All Win32 api's use STDCALL, which is what I believe extern(Windows) sets. -- Joel Lucsy "The dinosaurs became extinct because they didn't have a space program." -- Larry Niven
Nov 27 2007
Joel Lucsy wrote:Tobias Wassermann wrote:I thought the same thing but couldn't get it to link with extern(Windows) on those two. I've just looked at the psapi.h header in my SDK I see: #ifdef __cplusplus extern "C" { #endif BOOL WINAPI EnumProcesses( DWORD * lpidProcess, DWORD cb, DWORD * cbNeeded ); note the extern "C" there. I believe that confirms it's C linkage and not Windows linkage. Thanks for the suggestion though :) It seems the same problem occurs when Tobias calls the routines from C which suggests a problem with the implib used to convert the dll into a library. Reganextern (Windows) HANDLE OpenProcess(uint dwDesiredAccess, BOOL bInheritHandle, uint dwProcessId); extern (C) { BOOL EnumProcesses(DWORD* pProcessIds, DWORD cb, DWORD* pBytesReturned); DWORD GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule, char* fileName, uint size); }Ah, I would tend to think that EnumProcesses and GetModuleFileNameExA should be extern(Windows) as well. All Win32 api's use STDCALL, which is what I believe extern(Windows) sets.
Nov 27 2007
Regan Heath wrote:I've just looked at the psapi.h header in my SDK I see: #ifdef __cplusplus extern "C" { #endif BOOL WINAPI EnumProcesses( DWORD * lpidProcess, DWORD cb, DWORD * cbNeeded ); note the extern "C" there. I believe that confirms it's C linkage and not Windows linkage.Actually, the WINAPI is what sets STDCALL. I believe the extern "C" is for telling the compiler how to mangle, or not mangle in this case, the name of the function. -- Joel Lucsy "The dinosaurs became extinct because they didn't have a space program." -- Larry Niven
Nov 27 2007
The problem is: EnumProcesses() and GetModuleFileNameExA() both are marked as extern "C" within the psapi.h - the difference is: EnumProcesses works and GetModuleFileNameExA() in D and with DMC seems to corrupt the stack. If I move the C-ported code to the Microsoft Visual C++ and compile it, it works fine. On the other side: extern (C) within D is the only possibility to use for this two functions, if I use extern (Windows) I'll get linker errors (linker can not find symbols _EnumProcesses 12 and _GetModuleFileNameExA 16). With extern (Windows) it seems to be correct - remember: EnumProcesses() works fine, only GetModuleFileNameExA() causes the problem. Additional note: GetProcessImageFileNameA() (which could be an alternative to GetModuleFileNameExA()) causes the same problem. Joel Lucsy Wrote:Regan Heath wrote:I've just looked at the psapi.h header in my SDK I see: #ifdef __cplusplus extern "C" { #endif BOOL WINAPI EnumProcesses( DWORD * lpidProcess, DWORD cb, DWORD * cbNeeded ); note the extern "C" there. I believe that confirms it's C linkage and not Windows linkage.Actually, the WINAPI is what sets STDCALL. I believe the extern "C" is for telling the compiler how to mangle, or not mangle in this case, the name of the function. -- Joel Lucsy "The dinosaurs became extinct because they didn't have a space program." -- Larry Niven
Nov 27 2007
Tobias Wassermann escribió:The problem is: EnumProcesses() and GetModuleFileNameExA() both are marked as extern "C" within the psapi.h - the difference is: EnumProcesses works and GetModuleFileNameExA() in D and with DMC seems to corrupt the stack. If I move the C-ported code to the Microsoft Visual C++ and compile it, it works fine. On the other side: extern (C) within D is the only possibility to use for this two functions, if I use extern (Windows) I'll get linker errors (linker can not find symbols _EnumProcesses 12 and _GetModuleFileNameExA 16). With extern (Windows) it seems to be correct - remember: EnumProcesses() works fine, only GetModuleFileNameExA() causes the problem. Additional note: GetProcessImageFileNameA() (which could be an alternative to GetModuleFileNameExA()) causes the same problem.You could use a .def file to alias _EnumProcesses 12 to EnumProcesses. -- Carlos Santander Bernal
Nov 28 2007
How could this be done? I never made an alias via a def-file before ;)> On the other side: extern (C) within D is the only possibility to use for > this two functions, if I use extern (Windows) I'll get linker errors (linker > can not find symbols _EnumProcesses 12 and _GetModuleFileNameExA 16). > > With extern (Windows) it seems to be correct - remember: EnumProcesses() > works fine, only GetModuleFileNameExA() causes the problem. > > Additional note: GetProcessImageFileNameA() (which could be an alternative to > GetModuleFileNameExA()) causes the same problem. > You could use a .def file to alias _EnumProcesses 12 to EnumProcesses.
Nov 28 2007
Tobias Wassermann escribió:How could this be done? I never made an alias via a def-file before ;)Check http://www.digitalmars.com/ctg/ctgDefFiles.html#exports -- Carlos Santander Bernal> On the other side: extern (C) within D is the only possibility to use for > this two functions, if I use extern (Windows) I'll get linker errors (linker > can not find symbols _EnumProcesses 12 and _GetModuleFileNameExA 16). > > With extern (Windows) it seems to be correct - remember: EnumProcesses() > works fine, only GetModuleFileNameExA() causes the problem. > > Additional note: GetProcessImageFileNameA() (which could be an alternative to > GetModuleFileNameExA()) causes the same problem. > You could use a .def file to alias _EnumProcesses 12 to EnumProcesses.
Nov 29 2007