如何正确解决 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::GetMessage
和 ID3D12InfoQueue::GetMessage
(以及 ID3D11InfoQueue::GetMessage
ID3D10InfoQueue::GetMessage
)
冲突
我在 Whosebug 和 Github 上发现的关于此宏的其他讨论都说应该将其 GetMessage
函数名称更改为其他名称,但很明显,因为我没有开发 DirectX API,我无法控制这个...
我将 Windows API 和 DirectX API header 一起包含在预编译的 header 文件中
Imperfect/Failed 目前我尝试过的解决方案:
- 我可以忽略这个问题或者在我调用这些方法之前写
#undef GetMessage
,那么它们的名字将变成IDXGIInfoQueue::GetMessageW
,ID3D12InfoQueue::GetMessageW
,ID3D11InfoQueue::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 而不是他们在这里相关的名字,所以代码在这里运行正常。但是,使用错误的名称仍然感觉不对...
- 如果我在包含 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);
}
...
- 我尝试在
#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
扩展为 GetMessageW
或GetMessageA
。在您的代码中相同,它调用接口上的方法(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
问题:
我正在开发一个桌面 D3D12 应用程序,所以自然地,我需要 <Windows.h>
和 <WinUser.h>
来创建一个 window,但是有一个 GetMessage 宏与 IDXGIInfoQueue::GetMessage
和 ID3D12InfoQueue::GetMessage
(以及 ID3D11InfoQueue::GetMessage
ID3D10InfoQueue::GetMessage
)
我在 Whosebug 和 Github 上发现的关于此宏的其他讨论都说应该将其 GetMessage
函数名称更改为其他名称,但很明显,因为我没有开发 DirectX API,我无法控制这个...
我将 Windows API 和 DirectX API header 一起包含在预编译的 header 文件中
Imperfect/Failed 目前我尝试过的解决方案:
- 我可以忽略这个问题或者在我调用这些方法之前写
#undef GetMessage
,那么它们的名字将变成IDXGIInfoQueue::GetMessageW
,ID3D12InfoQueue::GetMessageW
,ID3D11InfoQueue::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 而不是他们在这里相关的名字,所以代码在这里运行正常。但是,使用错误的名称仍然感觉不对...
- 如果我在包含 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);
}
...
- 我尝试在
#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
扩展为 GetMessageW
或GetMessageA
。在您的代码中相同,它调用接口上的方法(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