線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:2522
推到 Plurk!
推到 Facebook!

DLL的自訂物件如何共用? 如何讓多支AP動態連接上DLL後, 所有的AP共用同一個物件?

尚未結案
Chen168
一般會員


發表:2
回覆:15
積分:8
註冊:2004-08-17

發送簡訊給我
#1 引用回覆 回覆 發表時間:2005-03-13 00:14:11 IP:220.136.xxx.xxx 未訂閱
小弟是BCB新手, 找了很多天了試了不少方式如 共享變數等方式都無法達成目的, 困擾許久! 只好來請教各位先進.    [問題] DLL的自訂物件如何共用? 如何讓多支AP動態連接上DLL後, 所有的AP共用同一個物件?    假設我自定一個類別Class A , 我寫入一個DLL專案叫B.dll如下:
 
//A.H
CLASS A;          //我的自定類別
 {
   public:
       unsigned int       Value;              
       A() { Value = 100; };  //把Value初值設100
 }    //B.CPP
extern "C" __declspec(dllexport) int __stdcall Set_Value(int Com);   
extern "C" __declspec(dllexport) int __stdcall Get_Value();
.
.
A a;      //由A類別產生的a物件
.
.
.
int __stdcall Set_Value(int Com)    //DLL分享的設定涵數Set_Value()
{
 a.Value = Com;    //改變a物件中的Value的值
 return a.Value;   //傳回已改變的a物件中的Value的值
}
//------------------------------------------------------------------
int __stdcall Get_Value()           //DLL分享的讀取涵數Get_Value()
{
 return a.Value;   傳回由A類別產生的a物件中的Value的值
}
如果當有一個應用程式1呼叫B.dll的設定涵數Set_Value(200)將a物件的Value的值改成200 , 由應用程式1呼叫B.dll的讀取涵數Get_Value傳回200 , 但由其他應用程式2呼叫B.dll的讀取涵數Get_Value傳回100 *要怎樣才能讓每個應用程式呼叫B.dll的讀取涵數Get_Value時得已改變的a.Value值200呢? *若改用*指標, 將a物件在B.dll涵數中new出來, 又要如果做呢?
rogan321
高階會員


發表:21
回覆:307
積分:200
註冊:2003-05-15

發送簡訊給我
#2 引用回覆 回覆 發表時間:2005-03-13 03:36:19 IP:203.204.xxx.xxx 未訂閱
Win95以後的DLL無法共用變數~在記憶體中~會各自複製一個變數值~ 也就是雖然共用該DLL物件(程式區間)但是關於變數的存取其實是各改各的~~ 就算寫成全域變數也沒用~ 要真正共用變數可使用Package的方式達成~~或在dll中放入VCL元件,利用VCL元 件所宣告的static變數來達成~因為VCL元件就是包裝成Package的方式
Chen168
一般會員


發表:2
回覆:15
積分:8
註冊:2004-08-17

發送簡訊給我
#3 引用回覆 回覆 發表時間:2005-03-13 10:56:43 IP:218.168.xxx.xxx 未訂閱
引言: Win95以後的DLL無法共用變數~在記憶體中~會各自複製一個變數值~ 也就是雖然共用該DLL物件(程式區間)但是關於變數的存取其實是各改各的~~ 就算寫成全域變數也沒用~ 要真正共用變數可使用Package的方式達成~~或在dll中放入VCL元件,利用VCL元 件所宣告的static變數來達成~因為VCL元件就是包裝成Package的方式
rogan321大大所提基本上是對的, 但Windows API有提供共用記憶體的方式, 在VC及BCB中都對這種共享記憶體的方式有支援, 我只有研究過BCB的方式, 提供出來給大家參考:
 
//B.CPP
#pragma option -zRSHSEG      // 改變缺省數據段名 *共享記憶體用
#pragma option -zTSHCLASS    // 改變缺省數據類名 *共享記憶體用
//--------------------------------------------------
#include 
.
.
.
//---------------------------------------------------------------------------
#pragma argsused
// 以下都將是共享區內存變量
A a[255];                //產生255個串口物件的宣告 *宣告共享記憶體用物件
int    LoadCount=0;        // DLL裝入次數計數        *宣告共享記憶體用變數    //---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
    if (reason==DLL_PROCESS_ATTACH)    // DLL入口
       LoadCount =1;                   // 裝入計數
    else
       if (reason==DLL_PROCESS_DETACH) // DLL出口處理
        {
          LoadCount-=1;
        }
    return 1;
}
建立一個本文檔B.DEF, 內容只有一行SEGMENTS SHSEG CLASS 'SHCLASS' SHARED 在你的B專案中用Add to Project將B.DEF加入你的專案中. 這樣就建立了共享變數LoadCount [DLL裝入次數計數] *但問題來了, 所有呼叫B.dll的應用程式都能正確取得共享變數LoadCount所記錄的[DLL裝入次數計數]無誤, 但我另外一個宣告A a[255]所產生的A類別a[255]物件, 在第二個以上呼叫B.dll的應用程式中確無法取得已經被其他應用程式改變的a.Value的值, 只能取得自己改變的a.Value的值, 就像a物件是個獨立屬於所呼叫的應用程式而無法共享. *要真正共用變數可使用Package的方式達成~~或在dll中放入VCL元件,利用VCL元件所宣告的static變數來達成~因為VCL元件就是包裝成Package的方式 我的DLL只用到Windows API, 並沒有用到VCL元件, 而且我不希望DLL太大. 發表人 - chen168 於 2005/03/13 11:00:31 發表人 - chen168 於 2005/03/13 11:03:33
rogan321
高階會員


發表:21
回覆:307
積分:200
註冊:2003-05-15

發送簡訊給我
#4 引用回覆 回覆 發表時間:2005-03-13 14:20:56 IP:203.204.xxx.xxx 未訂閱
你一說我才想到~WINAPI的 OpenFileMapping和CreateFileMapping兩個函式可能可以達到你的要求 記得曾經用這兩個函式來實做生產者與消費者的兩支程式共用記憶體的 共同區間~將其使用在DLL上不知可行否?
Chen168
一般會員


發表:2
回覆:15
積分:8
註冊:2004-08-17

發送簡訊給我
#5 引用回覆 回覆 發表時間:2005-03-13 15:27:06 IP:218.168.xxx.xxx 未訂閱
引言: 你一說我才想到~WINAPI的 OpenFileMapping和CreateFileMapping兩個函式可能可以達到你的要求 記得曾經用這兩個函式來實做生產者與消費者的兩支程式共用記憶體的 共同區間~將其使用在DLL上不知可行否?
OpenFileMapping和CreateFileMapping兩個函式用在DLL中當然是可以的, 但是我的問題是如果我放的是我自訂的a物件而不是變數要給其他同時連上B.dll的應用程式用結果就不行了. *也試過宣告一個指向A類別的*c[255]指標放在共享區, 然後在B.dll的涵數中new一個A類別的物件指向c指標中: >指標去操作其他應用程式動態產生的 >指標取用才能得到正確的結果. 不知道這樣抽述各位大大能明白嗎? 請幫幫我吧!
rogan321
高階會員


發表:21
回覆:307
積分:200
註冊:2003-05-15

發送簡訊給我
#6 引用回覆 回覆 發表時間:2005-03-13 18:23:17 IP:203.204.xxx.xxx 未訂閱
引言:
引言:
 
//B.CPP
#pragma option -zRSHSEG      // 改變缺省數據段名 *共享記憶體用
#pragma option -zTSHCLASS    // 改變缺省數據類名 *共享記憶體用
//--------------------------------------------------
#include 
.
.
.
//---------------------------------------------------------------------------
#pragma argsused
// 以下都將是共享區內存變量
A a[255];                //產生255個串口物件的宣告 *宣告共享記憶體用物件
int    LoadCount=0;        // DLL裝入次數計數        *宣告共享記憶體用變數    //---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
    if (reason==DLL_PROCESS_ATTACH)    // DLL入口
       LoadCount =1;  //你確定是正確的?你載入幾個副本測試?照道理LoadCount應該是無法共用的吧?                 // 裝入計數
    else
       if (reason==DLL_PROCESS_DETACH) // DLL出口處理
        {
          LoadCount-=1;
        }
    return 1;
}
Chen168
一般會員


發表:2
回覆:15
積分:8
註冊:2004-08-17

發送簡訊給我
#7 引用回覆 回覆 發表時間:2005-03-13 20:56:16 IP:220.136.xxx.xxx 未訂閱
引言:
引言:
引言:
 
//B.CPP
#pragma option -zRSHSEG      // 改變缺省數據段名 *共享記憶體用
#pragma option -zTSHCLASS    // 改變缺省數據類名 *共享記憶體用
//--------------------------------------------------
#include 
.
.
.
//---------------------------------------------------------------------------
#pragma argsused
// 以下都將是共享區內存變量
A a[255];                //產生255個串口物件的宣告 *宣告共享記憶體用物件
int    LoadCount=0;        // DLL裝入次數計數        *宣告共享記憶體用變數    //---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
    if (reason==DLL_PROCESS_ATTACH)    // DLL入口
       LoadCount =1;  //你確定是正確的?你載入幾個副本測試?照道理LoadCount應該是無法共用的吧?                 // 裝入計數
    else
       if (reason==DLL_PROCESS_DETACH) // DLL出口處理
        {
          LoadCount-=1;
        }
    return 1;
}
哦! 上面的LoadCount的確是可以的, 你可以照做一個dll專案, 測試一下就知道了! 這可是我找了好幾天才找到的BCB的設定方法, 關鍵是 #pragma option -zRSHSEG // 改變缺省數據段名 *共享記憶體用 #pragma option -zTSHCLASS // 改變缺省數據類名 *共享記憶體用 還有你宣告共用變數放的位置: #pragma argsused // 以下都將是共享區內存變量 A a[255]; //產生255個串口物件的宣告 *宣告共享記憶體用物件 int LoadCount=0; // DLL裝入次數計數 *宣告共享記憶體用變數 //--------------------------------------------------------------------------- int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved) { return 1; } 還有記得在專案中用Add to Porject加入B.DEF那個檔, 它也是告訴BCB要建立一塊共享記憶區域用的. 以上我試過沒問題的; 只是宣告的變數都能得到正確結果, 但物件或物件指標就不行了, 我的問題也就太此.
Chen168
一般會員


發表:2
回覆:15
積分:8
註冊:2004-08-17

發送簡訊給我
#8 引用回覆 回覆 發表時間:2005-03-13 20:57:04 IP:220.136.xxx.xxx 未訂閱
[/quote]
 
//B.CPP
#pragma option -zRSHSEG      // 改變缺省數據段名 *共享記憶體用
#pragma option -zTSHCLASS    // 改變缺省數據類名 *共享記憶體用
//--------------------------------------------------
#include 
.
.
.
//---------------------------------------------------------------------------
#pragma argsused
// 以下都將是共享區內存變量
A a[255];                //產生255個串口物件的宣告 *宣告共享記憶體用物件
int    LoadCount=0;        // DLL裝入次數計數        *宣告共享記憶體用變數    //---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
    if (reason==DLL_PROCESS_ATTACH)    // DLL入口
       LoadCount =1;  //你確定是正確的?你載入幾個副本測試?照道理LoadCount應該是無法共用的吧?                 // 裝入計數
    else
       if (reason==DLL_PROCESS_DETACH) // DLL出口處理
        {
          LoadCount-=1;
        }
    return 1;
}
[/quote] 哦! 上面的LoadCount的確是可以的, 你可以照做一個dll專案, 測試一下就知道了! 這可是我找了好幾天才找到的BCB的設定方法, 關鍵是 #pragma option -zRSHSEG // 改變缺省數據段名 *共享記憶體用 #pragma option -zTSHCLASS // 改變缺省數據類名 *共享記憶體用 還有你宣告共用變數放的位置: #pragma argsused // 以下都將是共享區內存變量 A a[255]; //產生255個串口物件的宣告 *宣告共享記憶體用物件 int LoadCount=0; // DLL裝入次數計數 *宣告共享記憶體用變數 //--------------------------------------------------------------------------- int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved) { return 1; } 還有記得在專案中用Add to Porject加入B.DEF那個檔, 它也是告訴BCB要建立一塊共享記憶區域用的. 以上我試過沒問題的; 只是宣告的變數都能得到正確結果, 但物件或物件指標就不行了, 我的問題也就在此. 發表人 - chen168 於 2005/03/13 21:01:03 發表人 - chen168 於 2005/03/13 21:05:07
pwipwi
版主


發表:68
回覆:629
積分:349
註冊:2004-04-08

發送簡訊給我
#9 引用回覆 回覆 發表時間:2005-03-13 22:29:12 IP:211.76.xxx.xxx 未訂閱
Chen168你好: 有個方法可以在已存在的記憶體上配置物件。你可以先用File mapping取得一個記憶體的區塊,然後用operator new手法在上面建立物件。應該可以解決你的問題。 但是,這有個限制是配置的物件本身不能含有像char* text這類的指標變數。
rogan321
高階會員


發表:21
回覆:307
積分:200
註冊:2003-05-15

發送簡訊給我
#10 引用回覆 回覆 發表時間:2005-03-14 00:49:27 IP:203.204.xxx.xxx 未訂閱
用google搜尋了一下的確有大大說的這種方便的用法~我沒試過~不過如果真的如大大所說的無法共用物件~那或許可改個方向~參考參考~
引言:
 
#pragma option -zRSHSEG      // 改變缺省數據段名 *共享記憶體用
#pragma option -zTSHCLASS    // 改變缺省數據類名 *共享記憶體用
//--------------------------------------------------
#include 
// 以下都將是共享區內存變量
A a[255];                //產生255個串口物件的宣告 *宣告共享記憶體用物件
int    LoadCount=0;
int A_ValueTmp;
//A.H
CLASS A;          //我的自定類別
 {
   public:
       unsigned int       Value;              
       A() { Value = 100; };  //把Value初值設100
 }    //B.CPP
extern "C" __declspec(dllexport) int __stdcall Set_Value(int Com);   
extern "C" __declspec(dllexport) int __stdcall Get_Value();
.
.
A a;      //由A類別產生的a物件
.
.
.
int __stdcall Set_Value(int Com)    //DLL分享的設定涵數Set_Value()
{
 A_ValueTmp=Com;
 a.Value = Com;    //改變a物件中的Value的值
 
 return a.Value;   //傳回已改變的a物件中的Value的值
}
//------------------------------------------------------------------
int __stdcall Get_Value()           //DLL分享的讀取涵數Get_Value()
{
 //return a.Value;   //傳回由A類別產生的a物件中的Value的值
 return A_ValueTmp;
}
發表人 - rogan321 於 2005/03/14 00:52:07
Chen168
一般會員


發表:2
回覆:15
積分:8
註冊:2004-08-17

發送簡訊給我
#11 引用回覆 回覆 發表時間:2005-03-14 15:43:27 IP:220.136.xxx.xxx 未訂閱
引言: Chen168你好: 有個方法可以在已存在的記憶體上配置物件。你可以先用File mapping取得一個記憶體的區塊,然後用operator new手法在上面建立物件。應該可以解決你的問題。 但是,這有個限制是配置的物件本身不能含有像char* text這類的指標變數。
Pwipwi大大你所說的File mapping取得一個記憶體的區塊, 是用這兩個Windows API指令嗎? OpenFileMapping CreateFileMapping 還是BCB也用提供File mapping的指令. 我是BCB新手, Pwipwi大大能不能直接給個範例? 另外rogan321大大所提的方式並不是我所要的, 我的每個A物件是獨立控制了一些硬體, 我要的是用兩個硬體就叫B.dll new 兩個A物件來控制, 而每個同時透過呼叫B.dll的應用程式都能直接控制這些A物件.
pwipwi
版主


發表:68
回覆:629
積分:349
註冊:2004-04-08

發送簡訊給我
#12 引用回覆 回覆 發表時間:2005-03-15 00:16:25 IP:211.76.xxx.xxx 未訂閱
第一步取得一個char* mData指向一個共同的記憶體區塊 請參考rogan大大的範例 http://delphi.ktop.com.tw/topic.php?topic_id=61810    第二步在其上配置記憶體以下是一個簡單的範例  
 
class A{
public:
    int i;
    int ii;
};
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    char data[8];
    A* p_A = new (data) A(); // 在data上配置一個A物件
    p_A->i = 10;
    p_A->ii = 20;
}
pwipwi
版主


發表:68
回覆:629
積分:349
註冊:2004-04-08

發送簡訊給我
#13 引用回覆 回覆 發表時間:2005-03-15 00:20:38 IP:211.76.xxx.xxx 未訂閱
少了一點,如果配置完後,要其他程式使用時只要直接用pointer指向就好了 以上面的例子,如果data指向的區塊已經初始化完成,之後要用就可以直接     
 
A* p_a = (A*)data;
...
Chen168
一般會員


發表:2
回覆:15
積分:8
註冊:2004-08-17

發送簡訊給我
#14 引用回覆 回覆 發表時間:2005-03-16 16:39:40 IP:61.64.xxx.xxx 未訂閱
引言: 第一步取得一個char* mData指向一個共同的記憶體區塊 請參考rogan大大的範例 http://delphi.ktop.com.tw/topic.php?topic_id=61810 第二步在其上配置記憶體以下是一個簡單的範例
 
class A{
public:
    int i;
    int ii;
};
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    char data[8];
    A* p_A = new (data) A(); // 在data上配置一個A物件
    p_A->i = 10;
    p_A->ii = 20;
}
pwipwi大大, 我試了你說的方式, 但可能因是BCB新手搞不清楚你的範例跟rogan大大的範例裹不一樣的型態或變數怎麼合成一個完整範例, 編譯總是不過, 您就好人做到底給一個完整的例子吧.
pwipwi
版主


發表:68
回覆:629
積分:349
註冊:2004-04-08

發送簡訊給我
#15 引用回覆 回覆 發表時間:2005-03-17 03:11:52 IP:211.76.xxx.xxx 未訂閱
如果可以的話, 請你放上現在compile過不了的碼, 讓大家幫忙看看...    我最近太忙太累...難以空出時間寫個完整的範例~抱歉了
Chen168
一般會員


發表:2
回覆:15
積分:8
註冊:2004-08-17

發送簡訊給我
#16 引用回覆 回覆 發表時間:2005-03-17 09:34:44 IP:218.168.xxx.xxx 未訂閱
引言: 如果可以的話, 請你放上現在compile過不了的碼, 讓大家幫忙看看... 我最近太忙太累...難以空出時間寫個完整的範例~抱歉了 < face="Verdana, Arial, Helvetica"> 己有進展了,原來使用operator new還要宣告#include 才能編譯過, 不像new直接用就可以了. 目前已經建立了一個共用物件, 別的應用程式不在看不到這個物件了, 但出現新的錯誤, 可能是我的物件裹有錯誤或其他問題造成的. 還在努力中. 有進展再向各位大大報告.
系統時間:2024-05-07 6:31:59
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!