MSMQ (Microsoft Message Queuing) 提供可靠、非同步、跨機器的訊息傳遞基礎設施。本文示範使用 VC++ #import 匯入 MSMQ Type Library,透過 COM 介面 (IMSMQQueueInfo, IMSMQQueue, IMSMQMessage) 實現:建立佇列 (公用/私有)、發送訊息、接收訊息 (含期刊佇列)。
#import "mqoa.tlb" no_namespace // MSMQ Type Library
// 或 #import "C:\\Windows\\System32\\mqoa.tlb"
#include
// 介面指標
IMSMQQueueInfoPtr qInfo; // 佇列資訊 (建立/開啟)
IMSMQQueuePtr qDest; // 開啟後的佇列 (發送/接收)
IMSMQMessagePtr qMsg; // 訊息物件
// COM 初始化
CoInitialize(NULL);
try {
qInfo.CreateInstance("MSMQ.MSMQQueueInfo");
qMsg.CreateInstance("MSMQ.MSMQMessage");
// 取得電腦名作為佇列路徑基礎
TCHAR szName[MAX_COMPUTERNAME_LENGTH + 1];
DWORD dwSize = MAX_COMPUTERNAME_LENGTH + 1;
GetComputerName(szName, &dwSize);
m_strServer = szName; // 顯示於介面
} catch (_com_error& e) {
MessageBox(_T("MSMQ 初始化失敗"), _T("錯誤"), MB_ICONERROR);
}
// 路徑格式:
// 私有佇列: .\\Private$\\MyQueue (本機) / machinename\\Private$\\MyQueue (遠端)
// 公用佇列: .\\MyQueue (需 AD 整合)
CString path = _T(".\\Private$\\MyTestQueue"); // 私有佇列
qInfo->PathName = path.AllocSysString();
qInfo->Label = _T("My Test Queue").AllocSysString();
// 格式名稱 (直接開啟用)
CString fmt = _T("DIRECT=OS:") + path;
qInfo->FormatName = fmt.AllocSysString();
// 建立
qInfo->Create();
// 啟用期刊 (記錄已送達/已接收訊息副本)
qInfo->Journal = VARIANT_TRUE;
qInfo->Update();
qInfo->Refresh();
try {
// 開啟發送權限
qDest = qInfo->Open(MQ_SEND_ACCESS, MQ_DENY_NONE);
qMsg->Label = _T("Test Message").AllocSysString();
VARIANT vBody; VariantInit(&vBody);
vBody.vt = VT_BSTR;
vBody.bstrVal = _T("Hello MSMQ!").AllocSysString();
qMsg->put_Body(vBody);
VariantClear(&vBody);
qMsg->Send(qDest); // 同步發送
qDest->Close();
} catch (_com_error& e) {
MessageBox(_T("發送失敗"), _T("錯誤"), MB_ICONERROR);
}
try {
IMSMQQueueInfoPtr qRead; qRead.CreateInstance("MSMQ.MSMQQueueInfo");
qRead->PathName = path.AllocSysString();
CString fmt = _T("DIRECT=OS:") + path;
if (bReadJournal) fmt += _T(";Journal"); // 讀取期刊佇列
qRead->FormatName = fmt.AllocSysString();
qDest = qRead->Open(MQ_RECEIVE_ACCESS, MQ_DENY_NONE);
// 同步接收 (逾時參數 vtReceiveTimeout)
VARIANT vtMissing; VariantInit(&vtMissing); vtMissing.vt = VT_ERROR; vtMissing.scode = DISP_E_PARAMNOTFOUND;
VARIANT vtTimeout; VariantInit(&vtTimeout); vtTimeout.vt = VT_I4; vtTimeout.lVal = 5000; // 5秒
qMsg = qDest->Receive(&vtMissing, &vtMissing, &vtMissing, &vtTimeout);
if (qMsg == NULL) return; // 逾時無訊息
_bstr_t label = qMsg->GetLabel();
_variant_t body = qMsg->GetBody();
m_strLabel = (LPCSTR)label;
m_strBody = (LPCSTR)(_bstr_t)body; // VT_BSTR 轉換
UpdateData(FALSE); // 顯示到介面
qDest->Close();
} catch (_com_error& e) {
MessageBox(_T("接收失敗"), _T("錯誤"), MB_ICONERROR);
}
| 常數 | 值 | 說明 |
|---|---|---|
| MQ_SEND_ACCESS | 2 | 發送存取 |
| MQ_RECEIVE_ACCESS | 1 | 接收存取 |
| MQ_DENY_NONE | 0 | 共享模式 |
| DIRECT=OS: | - | 格式名稱前綴,繞過 AD 查詢,直接開啟 |
| ;Journal | - | 格式名稱後綴,開啟期刊佇列 |
Private$);公用佇列需 Active Directory 整合 (網域環境)。IMSMQTransaction / IMSMQTransactionDispenser 保證完全一次 (Exactly Once) 投遞。BeginReceive/EndReceive 或事件 ReceiveCompleted 避免阻塞 UI 執行緒。qMsg->Priority, qMsg->TimeToBeReceived。System.Messaging.MessageQueue,互通相容。完整測試專案 (對話框介面,含建立/發送/接收/期刊切換) 可下載,VC6.0/VS.NET 編譯通過。