我已将我的小项目从之前版本的Builder C ++转移到10.1柏林,我得到了未解决的外部错误。根据建议,我已将TMessage更改为TMessageBase。 下面提到的代码用作Win32,但在Win64上不起作用。
错误:
[ilink64 Error] Error: Unresolved external
'System::Messaging::TMessageManager::SendMessageW(System::TObject*,
System::Messaging::TMessageBase*, bool)' referenced from
C:\USERS\TOM\DOCUMENTS\EMBARCADERO\STUDIO\PROJECTS\PROJECT\WIN64\DEBUG\UNIT.O
代码:
TMessageManager *MessageManager;
TMessage__1 *Message;
Message = new TMessage__1("_FINISHED");
MessageManager = TMessageManager::DefaultManager;
MessageManager->SendMessage(this, Message, true);
有人可以帮我解决这个问题吗?谢谢。 汤姆
答案 0 :(得分:0)
这是C / C ++环境中Win32 API的经典问题。
TMessageManager
没有SendMessageW()
方法。它改为使用SendMessage()
方法。并且Win32 API具有自己的SendMessage()
函数,#define
标头中包含winuser.h
个语句,用于将通用SendMessage
名称映射到Ansi(SendMessageA
)或该函数的Unicode(SendMessageW
)变体:
WINUSERAPI
LRESULT
WINAPI
SendMessageA(
__in HWND hWnd,
__in UINT Msg,
__in WPARAM wParam,
__in LPARAM lParam);
WINUSERAPI
LRESULT
WINAPI
SendMessageW(
__in HWND hWnd,
__in UINT Msg,
__in WPARAM wParam,
__in LPARAM lParam);
#ifdef UNICODE
#define SendMessage SendMessageW
#else
#define SendMessage SendMessageA
#endif // !UNICODE
#define
语句是全局范围的,它们不尊重名称空间边界,类边界等。因此,此重新映射会影响SendMessage
名称的所有使用,无论其名称如何上下文。多年来,微软多次被要求在Win32 API for C ++中修复此问题,其中一个简单的修复(对于所有受影响的API函数)看起来像这样:
#if defined(UNICODE)
#define _MAP_WINNAME(n) n ## W
#else
#define _MAP_WINNAME(n) n ## A
#endif // UNICODE || _UNICODE
...
#ifdef __cplusplus
inline LRESULT WINAPI SendMessage(
__in HWND hWnd,
__in UINT Msg,
__in WPARAM wParam,
__in LPARAM lParam)
{
return _MAP_WINNAME(SendMessage)(hWnd, Msg, wParam, lParam);
}
#else
#ifdef UNICODE
#define SendMessage SendMessageW
#else
#define SendMessage SendMessageA
#endif // !UNICODE
#endif
干净,简单,没有歧义,尊重类/命名空间等等。但遗憾的是,微软并没有为其C ++用户做过这样的事情。
在任何情况下,对于您的情况,预处理器在编译器看到之前默默地将TMessageManager
的{{1}}方法的声明更改为SendMessage()
。预处理器也在更改您的代码,以便调用SendMessageW()
而不是MessageManager->SendMessageW(...)
。编译器非常乐意接受这些更改,从而在编译的目标文件中生成MessageManager->SendMessage(...)
的代码引用。
但是TMessageManager::SendMessageW()
方法的真实名称在实现它的预编译库中仍然是TMessageManager
。链接器找不到SendMessage()
的实现,因此它无法解析编译器生成的引用,从而导致错误。
Embarcadero实际上有一个针对这个底层Win32 API问题的解决方案(这是C ++ Builder中众所周知的一个问题) - #pragma alias
。受此问题影响的大多数VCL标头都有合适的TMessageManager::SendMessageW()
语句(在其Pascal源代码中使用相应的#pragma alias
语句来生成这些{$HPPEMIT}
语句)。但Embarcadero尚未将此解决方案应用于#pragma
。我已经在Quality Portal中提交了一份错误报告:
在Embarcadero修复它之前,您可以直接将以下修复应用于您自己的代码:
TMessageManager
在10.0西雅图(可能更早),别名略有不同:
#if defined(_VCL_ALIAS_RECORDS)
#if !defined(UNICODE)
#pragma alias "@System@Messaging@TMessageManager@SendMessageA$qqrxp14System@TObjectp29System@Messaging@TMessageBase"="@System@Messaging@TMessageManager@SendMessage$qqrxp14System@TObjectp29System@Messaging@TMessageBase"
#pragma alias "@System@Messaging@TMessageManager@SendMessageA$qqrxp14System@TObjectp29System@Messaging@TMessageBaseo"="@System@Messaging@TMessageManager@SendMessage$qqrxp14System@TObjectp29System@Messaging@TMessageBaseo"
#else
#pragma alias "@System@Messaging@TMessageManager@SendMessageW$qqrxp14System@TObjectp29System@Messaging@TMessageBase"="@System@Messaging@TMessageManager@SendMessage$qqrxp14System@TObjectp29System@Messaging@TMessageBase"
#pragma alias "@System@Messaging@TMessageManager@SendMessageW$qqrxp14System@TObjectp29System@Messaging@TMessageBaseo"="@System@Messaging@TMessageManager@SendMessage$qqrxp14System@TObjectp29System@Messaging@TMessageBaseo"
#endif
#endif
TMessageManager *MessageManager;
TMessage__1 *Message;
Message = new TMessage__1("_FINISHED");
MessageManager = TMessageManager::DefaultManager;
MessageManager->SendMessage(this, Message, true);
答案 1 :(得分:0)
我已经找到了解决方案。问题是Win64中的签名完全不是Win32。问题出在导入库“rtle.a”中,因为那里只提到TMessageE而不是TMessageBaseE。 Linker正在寻找TMessage的签名。它似乎是由“rtle.a”引起的两个错误的集合 - SendMessage vs SendMessageW和TMessage vs TMessageBase。 Win32中的库“rtle.lib”是正常的,它可以工作。 正确的代码在这里:
#if _WIN64
#if defined(UNICODE)
#pragma alias "_ZN6System9Messaging15TMessageManager12SendMessageWEPNS_7TObjectEPNS0_12TMessageBaseE"="_ZN6System9Messaging15TMessageManager11SendMessageEPNS_7TObjectEPNS0_12TMessageBaseE"
#pragma alias "_ZN6System9Messaging15TMessageManager12SendMessageWEPNS_7TObjectEPNS0_12TMessageBaseEb"="_ZN6System9Messaging15TMessageManager11SendMessageEPNS_7TObjectEPNS0_12TMessageBaseEb"
#else
#pragma alias "_ZN6System9Messaging15TMessageManager12SendMessageAEPNS_7TObjectEPNS0_12TMessageBaseE"="_ZN6System9Messaging15TMessageManager11SendMessageEPNS_7TObjectEPNS0_12TMessageBaseE"
#pragma alias "_ZN6System9Messaging15TMessageManager12SendMessageAEPNS_7TObjectEPNS0_12TMessageBaseEb"="_ZN6System9Messaging15TMessageManager11SendMessageEPNS_7TObjectEPNS0_12TMessageBaseEb"
#endif
#endif
感谢大家的帮助。