首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

ActiveX 控件傳遞自訂結構:SAFEARRAY 與 IDL 定義實戰

     編輯:關於VC++

背景與工具選擇

原嘗試用 .ocx 控件傳遞自訂結構,發現無能為力。最終採用 VC++ 6.0 ATL 開發組件。應用於配電自動化饋線自動化 (FA) 功能,自行設計開發。

核心技術:SAFEARRAY 封裝結構數據

客戶端調用組件函數 SendData、ReceiveData 的完整代碼:

1. 定義結構 (C++ 端)


struct Line {
  long id;           // ID 號
  BOOL Power;        // 有電標志
  BSTR LineName;     // 線路名稱
  long StaPoint_x;   // 起點 X
  long StaPoint_y;   // 起點 Y
  long EndPoint_x;   // 終點 X
  long EndPoint_y;   // 終點 Y
  short EndType;     // 1負荷 2電源 0其他
  long Longth;
  BOOL ShCirFlag;    // 短路標志
};

struct Dot {
  long id;
  BOOL Power;        // 開合標志
  BSTR DotName;      // 線路名稱
  long StaPoint_x;
  long StaPoint_y;
  long EndPoint_x;
  long EndPoint_y;
  short DotType;     // 0不可遙控 1可遙控 2刀閘 3節點 4變壓器
  short HighCurrent; // 過流標志 -1無數據 >=0有數據
  BOOL CutFlag;      // 跳閘標志
};

2. 客戶端:填充 SAFEARRAY 並調用


// --- 發送 Line 陣列 ---
VARIANT LineVal;
SAFEARRAY FAR* pLSA = NULL;
SAFEARRAYBOUND dimension[1];
dimension[0].lLbound = 0;
dimension[0].cElements = MAX * 10;
pLSA = SafeArrayCreate(VT_BSTR, 1, dimension); // 注意:此處 VT_BSTR 實為佔位,實際存結構指標

Line FAR* pLineData = NULL;
::SafeArrayAccessData(pLSA, (void HUGEP* FAR*)&pLineData);
for (i = 0; i < MAX; i++) {
  pLineData[i].StaPoint_x = LineData[i].StaPoint_x;
  pLineData[i].StaPoint_y = LineData[i].StaPoint_y;
  pLineData[i].EndPoint_x = LineData[i].EndPoint_x;
  pLineData[i].EndPoint_y = LineData[i].EndPoint_y;
  pLineData[i].EndType = LineData[i].EndType;
  pLineData[i].id = LineData[i].id;
  pLineData[i].LineName = LineData[i].LineName;
  pLineData[i].Longth = LineData[i].Longth;
  pLineData[i].Power = LineData[i].Power;
  pLineData[i].ShCirFlag = LineData[i].ShCirFlag;
}
::SafeArrayUnaccessData(pLSA);
LineVal.vt = VT_ARRAY;
LineVal.parray = pLSA;

// --- 發送 Dot 陣列 (同理) ---
VARIANT DotVal;
SAFEARRAY FAR* pDSA = NULL;
Dot FAR* pDotData = NULL;
pDSA = SafeArrayCreate(VT_BSTR, 1, dimension);
::SafeArrayAccessData(pDSA, (void HUGEP* FAR*)&pDotData);
for (i = 0; i < MAX; i++) {
  pDotData[i].CutFlag = DotData[i].CutFlag;
  pDotData[i].DotName = DotData[i].DotName;
  pDotData[i].DotType = DotData[i].DotType;
  pDotData[i].StaPoint_x = DotData[i].StaPoint_x;
  pDotData[i].StaPoint_y = DotData[i].StaPoint_y;
  pDotData[i].EndPoint_x = DotData[i].EndPoint_x;
  pDotData[i].EndPoint_y = DotData[i].EndPoint_y;
  pDotData[i].HighCurrent = DotData[i].HighCurrent;
  pDotData[i].id = DotData[i].id;
  pDotData[i].Power = DotData[i].Power;
}
::SafeArrayUnaccessData(pDSA);
DotVal.vt = VT_ARRAY;
DotVal.parray = pDSA;

// --- 呼叫組件 ---
result = qfa.SendData(LineVal, DotVal, 3);

// --- 接收回傳數據 ---
long LineCount, DotCount;
SAFEARRAY FAR* pReLSA = NULL;
SAFEARRAY FAR* pReDSA = NULL;
Line* pLData = NULL;
Dot* pDData = NULL;
qfa.ReceiveData(&LineVal, &LineCount, &DotVal, &DotCount);
pReLSA = LineVal.parray;
pReDSA = DotVal.parray;
::SafeArrayAccessData(pReDSA, (void HUGEP* FAR*)&pDotData);
::SafeArrayUnaccessData(pReDSA);
// 後續處理接收數據...

3. IDL 定義:讓類型庫識別自訂結構


typedef
[
  uuid(D124B04A-C5F9-4a16-9671-1E67B75DB1A1),
  helpstring("NetWork Node Struct")
]
struct Line {
  long id;
  BOOL Power;
  BSTR LineName;
  long StaPoint_x;
  long StaPoint_y;
  long EndPoint_x;
  long EndPoint_y;
  short EndType;
  long Longth;
  BOOL ShCirFlag;
} Line;

typedef
[
  uuid(D124B04A-C5F9-4a16-9671-1E67B75DB1A2),
  helpstring("NetWork Node Struct")
]
struct Dot {
  long id;
  BOOL Power;
  BSTR DotName;
  long StaPoint_x;
  long StaPoint_y;
  long EndPoint_x;
  long EndPoint_y;
  short DotType;
  short HighCurrent;
  BOOL CutFlag;
} Dot;

定義後即可在介面方法中直接使用 Line、Dot 類型。

使用說明

  1. 先註冊組件:regsvr32 c:\qfa2004.dll (路徑自行調整)。
  2. VC++ 6.0 開啟專案編譯客戶端測試程式。
  3. 組件 QFA2004 源碼不公開,請見諒。

討論與改進方向

本文展示的方法雖可行,但 SafeArrayCreate(VT_BSTR...) 存放結構指標屬於「非常規用法」,可能存在跨進程封送問題。更標準的做法包括:

  • 使用 VT_RECORD 搭配 IRecordInfo 正確描述結構佈局(需 MIDL 支援 UDT)。
  • 將結構拆解為多個基本類型陣列或改用介面集合。
  • 若為進程內組件,直接傳遞結構指標 (配合 size_is) 效能最佳。

歡迎高手提供更優雅的自訂結構傳遞方案。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved