digitalmars.D - Re: Windows API: Strange behaviour after calling GetModuleFileNameExA
- Tobias Wassermann <mail tobias-wassermann.de> Nov 26 2007
- Regan Heath <regan netmail.co.nz> Nov 27 2007
- Tobias Wassermann <mail ingrid-wassermann.de> Nov 27 2007
- Regan Heath <regan netmail.co.nz> Nov 27 2007
- Tobias Wassermann <mail ingrid-wassermann.de> Nov 27 2007
- Joel Lucsy <jjlucsy gmail.com> Nov 27 2007
- Regan Heath <regan netmail.co.nz> Nov 27 2007
- Joel Lucsy <jjlucsy gmail.com> Nov 27 2007
- Tobias Wassermann <mail tobias-wassermann.de> Nov 27 2007
- Carlos Santander <csantander619 gmail.com> Nov 28 2007
- Tobias Wassermann <mail tobias-wassermann.de> Nov 28 2007
- Carlos Santander <csantander619 gmail.com> Nov 29 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: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;
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
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]; writefln("Process #%d - PID: %d", i, pid); 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]; printf("Process #%d - PID: %d\r\n", i, pid); 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: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.
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. Regan
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 ;)> 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.
Check http://www.digitalmars.com/ctg/ctgDefFiles.html#exports -- Carlos Santander Bernal
Nov 29 2007