Ilink64错误:未解析的外部 - SendMessageW

时间:2016-05-26 10:03:22

标签: c++builder

我已将我的小项目从之前版本的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);

有人可以帮我解决这个问题吗?谢谢。 汤姆

2 个答案:

答案 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中提交了一份错误报告:

[RSP-15041] System.Messaging.hpp is missing #pragma alias statements for TMessageManager::SendMessage()

在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

感谢大家的帮助。