使用 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"));
最近问了一个关于使用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"));