2009-11-22 27 views
11

Tôi có một hàm COM sẽ trả về một SafeArray thông qua tham số LPSAFEARRAY*. Hàm này tạo SafeArray bằng cách sử dụng lớp mẫu của ATL CComSafeArray. thực hiện ngây thơ của tôi sử dụng CComSafeArray<T>::Detach() để chuyển quyền sở hữu từ biến địa phương để các tham số đầu ra:Làm cách nào để trả về một CComSafeArray cục bộ thành tham số đầu ra LPSAFEARRAY?

void foo(LPSAFEARRAY* psa) 
{ 
    CComSafeArray<VARIANT> ret; 
    ret.Add(CComVariant(42)); 
    *psa = ret.Detach(); 
} 

int main() 
{ 
    CComSafeArray<VARIANT> sa; 
    foo(sa.GetSafeArrayPtr()); 

    std::cout << sa[0].lVal << std::endl; 
} 

Vấn đề là CComSafeArray::Detach() thực hiện một hoạt động Unlock để khi chủ sở hữu mới của SAFEARRAY (chính sa trong này trường hợp) bị phá hủy khóa không phải là số không và Destroy không mở khóa SafeArray với E_UNEXPECTED (điều này dẫn đến rò rỉ bộ nhớ vì SafeArray không được deallocated).

Cách chính xác để chuyển quyền sở hữu giữa cho CComSafeArrays qua ranh giới phương thức COM là gì?


Edit: Từ câu trả lời đơn cho đến nay có vẻ như rằng lỗi là ở phía client (main) và không phải từ phía máy chủ (foo), nhưng tôi thấy nó khó để tin rằng CComSafeArray wasn Không được thiết kế cho trường hợp sử dụng tầm thường này, phải có một cách thanh lịch để có được một SafeArray trong một phương thức COM thành một CComSafeArray.

+0

Bạn đang sử dụng phiên bản Visual Studio nào? –

+0

Điều này xảy ra cho cả VS8 (2005) và VS9 (2008) – Motti

+2

Dựa trên kinh nghiệm của tôi, tôi tin rằng bất cứ ai thiết kế CComSafeArray chưa bao giờ thực sự sử dụng nó. Bạn có thể sử dụng lớp wrapper của riêng bạn nếu bạn muốn. – Amnon

Trả lời

10

Vấn đề là bạn đặt trực tiếp con trỏ bên trong của CComSafeArray. Sử dụng phương pháp Attach() để đính kèm một hiện SAFEARRAY đến một CComSafeArray:

LPSAFEARRAY ar; 
foo(&ar); 
CComSafeArray<VARIANT> sa; 
sa.Attach(ar); 
+0

Chắc chắn đây không phải là cách 'CComSafeArray' được cho là được sử dụng, nó đi ngược lại với' CComVariant' và 'CComBSTR'. – Motti

+0

Như bạn đã thấy trong mã, CComSafeArray mong đợi SAFEARRAY bị khóa. Bạn phải khóa nó bằng cách này hay cách khác. – Amnon

+0

Và không có chức năng Đính kèm giống như khóa và cũng không có chức năng Detach giống như không mở khóa - do đó công việc phải được thực hiện trên cả hai người gọi hoặc bên callees. –

1

Tôi đoán rằng nơi đã không có ý định để cho phép một trường hợp sử dụng đó. Có lẽ đó không phải là nhà phát triển tương tự đã viết CComVariant & CComPtr :)

Tôi tin rằng tác giả coi trọng giá trị ngữ nghĩa là mục tiêu chính; Đính kèm/tách có thể chỉ đơn giản là một tính năng "tiền thưởng".

+1

Và ngay cả với lý do này, tôi vẫn cảm thấy như ctor mặc định 'CComSafeArray' và' GetSafeArrayPtr' là sai sót thiết kế/cách giải quyết ... – Andrey

5

Chỉ để xác nhận rằng câu trả lời được đánh dấu là đúng. Trình bao bọc RAII không thể hoạt động trên các ranh giới COM.

Triển khai phương pháp đã đăng không đúng, bạn không thể giả định rằng người gọi sẽ cung cấp SAFEARRAY hợp lệ. Chỉ cần [out] không phải là thuộc tính hợp lệ trong Tự động hóa, nó phải là [out, retval] hoặc [in, out]. Nếu nó là [out, retval], nó trông giống như vậy, thì phương thức này phải tạo một mảng mới từ đầu. Nếu nó là [in, out] thì phương thức đó phải phá hủy mảng được truyền vào nếu nó không phù hợp với kiểu mảng dự kiến ​​và tạo một mảng mới.

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