Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
248 views
in Technique[技术] by (71.8m points)

c++ - How To Fix Unicode/MultiByte Compatibility Issues

I want to leave my project on multibyte instead of switching it to Unicode. I'm getting some errors trying to make my types work together as follows (VS2019 set to multibye):

The original error is: argument of type "char *" is incompatible with type "const wchar_t *" for the following line:

if (!wcscmp(ModuleEntry.szModule, ModuleName)

ModuleEntry is of type MODULEENTRY32

If I change the type of ModuleEntry to MODULEENTRY32W I get the following error:

Argument type "MODULEENTRY32W" is incompatible with type "LPMODULEENTRY32".

Here's the full function for reference:

DWORD GetModuleBaseAddress(const wchar_t* ModuleName, DWORD ProcessId) {
    MODULEENTRY32 ModuleEntry = { 0 };
    HANDLE SnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, ProcessId);

    if (!SnapShot)
        return NULL;

    ModuleEntry.dwSize = sizeof(ModuleEntry);

    if (!Module32First(SnapShot, &ModuleEntry))
        return NULL;
    do {    
        if (!wcscmp(ModuleEntry.szModule, ModuleName)) {        
            CloseHandle(SnapShot);
            return (DWORD)ModuleEntry.modBaseAddr;
        }   
    } while (Module32Next(SnapShot, &ModuleEntry));

    CloseHandle(SnapShot);
    return NULL;
}

Thank you.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

First, you are leaking the SnapShot handle if Module32First() fails.

Second, you are using the TCHAR-based version of the Module32 API, but you are passing in wchar_t Unicode data to compare the enumerated module data to. You have your project setup to MultiByte, which means TCHAR maps to char and TCHAR-based APIs map to ANSI APIs.

So, you are actually calling the ANSI version of the Module32 API, ie MODULEENTRY32 maps to MODULEENTRY32A, and Module32First()/Module32Next() map to Module32FirstA()/Module32NextA().

You cannot pass char data to wcscmp(), and you cannot pass wchar_t data to strcmp(). So, if you continue using the ANSI APIs, then you MUST perform a data conversion at runtime in one direction or the other, either to:

  • convert the char module data to wchar_t via MultiByteToWieChar()

  • convert the wchar_t comparison data to char via WideCharToMultiByte()

Only then can you use an appropriate function to compare the two datas.

Since you are passing in wchar_t data for comparison, you should explicitly call the Unicode version of the Module32 API, not the TCHAR version. You do not have to set the whole project to Unicode in order to use Unicode APIs, eg:

void* GetModuleBaseAddress(const wchar_t* ModuleName, DWORD ProcessId)
{
    HANDLE SnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, ProcessId);
    if (SnapShot)
    {
        MODULEENTRY32W ModuleEntry = { 0 };
        ModuleEntry.dwSize = sizeof(ModuleEntry);

        if (Module32FirstW(SnapShot, &ModuleEntry))
        {
            do
            {
                if (wcscmp(ModuleEntry.szModule, ModuleName) == 0)
                {
                    CloseHandle(SnapShot);
                    return ModuleEntry.modBaseAddr;
                }   
            }
            while (Module32NextW(SnapShot, &ModuleEntry));
        }

        CloseHandle(SnapShot);
    }

    return NULL;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...