1. 程式人生 > 其它 >#pragma data_seg 共享資料區(轉) #pragma data_seg 共享資料區(轉)#pragma data_seg 共享資料區(轉)

#pragma data_seg 共享資料區(轉) #pragma data_seg 共享資料區(轉)#pragma data_seg 共享資料區(轉)

#pragma data_seg 共享資料區(轉)

 

#pragma data_seg 共享資料區(轉)

 

1)#pragma data_seg()一般用於DLL中。也就是說,在DLL中定義一個共享的,有名字的資料段。最關鍵的是:這個資料段中的全域性變數可以被多個程序共享。否則多個程序之間無法共享DLL中的全域性變數。


2)共享資料必須初始化,否則微軟編譯器會把沒有初始化的資料放到.BSS段中,從而導致多個程序之間的共享行為失敗。

 

3)你所謂的結果正確是一種錯覺。如果你在一個DLL中這麼寫:
      #pragma data_seg("MyData")
      int g_Value; // Note that the global is not initialized.
      #pragma data_seg()

 

DLL提供兩個介面函式:

   

int GetValue()
{
      return g_Value;
}
void SetValue(int n)
{
      g_Value = n;
}  

啟動兩個程序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!這就實現了跨程序之間的資料通訊!

 
       有的時候我們可能想讓一個應用程式只啟動一次,就像單件模式(singleton)一樣,實現的方法可能有多種,這裡說說#pragma data_seg來實現的方法,很是簡潔便利。應用程式的入口檔案前面加上
              #pragma data_seg("flag_data")
              int app_count = 0;
              #pragma data_seg()
              #pragma comment(linker,"/SECTION:flag_data,RWS")


               然後程式啟動的地方加上

 

if(app_count>0)     // 如果計數大於0,則退出應用程式。
{
//MessageBox(NULL, "已經啟動一個應用程式", "Warning", MB_OK); 
return FALSE;
}
app_count++;  

這種方法只能在沒有def檔案時使用,如果通過def檔案進行匯出的話,那麼設定就要在def檔案內設定而不能在程式碼裡設定了。

SETCTIONS 
flag_data READ WRITE SHARED


在主檔案中,用#pragma data_seg建立一 個新的資料段並定義共享資料,其具體格式為: 
#pragma data_seg ("shareddata") //名稱可以 


//自己定義,但必須與下面的一致。 
HWND sharedwnd=NULL;//共享資料 

#pragma data_seg() 
僅定義一個數據段還不能達到共享資料的目的,還要告訴編譯器該段的屬性,有兩種方法可以實現該目的 (其效果是相同的):

一種方法是在.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. 

  標籤: MFC

#pragma data_seg 共享資料區(轉)

 

1)#pragma data_seg()一般用於DLL中。也就是說,在DLL中定義一個共享的,有名字的資料段。最關鍵的是:這個資料段中的全域性變數可以被多個程序共享。否則多個程序之間無法共享DLL中的全域性變數。


2)共享資料必須初始化,否則微軟編譯器會把沒有初始化的資料放到.BSS段中,從而導致多個程序之間的共享行為失敗。

 

3)你所謂的結果正確是一種錯覺。如果你在一個DLL中這麼寫:
      #pragma data_seg("MyData")
      int g_Value; // Note that the global is not initialized.
      #pragma data_seg()

 

DLL提供兩個介面函式:

   

int GetValue()
{
      return g_Value;
}
void SetValue(int n)
{
      g_Value = n;
}  

啟動兩個程序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!這就實現了跨程序之間的資料通訊!

 
       有的時候我們可能想讓一個應用程式只啟動一次,就像單件模式(singleton)一樣,實現的方法可能有多種,這裡說說#pragma data_seg來實現的方法,很是簡潔便利。應用程式的入口檔案前面加上
              #pragma data_seg("flag_data")
              int app_count = 0;
              #pragma data_seg()
              #pragma comment(linker,"/SECTION:flag_data,RWS")


               然後程式啟動的地方加上

 

if(app_count>0)     // 如果計數大於0,則退出應用程式。
{
//MessageBox(NULL, "已經啟動一個應用程式", "Warning", MB_OK); 
return FALSE;
}
app_count++;  

這種方法只能在沒有def檔案時使用,如果通過def檔案進行匯出的話,那麼設定就要在def檔案內設定而不能在程式碼裡設定了。

SETCTIONS 
flag_data READ WRITE SHARED


在主檔案中,用#pragma data_seg建立一 個新的資料段並定義共享資料,其具體格式為: 
#pragma data_seg ("shareddata") //名稱可以 


//自己定義,但必須與下面的一致。 
HWND sharedwnd=NULL;//共享資料 

#pragma data_seg() 
僅定義一個數據段還不能達到共享資料的目的,還要告訴編譯器該段的屬性,有兩種方法可以實現該目的 (其效果是相同的):

一種方法是在.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.