⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 19.7.2 调用约定.txt

📁 网上第一本以TXT格式的VC++深入详解孙鑫的书.全文全以TXT格式,并每一章节都分了目录,清晰易读
💻 TXT
字号:
19.7.2 调用约定
如果这时我们将 Dll2工程中导出函数的调用约定改为标准约定,那么生成的 DLL,其导出函数名字会被改编吗?我们可以试验一下,在 VC++开发环境中重新打开 Dll2工程,然后修改 add和 subtract函数的定义,使它们都采用标准调用约定,结果如例 19-22所示。 
例19-22 

int 	_stdcall add(int a , int b) return a+b; 
irlt-stdcall subtract (int a , int b) 
return a-b; 
利用 Build命令生成最新的 Dll2.dll,然后利用 Dumpbin命令的 exports选项查看该 DLL的导出信息,将会发现导出函数的名字仍是 Dll2.def文件中列出的函数名称: add和 subtract,没有发生名字改编。
然后将最新的 Dll2.dll文件复制到 DllTest程序所在目录下。这时应注意,因为该 DLL中导出函数的调用约定发生了改变,那么测试程序 DllTest .中的调用该函数的代码也需要进行相应的改变,即在定义 ADDPROC这一函数指针类型时,也应该定义一个标准调用约定的函数指针类型,否则访问时将会出错。这时, CDllTestDlg类的 OnBtnAdd函数代码如例 19-23所示,其中加灰显示的那条代码就是新修改的代码。 
iJtl19-23 

void CDllTestDlg::0nBtnAdd() 
1. 11 TODO: Add your contro1 notification handler code here 


2. HINSTANCE h工 nst; 

3. hlnst=LoadLibrary("Dll2.dll"); 

4. typedef int (_stdca11 *ADDPROC) (int a , int b); 

5. ADDPROC Add=(ADDPROC)GetProcAddress(h工 ns t , "add" ) ; 

6. i f ( ! Add) 

7. { 

8. MessageBox ( "获取函数地址失败!"); 

9. return; 

10. } 

11. CString str; 


12 . str.Format( " 5+3=毛 d" , Add ( 5 , 3 ) ) ; 

13 . MessageBox(str); 


也就是说,当 DLL中导出函数采用的是标准调用约定时,访问该 DLL的客户端程序也应该采用该约定类型来访问相应的导出函数。
接下来,再分析这样一种情况:如果 DLL导出函数发生了名字改编,那么动态加载 DLL时会发生什么问题?
重新利用 VC++新建一个 Win32 Dynamic-Link Library类型的工程,工程取名为: Dll3 , 并在 AppWizard的第一个步选择" An empty D I1 project"选工页,即创建一个空的动态链接库工程。然后,为该工程添加一个 C++源文件 :Dll3.cpp,为了简单起见,在该源文件中仅编写一个完成加法运算的 add函数,并为其加上_declspec ( dllexport )标识符,表明该函数是导出函数。结果代码如例 19-24所示。
例 19-24 

_dec1spec(dllexport) int add(int a.int b) 

{ 
~~~ I 727 


第19 

return a+b; 
利用Build命令生成Dll3.dll,井将该文件复制到DllTest工程所在目录下。
然后,在VC++开发环境中打开DllTest程序,修改OnBtnAdd函数中加载DLL的那行代码(上述例 19-23所示代码中第3行代码),让该函数这时加载Dll3.dll这一动态链接库,然后将其下面的那行代码中的" stdcall"标识符注释起来,修改后的代码如例 19-25所示。
例 19-25 

void CDllTestDlg : :OnBtnAdd() 
1. 11 TODO : Add your contro1 notification handler code here 
2. H工NSTANCE hlnst; 
3. hInst=LoadLibrary ("Dll3. dll") ; 

4. typedef int (/*_stdca11*1 *ADDPROC) (int a , int b); 

5. ADDPROC Add= (ADDPROC) GetProcAddress (hlnst , "add"); 

6. if( ! Add) 

7. { 


8 . MessageBox ( "获取函数地址失败!" ); 

9. return; 

10. } 

11 . CString str; 

12 . str.Format("5+3=屯d" ,Add ( 5 , 3 ) ) ; 

13. MessageBox(str); 


然后Build并运行DllTest程序,当程序界面显示之后,单击其中的【Add】按钮,这时将弹出一个消息框,提示:"获取函数地址失败!"。这是因为在生成Dll3.dll程序时,导出函数 add的名称会发生名字改编。可以利用Dumpbin命令的 exports选项查看Dll3.dll的导出信息,结果如图 19.20所示。可以看到,这时导出函数 add的名称变为: "?add@ @YAI-llIH@Z飞因此,这时在DllTest程序中访问Dll3.dll的导出函数: add时,就找不到该函数。

图 19.20 Dll3.dll的导出信息

728 I ~如协

为了验证 "?add@@YAHHH@Z"就是 Dll3 .dll中导出函数 add的名字,我们可以修改 DllTest程序中获得 add函数地址的那行代码,即让 GetProcAddress函数直接获得 "?add@@YAHHH@Z"这一函数的地址,修改后的代码如例 19-26所示。
例 19-26 

void CDIITestDlg: :OnBtnAdd() 
1. // TODO: Add your control notification handler code here 

2. HINSTANCE h工 nst; 

3. hlnst=LoadL工 brary ("0113 . dll") ; 

4. typedef int (/ *_stdca11* / *ADDPROC) (int a , int b); 

5. AODPROC Add=(ADOPROC)GetProcAddress(h工 nst," ?add@@YAHHH@Z"); 


6. i f ( ! Add) 

7. { 

8. MessageBox ( "获取函数地址失败!"); 

9. return; 

10. } 

11. CString str; 


12 . str . Format("5+3 =毛 d " , Add ( 5 , 3 ) ) ; 

13 . MessageBox(str); 


Build并运行 Dl1Test程序,之后单击【 Add】按钮,可以发现调用成功。说明 "?add@@YAHHH@Z"确实是 Dll3 .dll中导出函数 add的名字。 
.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -