简体   繁体   English

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

[英]Correct way to use WideCharToMultiByte when using unicode

I asked a question recently about using unicode and the problems that arose here:我最近问了一个关于使用 unicode 的问题以及这里出现的问题:

argument of type "WCHAR *" is incompatible with parameter of type "LPCSTR" in c++ “WCHAR *”类型的参数与 c++ 中“LPCSTR”类型的参数不兼容

In solving one problem, I encountered another one that has taken me now a literal rabbit hole of differences between ansi and unicode.在解决一个问题时,我遇到了另一个问题,这让我陷入了 ansi 和 unicode 之间差异的字面意思。 I have learnt a lot but I still cannot seem to solve this problem after almost a week of trying.我学到了很多东西,但经过将近一周的尝试,我似乎仍然无法解决这个问题。

I looked at How do you properly use WideCharToMultiByte as I think this is what I need to convert the find_pid from unicode wchar back to char otherwise I get erros but to no avail.我查看了如何正确使用 WideCharToMultiByte ,因为我认为这是我需要将 find_pid 从 unicode wchar 转换回 char 否则我会出错但无济于事。

All help little or small is appreciated as this is driving me mad.感谢所有或多或少的帮助,因为这让我发疯。

Here is what I am trying to solve:这是我要解决的问题:

 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());

Most likely your problem is that you're compiling with UNICODE defined.您的问题很可能是您正在使用定义的UNICODE编译。 In this case PROCESSENTRY32 will actually be PROCESSENTRY32W .在这种情况下, PROCESSENTRY32实际上是PROCESSENTRY32W

But you're calling the ASCII-Version of Process32First instead of the unicode-version Process32FirstW .但是您调用的是Process32First的 ASCII 版本,而不是 unicode 版本的Process32FirstW

Most of the winapi functions that accept both ascii & unicode arguments have 2 separate versions:大多数同时接受 ascii 和 unicode arguments 的 winapi 函数有 2 个单独的版本:

  • the ascii one, those usually end with A (or nothing) ascii 一个,通常以A结尾(或什么都没有)
  • the unicode on, those usually end with W unicode on,通常以W结尾
  • A macro that switches between the ascii and unicode versions depending on wether UNICODE is defined or not.根据是否定义了UNICODE ,在 ascii 和 unicode 版本之间切换的宏。

In your case that would be:在你的情况下,这将是:

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

Also keep in mind that Process32First will also populate your PROCESSENTRY32 (with the first found entry).另请记住, Process32First还将填充您的PROCESSENTRY32 (包含第一个找到的条目)。 So with your current implementation you'll always skip over the first process.因此,对于您当前的实施,您将始终跳过第一个过程。


If you're building a windows app it's best to decide from the start if you want to use ascii or unicode.如果您正在构建 windows 应用程序,最好从一开始就决定是使用 ascii还是unicode。
(there's also the option to make both compile with TCHAR & friends) (也可以选择使用TCHAR和朋友进行编译)

Mixing them within a single app will lead to a lot of conversion problems (since not every unicode character can be represented in your ascii code page)在单个应用程序中混合它们会导致很多转换问题(因为不是每个 unicode 字符都可以在您的 ascii 代码页中表示)

Also it'll make your life a lot easier if you just rely on the linker to import the functions instead of using GetProcAddress() .此外,如果您仅依靠 linker 来导入函数而不是使用GetProcAddress() ,它也会让您的生活更轻松。

If you want to stick with unicode (the default for new projects), you could write your function like this:如果您想坚持使用 unicode(新项目的默认设置),您可以这样编写 function:

#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;
}

and call it like this:并这样称呼它:

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

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

If you want your application to be able to compile for both unicode & ascii, you'll have to use TCHAR :如果您希望您的应用程序能够为 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;
}

and call it like this:并这样称呼它:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM