DCOM 依賴 RPC,遠端呼叫需通過驗證。客戶端與伺服器帳號不同時,必須顯式提供憑證。核心流程:
HRESULT hr = CoInitializeSecurity(
NULL, -1, NULL, NULL,
RPC_C_AUTHN_LEVEL_NONE, // 驗證等級:無 (由客戶端決定)
RPC_C_IMP_LEVEL_IDENTIFY, // 模擬等級:識別
NULL, EOAC_ACCESS_CONTROL, NULL); // 啟用存取控制
// 註冊類別工廠等後續步驟...
HRESULT hr = CoInitialize(NULL);
MULTI_QI mqi = { &IID_ICRemoteTime, NULL, S_OK };
COAUTHIDENTITY authId = {0};
authId.User = L"Administrator"; // 遠端機器帳號
authId.UserLength = wcslen(authId.User);
authId.Domain = NULL; // 工作群組無網域
authId.DomainLength = 0;
authId.Password = L"password"; // 密碼
authId.PasswordLength = wcslen(authId.Password);
authId.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
COAUTHINFO authInfo = {0};
authInfo.dwAuthnSvc = RPC_C_AUTHN_WINNT;
authInfo.dwAuthzSvc = RPC_C_AUTHZ_NONE;
authInfo.pwszServerPrincName = NULL;
authInfo.dwAuthnLevel = RPC_C_AUTHN_LEVEL_DEFAULT;
authInfo.dwImpersonationLevel = RPC_C_IMP_LEVEL_IMPERSONATE;
authInfo.pAuthIdentityData = &authId;
authInfo.dwCapabilities = EOAC_NONE;
COSERVERINFO si = {0};
si.pwszName = L"192.168.1.100"; // 伺服器 IP/名稱
si.pAuthInfo = &authInfo;
hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_NONE, NULL);
hr = CoCreateInstanceEx(CLSID_CRemoteTime, NULL, CLSCTX_REMOTE_SERVER, &si, 1, &mqi);
if (FAILED(hr) || FAILED(mqi.hr)) { /* 錯誤處理 */ }
ICRemoteTime* pRemote = (ICRemoteTime*)mqi.pItf;
// 使用 pRemote...
pRemote->Release();
HRESULT hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_NONE, NULL);
COAUTHIDENTITY us = {0};
us.User = m_strName.AllocSysString(); // CString → BSTR
us.UserLength = wcslen(us.User);
us.Password = m_strPassword.AllocSysString();
us.PasswordLength = wcslen(us.Password);
us.Domain = m_strDomain.AllocSysString();
us.DomainLength = wcslen(us.Domain);
us.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
COAUTHINFO auth = {0};
auth.dwAuthnSvc = RPC_C_AUTHN_WINNT;
auth.dwAuthzSvc = RPC_C_AUTHZ_NONE;
auth.dwAuthnLevel = RPC_C_AUTHN_LEVEL_CONNECT;
auth.dwImpersonationLevel = RPC_C_IMP_LEVEL_IMPERSONATE;
auth.pAuthIdentityData = &us;
COSERVERINFO si = {0};
si.pwszName = CComBSTR(strComputer).m_str; // CString → LPWSTR
si.pAuthInfo = m_bAccess ? &auth : NULL;
MULTI_QI mqi = { &__uuidof(IRemoteControl), NULL, S_OK };
hr = CoCreateInstanceEx(__uuidof(RemoteControl), NULL, CLSCTX_SERVER, &si, 1, &mqi);
if (SUCCEEDED(hr) && SUCCEEDED(mqi.hr)) {
m_pIRemoteControl = (IRemoteControl*)mqi.pItf;
}
MULTI_QI mqi = { &IID_IUnknown, NULL, S_OK };
// ... 同範例 2 設定 si, auth ...
hr = CoCreateInstanceEx(__uuidof(RemoteControl), NULL, CLSCTX_SERVER, &si, 1, &mqi);
if (FAILED(hr) || FAILED(mqi.hr)) return;
IUnknown* pUnk = (IUnknown*)mqi.pItf;
IRemoteControl* pCtrl;
hr = pUnk->QueryInterface(__uuidof(IRemoteControl), (void**)&pCtrl);
pUnk->Release();
if (SUCCEEDED(hr)) {
// 使用 pCtrl...
pCtrl->Release();
}
| 參數 | 常用值 | 說明 |
|---|---|---|
| RPC_C_AUTHN_WINNT | NTLM 驗證 | Windows 整合驗證 |
| RPC_C_AUTHN_LEVEL_CONNECT | 連線時驗證 | 僅建立連線時驗證,不加密/簽章 |
| RPC_C_AUTHN_LEVEL_PKT_INTEGRITY | 封包完整性 | 簽章防竄改 |
| RPC_C_AUTHN_LEVEL_PKT_PRIVACY | 封包隱私 | 加密傳輸 (最高安全) |
| RPC_C_IMP_LEVEL_IMPERSONATE | 模擬客戶端 | 伺服器可用客戶端身分存取本機資源 |
| RPC_C_IMP_LEVEL_DELEGATE | 委派 | 伺服器可用客戶端身分存取**網路**資源 (需 Kerberos) |
| EOAC_NONE | 無額外能力 | |
| SEC_WINNT_AUTH_IDENTITY_UNICODE | Unicode 憑證 | 寬字元帳號/密碼 |
COAUTHIDENTITY caid = { /* 同上填入 */ };
hr = CoSetProxyBlanket(pInterface,
RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_IMPERSONATE,
&caid, EOAC_NONE);