Kỹ thuật sử dụng SAFEARRAY trong lập trình COM và ADO với C++

Khi làm việc với các công nghệ như ADO (ActiveX Data Objects) để tương tác với cơ sở dữ liệu trong C++, việc truyền tải các tập hợp dữ liệu thường yêu cầu sử dụng cấu trúc SAFEARRAY. Đây là một kiểu mảng an toàn trong COM, cho phép truyền dữ liệu giữa các tiến trình hoặc các ngôn ngữ lập trình khác nhau. Thực chất, SAFEARRAY thường không đứng độc lập mà được đóng gói bên trong một biến kiểu VARIANT trước khi truyền đi.

1. Cấu trúc và định nghĩa các thành phần cơ bản

Để khởi tạo một mảng SAFEARRAY, chúng ta cần xác định kích thước và phạm vi của nó thông qua cấu trúc SAFEARRAYBOUND.
// Định nghĩa biên cho mảng một chiều
SAFEARRAYBOUND bounds[1];
bounds[0].cElements = 4; // Số lượng phần tử trong mảng
bounds[0].lLbound = 0;   // Chỉ số (index) bắt đầu, thường là 0

// Khai báo con trỏ SAFEARRAY và biến VARIANT để đóng gói
SAFEARRAY* pSafeArray = nullptr;
VARIANT varContainer;
VariantInit(&varContainer);
Trong cấu trúc SAFEARRAYBOUND:
  • cElements: Xác định tổng số phần tử của chiều hiện tại.
  • lLbound: Là chỉ số logic bắt đầu. Nếu bạn đặt là 0, mảng sẽ chạy từ 0 đến n-1. Nếu đặt là 10, phần tử đầu tiên sẽ được truy cập qua chỉ số 10. Trong hầu hết các kịch bản lập trình hiện đại, giá trị này luôn được đặt là 0.

2. Khởi tạo mảng và đưa dữ liệu vào hệ thống

Việc khởi tạo mảng được thực hiện qua hàm SafeArrayCreate. Sau đó, chúng ta sử dụng SafeArrayPutElement để gán giá trị cho từng vị trí.
// Tạo mảng an toàn chứa các kiểu VARIANT
pSafeArray = SafeArrayCreate(VT_VARIANT, 1, bounds);

// Chuẩn bị dữ liệu mẫu
_variant_t dataItems[4];
dataItems[0] = _bstr_t("Enterprise");
dataItems[1] = _bstr_t("Architecture");
dataItems[2] = _bstr_t("Solution");
dataItems[3] = _bstr_t("Deployment");

// Duyệt và đưa dữ liệu vào SAFEARRAY
for (long i = 0; i < 4; i++) {
    // i đóng vai trò là mảng các chỉ số cho từng chiều (ở đây chỉ có 1 chiều)
    HRESULT hr = SafeArrayPutElement(pSafeArray, &i, &dataItems[i]);
    if (FAILED(hr)) {
        // Xử lý lỗi nếu cần
    }
}
Hàm SafeArrayCreate nhận vào ba tham số: loại dữ liệu phần tử (ví dụ VT_VARIANT), số chiều của mảng, và con trỏ đến cấu trúc định nghĩa biên đã tạo ở trên. Đối với mảng nhiều chiều, logic xử lý chỉ số sẽ phức tạp hơn một chút:
// Ví dụ logic cho mảng hai chiều
long indices[2];
for (long row = 0; row < maxRows; row++) {
    for (long col = 0; col < maxCols; col++) {
        indices[0] = row;
        indices[1] = col;
        SafeArrayPutElement(pSafeArray, indices, &value);
    }
}

3. Đóng gói SAFEARRAY vào VARIANT

Để có thể truyền SAFEARRAY qua các giao diện COM hoặc phương thức ADO, bạn phải bọc nó vào một VARIANT.
// Thiết lập kiểu dữ liệu: mảng (VT_ARRAY) kết hợp với kiểu phần tử (VT_VARIANT)
varContainer.vt = VT_ARRAY | VT_VARIANT;

// Gán con trỏ SAFEARRAY vào thành phần parray của VARIANT
varContainer.parray = pSafeArray;
Trong C++, bạn có thể sử dụng macro V_ARRAY(&varContainer) = pSafeArray; để thực hiện phép gán này một cách tường minh hơn. Việc kết hợp VT_ARRAY | VT_VARIANT thông báo cho hệ thống biết rằng VARIANT này đang chứa một mảng an toàn và các phần tử bên trong mảng đó cũng là các VARIANT. Lưu ý rằng khi sử dụng SafeArrayCreate, bộ nhớ sẽ được cấp phát trên heap. Nếu bạn sử dụng các lớp bao bọc như _variant_t, việc giải phóng bộ nhớ sẽ được quản lý tự động thông qua destructor khi biến ra khỏi phạm vi. Nếu quản lý thủ công, bạn cần gọi SafeArrayDestroy hoặc VariantClear để tránh rò rỉ bộ nhớ.

Thẻ: cpp COM ADO safearray variant

Đăng vào ngày 13 tháng 10 lúc 01:37