使用 unicode 时使用 WideCharToMultiByte 的正确方法

Correct way to use WideCharToMultiByte when using unicode

最近问了一个关于使用unicode的问题以及这里出现的问题:

在解决一个问题时,我遇到了另一个问题,这让我现在陷入了 ansi 和 unicode 之间的差异。我学到了很多,但经过将近一周的尝试,我似乎仍然无法解决这个问题。

我查看了 How do you properly use WideCharToMultiByte,因为我认为这就是我需要将 find_pid 从 unicode wchar 转换回 char 的方法,否则我会收到错误但无济于事。

感谢所有帮助,因为这让我发疯。

这是我要解决的问题:

 DWORD find_pid(const wchar_t* procname) {
// Dynamically resolve some functions
HMODULE kernel32 = GetModuleHandleA("Kernel32.dll");

using CreateToolhelp32SnapshotPrototype = HANDLE(WINAPI *)(DWORD, DWORD);
CreateToolhelp32SnapshotPrototype CreateToolhelp32Snapshot = (CreateToolhelp32SnapshotPrototype)GetProcAddress(kernel32, "CreateToolhelp32Snapshot");

using Process32FirstPrototype = BOOL(WINAPI *)(HANDLE, LPPROCESSENTRY32);
Process32FirstPrototype Process32First = (Process32FirstPrototype)GetProcAddress(kernel32, "Process32First");

using Process32NextPrototype = BOOL(WINAPI *)(HANDLE, LPPROCESSENTRY32);
Process32NextPrototype Process32Next = (Process32NextPrototype)GetProcAddress(kernel32, "Process32Next");

// Init some important local variables
HANDLE hProcSnap;
PROCESSENTRY32 pe32;
DWORD pid = 0;
pe32.dwSize = sizeof(PROCESSENTRY32);

// Find the PID now by enumerating a snapshot of all the running processes
hProcSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hProcSnap)
    return 0;

if (!Process32First(hProcSnap, &pe32)) {
    CloseHandle(hProcSnap);
    return 0;
}

while (Process32Next(hProcSnap, &pe32)) {
    if (lstrcmp(procname, pe32.szExeFile) == 0) {
        pid = pe32.th32ProcessID;
        break;
    }
}

// Cleanup
CloseHandle(hProcSnap);

return pid;
  }

//changing to std::wstring does not work, already tried
std::string parentProcess = "C:\hello.exe"
DWORD pid = find_pid(parentProcess.c_str());

您的问题很可能是您在编译时定义了 UNICODE。在这种情况下 PROCESSENTRY32 实际上是 PROCESSENTRY32W.

但是您调用的是 Process32First 的 ASCII 版本而不是 unicode 版本 Process32FirstW

大多数接受 ascii 和 unicode 参数的 winapi 函数有 2 个不同的版本:

  • ascii 码,通常以 A 结尾(或什么都没有)
  • 开启unicode,通常以W
  • 结尾
  • 根据是否定义 UNICODE 在 ascii 和 unicode 版本之间切换的宏。

你的情况是:

#ifdef UNICODE
#define Process32First Process32FirstW
#define Process32Next Process32NextW
#define PROCESSENTRY32 PROCESSENTRY32W
#define PPROCESSENTRY32 PPROCESSENTRY32W
#define LPPROCESSENTRY32 LPPROCESSENTRY32W
#endif  // !UNICODE

另请记住,Process32First 也会填充您的 PROCESSENTRY32(使用找到的第一个条目)。因此,对于您当前的实施,您将始终跳过第一个过程。


如果您正在构建 windows 应用程序,最好从一开始就决定是否要使用 ascii unicode。
(也可以选择与 TCHAR 和朋友一起编译)

在单个应用程序中混合使用它们会导致很多转换问题(因为并非每个 unicode 字符都可以在您的 ascii 代码页中表示)

此外,如果您仅依靠链接器导入函数而不是使用 GetProcAddress()

,您的生活会轻松很多

如果你想坚持使用 unicode(新项目的默认设置),你可以这样编写你的函数:

#include <windows.h>
#include <tlhelp32.h>

DWORD find_pid(const wchar_t* procname) {
    // Init some important local variables
    HANDLE hProcSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    PROCESSENTRY32 pe32;
    pe32.dwSize = sizeof(PROCESSENTRY32);

    // Find the PID now by enumerating a snapshot of all the running processes
    if (hProcSnap == INVALID_HANDLE_VALUE)
        return 0;

    if (!Process32First(hProcSnap, &pe32)) {
        CloseHandle(hProcSnap);
        return 0;
    }

    do {
        if (lstrcmp(procname, pe32.szExeFile) == 0) {
            CloseHandle(hProcSnap);
            return pe32.th32ProcessID;
        }
    } while (Process32Next(hProcSnap, &pe32));

    // not found
    CloseHandle(hProcSnap);
    return 0;
}

并这样称呼它:

std::wstring parentProcess = L"C:\hello.exe";
DWORD pid = find_pid(parentProcess.c_str());

// or just:
DWORD pid = find_pid(L"C:\hello.exe");

如果您希望您的应用程序能够针对 unicode 和 ascii 进行编译,则必须使用 TCHAR:

#include <windows.h>
#include <tlhelp32.h>
#include <tchar.h>

DWORD find_pid(const TCHAR* procname) {
    // Init some important local variables
    HANDLE hProcSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    PROCESSENTRY32 pe32;
    pe32.dwSize = sizeof(PROCESSENTRY32);

    // Find the PID now by enumerating a snapshot of all the running processes
    if (hProcSnap == INVALID_HANDLE_VALUE)
        return 0;

    if (!Process32First(hProcSnap, &pe32)) {
        CloseHandle(hProcSnap);
        return 0;
    }

    do {
        if (lstrcmp(procname, pe32.szExeFile) == 0) {
            CloseHandle(hProcSnap);
            return pe32.th32ProcessID;
        }
    } while (Process32Next(hProcSnap, &pe32));

    // not found
    CloseHandle(hProcSnap);
    return 0;
}

并这样称呼它:

DWORD pid = find_pid(_T("C:\hello.exe"));