C++ 获取进程标识符始终返回0

C++ 获取进程标识符始终返回0,c++,windows,winapi,C++,Windows,Winapi,所以这里的代码总是为我的进程标识符返回0 ::std::uint32_t GetPID(const char* windowName) { ::std::uint32_t pID; // when this is initialized to 0, my function returns 0 otherwise it returns rand HWND hWindow = FindWindow(NULL, (LPCWSTR)windowName); GetWindow

所以这里的代码总是为我的进程标识符返回0

::std::uint32_t GetPID(const char* windowName)
{
    ::std::uint32_t pID; // when this is initialized to 0, my function returns 0 otherwise it returns rand

    HWND hWindow = FindWindow(NULL, (LPCWSTR)windowName);

    GetWindowThreadProcessId(hWindow, &pID);

    return pID;
}
我尝试过使用我的另一个函数,该函数也可以获取进程标识符,它以前对我来说工作得非常完美,但它也返回了0。我也尝试过其他进程名称,但都不起作用

我试着调试它,发现当我将pID初始化为0时,函数返回0。我认为这是因为FindWindow的HWND在某种程度上是无效的,因此GetWindowThreadProcessId没有将我的pID变量设置为进程id,所以它保持为0。另外,当我刚刚定义pID时,我的函数返回的随机数不是pID的垃圾内存,因为它没有初始化,就好像FindWindow的句柄无效,因此在GetWindowThreadProcessId处没有为变量pID分配进程标识符一样

我认为这与FindWindow函数有关,但我尝试过输入其他进程名称,但没有任何更改。我可以使用PROCESSENTRY32,但我想知道这有什么问题


我觉得答案就在眼前,不知什么原因,我无法找到答案。

采用字符串参数的旧windows API函数有三种变体,一种采用窄字符串char,一种采用宽字符串wchar\t,另一种根据UNICODE宏设置tchar\t采用窄或宽

总是使用窄字符串的函数可以通过函数名末尾的A来标识,而总是使用宽字符串的函数可以通过W来标识

最近的API函数可能根本不提供狭义的ANSI版本,在这种情况下,上述内容不适用。然而,芬德温多并不是其中之一

您正在使用变量类型的变量,显然UNICODE设置为您更改了,因为您说代码以前工作过。但是,我确信您后来添加了LPCWSTR强制转换,因为无论哪种情况,该强制转换都是错误的

LPCWSTRwindowName将const char*指针强制转换为const wchar_t*指针LPCWSTR是const wchar_t*,但它实际上不会将指针指向的窄字符转换为宽字符。例如,在Windows上,字符宽度为两个字节,因此当函数取消引用指针时,windowName指向的数组的每两个字节都将被解释为一个字符。但这显然毫无意义。特别是空终止符在char中仅为一个字节,但在wchar\u t中需要为两个字节。因此,windowName指向的字符数组不太可能包含wchar_t*的正确对齐的空终止符,从而在函数迭代wchar_t*超出边界时导致未定义的行为

因此,在最好的情况下,您将FindWindow胡言乱语作为窗口名,但很可能会有未定义的行为

如果要传递窄字符串,请使用适当的函数:

HWND hWindow = FindWindowA(NULL, windowName);
一般来说,永远不要使用C风格的强制转换,因为它们可以做许多意想不到的事情。相反,使用静态转换或重新解释转换或任何其他合适的转换。单个静态类型转换通常没有问题,但是一旦您需要使用reinterpret类型转换,您就应该非常小心它实际上在做什么。C样式转换可以执行这些转换中的任何一种,因此需要特别小心才能隐藏此要求

您还应该始终检查API调用的结果是否存在错误,并正确处理这些错误。这很可能表明FindWindow调用有问题,即使调用中已经存在未定义的行为。这也是必要的,因为您可能无法保证在对GetPID的所有调用中都能找到窗口,然后返回的HWND将不是有效的窗口句柄:

HWND hWindow = FindWindowA(NULL, windowName);

if(!hWindow) {
    // handle error
}

不要像在LPCWSTRwindowName中那样使用C样式转换,而是使用reinterpret_cast,并且只有在您完全确定知道它的作用时才使用它。在这里,你的演员没有按照你的意愿去做。我想说的是,你的窗口找不到,因为名字错了。做一些错误检查。LPCWSTRwindowName你认为这是做什么的?我以为LPCWSTR将我的const char*转换为LPCWSTR@hobbes1235是的,但那没有意义,看我的答案。是的,这解决了它。我知道函数之间的区别,但我认为在需要时只需转换字符串就更容易了。我明白为什么现在这是个很糟糕的主意。谢谢:@hobbes1235,因为你可能没有意识到:如果你认为答案对解决问题最有帮助,你可以接受,请参阅。不过,您不需要这样做。@ErykSun在这种情况下,OP可能应该将函数参数从const char*windowName更改为const wchar\u t*windowName或LPCWSTR windowName,并将调用者端调整为仅使用宽字符串。@ErykSun啊,好的,谢谢。我在这个问题上加了一段话,但实际上我在Windows上没有太多经验,所以如果
ng是错误的、不精确的或不可理解的,请随意编辑我的答案,或让我知道。在我看来,这里最大的问题是缺乏错误检查。如果将一个api调用的输出传递给另一个api调用,而不检查错误,那么如何判断哪个调用失败?