﻿<?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++博客-酱坛子-文章分类-1. MFC</title><link>http://www.cppblog.com/sunraiing9/category/1806.html</link><description>专注C++技术  在这里写下自己的学习心得 感悟 
和大家讨论 共同进步（欢迎批评！！！）</description><language>zh-cn</language><lastBuildDate>Mon, 19 May 2008 14:48:26 GMT</lastBuildDate><pubDate>Mon, 19 May 2008 14:48:26 GMT</pubDate><ttl>60</ttl><item><title>WindowsMediaPlayer控件的使用</title><link>http://www.cppblog.com/sunraiing9/articles/14456.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Tue, 31 Oct 2006 16:36:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/articles/14456.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/14456.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/articles/14456.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/14456.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/14456.html</trackback:ping><description><![CDATA[
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td valign="top">
										<span class="arttitle">WindowsMediaPlayer控件的使用</span>
								</td>
						</tr>
						<tr>
								<td class="details" valign="top" align="right">By  孙悟空 发表于 2006-3-15 14:00:00  </td>
						</tr>
						<tr>
								<td class="artbody" valign="top">
										<br />[基本属性] 　 <br />URL:String; 指定媒体位置，本机或网络地址 <br />uiMode:String; 播放器界面模式，可为Full, Mini, None, Invisible <br />playState:integer; 播放状态，1=停止，2=暂停，3=播放，6=正在缓冲，9=正在连接，10=准备就绪 <br />enableContextMenu:Boolean; 启用/禁用右键菜单 <br />fullScreen:boolean; 是否全屏显示  
<p></p><p> [controls]  播放器基本控制 <br />controls.play; 播放 <br />controls.pause; 暂停 <br />controls.stop; 停止 <br />controls.currentPosition:double; 当前进度 <br />controls.currentPositionString:string; 当前进度，字符串格式。如“00:23” <br />controls.fastForward; 快进 <br />controls.fastReverse; 快退 <br />controls.next; 下一曲 <br />controls.previous; 上一曲 </p><p> [settings]播放器基本设置 <br />settings.volume:integer; 音量，0-100 <br />settings.autoStart:Boolean; 是否自动播放 <br />settings.mute:Boolean; 是否静音 <br />settings.playCount:integer; 播放次数 </p><p> [currentMedia] 当前媒体属性 <br />currentMedia.duration:double; 媒体总长度 <br />currentMedia.durationString:string; 媒体总长度，字符串格式。如“03:24” <br />currentMedia.getItemInfo(const string); 获取当前媒体信息"Title"=媒体标题，"Author"=艺术家，"Copyright"=版权信息，"Description"=媒体内容描述，"Duration"=持续时间（秒），"FileSize"=文件大小，"FileType"=文件类型，"sourceURL"=原始地址 <br />currentMedia.setItemInfo(const string); 通过属性名设置媒体信息 <br />currentMedia.name:string; 同 currentMedia.getItemInfo("Title") </p><p> [currentPlaylist] 当前播放列表属性 <br />currentPlaylist.count:integer; 当前播放列表所包含媒体数 <br />currentPlaylist.Item[integer]; 获取或设置指定项目媒体信息</p></td>
						</tr>
						<tr>
								<td valign="top"> </td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.cppblog.com/sunraiing9/aggbug/14456.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2006-11-01 00:36 <a href="http://www.cppblog.com/sunraiing9/articles/14456.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CSliderctrl类的成员函数 </title><link>http://www.cppblog.com/sunraiing9/articles/14451.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Tue, 31 Oct 2006 15:06:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/articles/14451.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/14451.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/articles/14451.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/14451.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/14451.html</trackback:ping><description><![CDATA[
		<h1>CSliderctrl类的成员函数 </h1>作者：未知<br /><br /><table height="150" width="150" align="right"><tbody><tr><td><div id="the300"> </div></td></tr></tbody></table>csliderctrl类的成员函数，可以对轨道条进行查询和设置：<br /><br />用getrange和setrange来查询和设置轨道条的范围，缺省的范围是0-100．函数的声明为<br /><br />void getrange( int&amp; nmin, int&amp; nmax ) const;<br /><br />void setrange( int nmin, int nmax, bool bredraw = false );<br /><br />参数nmin和nmax分别是最小和最大值，参数bredraw为true时将重绘控件．<br /><br />用getpos和setpos来查询和设置轨道条的当前值．函数的声明为<br /><br />int getpos( ) const;<br /><br />void setpos( int npos );<br /><br />用getlinesize和setlinesize来查询和设置在按一下左箭头键或右箭头键时滑尺的移动量，该移动量的缺省值是1个单位．函数的声明为<br /><br />int getlinesize( ) const;<br /><br />int setlinesize( int nsize );<br /><br />用getpagesize和setpagesize来查询和设置滑尺的块移动量，块移动量是指当按下pgup或pgdown键时滑尺的移动量．函数的声明为<br /><br />int getpagesize( ) const;<br /><br />int setpagesize( int nsize );<br /><br />用setticfreq设置轨道条的刻度的频度．缺省的频度是每个单位都有一个刻度，在范围较大时，为了使刻度不至于过密，需要调用该函数设置一个合理的频度．函数的声明为<br /><br />void setticfreq( int nfreq );<br /><br />参数nfreq说明了两个刻度之间的间隔．<br /><br />用函数settic来在指定位置设置刻度．windows自动显示的刻度是均匀的，利用该函数可以人为设置不均匀的刻度，该函数的声明为<br /><br />bool settic( int ntic );<br /><br />用函数cleartics来清除所有的刻度．该函数的声明为<br /><br />void cleartics( bool bredraw = false );<br /><br /><img src ="http://www.cppblog.com/sunraiing9/aggbug/14451.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2006-10-31 23:06 <a href="http://www.cppblog.com/sunraiing9/articles/14451.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SetTimer函数</title><link>http://www.cppblog.com/sunraiing9/articles/14449.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Tue, 31 Oct 2006 14:52:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/articles/14449.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/14449.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/articles/14449.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/14449.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/14449.html</trackback:ping><description><![CDATA[
		<div class="tit">SetTimer函数</div>
		<div class="date">2006年09月07日 星期四 15:10</div>
		<table style="TABLE-LAYOUT: fixed">
				<tbody>
						<tr>
								<td>
										<div class="cnt">
												<p>什么时候我们需要用到SetTimer函数呢？当你需要每个一段时间执行一件事的的时候托枰 褂肧etTimer函数了。 使用定时器的方法比较简单，通常告诉WINDOWS一个时间间隔，然后WINDOWS以此时间间隔周期性触发程序。通常有两种方法来实现：发送WM_TIMER消息和调用应用程序定义的回调函数。 </p>
												<p> </p>
												<p>1.1 用WM_TIMER来设置定时器</p>
												<p>先请看SetTimer这个API函数的原型 </p>
												<p>UINT_PTR SetTimer(<br />  HWND hWnd,              // 窗口句柄<br />  UINT_PTR nIDEvent,      // 定时器ID，多个定时器时，可以通过该ID判断是哪个定时器<br />  UINT uElapse,           // 时间间隔,单位为毫秒<br />  TIMERPROC lpTimerFunc   // 回调函数<br />);</p>
												<p>例如 <br />SetTimer(m_hWnd,1,1000,NULL); //一个1秒触发一次的定时器<br />在MFC程序中SetTimer被封装在CWnd类中，调用就不用指定窗口句柄了</p>
												<p>于是SetTimer函数的原型变为： </p>
												<p>UINT SetTimer(UINT nIDEvent,UINT nElapse,void(CALLBACK EXPORT *lpfnTimer)(HWND,UINT ,YINT ,DWORD)) </p>
												<p>当使用SetTimer函数的时候，就会生成一个计时器。函数中nIDEvent指的是计时器的标识，也就是名字。nElapse指的是时间间隔，也就是每隔多长时间触发一次事件。第三个参数是一个回调函数，在这个函数里，放入你想要做的事情的代码，你可以将它设定为NULL，也就是使用系统默认的回调函数，系统默认认的是onTime函数。这个函数怎么生成的呢？你需要在需要计时器的类的生成onTime函数：在ClassWizard里，选择需要计时器的类，添加WM_TIME消息映射，就自动生成onTime函数了。然后在函数里添加代码，让代码实现功能。每隔一段时间就会自动执行一次。 </p>
												<p>例： </p>
												<p>SetTimer(1,1000,NULL); </p>
												<p>1:计时器的名称； </p>
												<p>1000：时间间隔，单位是毫秒； </p>
												<p>NULL:使用onTime函数。 </p>
												<p>当不需要计时器的时候调用KillTimer(nIDEvent); </p>
												<p>例如：KillTimer(1); </p>
												<p>1.2 调用回调函数</p>
												<p>此方法首先写一个如下格式的回调函数</p>
												<p>void CALLBACK TimerProc(HWND hWnd,UINT nMsg,UINT nTimerid,DWORD dwTime);<br />然后再用SetTimer(1,100,TimerProc)函数来建一个定时器，第三个参数就是回调函数地址。</p>
												<p>二. 或许你会问，如果我要加入两个或者两个以上的 timer怎么办？ </p>
												<p>继续用SetTimer函数吧，上次的timer的ID是1，这次可以是2，3，4。。。。 </p>
												<p>SetTimer(2,1000,NULL); </p>
												<p>SetTimer(3,500,NULL); </p>
												<p>嗯，WINDOWS会协调他们的。当然onTimer函数体也要发生变化，要在函数体内添加每一个timer的处理代码： </p>
												<p>onTimer(nIDEvent) </p>
												<p>{ </p>
												<p>switch(nIDEvent) </p>
												<p>{ </p>
												<p>case 1:........; </p>
												<p>break; </p>
												<p>case 2:.......; </p>
												<p>break; </p>
												<p>case 3:......; </p>
												<p>break; </p>
												<p>} </p>
												<p>}</p>
												<p> </p>
												<p> </p>
												<p>在MFC用使用Timer 可以先用MFC Class Wizard给CXxxxDlg添加一个WM_TIMER的消息响应函数</p>
												<p>在void CLXWGDlg::OnTimer(UINT nIDEvent)中写入执行的操作  然后在响应的函数里用</p>
												<p> SetTimer(1,100,NULL)调用;</p>
										</div>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.cppblog.com/sunraiing9/aggbug/14449.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2006-10-31 22:52 <a href="http://www.cppblog.com/sunraiing9/articles/14449.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CToolBar的一些简单用法</title><link>http://www.cppblog.com/sunraiing9/articles/14004.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Sun, 22 Oct 2006 05:45:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/articles/14004.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/14004.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/articles/14004.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/14004.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/14004.html</trackback:ping><description><![CDATA[
		<p nd="4">1) Right click <a class="iAs" style="FONT-WEIGHT: normal; FONT-SIZE: 100%; PADDING-BOTTOM: 1px; COLOR: darkgreen; BORDER-BOTTOM: darkgreen 0.07em solid; BACKGROUND-COLOR: transparent; TEXT-DECORATION: underline" href="http://www.codeproject.com/useritems/UsingToolBarOnDialog.asp#" target="_blank" itxtdid="2890859">Solution</a> Explorer -&gt; Add -&gt; Resource -&gt; Tool Bar -&gt; New. This will open into Tool Bar Editor. 
</p>
		<p nd="5">2)You can Create/Paint Buttons here. Make sure you change the default Ids of these buttons to some proper usable ids. (Use Property Explorer for this), this will create a .bmp image in resources. (Lets say, The Tool Bar is ‘TDR_TOOLBAR1’ and the two buttons are ‘IDC_TBUTTON1’ and ‘IDC_TBUTTON2’ ) 
</p>
		<p nd="6">3)Now go to the .h for dialog(You can add a class to a dialog) on which toolbar need to be placed. Declare a ‘CToolBar’ Object </p>
		<pre nd="7">CToolBar m_FirstToolBar
</pre>
		<p nd="8">4)Now on the .cpp file of the dialog, in ‘OnInitDialog()’ add following code;(You Can add OnInitDialog event to the directly by declaring it in .h file added and using it in .cpp file) </p>
		<pre nd="9">if(!m_FirstToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) || !m_FirstToolBar.LoadToolBar(IDR_TOOLBAR1))
{
   EndDialog(IDCANCEL);
}

RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST,0);
 
</pre>
		<p nd="10">4.1. Here you can see the various attributes set for the toolbar in ‘CreateEx(...)’ like ‘TBSTYLE_FLAT’ for flat look of toolbar buttons; 
</p>
		<p nd="11">4.2 In ‘LoadToolBar(...)’ the Resource created for the toolbar is used. This maps our toolbar object ‘m_FirstToolBar’ with resource ‘IDR_TOOLBAR1’ 
</p>
		<p nd="12">4.3 ‘RepositionBars()’ is used to place the toolbar on the dialog. 
</p>
		<p nd="13">5) ‘MoveWindow()’ can be used to place the toolbar on the desired position. </p>
		<pre nd="14">m_FirstToolBar.MoveWindow( 50, 0,100, 100, 1 );
</pre>
		<p nd="4">Now if you have finalized the place where you want to place the tool bar you can put it there using MoveWindow(...), my suggestion is to put a label in the design of dialog at place you want to put you toolbar; Then at run time get the position of this label and place the toolbar there using MoveWindow(...) </p>
		<p nd="15">If you want to place this toolbar on Top Left and dynamically move all the controls accordingly and increase the dialog dimensions refer the article on this site I suggested above. 
</p>
		<p nd="16">6)This is how the buttons of Tool Bar can be made visible/invisible </p>
		<pre nd="17">m_FirstToolBar.GetToolBarCtrl().HideButton(IDC_TBUTTON1, TRUE);
</pre>
		<p nd="4">Notice that we have used the ‘IDC_TBUTTON1’ which we declared at the time of creating toolbar resource. </p>
		<p nd="18">7) Similarly </p>
		<pre nd="19">m_FirstToolBar.GetToolBarCtrl().EnableButton(IDC_TBUTTON1,false)
</pre>
		<p nd="4">can be used to disable a button. </p>
		<p nd="20">8) To handle Click events: 8.1 Add following line to BEGIN_MESSAGE_MAP() </p>
		<pre nd="21">ON_COMMAND(IDC_TBUTTON1,OnToolBarButton1) 
</pre>
		<p nd="4">8.2 Write the desired code in .cpp file </p>
		<pre nd="22">FirstToolBarDialog:: OnToolBarButton1()

{

- - - 

      - - - 

}
<br /> </pre>
<img src ="http://www.cppblog.com/sunraiing9/aggbug/14004.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2006-10-22 13:45 <a href="http://www.cppblog.com/sunraiing9/articles/14004.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MFC DLL向导(摘)</title><link>http://www.cppblog.com/sunraiing9/articles/13739.html</link><dc:creator>@王一伟</dc:creator><author>@王一伟</author><pubDate>Mon, 16 Oct 2006 00:42:00 GMT</pubDate><guid>http://www.cppblog.com/sunraiing9/articles/13739.html</guid><wfw:comment>http://www.cppblog.com/sunraiing9/comments/13739.html</wfw:comment><comments>http://www.cppblog.com/sunraiing9/articles/13739.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunraiing9/comments/commentRss/13739.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunraiing9/services/trackbacks/13739.html</trackback:ping><description><![CDATA[虽然能用DLL实现的东西都可以用COM来实现，但DLL的优点确实不少，它更容易创建。本文将讨论如何利用MFC来创建不同类型的DLL，以及如何使用他们。<br /><br />一、DLL的不同类型<br />    使用MFC可以生成两种类型的DLL：MFC扩展DLL和常规DLL。常规DLL有可以分为动态连接和静态连接。Visual C++还可以生成WIN32 DLL，但不是这里讨论的主要对象。<br />1、MFC扩展DLL<br />   每个DLL都有某种类型的接口：变量、指针、函数、客户程序访问的类。它们的作用是让客户程序使用DLL，MFC扩展DLL可以有C++的接口。也就是它可以导出C++类给客户端。导出的函数可以使用C++/MFC数据类型做参数或返回值，导出一个类时客户端能创建类对象或者派生这个类。同时，在DLL中也可以使用DLL和MFC。<br />   Visual C++使用的MFC类库也是保存在一个DLL中，MFC扩展DLL动态连接到MFC代码库的DLL，客户程序也必须要动态连接到MFC代码库的DLL。（这里谈到的两个DLL，一个是我们自己编写的DLL，一个装MFC类库的DLL）现在MFC代码库的DLL也存在多个版本，客户程序和扩展DLL都必须使用相同版本的MFC代码DLL。所以为了让MFC扩展DLL能很好的工作，扩展DLL和客户程序都必须动态连接到MFC代码库DLL。而这个DLL必须在客户程序运行的计算机上。<br />2、常规DLL<br />   使用MFC扩展DLL的一个问题就是DLL仅能和MFC客户程序一起工作，如果需要一个使用更广泛的DLL，最好采用常规DLL，因为它不受MFC的某些限制。常规DLL也有缺点：它不能和客户程序发送指针或MFC派生类和对象的引用。一句话就是常规DLL和客户程序的接口不能使用MFC，但在DLL和客户程序的内部还是可以使用MFC。<br />   当在常规DLL的内部使用MFC代码库的DLL时，可以是动态连接/静态连接。如果是动态连接，也就是常规DLL需要的MFC代码没有构建到DLL中，这种情况有点和扩展DLL类似，在DLL运行的计算机上必须要MFC代码库的DLL。如果是静态连接，常规DLL里面已经包含了需要的MFC代码，这样DLL的体积将比较大，但它可以在没有MFC代码库DLL的计算机上正常运行。<br /><br />二、建立DLL<br />    利用Visual C++提供的向导功能可以很容易建立一个不完成任何实质任务的DLL，这里就不多讲了，主要的任务是如何给DLL添加功能，以及在客户程序中利用这个DLL<br />1、导出类<br />   用向导建立好框架后，就可以添加需要导出类的.cpp .h文件到DLL中来，或者用向导创建C++ Herder File/C++ Source File。为了能导出这个类，在类声明的时候要加“_declspec(dllexport)”,如：<br />class _declspec(dllexport) CMyClass<br />{<br />     ...//声明<br />}<br />如果创建的MFC扩展DLL，可以使用宏：AFX_EXT_CLASS:<br />class AFX_EXT_CLASS CMyClass<br />{<br />     ...//声明<br />}<br />这样导出类的方法是最简单的，也可以采用.def文件导出，这里暂不详谈。<br />2、导出变量、常量、对象<br />   很多时候不需要导出一个类，可以让DLL导出一个变量、常量、对象，导出它们只需要进行简单的声明：_declspec(dllexport) int MyInt;<br />  _declspec(dllexport) extern const COLORREF MyColor=RGB(0,0,0);<br />  _declspec(dllexport) CRect rect(10,10,20,20);<br />要导出一个常量时必须使用关键字extern，否则会发生连接错误。<br />注意：如果客户程序识别这个类而且有自己的头文件，则只能导出一个类对象。如果在DLL中创建一个类，客户程序不使用头文件就无法识别这个类。<br />  当导出一个对象或者变量时，载入DLL的每个客户程序都有一个自己的拷贝。也就是如果两个程序使用的是同一个DLL，一个应用程序所做的修改不会影响另一个应用程序。<br />  我们在导出的时候只能导出DLL中的全局变量或对象，而不能导出局部的变量和对象，因为它们过了作用域也就不存在了，那样DLL就不能正常工作。如：<br />MyFunction()<br />{<br />      _declspec(dllexport) int MyInt;<br />      _declspec(dllexport) CMyClass object;<br />}<br />3、导出函数<br />导出函数和导出变量/对象类似，只要把_declspec(dllexport)加到函数原型开始的位置：<br />_declspec(dllexport) int MyFunction(int);<br />如果是常规DLL，它将和C写的程序使用，声明方式如下：<br />extern "c" _declspec(dllexport) int MyFunction(int);<br />实现：<br />extern "c" _declspec(dllexport) int MyFunction(int x)<br />{<br />     ...//操作<br />}<br />如果创建的是动态连接到MFC代码库DLL的常规DLL，则必须插入AFX_MANAGE_STATE作为导出函数的首行，因此定义如下：<br />extern "c" _declspec(dllexport) int MyFunction(int x)<br />{<br />     AFX_MANAGE_STATE(AfxGetStaticModuleState());<br />     ...//操作<br />}<br />有时候为了安全起见，在每个常规DLL里都加上，也不会有任何问题，只是在静态连接的时候这个宏无效而已。这是导出函数的方法，记住只有MFC扩展DLL才能让参数和返回值使用MFC的数据类型。<br />4、导出指针<br />导出指针的方式如下：<br />_declspec(dllexport) int *pint;<br />_declspec(dllexport) CMyClass object = new CMyClass;<br />如果声明的时候同时初始化了指针，就需要找到合适的地方类释放指针。在扩展DLL中有个函数DllMain()。（注意函数名中的两个l要是小写字母），可以在这个函数中处理指针：<br /># include "MyClass.h"<br />_declspec(dllexport) CMyClass *pobject = new CMyClass;<br />DllMain(HINSTANCE hInstance,DWORD dwReason,LPVOID lpReserved)<br />{<br />    if(dwReason == DLL_PROCESS_ATTACH)<br />    {<br />        .....//<br />    }<br />    else if(dwReason == DLL_PROCESS_DETACH)<br />    {<br />        delete pobject;<br />    }<br />}<br />常规DLL有一个从CWinApp派生的类对象处理DLL的开和关，可以使用类向导添加InitInstance/ExitInstance函数。<br />int CMyDllApp::ExitInstance()<br />{<br />    delete pobject;<br />    return CWinApp::ExitInstance();<br />}<br /><br />三、在客户程序中使用DLL<br />    编译一个DLL时将创建两个文件.dll文件和.lib文件。首先将这两个文件复制到客户程序项目的文件夹里，这里需要注意DLL和客户程序的版本问题，尽量使用相同的版本，都使用RELEASE或者都是DEBUG版本。<br />   接着就需要在客户程序中设置LIB文件，打开Project Settings---&gt;Link---&gt;Object/library Modules中输入LIB的文件名和路径。如：Debug/SampleDll.lib。除了DLL和LIB文件外，客户程序需要针对导出类、函数、对象和变量的头文件，现在进行导入添加的关键字就是：_declspec(dllimport)，如：<br />_declspec(dllimport) int MyFunction(int);<br />_declspec(dllimport) int MyInt;<br />_declspec(dllimport) CMyClass object;<br />extern "C" _declspec(dllimport) int MyFunction(int);<br />在有的时候为了导入类，要把相应类的头文件添加到客户程序中，不同的是要修改类声明的标志：<br />class _declspec(dllimport) CMyClass，如果创建的是扩展DLL，两个位置都是:<br />class AFX_EXT_CLASS CMyClass。<br /><br /><br />使用DLL的一个比较严重的问题就是编译器之间的兼容性问题。不同的编译器对c++函数在二进制级别的实现方式是不同的。所以对基于C++的DLL，如果编译器不同就有很麻烦的。如果创建的是MFC扩展DLL，就不会存在问题，因为它只能被动态连接到MFC的客户应用程序。这里不是本文讨论的重点。<br /><br />一、重新编译问题<br />我们先来看一个在实际中可能遇到的问题：<br />    比如现在建立好了一个DLL导出了CMyClass类，客户也能正常使用这个DLL，假设CMyClass对象的大小为30字节。如果我们需要修改DLL中的CMyClass类，让它有相同的函数和成员变量，但是给增加了一个私有的成员变量int类型，现在CMyClass对象的大小就是34字节了。当直接把这个新的DLL给客户使用替换掉原来30字节大小的DLL，客户应用程序期望的是30字节大小的对象，而现在却变成了一个34字节大小的对象，糟糕，客户程序出错了。<br />    类似的问题，如果不是导出CMyClass类，而在导出的函数中使用了CMyClass，改变对象的大小仍然会有问题的。这个时候修改这个问题的唯一办法就是替换客户程序中的CMyClass的头文件，全部重新编译整个应用程序，让客户程序使用大小为34字节的对象。<br />    这就是一个严重的问题，有的时候如果没有客户程序的源代码，那么我们就不能使用这个新的DLL了。<br /><br />二、解决方法   <br /> 为了能避免重新编译客户程序，这里介绍两个方法：（1）使用接口类。（2）使用创建和销毁类的静态函数。<br />1、使用接口类<br />   接口类的也就是创建第二个类，它作为要导出类的接口，所以在导出类改变时，也不需要重新编译客户程序，因为接口类没有发生变化。<br />   假设导出的CMyClass类有两个函数FunctionA FunctionB。现在创建一个接口类CMyInte***ce，下面就是在DLL中的CMyInte***ce类的头文件的代码：<br /># include "MyClass.h"<br />class _declspec(dllexport) CMyInte***ce<br />{<br />     CMyClass *pmyclass;<br />     CMyInte***ce();<br />     ~CMyInte***ce();<br />  public:<br />     int FunctionA(int);<br />     int FunctionB(int);<br />};<br />而在客户程序中的头文件稍不同，不需要INCLUDE语句，因为客户程序没有它的拷贝。相反，使用一个CMyClass的向前声明，即使没有头文件也能编译：<br />class _declspec(dllexport) CMyInte***ce<br />{<br />     class CMyClass;//向前声明<br />     CMyClass *pmyclass;<br />     CMyInte***ce();<br />     ~CMyInte***ce();<br />  public:<br />     int FunctionA(int);<br />     int FunctionB(int);<br />};<br />在DLL中的CMyInte***ce的实现如下：<br />CMyInte***ce::CMyInte***ce()<br />{<br />      pmyclass = new CMyClass();<br />}<br />CMyInte***ce::~CMyInte***ce()<br />{<br />     delete pmyclass;<br />}<br />int CMyInte***ce::FunctionA()<br />{<br />     return pmyclass-&gt;FunctionA();<br />}<br />int CMyInte***ce::FunctionB()<br />{<br />     return pmyclass-&gt;FunctionB();    <br />}<br />.....<br />对导出类CMyClass的每个成员函数，CMyInte***ce类都提供自己的对应的函数。客户程序与CMyClass没有联系，这样任意改CMyClass也不会有问题，因为CMyInte***ce类的大小没有发生变化。即使为了能访问CMyClass中的新增变量而给CMyInte***ce类加了函数也不会有问题的。<br />   但是这种方法也存在明显的问题，对导出类的每个函数和成员变量都要对应实现，有的时候这个接口类会很庞大。同时增加了客户程序调用所需要的时间。增加了程序的开销。<br /><br />2、使用静态函数<br />   还可以使用静态函数来创建和销毁类对象。创建一个导出类的时候，增加两个静态的公有函数CreateMe()/DestroyMe()，头文件如下：<br />class _declspec(dllexport) CMyClass<br />{<br />     CMyClass();<br />     ~CMyClass();<br />  public:<br />     static CMyClass *CreateMe();<br />     static void DestroyMe(CMyClass *ptr);<br />};<br />实现函数就是：<br />CMyClass * CMyClass::CMyClass()<br />{<br />      return new CMyClass;<br />}<br />void CMyClass::DestroyMe(CMyClass *ptr)<br />{<br />      delete ptr;<br />}<br />然后象其他类一样导出CMyClass类，这个时候在客户程序中使用这个类的方法稍有不同了。如若想创建一个CMyClass对象，就应该是：<br />CMyClass x;<br />CMyClass *ptr = CMyClass::CreateMe();<br />在使用完后删除：<br />CMyClass::DestroyMe(ptr);<br /><img src ="http://www.cppblog.com/sunraiing9/aggbug/13739.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunraiing9/" target="_blank">@王一伟</a> 2006-10-16 08:42 <a href="http://www.cppblog.com/sunraiing9/articles/13739.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>