编写DLL过程中遇到的一些问题

在编写DLL过程中,遇到由于DEF文件中的EXPORTS函数名与库文件中的函数名冲突导致的链接错误。解决方法是修改DEF文件中的函数名以避免冲突。然而,当使用private关键字时,虽然能阻止函数在导入库中暴露,但会导致应用程序隐式调用DLL时的链接错误,因为private函数不被放入导入库。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

关于编写DLL时,DEF文件(模板文件)的输出(EXPORTS)函数出现链接错误:

其中.def文件如下:

LIBRARY "usb_fm.dll"

EXPORTS   

Initialize    @1 private

链接错误信息如下:

Linking...

fm.def : warning LNK4022: cannot find unique match for symbol 'Initialize'

fm.def : warning LNK4002: "void __cdecl Initialize(struct HWND__ *)" (?Initialize@@YAXPAUHWND__@@@Z) defined in ./debug/main_operation.obj

fm.def : warning LNK4002: "public: virtual long __stdcall CAggDirectDraw::Initialize(struct _GUID *)" (?Initialize@CAggDirectDraw@@UAGJPAU_GUID@@@Z) defined in D:/InstallSoftware/Microsoft SDKs/Windows/v6.0/Samples/Multimedia/DirectShow/BaseClasses/Debug/Strmbasd.lib

fm.def : warning LNK4002: "public: virtual long __stdcall CAggDrawSurface::Initialize(struct IDirectDraw *,struct _DDSURFACEDESC *)" (?Initialize@CAggDrawSurface@@UAGJPAUIDirectDraw@@PAU_DDSURFACEDESC@@@Z) defined in D:/InstallSoftware/Microsoft SDKs/Windows/v6.0/Samples/Multimedia/DirectShow/BaseClasses/Debug/Strmbasd.lib

fm.def : warning LNK4002: "private: long __thiscall CDynamicOutputPin::Initialize(void)" (?Initialize@CDynamicOutputPin@@AAEJXZ) defined in D:/InstallSoftware/Microsoft SDKs/Windows/v6.0/Samples/Multimedia/DirectShow/BaseClasses/Debug/Strmbasd.lib

fm.def : warning LNK4002: "protected: void __thiscall CDHtmlDialog::Initialize(void)" (?Initialize@CDHtmlDialog@@IAEXXZ) defined in D:/InstallSoftware/VS2005/VC/atlmfc/lib/uafxcw.lib

fm.def : warning LNK4002: "public: long __thiscall CDataSourceControl::Initialize(void)" (?Initialize@CDataSourceControl@@QAEJXZ) defined in D:/InstallSoftware/VS2005/VC/atlmfc/lib/uafxcw.lib

fm.def : error LNK2001: unresolved external symbol Initialize

E:/PersonalProject/usb_fm/Debug/usb_fm.lib : fatal error LNK1120: 1 unresolved externals

从上面的错误可以看出提示Initialize函数没有定义,可我明明定义了啊?

找了半天,最后发现输出的警告信息中也是关于Initialize的,仔细一看,推测错误产生的原因应该是:因为在DLL的DEF文件中定义EXPORTS函数时,只需要指明函数名称,而不需要指出函数的返回值及参数(因此这种类型的错误只有编写DLL时才可能出现),在我的程序中输出了一个Initialize函数,但很多库文件(.LIB)也包含和Initialize同名的函数,所以出现链接错误。

于是将Initialize改为InitialFM,问题果然解决~~ 修改后的.def文件如下:

LIBRARY "usb_fm.dll"

EXPORTS   

InitialFM    @1 private

现在DLL工程可以成功通过编译,并生成了dll文件和lib文件。

接下来我在一个应用程序中显示调用dll中的函数,也可以成功;但当我用隐式的方法调用dll中的函数时,应用程序编译出现链接错误!

找了很久都没有发现问题,最后网上问到的!主要是private关键字引起的,MSDN中关于private的解释如下: The optional keyword PRIVATE prevents entryname from being placed in the import library generated by LINK. It has no effect on the export in the image also generated by LINK.

可选的PRIVATE关键字禁止将entryname(这里指函数名InitialFM)放到由LINK生成的导入库中。它对同样是由LINK生成的映像的导出无效。也就是说private关键字可以阻止应用程序隐式调用dll中的函数,因为private函数不会放到LINK生成的导入库,但不会阻止应用程序显式调用dll中的函数,因为private函数还是会放到LINK生成的导出库。

其实早就怀疑private了,但查以前写的COM组件,发现.def文件中的函数也是private的,也就没有多想了。

COM组件的输出(EXPORT)函数一般是private的原因:

因为DllRegisterServer这些dll中的函数本质上是由COM在运行时调用的,所以要禁止静态的编译后link,只容许被动态加载(也就是显式调用),所以只能定义成PRIVATE的,否则出错。

关于更多.def文件和dll的编写资料可在MSDN中通过索引查询“.def”和“DLLs”获取。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值