找回密码
 加入我们

QQ登录

只需一步,快速开始

搜索
查看: 5419|回复: 1

[例程] 【分享】#pragma data_seg介绍

[复制链接]

1214

主题

352

回帖

11

精华

管理员

菜鸟

积分
93755

贡献奖关注奖人气王精英奖乐于助人勋章

发表于 2009-5-27 21:41:43 | 显示全部楼层 |阅读模式
<p>
<p><font face="Verdana"></font></p>
<p><font face="Verdana"><font face="Verdana">参考:<a href="http://hi.baidu.com/anglecloudy/blog/item/6bd11e339be86047ad4b5f9c.html">http://hi.baidu.com/anglecloudy/blog/item/6bd11e339be86047ad4b5f9c.html</a></font></font></p>
<p><font face="Verdana">用#pragma data_seg建立一个新的数据段并定义共享数据,其具体格式为: <br/><br/><font color="#000080">  #pragma data_seg ("shareddata") <br/><br/>  HWND sharedwnd=NULL;//共享数据 <br/><br/>  #pragma data_seg()</font>&nbsp;&nbsp;&nbsp;<br/>----------------------------------------------------------------------------------------------------- </p>
<h2><font size="3"><span><font face="Times new=" Roman? New?>1</font></span><span>,</span><span><font face="Times new=" Roman? New?>#pragma data_seg()</font></span><span>一般用于</span><span><font face="Times new=" Roman? New?>DLL</font></span><span>中。也就是说,在</span><span><font face="Times new=" Roman? New?>DLL</font></span><span>中定义一个共享的,有名字的数据段。<span style="COLOR: blue">最关键的是:这个数据段中的全局变量可以被多个进程共享。否则多个进程之间无法共享</span><font face="Times new=" Roman? New?>DLL</font>中的全局变量。</span></font><span><br/><br/><font size="3" face="Times new=" Roman? New?>2</font></span><span><font size="3">,<span style="COLOR: red">共享数据必须初始化,否则微软编译器会把没有初始化的数据放到</span><font face="Times new=" Roman? New?>.BSS</font>段中,从而导致多个进程之间的共享行为失败。</font></span><span><br/><br/><font size="3" face="Times new=" Roman? New?>3</font></span><font size="3"><span>,你所谓的结果正确是一种错觉。如果你在一个</span><span><font face="Times new=" Roman? New?>DLL</font></span><span>中这么写:</span></font><span><br/><br/><font size="3" face="Times new=" Roman? New?>#pragma data_seg("MyData")<br/><br/>int g_Value; // Note that the global is not initialized.<br/><br/>#pragma data_seg()<br/><br/>DLL</font></span><span><font size="3">提供两个接口函数:</font></span><span><br/><br/><font size="3" face="Times new=" Roman? New?>int GetValue()<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return g_Value;<br/>}<br/><br/>void SetValue(int n)<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; g_Value = n;<br/>}<br/><br/></font></span><font size="3"><span>然后启动两个进程</span><span><font face="Times new=" Roman? New?>A</font></span><span>和</span><span><font face="Times new=" Roman? New?>B</font></span><span>,</span><span><font face="Times new=" Roman? New?>A</font></span><span>和</span><span><font face="Times new=" Roman? New?>B</font></span><span>都调用了这个</span><span><font face="Times new=" Roman? New?>DLL</font></span><span>,假如</span><span><font face="Times new=" Roman? New?>A</font></span><span>调用了</span><span><font face="Times new=" Roman? New?>SetValue(5); B</font></span><span>接着调用</span><span><font face="Times new=" Roman? New?>int m = GetValue(); </font></span><span>那么</span><span><font face="Times new=" Roman? New?>m</font></span><span>的值不一定是</span><span><font face="Times new=" Roman? New?>5</font></span><span>,而是一个未定义的值。因为</span><span><font face="Times new=" Roman? New?>DLL</font></span><span>中的全局数据对于每一个调用它的进程而言,是私有的,不能共享的。<span style="COLOR: blue">假如你对</span><font face="Times new=" Roman? New?>g_Value</font>进行了初始化,那么</span><span><font face="Times new=" Roman? New?>g_Value</font>就一定会被放进</span><span><font face="Times new=" Roman? New?>MyData</font>段中。换句话说,如果</span><span><font face="Times new=" Roman? New?>A</font>调用了</span><span><font face="Times new=" Roman? New?>SetValue(5); B</font>接着调用</span><span><font face="Times new=" Roman? New?>int m = GetValue(); </font>那么</span><span><font face="Times new=" Roman? New?>m</font>的值就一定是</span><span><font face="Times new=" Roman? New?>5</font>!这就实现了跨进程之间的数据通信!</span></font></h2></font>
<p><font face="Verdana">&nbsp;&nbsp;&nbsp;&nbsp;<font size="3"> 有的时候我们可能想让一个应用程序只启动一次,就像单件模式(singleton)一样,实现的方法可能有多种,这里说说用#pragma data_seg来实现的方法,很是简洁便利。</font></p>
<p><font size="3"></font></p>
<p>&nbsp;</p>
<p><strong><font color="#0000ff">下面看一个实际应用,用共享数据来统计应用程序启动的次数,并作相应的处理。</font></strong> </p>
<p><br/>在应用程序的入口处:<br/>//控制应用程序只能启动一次<br/>#pragma data_seg("flag_data")<br/>&nbsp;&nbsp; int count=0;<br/>#pragma data_seg()<br/>#pragma comment(linker,"/SECTION:flag_data,RWS")</p>
<p><font size="3">然后程序启动的地方加上(</font>程序中):<br/>&nbsp;&nbsp; if(count&gt;1)<br/>&nbsp;&nbsp;&nbsp;&nbsp; {<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MessageBox("已经启动了一个应用程序","Warning",MB_OK);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; //printf("no%d application", app_count);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return FLASE;<br/>}<br/>&nbsp;&nbsp; count++;</p>
<p>
<p><font size="3"></font>&nbsp;</p></p>
<p><font size="3">Windows在一个Win32程序的地址空间周围筑了一道墙。通常,一个程序的地址空间中的数据是私有的,对别的程序而言是不可见的。但是执行STRPROG的多个执行实体表示了STRLIB在程序的所有执行实体之间共享数据是毫无问题的。当您在一个STRPROG窗口中增加或者删除一个字符串时,这种改变将立即反映在其它的窗口中。</font></p>
<p><font size="3">在全部例程之间,STRLIB共享两个变量:一个字符数组和一个整数(记录已储存的有效字符串的个数)。STRLIB将这两个变量储存在共享的一个特殊内存区段中:</font></p>
<p><font size="3"></font>&nbsp;</p>
<p><font size="3">#pragma&nbsp; data_seg ("shared")&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;int&nbsp;&nbsp; iTotal = 0 ;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;WCHAR&nbsp; szStrings [MAX_STRINGS][MAX_LENGTH + 1] = { '\0' } ;<br/>#pragma&nbsp;&nbsp;&nbsp; data_seg ()</font></p>
<p><br/><font size="3">第一个#pragma叙述建立数据段,这里命名为shared。您可以将这段命名为任何一个您喜欢的名字。在这里的#pragma叙述之后的所有初始化了的变量都放在shared数据段中。第二个#pragma叙述标示段的结束。对变量进行专门的初始化是很重要的,否则编译器将把它们放在普通的未初始化数据段中而不是放在shared中。</font></p>
<p><br/><font size="3">连结器必须知道有一个「shared」共享数据段。在「Project Settings」对话框选择「Link」页面卷标。选中「STRLIB」时在「Project Options」字段(在Release和Debug设定中均可),包含下面的连结叙述:</font></p>
<p><font size="3">/SECTION:shared,RWS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br/>字母RWS表示段具有读、写和共享属性。或者,您也可以直接用DLL原始码指定连结选项,就像我们在STRLIB.C那样:</font></p>
<p><font size="3"></font>&nbsp;</p>
<p><font size="3">#pragma comment(linker,"/SECTION:shared,RWS") <br/>共享的内存段允许iTotal变量和szStrings字符串数组在STRLIB的所有例程之间共享。因为MAX_STRINGS等于256,而MAX_LENGTH等于63,所以,共享内存段的长度为32,772字节-iTotal变量需要4字节,256个指针中的每一个都需要128字节。<br/></font></font></p>
[此贴子已经被作者于2009-5-27 22:13:05编辑过]
【VB】QQ群:1422505加的请打上VB好友
【易语言】QQ群:9531809  或 177048
【FOXPRO】QQ群:6580324  或 33659603
【C/C++/VC】QQ群:3777552
【NiceBasic】QQ群:3703755

1214

主题

352

回帖

11

精华

管理员

菜鸟

积分
93755

贡献奖关注奖人气王精英奖乐于助人勋章

 楼主| 发表于 2009-5-27 21:57:06 | 显示全部楼层
<p><font face="Verdana">http://www.cnblogs.com/ahuo/archive/2008/04/08/1143488.html </font></p>
<p><font face="Verdana">#pragma data_seg("flag_data")<br/>&nbsp;&nbsp; int count=0;<br/>#pragma data_seg()<br/>#pragma comment(linker,"/SECTION:flag_data,RWS")<br/>这种方法只能在没有def文件时使用,如果通过def文件进行导出的话,那么设置就要在def文件内设置而不能<br/>在代码里设置了。<br/>SETCTIONS <br/>flag_data READ WRITE SHARED</font></p>
<p><font face="Verdana">在主文件中,用#pragma data_seg建立一 </font></p>
<p><font face="Verdana">个新的数据段并定义共享数据,其具体格式为: </font></p>
<p><font face="Verdana">#pragma data_seg ("shareddata") //名称可以 </font></p>
<p><font face="Verdana">//自己定义,但必须与下面的一致。 </font></p>
<p><font face="Verdana">HWND sharedwnd=NULL;//共享数据 </font></p>
<p><font face="Verdana">#pragma data_seg() </font></p>
<p><font face="Verdana">仅定义一个数据段还不能达到共享数据的目的,还要告诉编译器该段的属性,有两种方法可以实现该目的(其效果是相同的),一种方法是在.DEF文件中加入如下语句: SETCTIONS shareddata READ WRITE SHARED 另一种方法是在项目设置链接选项(Project Setting --〉Link)中加入如下语句: /SECTION:shareddata,rws </font></p>
<p><font face="Verdana">第一点:什么是共享数据段?为什么要用共享数据段??它有什么用途?? <br/>在Win16环境中,DLL的全局数据对每个载入它的进程来说都是相同的;而在Win32环境中,情况却发生了变化,DLL函数中的代码所创建的任何对象(包括变量)都归调用它的线程或进程所有。当进程在载入DLL时,操作系统自动把DLL地址映射到该进程的私有空间,也就是进程的虚拟地址空间,而且也复制该DLL的全局数据的一份拷贝到该进程空间。也就是说每个进程所拥有的相同的DLL的全局数据,它们的名称相同,但其值却并不一定是相同的,而且是互不干涉的。 </font></p>
<p><font face="Verdana">因此,在Win32环境下要想在多个进程中共享数据,就必须进行必要的设置。在访问同一个Dll的各进程之间共享存储器是通过存储器映射文件技术实现的。也可以把这些需要共享的数据分离出来,放置在一个独立的数据段里,并把该段的属性设置为共享。必须给这些变量赋初值,否则编译器会把没有赋初始值的变量放在一个叫未被初始化的数据段中。 </font></p>
<p><font face="Verdana">#pragma data_seg预处理指令用于设置共享数据段。例如: </font></p>
<p><font face="Verdana">#pragma data_seg("SharedDataName") HHOOK hHook=NULL; //必须在定义的同时进行初始化!!!!#pragma data_seg() </font></p>
<p><font face="Verdana">在#pragma data_seg("SharedDataName")和#pragma data_seg()之间的所有变量将被访问该Dll的所有进程看到和共享。再加上一条指令#pragma comment(linker,"/section:.SharedDataName,rws"),[注意:数据节的名称is case sensitive]那么这个数据节中的数据可以在所有DLL的实例之间共享。所有对这些数据的操作都针对同一个实例的,而不是在每个进程的地址空间中都有一份。 </font></p>
<p><font face="Verdana">当进程隐式或显式调用一个动态库里的函数时,系统都要把这个动态库映射到这个进程的虚拟地址空间里(以下简称"地址空间")。这使得DLL成为进程的一部分,以这个进程的身份执行,使用这个进程的堆栈。(这项技术又叫code Injection技术,被广泛地应用在了病毒、黑客领域!呵呵^_^) </font></p>
<p><font face="Verdana"><br/></font>&nbsp;</p>
【VB】QQ群:1422505加的请打上VB好友
【易语言】QQ群:9531809  或 177048
【FOXPRO】QQ群:6580324  或 33659603
【C/C++/VC】QQ群:3777552
【NiceBasic】QQ群:3703755
您需要登录后才可以回帖 登录 | 加入我们

本版积分规则

快速回复 返回顶部 返回列表