2008-11-17 38 views
6

Tôi là một đối tượng COM được viết bằng ATL được sử dụng từ một ứng dụng C++ và tôi muốn truyền một mảng các BYTE giữa hai ứng dụng. Kinh nghiệm của tôi về COM/IDL cho đến nay được giới hạn để truyền các loại đơn giản (BSTRs, LONGs, v.v.).Truyền một mảng bằng COM?

Có cách nào tương đối dễ dàng để đối tượng COM chuyển mảng tới người gọi không? Ví dụ: tôi muốn chuyển một hình ảnh thô (TIFF) thay vì làm rối tung các tệp tạm thời.

+10

Vui vẻ phải là đối tượng COM. :-) – Danra

Trả lời

11

Thử truyền một biến thể an toàn cho đối tượng COM. Một cái gì đó như thế này để đặt một mảng BYTE bên trong một biến thể an toàn ....

bool ArrayToVariant(CArray<BYTE, BYTE>& array, VARIANT& vtResult) 
{ 
SAFEARRAY FAR* psarray; 
SAFEARRAYBOUND sabounds[1]; 

sabounds[0].lLbound=0; 
sabounds[0].cElements = (ULONG)array.GetSize(); 

long nLbound; 

psarray = SafeArrayCreate(VT_UI1, 1, sabounds); 
if(psarray == NULL) 
    return false; 

for(nLbound = 0; nLbound < (long)sabounds[0].cElements ; nLbound++){ 
    if(FAILED(SafeArrayPutElement(psarray, &nLbound, &array[nLbound]))){ 
     SafeArrayDestroy(psarray); 
     return false; 
    } 
} 

VariantFree(vtResult); 
vtResult.vt = VT_ARRAY|VT_UI1; 
vtResult.parray = psarray; 
return true; 
} 
+0

Cảm ơn - Tôi tìm thấy một lớp ATL rất hữu ích được gọi là CComSafeArray mà làm cho điều này rất dễ dàng (phiên bản cũ của MFC có thể sử dụng COleSafeArray). – Rob

0

Khám phá bằng cách sử dụng safearrays. Dưới đây là một số mã ví dụ:

Các SAFEARRAY được trả về như một con trỏ đến một VARIANT

[id(1), helpstring("LogCache")] HRESULT LogCache([out,retval] VARIANT* logCache); 

Safearrays là khá dễ sử dụng. Dưới đây là một số ví dụ mã mà là một bộ nhớ cache của 1000 thông điệp đăng nhập mới nhất của một số ứng dụng:

safearray_t<bstr_t> m_logCache; 
    ... 
    if (m_logCache.size() > 1000) 
    { 
     m_logCache.pop_back(); 
    } 

    m_logCache.push_front(Msg.str(), 0); 


    variant_t LogCache() 
    { 
     if (!m_logCache.is_empty()) 
     { 
      variant_t cache(m_logCache); 
      return cache; 
     } 
    } 

Lưu ý rằng cú pháp trong trường hợp của bạn là gần như chắc chắn sẽ khác nhau kể từ khi tôi đang sử dụng comet COM library, nhưng những ý tưởng/khái niệm là như nhau.

-1

Bạn có thể sử dụng BSTR để chuyển một mảng byte.

BYTE array[buffer_size]; 
... 
BSTR toBePassed = SysAllocStringByteLen((OLECHAR*)array,length); 
YourCOMMethod(toBePassed); 
SysFreeString(toBePassed); 

Trong phương pháp của bạn:

BYTE* pData = (BYTE*)bstrPassed; 
DWORD dataLength = SysStringByteLen(bstrPassed); 
+4

KHÔNG LÀM VIỆC. Nội dung mảng có thể được dịch từ trang mã ANSI sang Unicode hoặc ngược lại, làm cho các giá trị nhị phân thay đổi. Ứng dụng của khách hàng có thể không phải lúc nào cũng biết khi nào điều này xảy ra và họ sẽ tìm thấy dữ liệu của họ bị hỏng. –

+2

Để làm rõ: Mặc dù các lập trình viên dự định mảng để giữ dữ liệu nhị phân, các thói quen hệ thống khác nhau không biết ý định của lập trình viên. BSTR được thiết kế để giữ các chuỗi Unicode, và các thói quen hệ thống sẽ làm cho giả định đó. –

2

SAFEARRAYs là con đường để đi nếu bạn muốn tuân thủ OLE-Tự động hóa, và có thể sử dụng giao diện COM từ các ngôn ngữ khác như VB6. Nhưng có một sự thay thế trong IDL, ví dụ: -

void Fx([in] long cItems, [in, size_is(cItems)] BYTE aItems[]); 

này mô tả một phương pháp nơi mã marshalling có thể suy ra số byte được chuyển giao bằng cách kiểm tra giá trị của tham số đầu tiên.

Điều này là tốt nếu khách hàng của bạn đều được viết bằng C/C++, nhưng tôi nghĩ rằng một giao diện chứa này sẽ không được tự động hóa tuân thủ, vì vậy không thể sử dụng từ VB6, và thể các marshaler tiêu chuẩn sẽ không có thể làm marshaling, vì vậy bạn cần tạo proxy/stub DLL của riêng bạn từ IDL. Không khó để làm, nhưng khó hơn một chút so với sử dụng SAFEARRAYs.

Các vấn đề liên quan