﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-时间的痕迹-文章分类-DLL 技术</title><link>http://www.cppblog.com/ivenher/category/428.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 23 May 2008 10:59:04 GMT</lastBuildDate><pubDate>Fri, 23 May 2008 10:59:04 GMT</pubDate><ttl>60</ttl><item><title>利用VC从DLL传递消息到EXE </title><link>http://www.cppblog.com/ivenher/articles/37002.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Tue, 20 Nov 2007 04:18:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/37002.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/37002.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/37002.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/37002.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/37002.html</trackback:ping><description><![CDATA[&nbsp;在进行DLL开发过程中，尤其在进行底层硬件开发过程中，比如实时接收数据，进程需要和应用程序进行交互，而DLL和应用程序最好的交互就是发消息了，在DLL中定义消息的方式和在应用程序中定义消息的方式非常相似。下面谈谈这两种定义的方法：
<p>&#160;</p>
<p>&nbsp; 一、在应用程序自定义消息方法：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一般自定义消息有一定的范围，虽然说自定义消息从WM_USER开始，但是由于我们的工程里面一般还有很多其他的控件，他们也要占用一部分WM_USER消息范围，所以我们必须为他们留出一部分范围，这里，我们保留100个消息，一般情况下，这可以满足我们的要求。</p>
<p>&nbsp; (1)&nbsp;&nbsp;&nbsp; 定义消息的值。在我们要发生消息的地方(例如CMyView.cpp的开始部分)或者stdafx..h文件，进行如下定义：</p>
<p>
<table borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
    <tbody>
        <tr>
            <td width=10><br></td>
            <td>#define WM_MSG&nbsp; (WM_USER+101)</td>
        </tr>
    </tbody>
</table>
</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 接下来的工作其实很简单，我们在前面说了，消息正常工作有3个部分必须协调：消息声明、消息映射、消息体。我们就一次进行手工加入。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (2)首先在AFX_MSG块中加入消息声明：在CMyView.h中，找到如下部分，并加入消息声明：</p>
<p>
<table borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
    <tbody>
        <tr>
            <td width=10><br></td>
            <td>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protected:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // {{AFX_MSG（CMyView)</p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ......</p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; afx_msg LRESULT OnMyMsg(WPARAM wParam,LPARAM lParam);</p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="file://}}AFX_MSG/"><u><font color=#0000ff>file://}}AFX_MSG</font></u></a> </p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (3)在MESSAGE_MAP块中添加ON_MESSAGE宏指令：</p>
<p>
<table borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
    <tbody>
        <tr>
            <td width=10><br></td>
            <td>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BEGIN_MESSAGE_MAP(CMyView, CView) </p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="file://{{AFX_MSG_MAP(CMyView/"><u><font color=#0000ff>file://{{AFX_MSG_MAP(CMyView</font></u></a>) </p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .....</p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ON_MESSAGE(WM_MSG, OnMyMsg) </p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="file://}}AFX_MSG_MAP/"><u><font color=#0000ff>file://}}AFX_MSG_MAP</font></u></a> </p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; END_MESSAGE_MAP() </p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (4)添加消息函数体：</p>
<p>
<table borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
    <tbody>
        <tr>
            <td width=10><br></td>
            <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LPESULT CMyView::OnMyMsg(WPARAM wParam, LPARAM lParam)
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { </p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;</p>
<p>
<table borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
    <tbody>
        <tr>
            <td width=10><br></td>
            <td>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AfxMessageBox("消息已经收到！"); </p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0; </p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } </p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 消息至此就已经定义完毕，接下来我们就可以激活消息了，就可以用我们前面所说的PostMessage/SendMessage来发送消息了。</p>
<p>　　　　如：::PostMessage(hwnd,WM_MSG,0,1);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PostMessage:不用等消息返回。</p>
<p>　　　 SendMessage:需要等消息返回。</p>
<p>&nbsp; 二、从DLL中传递消息到EXE</p>
<p>　　　在DLL中定义消息和上面的方法很相似，有两点不同的地方：</p>
<p>&nbsp; 1、&nbsp; 在DLL和应用程序中两个地方定义相同的消息。</p>
<p>&nbsp; 2、&nbsp; 应用程序调用DLL程序之后，需要将应用程序的窗口句柄传递给DLL，以便DLL中的消息返回。</p>
<p>&nbsp; 在DLL工程中：</p>
<p>&nbsp; （1）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在stdafx.h头文件中添加消息定义：</p>
<p>
<table borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
    <tbody>
        <tr>
            <td width=10><br></td>
            <td>&nbsp;#define WM_MSG WM_USER + 102</td>
        </tr>
    </tbody>
</table>
</p>
<p>　　　　　　　</p>
<p>&nbsp; （2）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 添加启动消息的输出函数：</p>
<p>
<table borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
    <tbody>
        <tr>
            <td width=10><br></td>
            <td>
            <p>　　　　　　　CMessageDLLApp theApp;</p>
            <p>&nbsp; //发送消息</p>
            <p>extern "C" _declspec(dllexport) void StartSendMessage(HWND hwnd)</p>
            <p>{</p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; theApp.SendMessage(hwnd);</p>
            <p>}　　　　　</p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>&nbsp;</p>
<p>　　&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 其中hwnd是接收消息的窗口句柄。</p>
<p>&nbsp; （3）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 添加启动消息的实现函数：</p>
<p>在头文件中添加函数声明：</p>
<p>
<table borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
    <tbody>
        <tr>
            <td width=10><br></td>
            <td>&nbsp; void SendMessage(HWND hwnd);</td>
        </tr>
    </tbody>
</table>
</p>
<p>&nbsp;</p>
<p>&nbsp; 在CPP文件中添加函数实现</p>
<p>&nbsp; //启动发送消息</p>
<p>
<table borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
    <tbody>
        <tr>
            <td width=10><br></td>
            <td>
            <p>void CMessageDLLApp::SendMessage(HWND hwnd)</p>
            <p>{</p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ::PostMessage(hwnd,WM_MSG,0,1);</p>
            <p>}</p>
            <p>&nbsp; 在应</p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>用程序中：</p>
<p>&nbsp; （1）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在stdafx.h头文件中添加消息定义：</p>
<p>
<table borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
    <tbody>
        <tr>
            <td width=10><br></td>
            <td>#define WM_MSG WM_USER + 102</td>
        </tr>
    </tbody>
</table>
</p>
<p>　　　　　　　 </p>
<p>&nbsp; （2）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 首先在AFX_MSG块中加入消息声明：在CTestMessageDLLDlg.h中，找到如下部分，并加入消息声明：</p>
<p>。。。。。。</p>
<p>
<table borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
    <tbody>
        <tr>
            <td width=10><br></td>
            <td>
            <p>　　　　　　　 afx_msg LRESULT OnMyMsg(WPARAM wParam,LPARAM lParam);</p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DECLARE_MESSAGE_MAP()</p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>&nbsp;</p>
<p>&nbsp; （3）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在MESSAGE_MAP块中添加ON_MESSAGE宏指令：</p>
<p>
<table borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
    <tbody>
        <tr>
            <td width=10><br></td>
            <td>
            <p>　　　　　　　 BEGIN_MESSAGE_MAP(CTestMessageDLLDlg, CDialog)</p>
            <p>&nbsp;&nbsp;&nbsp; 　　　　　　。。。。。。</p>
            <p>&nbsp;&nbsp;&nbsp; 　　　　　　ON_MESSAGE(WM_MSG, OnMyMsg) </p>
            <p>&nbsp;&nbsp;&nbsp; 　　　　　　//}}AFX_MSG_MAP</p>
            <p>&nbsp;&nbsp;&nbsp; 　　　　　　END_MESSAGE_MAP()</p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>&nbsp;</p>
<p>&nbsp; （4）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 添加消息函数体：</p>
<p>
<table borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
    <tbody>
        <tr>
            <td width=10><br></td>
            <td>　　　　　　 LRESULT CTestMessageDLLDlg::OnMyMsg(WPARAM wParam, LPARAM lParam)
            <p>&nbsp;{ <br></p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 　　　　 AfxMessageBox("消息已经收到！"); </p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 　　　　 return 0; </p>
            <p>&nbsp;　　　　}</p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>　（5）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在对话框上添加一个按钮，在按钮事件中，先调用DLL文件，然后发送一个测试消息响应的命令：</p>
<p>
<table borderColor=#55aaff cellSpacing=0 cellPadding=0 rules=none width=500 align=center bgColor=#ddedfb border=1>
    <tbody>
        <tr>
            <td width=10><br></td>
            <td>
            <p>void CTestMessageDLLDlg::OnBnClickedButton1()</p>
            <p>{</p>
            <p>&nbsp;&nbsp;&nbsp; // TODO: 在此添加控件通知处理程序代码</p>
            <p>&nbsp;&nbsp;&nbsp; //定义函数</p>
            <p>&nbsp;&nbsp;&nbsp; typedef void (_cdecl*STARTSENDMESSAGE)(HWND hwnd);</p>
            <p>&nbsp;&nbsp;&nbsp; HMODULE hmessage = NULL;</p>
            <p>&nbsp;&nbsp;&nbsp; STARTSENDMESSAGE StartSendMessage = NULL;</p>
            <p>　　//导入DLL库文件</p>
            <p>&nbsp;&nbsp;&nbsp; hmessage = LoadLibrary("MessageDLL.dll");</p>
            <p>&nbsp;&nbsp;&nbsp; if(hmessage==NULL)</p>
            <p>&nbsp;&nbsp;&nbsp; {</p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FreeLibrary(hmessage);</p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exit(0);</p>
            <p>&nbsp;&nbsp;&nbsp; }</p>
            <p>　　//导入DLL中测试消息函数</p>
            <p>&nbsp;&nbsp;&nbsp; StartSendMessage = (STARTSENDMESSAGE)GetProcAddress(hmessage,"StartSendMessage");</p>
            <p>&nbsp;&nbsp;&nbsp; if(StartSendMessage==NULL)</p>
            <p>&nbsp;&nbsp;&nbsp; {</p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FreeLibrary(hmessage);</p>
            <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exit(1);</p>
            <p>&nbsp;&nbsp;&nbsp; }</p>
            <p>&nbsp;&nbsp;&nbsp; //获取对话框的窗口句柄</p>
            <p>&nbsp;&nbsp;&nbsp; HWND hwnd = this-＞GetSafeHwnd();</p>
            <p>&nbsp;&nbsp;&nbsp; //发送测试消息函数</p>
            <p>&nbsp;&nbsp;&nbsp; (*StartSendMessage)(hwnd);</p>
            <p>}</p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>&nbsp;</p>
<p>运行应用程序，就可以看到测试结果了。<br>&nbsp;<br></p>
<p><br><br><br><br><br clear=all></p>
<p><br><br><br></p>
<img src ="http://www.cppblog.com/ivenher/aggbug/37002.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2007-11-20 12:18 <a href="http://www.cppblog.com/ivenher/articles/37002.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MFC规则DLL的调用</title><link>http://www.cppblog.com/ivenher/articles/1322.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Fri, 25 Nov 2005 10:50:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/1322.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/1322.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/1322.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/1322.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/1322.html</trackback:ping><description><![CDATA[笔者编写了如图12的对话框MFC程序（下载本工程<A href="http://www.pconline.com.cn/pcedu/empolder/gj/vc/0509/acc/RegularDllCall.zip">附件</A>）来调用5.3节的MFC规则DLL，在这个程序的对话框上点击“调用DLL”按钮时弹出5.3节MFC规则DLL中的对话框。<BR>
<P align=center><IMG alt="" src="http://www.pconline.com.cn/pcedu/empolder/gj/vc/0509/pic/05-09-22-vc-12.jpg" border=0></P>
<P align=center>图12 MFC规则DLL的调用例子</P>
<P>　　下面是“调用DLL”按钮单击事件的消息处理函数：<BR></P>
<P class=code>void CRegularDllCallDlg::OnCalldllButton() <BR><BR>{<BR><BR>typedef void (*lpFun)(void);<BR><BR><BR>HINSTANCE hDll; //DLL句柄 <BR><BR>hDll = LoadLibrary("RegularDll.dll");<BR><BR>if (NULL==hDll)<BR><BR>{<BR><BR>MessageBox("DLL加载失败");<BR><BR>}<BR><BR><BR><BR>lpFun addFun; //函数指针<BR><BR>lpFun pShowDlg = (lpFun)GetProcAddress(hDll,"ShowDlg");<BR><BR>if (NULL==pShowDlg)<BR><BR>{<BR><BR>MessageBox("DLL中函数寻找失败"); <BR><BR>}<BR><BR>pShowDlg();<BR><BR>}</P><BR>　　上述例子中给出的是显示调用的方式，可以看出，其调用方式与第4节中非MFC DLL的调用方式没有什么不同。<BR>我们照样可以在EXE程序中隐式调用MFC规则DLL，只需要将DLL工程生成的.lib文件和.dll文件拷入当前工程所在的目录，并在RegularDllCallDlg.cpp文件（图12所示对话框类的实现文件）的顶部添加：<BR>
<P class=code>#pragma comment(lib,"RegularDll.lib")<BR><BR>void ShowDlg(void); </P><BR>　　并将void CRegularDllCallDlg::OnCalldllButton() 改为：<BR>
<P class=code>void CRegularDllCallDlg::OnCalldllButton() <BR><BR>{<BR><BR>ShowDlg();<BR><BR>}</P><img src ="http://www.cppblog.com/ivenher/aggbug/1322.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2005-11-25 18:50 <a href="http://www.cppblog.com/ivenher/articles/1322.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MFC规则DLL   简单的例子</title><link>http://www.cppblog.com/ivenher/articles/1321.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Fri, 25 Nov 2005 10:49:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/1321.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/1321.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/1321.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/1321.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/1321.html</trackback:ping><description><![CDATA[这个DLL的例子（属于静态链接到MFC 的规则DLL）中提供了一个如图11所示的对话框。<BR>（下载本工程<A href="http://www.pconline.com.cn/pcedu/empolder/gj/vc/0509/acc/RegularDll.zip">附件</A>）：<BR>
<P align=center><IMG alt="" src="http://www.pconline.com.cn/pcedu/empolder/gj/vc/0509/pic/05-09-22-vc-11.jpg" border=0></P>
<P align=center>图11 MFC规则DLL例子</P>
<P>　　在DLL中添加对话框的方式与在MFC应用程序中是一样的。<BR><BR>　　在图11所示DLL中的对话框的Hello按钮上点击时将MessageBox一个“Hello,pconline的网友”对话框，下面是相关的文件及源代码，其中删除了MFC向导自动生成的绝大多数注释。<BR>第一组文件：CWinApp继承类的声明与实现<BR></P>
<P></P>
<P class=code>// RegularDll.h : main header file for the REGULARDLL DLL<BR><BR><BR><BR>#if !defined(AFX_REGULARDLL_H__3E9CB22B_588B_4388_B778_B3416ADB79B3__INCLUDED_)<BR><BR>#define AFX_REGULARDLL_H__3E9CB22B_588B_4388_B778_B3416ADB79B3__INCLUDED_<BR><BR><BR><BR>#if _MSC_VER &gt; 1000<BR><BR>#pragma once<BR><BR>#endif // _MSC_VER &gt; 1000<BR><BR><BR><BR>#ifndef __AFXWIN_H__<BR><BR>#error include 'stdafx.h' before including this file for PCH<BR><BR>#endif<BR><BR>#include "resource.h" // main symbols<BR><BR><BR><BR>class CRegularDllApp : public CWinApp<BR><BR>{<BR><BR>public:<BR><BR>CRegularDllApp();<BR><BR><BR><BR>DECLARE_MESSAGE_MAP()<BR><BR>};<BR><BR>#endif <BR><BR><BR><BR>// RegularDll.cpp : Defines the initialization routines for the DLL.<BR><BR><BR><BR>#include "stdafx.h"<BR><BR>#include "RegularDll.h"<BR><BR><BR><BR>#ifdef _DEBUG<BR><BR>#define new DEBUG_NEW<BR><BR>#undef THIS_FILE<BR><BR>static char THIS_FILE[] = __FILE__;<BR><BR>#endif<BR><BR><BR><BR>BEGIN_MESSAGE_MAP(CRegularDllApp, CWinApp)<BR><BR>END_MESSAGE_MAP()<BR><BR><BR><BR>/////////////////////////////////////////////////////////////////////////////<BR><BR>// CRegularDllApp construction<BR><BR><BR><BR>CRegularDllApp::CRegularDllApp()<BR><BR>{<BR><BR>}<BR><BR><BR><BR>/////////////////////////////////////////////////////////////////////////////<BR><BR>// The one and only CRegularDllApp object<BR><BR>CRegularDllApp theApp;</P>
<P><BR>　　分析：<BR><BR>　　在这一组文件中定义了一个继承自CWinApp的类CRegularDllApp，并同时定义了其的一个实例theApp。乍一看，您会以为它是一个MFC应用程序，因为MFC应用程序也包含这样的在工程名后添加“App”组成类名的类（并继承自CWinApp类），也定义了这个类的一个全局实例theApp。<BR>我们知道，在MFC应用程序中CWinApp取代了SDK程序中WinMain的地位，SDK程序WinMain所完成的工作由CWinApp的三个函数完成：<BR></P>
<P class=code>virtual BOOL InitApplication( );<BR><BR>virtual BOOL InitInstance( );<BR><BR>virtual BOOL Run( ); //传说中MFC程序的“活水源头”</P>
<P><BR>　　但是MFC规则DLL并不是MFC应用程序，它所继承自CWinApp的类不包含消息循环。这是因为，MFC规则DLL不包含CWinApp::Run机制，主消息泵仍然由应用程序拥有。如果DLL 生成无模式对话框或有自己的主框架窗口，则应用程序的主消息泵必须调用从DLL 导出的函数来调用PreTranslateMessage成员函数。<BR><BR>　　另外，MFC规则DLL与MFC 应用程序中一样，需要将所有 DLL中元素的初始化放到InitInstance 成员函数中。<BR><BR>　　第二组文件 自定义对话框类声明及实现(点击查看<A href="http://www.pconline.com.cn/pcedu/empolder/gj/vc/0509/acc/05-09-22-vc-1.txt">附件</A>)<BR><BR>　　分析：<BR><BR>　　这一部分的编程与一般的应用程序根本没有什么不同，我们照样可以利用MFC类向导来自动为对话框上的控件添加事件。MFC类向导照样会生成类似ON_BN_CLICKED(IDC_HELLO_BUTTON, OnHelloButton)的消息映射宏。<BR><BR>　　第三组文件 DLL中的资源文件<BR></P>
<P class=code>//{{NO_DEPENDENCIES}}<BR><BR>// Microsoft Developer Studio generated include file.<BR><BR>// Used by RegularDll.rc<BR><BR>//<BR><BR>#define IDD_DLL_DIALOG 1000<BR><BR>#define IDC_HELLO_BUTTON 1000</P>
<P><BR>　　分析：<BR><BR>　　在MFC规则DLL中使用资源也与在MFC应用程序中使用资源没有什么不同，我们照样可以用Visual C++的资源编辑工具进行资源的添加、删除和属性的更改。<BR><BR>　　第四组文件 MFC规则DLL接口函数<BR></P>
<P class=code>#include "StdAfx.h"<BR><BR>#include "DllDialog.h"<BR><BR><BR>extern "C" __declspec(dllexport) void ShowDlg(void) <BR><BR>{<BR><BR>CDllDialog dllDialog;<BR><BR>dllDialog.DoModal();<BR><BR>}</P>
<P><BR>　　分析：<BR><BR>　　这个接口并不使用MFC，但是在其中却可以调用MFC扩展类CdllDialog的函数，这体现了“规则”的概类。<BR><BR>　　与非MFC DLL完全相同，我们可以使用__declspec(dllexport)声明或在.def中引出的方式导出MFC规则DLL中的接口。<BR></P><img src ="http://www.cppblog.com/ivenher/aggbug/1321.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2005-11-25 18:49 <a href="http://www.cppblog.com/ivenher/articles/1321.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MFC规则DLL的创建</title><link>http://www.cppblog.com/ivenher/articles/1320.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Fri, 25 Nov 2005 10:46:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/1320.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/1320.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/1320.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/1320.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/1320.html</trackback:ping><description><![CDATA[<BR>　　我们来一步步讲述使用MFC向导创建MFC规则DLL的过程，首先新建一个project，如图9，选择project的类型为MFC AppWizard(dll)。点击OK进入如图10所示的对话框。<BR>
<P align=center><IMG alt="" src="http://www.pconline.com.cn/pcedu/empolder/gj/vc/0509/pic/05-09-22-vc-9.jpg" border=0></P>
<P align=center>图9 MFC DLL工程的创建</P>
<P>　　图10所示对话框中的1区选择MFC DLL的类别。<BR><BR>　　2区选择是否支持automation（自动化）技术， automation 允许用户在一个应用程序中操纵另外一个应用程序或组件。例如，我们可以在应用程序中利用 Microsoft Word 或Microsoft Excel的工具，而这种使用对用户而言是透明的。自动化技术可以大大简化和加快应用程序的开发。<BR><BR>　　3区选择是否支持Windows Sockets，当选择此项目时，应用程序能在 TCP/IP 网络上进行通信。 CWinApp派生类的InitInstance成员函数会初始化通讯端的支持，同时工程中的StdAfx.h文件会自动include &lt;AfxSock.h&gt;头文件。<BR>添加socket通讯支持后的InitInstance成员函数如下：<BR></P>
<P></P>
<P class=code>BOOL CRegularDllSocketApp::InitInstance()<BR><BR>{<BR><BR>if (!AfxSocketInit())<BR><BR>{<BR><BR>AfxMessageBox(IDP_SOCKETS_INIT_FAILED);<BR><BR>return FALSE;<BR><BR>}<BR><BR><BR>return TRUE;<BR><BR>}</P>
<P><BR>　　4区选择是否由MFC向导自动在源代码中添加注释，一般我们选择“Yes,please”。<BR></P>
<P align=center><IMG alt="" src="http://www.pconline.com.cn/pcedu/empolder/gj/vc/0509/pic/05-09-22-vc-10.jpg" border=0></P>
<P align=center>图10 MFC DLL的创建选项</P><img src ="http://www.cppblog.com/ivenher/aggbug/1320.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2005-11-25 18:46 <a href="http://www.cppblog.com/ivenher/articles/1320.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MFC规则DLL  概述</title><link>http://www.cppblog.com/ivenher/articles/1319.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Fri, 25 Nov 2005 10:43:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/1319.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/1319.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/1319.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/1319.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/1319.html</trackback:ping><description><![CDATA[MFC规则DLL的概念体现在两方面：<BR><BR>　　（1） 它是MFC的<BR><BR>　　“是MFC的”意味着可以在这种DLL的内部使用MFC；<BR><BR>　　（2） 它是规则的<BR><BR>　　“是规则的”意味着它不同于MFC扩展DLL，在MFC规则DLL的内部虽然可以使用MFC，但是其与应用程序的接口不能是MFC。而MFC扩展DLL与应用程序的接口可以是MFC，可以从MFC扩展DLL中导出一个MFC类的派生类。<BR><BR>　　Regular DLL能够被所有支持DLL技术的语言所编写的应用程序调用，当然也包括使用MFC的应用程序。在这种动态连接库中，包含一个从CWinApp继承下来的类，DllMain函数则由MFC自动提供。<BR><BR>　　Regular DLL分为两类：<BR><BR>　　（1）静态链接到MFC 的规则DLL<BR><BR>　　静态链接到MFC的规则DLL与MFC库（包括MFC扩展 DLL）静态链接，将MFC库的代码直接生成在.dll文件中。在调用这种DLL的接口时，MFC使用DLL的资源。因此，在静态链接到MFC 的规则DLL中不需要进行模块状态的切换。<BR><BR>　　使用这种方法生成的规则DLL其程序较大，也可能包含重复的代码。<BR><BR>　　（2）动态链接到MFC 的规则DLL<BR><BR>　　动态链接到MFC 的规则DLL 可以和使用它的可执行文件同时动态链接到 MFC DLL 和任何MFC扩展 DLL。在使用了MFC共享库的时候，默认情况下，MFC使用主应用程序的资源句柄来加载资源模板。这样，当DLL和应用程序中存在相同ID的资源时（即所谓的资源重复问题），系统可能不能获得正确的资源。因此，对于共享MFC DLL的规则DLL，我们必须进行模块切换以使得MFC能够找到正确的资源模板。<BR>我们可以在Visual C++中设置MFC规则DLL是静态链接到MFC DLL还是动态链接到MFC DLL。如图8，依次选择Visual C++的project -&gt; Settings -&gt; General菜单或选项，在Microsoft Foundation Classes中进行设置。<BR><img src ="http://www.cppblog.com/ivenher/aggbug/1319.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2005-11-25 18:43 <a href="http://www.cppblog.com/ivenher/articles/1319.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DLL导出类</title><link>http://www.cppblog.com/ivenher/articles/1318.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Fri, 25 Nov 2005 10:26:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/1318.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/1318.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/1318.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/1318.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/1318.html</trackback:ping><description><![CDATA[<STRONG>DLL导出类<BR><BR></STRONG>　　DLL中定义的类可以在应用工程中使用。<BR><BR>　　下面的例子里，我们在DLL中定义了point和circle两个类，并在应用工程中引用了它们（单击此处下载本工程<A href="http://www.pconline.com.cn/pcedu/empolder/gj/vc/0509/acc/dllTest7_dcl.zip">附件</A>）。<BR>
<P class=code>//文件名：point.h，point类的声明<BR><BR>#ifndef POINT_H<BR><BR>#define POINT_H<BR><BR>#ifdef DLL_FILE<BR><BR>class _declspec(dllexport) point //导出类point<BR><BR>#else<BR><BR>class _declspec(dllimport) point //导入类point<BR><BR>#endif<BR><BR>{<BR><BR>public:<BR><BR>float y;<BR><BR>float x;<BR><BR>point();<BR><BR>point(float x_coordinate, float y_coordinate);<BR><BR>};<BR><BR>#endif<BR><BR><BR>//文件名：point.cpp，point类的实现<BR><BR>#ifndef DLL_FILE<BR><BR>#define DLL_FILE<BR><BR>#endif<BR><BR>#include "point.h"<BR><BR>//类point的缺省构造函数<BR><BR>point::point()<BR><BR>{<BR><BR>x = 0.0;<BR><BR>y = 0.0;<BR><BR>}<BR><BR>//类point的构造函数<BR><BR>point::point(float x_coordinate, float y_coordinate)<BR><BR>{<BR><BR>x = x_coordinate;<BR><BR>y = y_coordinate;<BR><BR>}<BR><BR><BR>//文件名：circle.h，circle类的声明<BR><BR>#ifndef CIRCLE_H<BR><BR>#define CIRCLE_H<BR><BR>#include "point.h" <BR><BR>#ifdef DLL_FILE<BR><BR>class _declspec(dllexport)circle //导出类circle<BR><BR>#else<BR><BR>class _declspec(dllimport)circle //导入类circle<BR><BR>#endif<BR><BR>{<BR><BR>public:<BR><BR>void SetCentre(const point ¢rePoint);<BR><BR>void SetRadius(float r);<BR><BR>float GetGirth();<BR><BR>float GetArea();<BR><BR>circle();<BR><BR>private:<BR><BR>float radius;<BR><BR>point centre;<BR><BR>};<BR><BR>#endif<BR><BR><BR>//文件名：circle.cpp，circle类的实现<BR><BR>#ifndef DLL_FILE<BR><BR>#define DLL_FILE<BR><BR>#endif<BR><BR>#include "circle.h"<BR><BR>#define PI 3.1415926<BR><BR>//circle类的构造函数<BR><BR>circle::circle()<BR><BR>{<BR><BR>centre = point(0, 0);<BR><BR>radius = 0;<BR><BR>}<BR><BR>//得到圆的面积<BR><BR>float circle::GetArea()<BR><BR>{<BR><BR>return PI *radius * radius;<BR><BR>}<BR><BR>//得到圆的周长<BR><BR>float circle::GetGirth()<BR><BR>{<BR><BR>return 2 *PI * radius;<BR><BR>}<BR><BR>//设置圆心坐标<BR><BR>void circle::SetCentre(const point ¢rePoint)<BR><BR>{<BR><BR>centre = centrePoint;<BR><BR>}<BR><BR>//设置圆的半径<BR><BR>void circle::SetRadius(float r)<BR><BR>{<BR><BR>radius = r;<BR><BR>}<BR><BR>类的引用：<BR></P>
<P class=code>#include "..\circle.h"　　//包含类声明头文件<BR><BR>#pragma comment(lib,"dllTest.lib");<BR><BR><BR>int main(int argc, char *argv[])<BR><BR>{<BR><BR>circle c;<BR><BR>point p(2.0, 2.0);<BR><BR>c.SetCentre(p);<BR><BR>c.SetRadius(1.0);<BR><BR>printf("area:%f girth:%f", c.GetArea(), c.GetGirth());<BR><BR><BR>return 0;<BR><BR>}</P>
<P class=code><BR>　　从上述源代码可以看出，由于在DLL的类实现代码中定义了宏DLL_FILE，故在DLL的实现中所包含的类声明实际上为：<BR></P>
<P class=code>class _declspec(dllexport) point //导出类point<BR><BR>{<BR><BR>…<BR><BR>}</P>
<P class=code><BR>　　和<BR></P>
<P class=code>class _declspec(dllexport) circle //导出类circle<BR><BR>{<BR><BR>…<BR><BR>}</P>
<P class=code><BR>　　而在应用工程中没有定义DLL_FILE，故其包含point.h和circle.h后引入的类声明为：<BR></P>
<P class=code>class _declspec(dllimport) point //导入类point<BR><BR>{<BR><BR>…<BR><BR>}</P>
<P class=code><BR>　　和<BR></P>
<P class=code>class _declspec(dllimport) circle //导入类circle<BR><BR>{<BR><BR>…<BR><BR>}</P>
<P class=code><BR clear=all></P><img src ="http://www.cppblog.com/ivenher/aggbug/1318.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2005-11-25 18:26 <a href="http://www.cppblog.com/ivenher/articles/1318.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DLL导出变量</title><link>http://www.cppblog.com/ivenher/articles/1317.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Fri, 25 Nov 2005 10:21:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/1317.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/1317.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/1317.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/1317.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/1317.html</trackback:ping><description><![CDATA[DLL定义的全局变量可以被调用进程访问；DLL也可以访问调用进程的全局数据，我们来看看在应用工程中引用DLL中变量的例子（单击此处下载本工程<A href="http://www.pconline.com.cn/pcedu/empolder/gj/vc/0509/acc/dllTest6_qjbl.zip">附件</A>）。<BR>
<P></P>
<P class=code>/* 文件名：lib.h　*/<BR><BR>#ifndef LIB_H<BR><BR>#define LIB_H<BR><BR>extern int dllGlobalVar;<BR><BR>#endif<BR><BR><BR>/* 文件名：lib.cpp */<BR><BR>#include "lib.h"<BR><BR>#include &lt;windows.h&gt;<BR><BR><BR>int dllGlobalVar;<BR><BR><BR>BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)<BR><BR>{<BR><BR>switch (ul_reason_for_call)<BR><BR>{<BR><BR>case DLL_PROCESS_ATTACH:<BR><BR>dllGlobalVar = 100; //在dll被加载时，赋全局变量为100<BR><BR>break;<BR><BR>case DLL_THREAD_ATTACH:<BR><BR>case DLL_THREAD_DETACH:<BR><BR>case DLL_PROCESS_DETACH:<BR><BR>break;<BR><BR>}<BR><BR>return TRUE;<BR><BR>}<BR><BR><BR>;文件名：lib.def<BR><BR>;在DLL中导出变量<BR><BR>LIBRARY "dllTest"<BR><BR>EXPORTS<BR><BR>dllGlobalVar CONSTANT<BR><BR>;或dllGlobalVar DATA<BR><BR>GetGlobalVar</P><BR>　　从lib.h和lib.cpp中可以看出，全局变量在DLL中的定义和使用方法与一般的程序设计是一样的。若要导出某全局变量，我们需要在.def文件的EXPORTS后添加：<BR>
<P class=code>变量名　CONSTANT　　　//过时的方法</P><BR>　　或<BR>
<P class=code>变量名　DATA　　　 　//VC++提示的新方法<BR><BR>在主函数中引用DLL中定义的全局变量：<BR></P>
<P class=code>#include &lt;stdio.h&gt;<BR><BR>#pragma comment(lib,"dllTest.lib")<BR><BR>extern int dllGlobalVar;<BR><BR>int main(int argc, char *argv[])<BR><BR>{<BR><BR>printf("%d ", *(int*)dllGlobalVar);<BR><BR>*(int*)dllGlobalVar = 1;<BR><BR>printf("%d ", *(int*)dllGlobalVar);<BR><BR><BR>return 0;<BR><BR>}</P>
<P class=code><BR>　　特别要注意的是用extern int dllGlobalVar声明所导入的并不是DLL中全局变量本身，而是其地址，应用程序必须通过强制指针转换来使用DLL中的全局变量。这一点，从*(int*)dllGlobalVar可以看出。因此在采用这种方式引用DLL全局变量时，千万不要进行这样的赋值操作：<BR></P>
<P class=code>dllGlobalVar = 1;</P>
<P class=code><BR>　　其结果是dllGlobalVar指针的内容发生变化，程序中以后再也引用不到DLL中的全局变量了。<BR><BR>　　在应用工程中引用DLL中全局变量的一个更好方法是：<BR></P>
<P class=code>#include &lt;stdio.h&gt;<BR><BR>#pragma comment(lib,"dllTest.lib")<BR><BR>extern int _declspec(dllimport) dllGlobalVar; //用_declspec(dllimport)导入<BR><BR>int main(int argc, char *argv[])<BR><BR>{<BR><BR>printf("%d ", dllGlobalVar);<BR><BR>dllGlobalVar = 1; //这里就可以直接使用, 无须进行强制指针转换<BR><BR>printf("%d ", dllGlobalVar);<BR><BR>return 0;<BR><BR>}</P>
<P class=code><BR>　　通过_declspec(dllimport)方式导入的就是DLL中全局变量本身而不再是其地址了，笔者建议在一切可能的情况下都使用这种方式。<BR></P><img src ="http://www.cppblog.com/ivenher/aggbug/1317.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2005-11-25 18:21 <a href="http://www.cppblog.com/ivenher/articles/1317.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>__stdcall约定</title><link>http://www.cppblog.com/ivenher/articles/1316.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Fri, 25 Nov 2005 10:19:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/1316.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/1316.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/1316.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/1316.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/1316.html</trackback:ping><description><![CDATA[如果通过VC++编写的DLL欲被其他语言编写的程序调用，应将函数的调用方式声明为__stdcall方式，WINAPI都采用这种方式，而C/C++缺省的调用方式却为__cdecl。__stdcall方式与__cdecl对函数名最终生成符号的方式不同。若采用C编译方式(在C++中需将函数声明为extern "C")，__stdcall调用约定在输出函数名前面加下划线，后面加“@”符号和参数的字节数，形如_functionname@number；而__cdecl调用约定仅在输出函数名前面加下划线，形如_functionname。<BR><BR>　　Windows编程中常见的几种函数类型声明宏都是与__stdcall和__cdecl有关的（节选自windef.h）：<BR>
<P class=code>#define CALLBACK __stdcall //这就是传说中的回调函数<BR><BR>#define WINAPI __stdcall //这就是传说中的WINAPI<BR><BR>#define WINAPIV __cdecl<BR><BR>#define APIENTRY WINAPI //DllMain的入口就在这里<BR><BR>#define APIPRIVATE __stdcall<BR><BR>#define PASCAL __stdcall</P><BR>　　在lib.h中，应这样声明add函数：<BR>
<P class=code>int __stdcall add(int x, int y);</P><BR>　　在应用工程中函数指针类型应定义为：<BR>
<P class=code>typedef int(__stdcall *lpAddFun)(int, int);</P><BR>　　若在lib.h中将函数声明为__stdcall调用，而应用工程中仍使用typedef int (* lpAddFun)(int,int)，运行时将发生错误（因为类型不匹配，在应用工程中仍然是缺省的__cdecl调用），<img src ="http://www.cppblog.com/ivenher/aggbug/1316.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2005-11-25 18:19 <a href="http://www.cppblog.com/ivenher/articles/1316.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DllMain函数</title><link>http://www.cppblog.com/ivenher/articles/1315.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Fri, 25 Nov 2005 10:12:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/1315.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/1315.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/1315.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/1315.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/1315.html</trackback:ping><description><![CDATA[Windows在加载DLL的时候，需要一个入口函数，就如同控制台或DOS程序需要main函数、WIN32程序需要WinMain函数一样。在前面的例子中，DLL并没有提供DllMain函数，应用工程也能成功引用DLL，这是因为Windows在找不到DllMain的时候，系统会从其它运行库中引入一个不做任何操作的缺省DllMain函数版本，并不意味着DLL可以放弃DllMain函数。<BR><BR>　　根据编写规范，Windows必须查找并执行DLL里的DllMain函数作为加载DLL的依据，它使得DLL得以保留在内存里。这个函数并不属于导出函数，而是DLL的内部函数。这意味着不能直接在应用工程中引用DllMain函数，DllMain是自动被调用的。<BR><BR>　　我们来看一个DllMain函数的例子（单击此处下载本工程<A href="http://www.pconline.com.cn/pcedu/empolder/gj/vc/0509/acc/dllTest4_DLLMain.zip">附件</A>）。<BR>
<P class=code>BOOL APIENTRY DllMain( HANDLE hModule, <BR><BR>DWORD ul_reason_for_call, <BR><BR>LPVOID lpReserved<BR><BR>)<BR><BR>{<BR><BR>switch (ul_reason_for_call)<BR><BR>{<BR><BR>case DLL_PROCESS_ATTACH:<BR><BR>printf("\nprocess attach of dll");<BR><BR>break;<BR><BR>case DLL_THREAD_ATTACH:<BR><BR>printf("\nthread attach of dll");<BR><BR>break;<BR><BR>case DLL_THREAD_DETACH:<BR><BR>printf("\nthread detach of dll");<BR><BR>break;<BR><BR>case DLL_PROCESS_DETACH:<BR><BR>printf("\nprocess detach of dll");<BR><BR>break;<BR><BR>}<BR><BR>return TRUE;<BR><BR>}</P><BR>　　DllMain函数在DLL被加载和卸载时被调用，在单个线程启动和终止时，DLLMain函数也被调用，ul_reason_for_call指明了被调用的原因。原因共有4种，即PROCESS_ATTACH、PROCESS_DETACH、THREAD_ATTACH和THREAD_DETACH，以switch语句列出。<BR>来仔细解读一下DllMain的函数头BOOL APIENTRY DllMain( HANDLE hModule, WORD ul_reason_for_call, LPVOID lpReserved )。<BR><BR>　　APIENTRY被定义为__stdcall，它意味着这个函数以标准Pascal的方式进行调用，也就是WINAPI方式；<BR><BR>　　进程中的每个DLL模块被全局唯一的32字节的HINSTANCE句柄标识，只有在特定的进程内部有效，句柄代表了DLL模块在进程虚拟空间中的起始地址。在Win32中，HINSTANCE和HMODULE的值是相同的，这两种类型可以替换使用，这就是函数参数hModule的来历。<BR><BR>　　执行下列代码：<BR>
<P class=code>hDll = LoadLibrary("..\\Debug\\dllTest.dll");<BR><BR>if (hDll != NULL)<BR><BR>{<BR><BR>addFun = (lpAddFun)GetProcAddress(hDll, MAKEINTRESOURCE(1));<BR><BR>//MAKEINTRESOURCE直接使用导出文件中的序号<BR><BR>if (addFun != NULL)<BR><BR>{<BR><BR>int result = addFun(2, 3);<BR><BR>printf("\ncall add in dll:%d", result);<BR><BR>}<BR><BR>FreeLibrary(hDll);<BR><BR>}</P><BR><BR>　　我们看到输出顺序为：<BR><BR>　　process attach of dll<BR><BR>　　call add in dll:5<BR><BR>　　process detach of dll<BR><BR>　　这一输出顺序验证了DllMain被调用的时机。<BR><BR>　　代码中的GetProcAddress ( hDll, MAKEINTRESOURCE ( 1 ) )值得留意，它直接通过.def文件中为add函数指定的顺序号访问add函数，具体体现在MAKEINTRESOURCE ( 1 )，MAKEINTRESOURCE是一个通过序号获取函数名的宏，定义为（节选自winuser.h）：<BR>
<P class=code>#define MAKEINTRESOURCEA(i) (LPSTR)((DWORD)((WORD)(i)))<BR><BR>#define MAKEINTRESOURCEW(i) (LPWSTR)((DWORD)((WORD)(i)))<BR><BR>#ifdef UNICODE<BR><BR>#define MAKEINTRESOURCE MAKEINTRESOURCEW<BR><BR>#else<BR><BR>#define MAKEINTRESOURCE MAKEINTRESOURCEA</P><img src ="http://www.cppblog.com/ivenher/aggbug/1315.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2005-11-25 18:12 <a href="http://www.cppblog.com/ivenher/articles/1315.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>非MFC DLL 之 DLL的调用方式</title><link>http://www.cppblog.com/ivenher/articles/1314.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Fri, 25 Nov 2005 10:10:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/1314.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/1314.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/1314.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/1314.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/1314.html</trackback:ping><description><![CDATA[<FONT color=#ff0000><STRONG>动态调用</STRONG></FONT><BR>typedef int(*lpAddFun)(int, int); //宏定义函数指针类型<BR><BR>int main(int argc, char *argv[])<BR><BR>{<BR><BR>HINSTANCE hDll; //DLL句柄 <BR><BR>lpAddFun addFun; //函数指针<BR><BR>hDll = LoadLibrary("..\\Debug\\dllTest.dll");<BR><BR>if (hDll != NULL)<BR><BR>{<BR><BR>addFun = (lpAddFun)GetProcAddress(hDll, "add");<BR><BR>if (addFun != NULL)<BR><BR>{<BR><BR>int result = addFun(2, 3);<BR><BR>printf("%d", result);<BR><BR>}<BR><BR>FreeLibrary(hDll);<BR><BR>}<BR><BR>return 0;<BR><BR>}<BR>　　在上边的例子中我们看到了由“LoadLibrary-GetProcAddress-FreeLibrary”系统Api提供的三位一体“DLL加载-DLL函数地址获取-DLL释放”方式，这种调用方式称为DLL的<FONT color=#ff0000>动态调用。<BR></FONT><BR>　　动态调用方式的特点是完全由编程者用 API 函数加载和卸载 DLL，程序员可以决定 DLL 文件何时加载或不加载，显式链接在运行时决定加载哪个 DLL 文件。<BR><BR>　　与动态调用方式相对应的就是静态调用方式，“有动必有静”，这来源于物质世界的对立统一。“动与静”，其对立与统一竟无数次在技术领域里得到验证，譬如静态IP与DHCP、静态路由与动态路由等。从前文我们已经知道，库也分为静态库与动态库DLL，而想不到，深入到DLL内部，其调用方式也分为静态与动态。“动与静”，无处不在。《周易》已认识到有动必有静的动静平衡观，《易．系辞》曰：“动静有常，刚柔断矣”。哲学意味着一种普遍的真理，因此，我们经常可以在枯燥的技术领域看到哲学的影子。<BR><BR>　　静态调用方式的特点是由编译系统完成对DLL的加载和应用程序结束时 DLL 的卸载。当调用某DLL的应用程序结束时，若系统中还有其它程序使用该 DLL，则Windows对DLL的应用记录减1，直到所有使用该DLL的程序都结束时才释放它。静态调用方式简单实用，但不如动态调用方式灵活。<BR><BR>　　下面我们来看看<STRONG><FONT style="BACKGROUND-COLOR: #ffffff" color=#ff0000>静态调用的例子</FONT></STRONG>，将编译dllTest工程所生成的.lib和.dll文件拷入dllCall工程所在的路径，dllCall执行下列代码：<BR>
<P class=code>#pragma comment(lib,"dllTest.lib") <BR><BR>//.lib文件中仅仅是关于其对应DLL文件中函数的重定位信息<BR><BR>extern "C" __declspec(dllimport) add(int x,int y); <BR><BR>int main(int argc, char* argv[])<BR><BR>{<BR><BR>int result = add(2,3); <BR><BR>printf("%d",result);<BR><BR>return 0;<BR><BR>}</P><BR>　　由上述代码可以看出，静态调用方式的顺利进行需要完成<STRONG><FONT color=#ff0000>两个动作</FONT></STRONG>：<BR><BR>　　(1)告诉编译器与DLL相对应的.lib文件所在的路径及文件名，#pragma comment(lib,"dllTest.lib")就是起这个作用。<BR><BR>　　程序员在建立一个DLL文件时，连接器会自动为其生成一个对应的.lib文件，该文件包含了DLL 导出函数的符号名及序号（并不含有实际的代码）。在应用程序里，.lib文件将作为DLL的替代文件参与编译。<BR><BR>　　(2)声明导入函数，extern "C" __declspec(dllimport) add(int x,int y)语句中的__declspec(dllimport)发挥这个作用。<BR><BR>　　静态调用方式不再需要使用系统API来加载、卸载DLL以及获取DLL中导出函数的地址。这是因为，当程序员通过静态链接方式编译生成应用程序时，应用程序中调用的与.lib文件中导出符号相匹配的函数符号将进入到生成的EXE 文件中，.lib文件中所包含的与之对应的DLL文件的文件名也被编译器存储在 EXE文件内部。当应用程序运行过程中需要加载DLL文件时，Windows将根据这些信息发现并加载DLL，然后通过符号名实现对DLL 函数的动态链接。这样，EXE将能直接通过函数名调用DLL的输出函数，就象调用程序内部的其他函数一样。<BR><img src ="http://www.cppblog.com/ivenher/aggbug/1314.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2005-11-25 18:10 <a href="http://www.cppblog.com/ivenher/articles/1314.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>非MFC DLL 之 声明导出函数</title><link>http://www.cppblog.com/ivenher/articles/1313.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Fri, 25 Nov 2005 09:59:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/1313.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/1313.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/1313.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/1313.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/1313.html</trackback:ping><description><![CDATA[<BR>　　DLL中导出函数的声明有两种方式：一种为4.1节例子中给出的在函数声明中加上__declspec(dllexport)，这里不再举例说明；另外一种方式是采用模块定义(.def) 文件声明，.def文件为链接器提供了有关被链接程序的导出、属性及其他方面的信息。<BR><BR>　　下面的代码演示了怎样同.def文件将函数add声明为DLL导出函数（需在dllTest工程中添加lib.def文件）：<BR>
<P class=code>; lib.def : 导出DLL函数<BR><BR>LIBRARY dllTest<BR><BR>EXPORTS<BR><BR>add @ 1</P><BR>.def文件的规则为：<BR><BR>　　(1)LIBRARY语句说明.def文件相应的DLL；<BR><BR>　　(2)EXPORTS语句后列出要导出函数的名称。可以在.def文件中的导出函数名后加@n，表示要导出函数的序号为n（在进行函数调用时，这个序号将发挥其作用）；<BR><BR>　　(3).def 文件中的注释由每个注释行开始处的分号 (;) 指定，且注释不能与语句共享一行。<BR><BR>　　由此可以看出，例子中lib.def文件的含义为生成名为“dllTest”的动态链接库，导出其中的add函数，并指定add函数的序号为1。<BR><img src ="http://www.cppblog.com/ivenher/aggbug/1313.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2005-11-25 17:59 <a href="http://www.cppblog.com/ivenher/articles/1313.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>非MFC DLL</title><link>http://www.cppblog.com/ivenher/articles/dll_2.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Fri, 25 Nov 2005 09:58:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/dll_2.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/1312.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/dll_2.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/1312.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/1312.html</trackback:ping><description><![CDATA[在建立的工程中添加lib.h及lib.cpp文件，源代码如下：<BR>
<P class=code>/* 文件名：lib.h　*/<BR><BR>#ifndef LIB_H<BR><BR>#define LIB_H<BR><BR>extern "C" int __declspec(dllexport)add(int x, int y);<BR><BR>#endif<BR><BR><BR>/* 文件名：lib.cpp　*/<BR><BR>#include "lib.h"<BR><BR>int add(int x, int y)<BR><BR>{<BR><BR>return x + y;<BR><BR>}<BR><BR>分析上述代码，dllTest工程中的lib.cpp文件与第2节静态链接库版本完全相同，不同在于lib.h对函数add的声明前面添加了__declspec(dllexport)语句。这个语句的含义是声明函数add为DLL的导出函数。DLL内的函数分为两种：<BR><BR>　　(1)DLL导出函数，可供应用程序调用；<BR><BR>　　(2) DLL内部函数，只能在DLL程序使用，应用程序无法调用它们。<BR><BR>与第2节对静态链接库的调用相似，我们也建立一个与DLL工程处于同一工作区的应用工程dllCall，它调用DLL中的函数add，其源代码如下：<BR></P>
<P class=code>#include &lt;stdio.h&gt;<BR><BR>#include &lt;windows.h&gt;<BR><BR>typedef int(*lpAddFun)(int, int); //宏定义函数指针类型<BR><BR>int main(int argc, char *argv[])<BR><BR>{<BR><BR>HINSTANCE hDll; //DLL句柄 <BR><BR>lpAddFun addFun; //函数指针<BR><BR>hDll = LoadLibrary("..\\Debug\\dllTest.dll");<BR><BR>if (hDll != NULL)<BR><BR>{<BR><BR>addFun = (lpAddFun)GetProcAddress(hDll, "add");<BR><BR>if (addFun != NULL)<BR><BR>{<BR><BR>int result = addFun(2, 3);<BR><BR>printf("%d", result);<BR><BR>}<BR><BR>FreeLibrary(hDll);<BR><BR>}<BR><BR>return 0;<BR><BR>}<BR>而应用程序对本DLL的调用和对第2节静态链接库的调用却有较大差异，下面我们来逐一分析。<BR><BR>　　首先，语句typedef int ( * lpAddFun)(int,int)定义了一个与add函数接受参数类型和返回值均相同的函数指针类型。随后，在main函数中定义了lpAddFun的实例addFun；<BR><BR>　　其次，在函数main中定义了一个DLL HINSTANCE句柄实例hDll，通过Win32 Api函数LoadLibrary动态加载了DLL模块并将DLL模块句柄赋给了hDll；<BR><BR>　　再次，在函数main中通过Win32 Api函数GetProcAddress得到了所加载DLL模块中函数add的地址并赋给了addFun。经由函数指针addFun进行了对DLL中add函数的调用；<BR><BR>　　最后，应用工程使用完DLL后，在函数main中通过Win32 Api函数FreeLibrary释放了已经加载的DLL模块。<BR><BR>　　通过这个简单的例子，我们获知DLL定义和调用的一般概念：<BR><BR>　　(1)DLL中需以某种特定的方式声明导出函数（或变量、类）；<BR><BR>　　(2)应用工程需以某种特定的方式调用DLL的导出函数（或变量、类）。<BR></P><img src ="http://www.cppblog.com/ivenher/aggbug/1312.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2005-11-25 17:58 <a href="http://www.cppblog.com/ivenher/articles/dll_2.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Lib   静态链接库</title><link>http://www.cppblog.com/ivenher/articles/1310.html</link><dc:creator>爱饭盒</dc:creator><author>爱饭盒</author><pubDate>Fri, 25 Nov 2005 09:24:00 GMT</pubDate><guid>http://www.cppblog.com/ivenher/articles/1310.html</guid><wfw:comment>http://www.cppblog.com/ivenher/comments/1310.html</wfw:comment><comments>http://www.cppblog.com/ivenher/articles/1310.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/ivenher/comments/commentRss/1310.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ivenher/services/trackbacks/1310.html</trackback:ping><description><![CDATA[VC动态链接库的分类<BR>　　Visual C++支持三种DLL，它们分别是Non-MFC DLL（非MFC动态库）、MFC Regular DLL（MFC规则DLL）、MFC Extension DLL（MFC扩展DLL）。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;非MFC动态库不采用MFC类库结构，其导出函数为标准的C接口，能被非MFC或MFC编写的应用程序所调用；<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MFC规则DLL 包含一个继承自CWinApp的类，但其无消息循环；<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MFC扩展DLL采用MFC的动态链接版本创建，它只能被用MFC类库所编写的应用程序所调用。<BR><BR><STRONG>静态链接库<BR></STRONG>在VC++6.0中new一个名称为libTest的static library工程，并新建lib.h和lib.cpp两个文件，lib.h和lib.cpp的源代码如下：<BR>
<P class=code><STRONG>//文件：lib.h<BR>#ifndef LIB_H<BR>#define LIB_H<BR>extern "C" int add(int x,int y);　　　//声明为C编译、连接方式的外部函数<BR>#endif<BR><BR>//文件：lib.cpp<BR>#include "lib.h"<BR>int add(int x,int y)<BR>{<BR>return x + y;<BR>}</STRONG></P>
<P><BR><STRONG>　　编译这个工程就得到了一个.lib文件，这个文件就是一个函数库，它提供了add的功能。将头文件和.lib文件提交给用户后，用户就可以直接使用其中的add函数了。<BR><BR>　　标准Turbo C2.0中的C库函数（我们用来的scanf、printf、memcpy、strcpy等）就来自这种静态库。<BR><BR></STRONG>下面来看看怎么使用这个库，在libTest工程所在的工作区内new一个libCall工程。libCall工程仅包含一个main.cpp文件，它演示了静态链接库的调用方法，其源代码如下：<BR></P>
<P></P>
<P class=code><STRONG>#include &lt;stdio.h&gt;<BR>#include "..\lib.h"<BR>#pragma comment( lib, "..\\debug\\libTest.lib" ) 　//指定与静态库一起连接<BR>int main(int argc, char* argv[])<BR>{<BR>printf( "2 + 3 = %d", add( 2, 3 ) );<BR>}</STRONG></P>
<P><BR><STRONG>　　静态链接库的调用就是这么简单，或许我们每天都在用，可是我们没有明白这个概念。代码中#pragma comment( lib , "..\\debug\\libTest.lib" )的意思是指本文件生成的.obj文件应与libTest.lib一起连接。<BR><BR><BR><BR></STRONG></P><img src ="http://www.cppblog.com/ivenher/aggbug/1310.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ivenher/" target="_blank">爱饭盒</a> 2005-11-25 17:24 <a href="http://www.cppblog.com/ivenher/articles/1310.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>