more simply api, way not exist.
1.) wrong return type - MODULEENTRY32
. really impossible return structure, which not fit generic register size. when compiler view T fn(..) { * }
it silently change this to void fn(T* t, ...) {*}
and in your code Entry
will be copied, what really not need. you must not try return MODULEENTRY32
but pass pointer to it as function argument.
2.) you lost error value. the GetModule
can fail by different reasons - can not exist process with such id (STATUS_INVALID_CID
), you can fail open target process (STATUS_ACCESS_DENIED
), module can simply not exist in process. without returned error value - you can not know reason why function fail. really the best practice always return win32 error code (or NTSTATUS
) from function.
3.) why you use module name as ansi string ? this is always bad and error design. use unicode name format. and you will be not need convert it (i already not say that if module name (this is rarely and never for system modules) use non english chars - it can not have correct ansi name at all(and depend from system locale - you encode it on self comp in one locale, on another comp - can be another locale. but ansi name depend from it).
4.) so signature of function must be ULONG GetModule(DWORD th32ProcessID, MODULEENTRY32* Entry, PCWSTR szModule)
5.) use wcscmp
is wrong here. we need case insensitive compare. - _wcsicmp
6.) Return the module base 0x0 if we don't find any module - how i say - we need return appropriate error code in this case, instead set base address at 0 (we can left it undefined). client code must check not base address for 0, but error code for 0 (NOERROR
).
7.) not forget about 32-64 bit issues here (are your and target process have some bit-ness)
so code can look like:
ULONG GetModule(DWORD th32ProcessID, MODULEENTRY32* Entry, PCWSTR szModule)
{
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, th32ProcessID);
if (hSnapshot != INVALID_HANDLE_VALUE)
{
ULONG dwError = ERROR_NOT_FOUND;
Entry->dwSize = sizeof(MODULEENTRY32);
if (Module32FirstW(hSnapshot, Entry))
{
do
{
if (!_wcsicmp(Entry->szModule, szModule))
{
dwError = NOERROR;
break;
}
} while (Module32NextW(hSnapshot, Entry));
}
CloseHandle(hSnapshot);
return dwError;
}
// return RtlGetLastNtStatus();
// this is much more better compare GetLastError();
return GetLastError();
}
and usage:
MODULEENTRY32 Entry;
if (ULONG dwError = GetModule(*, &Entry, L"*"))
{
// error, dont touch Entry
}
else
{
//ok, use Entry
}