我作了一个动态链接库,我只希望用户通过头文件和lib文件来链接我的动态链接库。而不希望用户通过loadlibrary和GetProceAddress来调用我的输出函数。我找遍了MSDN,也没有找到一个合适的办法。
附MSDN关于动态和静态加载的说明:
隐式链接有时称为静态加载或加载时动态链接。显式链接有时称为动态加载或运行时动态链接。在隐式链接下,使用 DLL 的可执行文件链接到此 DLL 的创建者所提供的导入库(.LIB 文件)。使用 DLL 的可执行文件加载时,操作系统加载此 DLL。客户端可执行文件调用 DLL 的导出函数,就好像这些函数包含在可执行文件内一样。在显式链接下,使用 DLL 的可执行文件必须进行函数调用以显式加载和卸载此 DLL,并访问此 DLL 的导出函数。客户端可执行文件必须通过函数指针调用导出函数。可执行文件对两种链接方法可以使用同一个 DLL。另外,由于一个可执行文件可隐式链接到某个 DLL,而另一个可显式附加到此 DLL,故这些机制不是互斥的。为隐式链接到 DLL,可执行文件必须从 DLL 的提供程序获取下列各项: 包含导出函数和/或 C++ 类的声明的头文件(.H 文件)。
要链接的导入库(.LIB files)。(生成 DLL 时链接器创建导入库。)
实际的 DLL(.DLL 文件)。
使用 DLL 的可执行文件必须包括头文件,此头文件包含每个源文件中的导出函数(或 C++ 类),而这些源文件包含对导出函数的调用。从编码的角度讲,导出函数的函数调用与任何其他函数调用一样。若要生成调用可执行文件,必须与导入库链接。如果使用的是外部生成文件,请指定导入库的文件名,此导入库中列出了要链接到的其他对象 (.OBJ) 文件或库。操作系统在加载调用可执行文件时,必须能够定位 .DLL 文件。
在显式链接下,应用程序必须进行函数调用以在运行时显式加载 DLL。为显式链接到 DLL,应用程序必须:
调用 LoadLibrary(或相似的函数)以加载 DLL 和获取模块句柄。
调用 GetProcAddress,以获取指向应用程序要调用的每个导出函数的函数指针。由于应用程序是通过指针调用 DLL 的函数,编译器不生成外部引用,故无需与导入库链接。
使用完 DLL 后调用 FreeLibrary。
例如:
typedef UINT (CALLBACK* LPFNDLLFUNC1)(DWORD,UINT);
...HINSTANCE hDLL; // Handle to DLL
LPFNDLLFUNC1 lpfnDllFunc1; // Function pointer
DWORD dwParam1;
UINT uParam2, uReturnVal;hDLL = LoadLibrary("MyDLL");
if (hDLL != NULL)
{
lpfnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(hDLL,
"DLLFunc1");
if (!lpfnDllFunc1)
{
// handle the error
FreeLibrary(hDLL);
return SOME_ERROR_CODE;
}
else
{
// call the function
uReturnVal = lpfnDllFunc1(dwParam1, uParam2);
}
}
附MSDN关于动态和静态加载的说明:
隐式链接有时称为静态加载或加载时动态链接。显式链接有时称为动态加载或运行时动态链接。在隐式链接下,使用 DLL 的可执行文件链接到此 DLL 的创建者所提供的导入库(.LIB 文件)。使用 DLL 的可执行文件加载时,操作系统加载此 DLL。客户端可执行文件调用 DLL 的导出函数,就好像这些函数包含在可执行文件内一样。在显式链接下,使用 DLL 的可执行文件必须进行函数调用以显式加载和卸载此 DLL,并访问此 DLL 的导出函数。客户端可执行文件必须通过函数指针调用导出函数。可执行文件对两种链接方法可以使用同一个 DLL。另外,由于一个可执行文件可隐式链接到某个 DLL,而另一个可显式附加到此 DLL,故这些机制不是互斥的。为隐式链接到 DLL,可执行文件必须从 DLL 的提供程序获取下列各项: 包含导出函数和/或 C++ 类的声明的头文件(.H 文件)。
要链接的导入库(.LIB files)。(生成 DLL 时链接器创建导入库。)
实际的 DLL(.DLL 文件)。
使用 DLL 的可执行文件必须包括头文件,此头文件包含每个源文件中的导出函数(或 C++ 类),而这些源文件包含对导出函数的调用。从编码的角度讲,导出函数的函数调用与任何其他函数调用一样。若要生成调用可执行文件,必须与导入库链接。如果使用的是外部生成文件,请指定导入库的文件名,此导入库中列出了要链接到的其他对象 (.OBJ) 文件或库。操作系统在加载调用可执行文件时,必须能够定位 .DLL 文件。
在显式链接下,应用程序必须进行函数调用以在运行时显式加载 DLL。为显式链接到 DLL,应用程序必须:
调用 LoadLibrary(或相似的函数)以加载 DLL 和获取模块句柄。
调用 GetProcAddress,以获取指向应用程序要调用的每个导出函数的函数指针。由于应用程序是通过指针调用 DLL 的函数,编译器不生成外部引用,故无需与导入库链接。
使用完 DLL 后调用 FreeLibrary。
例如:
typedef UINT (CALLBACK* LPFNDLLFUNC1)(DWORD,UINT);
...HINSTANCE hDLL; // Handle to DLL
LPFNDLLFUNC1 lpfnDllFunc1; // Function pointer
DWORD dwParam1;
UINT uParam2, uReturnVal;hDLL = LoadLibrary("MyDLL");
if (hDLL != NULL)
{
lpfnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(hDLL,
"DLLFunc1");
if (!lpfnDllFunc1)
{
// handle the error
FreeLibrary(hDLL);
return SOME_ERROR_CODE;
}
else
{
// call the function
uReturnVal = lpfnDllFunc1(dwParam1, uParam2);
}
}
解决方案 »
- @__>高手们都来说说多语言界面实现的问题
- 新手上路,htons菜鸟问题,在线等....
- slider控件如何设置每次移动的步长。
- bho无法被myie(maxthon)加载的问题
- 已经一个星期了
- MTS和COM+问题
- MFC中WebBrowser控件加载html
- 超!超!!超!!!高分!!!! 那里有<windows操作系统原理>这本书下载!在线等待!!!!!!!!!!
- vs2008如何延时
- 在dll制作的服务里面loadlibrary调了其他dll文件
- 我在WIN2000高级服务器版下装了VC++6.0但系统老是报错,说内存什么的只能为Read
- 如何由CString s="12"转换为int t=12
应用程序的代码调用导出 DLL 函数时发生隐式链接。当调用可执行文件的源代码被编译或被汇编时,DLL 函数调用在对象代码中生成一个外部函数引用。要解析此外部引用,应用程序必须与 DLL 的创建者所提供的导入库(.LIB 文件)链接。导入库仅包含加载 DLL 的代码和实现 DLL 函数调用的代码。在导入库中找到外部函数后,会通知链接器此函数的代码在 DLL 中。要解析对 DLL 的外部引用,链接器只需向可执行文件中添加信息,通知系统在进程启动时应在何处查找 DLL 代码。系统启动包含动态链接引用的程序时,它使用程序的可执行文件中的信息定位所需的 DLL。如果系统无法定位 DLL,它将终止进程并显示一个对话框来报告错误。否则,系统将 DLL 模块映射到进程的地址空间中。如果任何 DLL 具有(用于初始化代码和终止代码的)入口点函数,操作系统将调用此函数。在传递到入口点函数的参数中,有一个指定用以指示 DLL 正在附带到进程的代码。如果入口点函数没有返回 TRUE,系统将终止进程并报告错误。最后,系统修改进程的可执行代码以提供 DLL 函数的起始地址。与程序代码的其余部分一样,DLL 代码在进程启动时映射到进程的地址空间中,且仅当需要时才加载到内存中。因此,由 .DEF 文件用来在 Windows 的早期版本中控制加载的 PRELOAD 和 LOADONCALL 代码属性不再具有任何意义。显式链接
大部分应用程序使用隐式链接,因为这是最易于使用的链接方法。但是有时也需要显式链接。下面是一些使用显式链接的常见原因: 直到运行时,应用程序才知道需要加载的 DLL 的名称。例如,应用程序可能需要从配置文件获取 DLL 的名称和导出函数名。
如果在进程启动时未找到 DLL,操作系统将终止使用隐式链接的进程。同样是在此情况下,使用显式链接的进程则不会被终止,并可以尝试从错误中恢复。例如,进程可通知用户所发生的错误,并让用户指定 DLL 的其他路径。
如果使用隐式链接的进程所链接到的 DLL 中有任何 DLL 具有失败的 DllMain 函数,该进程也会被终止。同样是在此情况下,使用显式链接的进程则不会被终止。
因为 Windows 在应用程序加载时加载所有的 DLL,故隐式链接到许多 DLL 的应用程序启动起来会比较慢。为提高启动性能,应用程序可隐式链接到那些加载后立即需要的 DLL,并等到在需要时显式链接到其他 DLL。
显式链接下不需将应用程序与导入库链接。如果 DLL 中的更改导致导出序号更改,使用显式链接的应用程序不需重新链接(假设它们是用函数名而不是序号值调用 GetProcAddress),而使用隐式链接的应用程序必须重新链接到新的导入库。
下面是需要注意的显式链接的两个缺点: 如果 DLL 具有 DllMain 入口点函数,则操作系统在调用 LoadLibrary 的线程上下文中调用此函数。如果由于以前调用了 LoadLibrary 但没有相应地调用 FreeLibrary 函数而导致 DLL 已经附加到进程,则不会调用此入口点函数。如果 DLL 使用 DllMain 函数为进程的每个线程执行初始化,显式链接会造成问题,因为调用 LoadLibrary(或 AfxLoadLibrary)时存在的线程将不会初始化。
如果 DLL 将静态作用域数据声明为 __declspec(thread),则在显式链接时 DLL 会导致保护错误。用 LoadLibrary 加载 DLL 后,每当代码引用此数据时 DLL 就会导致保护错误。(静态作用域数据既包括全局静态项,也包括局部静态项。)因此,创建 DLL 时应避免使用线程本地存储区,或者应(在用户尝试动态加载时)告诉 DLL 用户潜在的缺陷。
如果我在DllMain中调用LoadLibrary或者使用__declspec(thread),我觉得这不是一个理想的解决办法。
请帮我回答,分值可以追加到200分。
=================不理解,为什么不用静态的库呢?
你就当作是一个应聘面试题就行了。
我只要答案,不需要why not?
然后jmp或call进去,你能拦的住吗
不过我猜想反正动态加载是通过调用loadlibrary和getproceaddress实现的。只要这两个函数有一个执行失败,就无法调用了。
如果实在没有更好的办法的话,我不妨就用dllmain调用loadlibrary,导致循环加载使得loadlibrary返回NULL实现它。不过我敢确信这不是对方要的答案。
关键是你所谓的授权用户和未授权用户的差别在哪里?授权用户用手头有.lib和.h?我的意思是授权用户手里得有别人没有的信息。
不过我最关心是答案,也就是说在Visual C++的链接选项中,是否存在这样的设置。
所以应该只能在GetProcessAddress上打算,但GetProcessAdress的结果只依赖于DLL文件的导出函数,即DLL文件的结构决定了结果,所以我想我想不出办法了。
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
MessageBox(0,"真不好意思,这么简单的问题就要了你200分。不过我可花了20分钟建了3个工程做实验,一下就试出来了。","太简单了",MB_OK);
if(lpReserved) return TRUE; else return FALSE;//答案就是这一句
}
好的,我试验一下,如果满足上面要求,决不食言!
3Q very much!
如果用两个测试程序(分别用两种链接方式)调用同一个动态链接库,将DLL设为启动程序,两个项目的输出文件设为加载调试程序,当跟踪到DLLMain函数时就会发现这一点。
谢谢 icansaymyabc(学习与进步) ,分先欠着,我一定给您。
预祝明天面试成功!