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

VC 下 ADO 編程入門 (2-3):COM API 底層調用 ADO 實現資料庫查詢

     編輯:VC 教學

為什麼學習 COM API 方式?

`#import` 產生的智能指標 (`_ConnectionPtr` 等) 封裝了 COM 細節,但理解底層 `CoCreateInstance`、`QueryInterface`、`IDispatch::Invoke` 流程,有助於:除錯邊界情況、跨語言調用 (C/Assembly)、效能極致優化、不依賴 VC 編譯器擴展的環境。

完整 COM API 代碼 (主控台程式)

#include 
#include 
#include 
#include "adoid.h"    // ADO GUID 定義
#include "adoint.h"   // ADO 介面定義

// RAII COM 初始化
struct InitOle {
    InitOle()  { ::CoInitialize(NULL); }
    ~InitOle() { ::CoUninitialize(); }
} _init_InitOle_;

void main() {
    HRESULT hr = S_OK;
    ADORecordset* pRs = NULL;          // 原始介面指標
    VARIANT vSource, vConnect;
    VariantInit(&vSource); VariantInit(&vConnect);

    // 設定查詢 SQL (Unicode BSTR)
    vSource.vt = VT_BSTR;
    vSource.bstrVal = ::SysAllocString(L"SELECT * FROM Customers");

    // 設定連接字串
    vConnect.vt = VT_BSTR;
    vConnect.bstrVal = ::SysAllocString(
        L"Provider=SQLOLEDB; Data Source=127.0.0.1; Initial Catalog=Northwind; User ID=sa; Password=;");

    // 1. 創建 Recordset 物件 (CLSID_CADORecordset)
    hr = CoCreateInstance(CLSID_CADORecordset, NULL, CLSCTX_INPROC_SERVER,
                          IID_IADORecordset, (LPVOID*)&pRs);

    if (SUCCEEDED(hr)) {
        // 2. 設定游標位置 (客戶端游標支援 RecordCount)
        pRs->put_CursorLocation(adUseClient);

        // 3. 開啟資料集
        hr = pRs->Open(vSource, vConnect, adOpenForwardOnly, adLockReadOnly, -1);
        if (SUCCEEDED(hr)) {
            long nCount = 0;
            pRs->get_RecordCount(&nCount);  // 取得記錄數
            ::MessageBox(NULL, L"Success!", L"", MB_OK);
            printf("Record Count: %d\n", nCount);
        }

        // 4. 清理
        pRs->Close();
        pRs->Release(); pRs = NULL;
    }

    // 釋放 BSTR
    ::SysFreeString(vSource.bstrVal);
    ::SysFreeString(vConnect.bstrVal);
}

關鍵 COM 流程解析

步驟API/介面說明
1CoInitialize初始化 COM 庫 (單執行緒單元 STA)
2CoCreateInstance實例化 `CLSID_CADORecordset`,取得 `IADORecordset` 介面
3put_CursorLocation設 `adUseClient` 才能取得 `RecordCount`
4Open (IDispatch::Invoke)傳入 SQL、連接字串、游標/鎖定類型,同步執行
5get_RecordCount取得記錄數 (需客戶端游標)
6Close/Release釋放介面引用計數
7SysFreeString釋放 BSTR 記憶體
8CoUninitialize反初始化 COM

VARIANT 與 BSTR 處理要點

  • `VariantInit` 必須在使用前呼叫,`VariantClear` 釋放內部資源
  • `VT_BSTR` 表示 Unicode 字串,記憶體由 `SysAllocString`/`SysFreeString` 管理
  • `VT_ERROR` + `DISP_E_PARAMNOTFOUND` 表示選填參數省略 (對應 `adCmdText` 等)
  • 錯誤處理:每個 `HRESULT` 回傳值必須用 `SUCCEEDED`/`FAILED` 宏檢查

與 `#import` 智能指標對比

維度COM API#import 智能指標
代碼量大 (手動管理引用計數、VARIANT、BSTR)小 (RAII 自動管理)
型別安全低 (介面指標轉換需 `QueryInterface`)高 (模板 `_com_ptr_t` 封裝)
例外處理手動檢查 HRESULT拋出 `_com_error` 例外
編譯依賴僅需 `adoid.h` `adoint.h` (SDK)需 VC 編譯器支援 `#import`
適用場景驅動開發、嵌入式、跨編譯器、教學一般應用開發 (推薦)

結語

COM API 方式雖繁瑣,但揭示了 ADO 底層運作真相:`CoCreateInstance` 創建物件 → `QueryInterface` 獲取功能介面 → `IDispatch::Invoke` 呼叫方法/屬性 → 參數封裝為 `VARIANT` → 返回 `HRESULT`。掌握此流程,對排查 `#import` 產生的神秘錯誤、編寫高效能資料存取層、移植至非 VC 環境極有幫助。實務開發仍強烈建議使用 `#import` 智能指標。

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