如何正确解决 Windows API 和 DirectX API & other API 之间的宏冲突 (GetMessage) 由微软开发

How to properly solve macro conflict (GetMessage) between Windows API and DirectX API & other APIs developed by microsoft

问题:

我正在开发一个桌面 D3D12 应用程序,所以自然地,我需要 <Windows.h><WinUser.h> 来创建一个 window,但是有一个 GetMessage 宏与 IDXGIInfoQueue::GetMessageID3D12InfoQueue::GetMessage(以及 ID3D11InfoQueue::GetMessage ID3D10InfoQueue::GetMessage

冲突

我在 Whosebug 和 Github 上发现的关于此宏的其他讨论都说应该将其 GetMessage 函数名称更改为其他名称,但很明显,因为我没有开发 DirectX API,我无法控制这个...

我将 Windows API 和 DirectX API header 一起包含在预编译的 header 文件中

Imperfect/Failed 目前我尝试过的解决方案:

  1. 我可以忽略这个问题或者在我调用这些方法之前写#undef GetMessage,那么它们的名字将变成IDXGIInfoQueue::GetMessageWID3D12InfoQueue::GetMessageWID3D11InfoQueue::GetMessageW ...
// RenderPipeline.cpp
CComPtr<IDXGIInfoQueue> DXGIInfoQueue;
CComPtr<ID3D12InfoQueue> D3D12InfoQueue;
...
#undef GetMessage
SIZE_T Size = 0;
//HRESULT result = DXGIInfoQueue->GetMessage(0, nullptr, &Size);  // compile error
HRESULT result = DXGIInfoQueue->GetMessageW(0, nullptr, &Size);  // compile success, runs ok
//HRESULT result = D3D12InfoQueue->GetMessage(0, nullptr, &Size);  // compile error
HRESULT result = D3D12InfoQueue->GetMessageW(0, nullptr, &Size);  // compile success, runs ok
...

一开始我有点惊讶,虽然名字不对,但编译成功,这些方法仍然可以在运行时正常调用(在名字GetMessageW下),然后我认为之所以可行,是因为相应的原始方法仍然采用相同的参数,并且它们的地址仍在其接口的虚方法 table 中的相同索引位置,这是它们在虚方法中的索引 table 而不是他们在这里相关的名字,所以代码在这里运行正常。但是,使用错误的名称仍然感觉不对...

  1. 如果我在包含 DirectX headers 之前写 #undef GetMessage,我实际调用的代码 GetMessage 从 window 消息 queue 将是错误的,当然我可以将其从 GetMessage(&Msg...) 更改为 GetMessageW(&Msg...) 但我现在有点习惯使用这些宏 ...
// pch.h
...
#include <Windows.h>
#undef GetMessage
...

// Run.cpp
...
MSG Msg;
//while (GetMessage(&Msg, nullptr, 0, 0)) {  // compile error, but I want this to work because it looks nicer
while (GetMessageW(&Msg, nullptr, 0, 0)) {  // compile success
    TranslateMessage(&Msg);
    DispatchMessage(&Msg);
}
...
  1. 我尝试在#include <Windows.h>之前的预编译header文件中添加#define NOUSER(之后是#undef NOUSER),然后在[=]中再次添加#include <WinUser.h> 36=] 我在其中处理 window 消息,但这没有用,宏没有返回,因为 <WinUser.h> 文件中有 #ifndef _WINUSER_ #define _WINUSER_ 定义防止该文件被多次包含...
// pch.h
...
#define NOUSER
#include <Windows.h>
#undef NOUSER
...

// Run.cpp
...
#include <WinUser.h>  // doesn't work...
MSG Msg;
//while (GetMessage(&Msg, nullptr, 0, 0)) {  // compile error
while (GetMessageW(&Msg, nullptr, 0, 0)) {  // compile success
    TranslateMessage(&Msg);
//  DispatchMessage(&Msg);  // compile error
    DispatchMessageW(&Msg);  // compile success
}
...

旁注:

GetMessage 不是唯一产生名称冲突的宏,我记得有一个 GetObject 宏可以与媒体基础 API 中具有相同名称的方法冲突(这个API当然也是微软开发的)...有点懊恼微软这些年不考虑解决这些宏冲突...

编辑: 感谢大家 comments/answers,最后我听取了 Remy Lebeau 的建议,将我的 DirectX 代码放入解决方案中的一个单独的项目中(并在其 pch header 中添加了 #define NOUSER)并且它的工作方式如下打算

这里不需要做任何事情,您的代码中也没有任何冲突或问题。你自己已经看过了

it compiled successfully and these methods can still be called normally runtime

你更正了 - 在虚拟 table 中不是按名称而是按地址调用的方法。 winuser.h 总是包含在 IDXGIInfoQueue 声明之前,因此已经在接口声明中 GetMessage 扩展为 GetMessageWGetMessageA。在您的代码中相同,它调用接口上的方法(DXGIInfoQueue->GetMessage)。结果名称一致。

But still, it just feels wrong using the wrong names...

这里你有错误的感觉。再次 - 一切正常,无需做任何事情

最近我找到了一个对我来说更优雅的解决方案;我可以在包含 DirectX headers:

的同时执行此操作
#pragma push_macro("GetMessage")
#undef GetMessage // temporarily disable GetMessage macro
#include <DXGI.h> // now GetMessage won't be named GetMessageW anymore
#include <D3D11.h>
// and possibly some other headers...
#pragma pop_macro("GetMessage") // now GetMessage macro returns to normal