原文地址:http://www.cnblogs.com/CBDoctor/archive/2013/01/26/2878201.htmlhtml
1)#pragma data_seg()通常用於DLL中。也就是說,在DLL中定義一個共享的,有名字的數據段。最關鍵的是:這個數據段中的全局變量能夠被多個進程共享。不然多個進程之間沒法共享DLL中的全局變量。app
2)共享數據必須初始化,不然微軟編譯器會把沒有初始化的數據放到.BSS段中,從而致使多個進程之間的共享行爲失敗。ide
3)你所謂的結果正確是一種錯覺。若是你在一個DLL中這麼寫:
#pragma data_seg("MyData")
int g_Value; // Note that the global is not initialized.
#pragma data_seg()
DLL提供兩個接口函數:函數
啓動兩個進程A和B,A和B都調用了這個DLL,假如A調用了SetValue(5); B接着調用int m = GetValue(); 那麼m的值不必定是5,而是一個未定義的值。由於DLL中的全局數據對於每個調用它的進程而言,是私有的,不能共享的。假如你對g_Value進行了初始化,那麼g_Value就必定會被放進MyData段中。換句話說,若是A調用了SetValue(5); B接着調用int m = GetValue();那麼m的值就必定是5!這就實現了跨進程之間的數據通訊!this
有的時候咱們可能想讓一個應用程序只啓動一次,就像單件模式(singleton)同樣,實現的方法可能有多種,這裏說說#pragma data_seg來實現的方法,非常簡潔便利。應用程序的入口文件前面加上
#pragma data_seg("flag_data")
int app_count = 0;
#pragma data_seg()
#pragma comment(linker,"/SECTION:flag_data,RWS")spa
而後程序啓動的地方加上操作系統
這種方法只能在沒有def文件時使用,若是經過def文件進行導出的話,那麼設置就要在def文件內設置而不能在代碼裏設置了。線程
SETCTIONS
flag_data READ WRITE SHARED
在主文件中,用#pragma data_seg創建一 個新的數據段並定義共享數據,其具體格式爲:
#pragma data_seg ("shareddata") //名稱能夠
//本身定義,但必須與下面的一致。
HWND sharedwnd=NULL;//共享數據 rest
#pragma data_seg()
僅定義一個數據段還不能達到共享數據的目的,還要告訴編譯器該段的屬性,有兩種方法能夠實現該目的 (其效果是相同的):code
一種方法是在.DEF文件中加入以下語句: SETCTIONS shareddata READ WRITE SHARED ;
另外一種方法是在項目設置連接選項(Project Setting --〉Link)中加入以下語句: /SECTION:shareddata,rws
什麼是共享數據段?爲何要用共享數據段??它有什麼用途??
在Win32環境中,DLL函數中的代碼所建立的任何對象 (包括變量)都歸調用它的線程或進程全部。當進程在載入DLL時,操做系統自動把DLL地址映射到該進程的私有空間,也就是進程的虛擬地址空間,並且也復 制該DLL的全局數據的一份拷貝到該進程空間。也就是說每一個進程所擁有的相同的DLL的全局數據,它們的名稱相同,但其值卻並不必定是相同的,並且是互不干涉的。
所以,在Win32環境下要想在多個進程中共享數據,就必須進行必要的設置。在訪問同一個Dll的各進程之間共享存儲器是經過存儲器映射文件技術 實現的。也能夠把這些須要共享的數據分離出來,放置在一個獨立的數據段裏,並把該段的屬性設置爲共享。必須給這些變量賦初值,不然編譯器會把沒有賦初始值的變量放在一個叫未被初始化的數據段中。 #pragma data_seg預處理指令用於設置共享數據段。例如:
#pragma data_seg("SharedDataName")
HHOOK hHook=NULL; //必須在定義的同時進行初始化!!!!
#pragma data_seg()
在#pragma data_seg("SharedDataName")和#pragma data_seg()之間的全部變量將被訪問該Dll的全部進程看到和共享。再加上一條指令#pragma comment(linker,"/section:.SharedDataName,rws"),[注意:數據節的名稱is case sensitive]那麼這個數據節中的數據能夠在全部DLL的實例之間共享。全部對這些數據的操做都針對同一個實例的,而不是在每一個進程的地址空間中都有一份。
那麼動態鏈接庫執行的理論依據也就是內部原理是:當進程隱式或顯式調用一個動態庫裏的函數時,系統都要把這個動態庫映射到這個進程的虛擬地址空間裏(如下簡稱"地址空間")。這使得DLL成爲進程的一部分,以這個進程的身份執行,使用這個進程的堆棧。(這項技術又叫code Injection技術,被普遍地應用在了病毒、黑客領域)
在具體使用共享數據段時須要注意的一些問題!
Win32 DLLs are mapped into the address space of the calling process. By default, each process using a DLL has its own instance of all the DLLs global and static variables. (注意: 即便是全局變量和靜態變量也都不是共享的!) If your DLL needs to share data with other instances of it loaded by other applications, you can use either of the following approaches:
· Create named data sections using the data_seg pragma.
· Use memory mapped files. See the Win32 documentation about memory mapped files. (使用內存映射文件)
Here is an example of using the data_seg pragma:
#pragma data_seg (".myseg")
int i = 0;
char a[32] = "hello world";
#pragma data_seg()
data_seg can be used to create a new named section (.myseg in this example). The most typical usage is to call the data segment .shared for clarity. You then must specify the correct sharing attributes for this new named data section in your .def file or with the linker option /SECTION:.MYSEC,RWS. (這個編譯參數既能夠使用pragma指令來指定,也能夠在VC的IDE中指定!) There are restrictions to consider before using a shared data segment: · Any variables in a shared data segment must be statically initialized(全部的變量在定義時必須被初始化). In the above example, i is initialized to 0 and a is 32 characters initialized to hello world. · All shared variables are placed in the compiled DLL in the specified data segment. Very large arrays can result in very large DLLs(很大的變量將會致使dll很是大). This is true of all initialized global variables. · Never store process-specific information in a shared data segment. Most Win32 data structures or values (such as HANDLEs) are really valid only within the context of a single process(不要將標誌進程的數據放在data_seg中,例如句柄等). · Each process gets its own address space. It is very important that pointers are never stored in a variable contained in a shared data segment. A pointer might be perfectly valid in one application but not in another. · It is possible that the DLL itself could get loaded at a different address in the virtual address spaces of each process. It is not safe to have pointers to functions in the DLL or to other shared variables.