2011-08-11 32 views
9

Tôi đang viết một API trong COM trong C++, và cũng viết một chương trình tiêu thụ API này trong C#. Câu hỏi của tôi là về ngữ nghĩa quản lý bộ nhớ BSTR khi chuyển BSTR vào các hàm COM. Nói IDL của tôi trông giống như:Công ước để chuyển BSTR vào các hàm COM từ C# (COM interop)

HRESULT SomeFunction([in] BSTR input); 

Hiện tại chức năng này được thực hiện như thế này:

HRESULT SomeFunction(BSTR input) { 
    // Do stuff ..., then: 
    SysFreeString(input); 
} 

Khi tôi gọi nó từ C# với một cái gì đó giống như SomeFunction(myString), sẽ C# tạo ra một cái gì đó như thế này (giả):

myString = SysAllocString("string"); 
SomeFunction(myString); 

Hay đúng hơn là như thế này:

myString = SysAllocString("string"); 
SomeFunction(myString); 
SysFreeString(myString); 

Tức là, không C# miễn phí BSTR mà nó tạo ra để so sánh với giao diện COM, hoặc tôi nên giải phóng nó bên trong chức năng của tôi? Cảm ơn!

Trả lời

14

Từ Allocating and Releasing Memory for a BSTR:

Khi bạn gọi vào một chức năng mà hy vọng một cuộc tranh luận BSTR, bạn phải cấp phát bộ nhớ cho BSTR trước khi cuộc gọi và phát hành nó sau đó. ...

Vì vậy, không giải phóng nếu đó là thông số đầu vào. C# (và bất kỳ thời gian chạy nào khác sử dụng các đối tượng COM) phải tôn trọng quy ước COM để quản lý việc truyền vào bộ nhớ của các đối tượng COM và do đó phải quản lý bộ nhớ cho chuỗi nếu nó là tham số đầu vào. Nếu không, làm thế nào một đối tượng COM biết rằng nó đang được gọi từ C# hoặc một số thời gian chạy ngôn ngữ khác?

bổ sung google-fu bật lên này: Marshaling between Managed and Unmanaged Code

... Về vấn đề sở hữu, CLR sau COM kiểu ước:

  • Memory trôi qua như [trong] thuộc sở hữu của người gọi và phải là cả hai
    được người gọi cấp phát và được người gọi giải phóng. Các callee nên
    không cố gắng giải phóng hoặc sửa đổi bộ nhớ đó.
  • Bộ nhớ được cấp bởi callee và được chuyển thành [out] hoặc trả lại do người gọi sở hữu và phải được người gọi giải phóng.
  • Callee có thể giải phóng bộ nhớ khi [in, out] từ người gọi, cấp phát bộ nhớ mới cho nó và ghi đè giá trị con trỏ cũ, do đó chuyển nó đi. Bộ nhớ mới được sở hữu bởi người gọi. Điều này đòi hỏi hai cấp độ của indirection, chẳng hạn như char **.

Trong thế giới interop, người gọi/callee trở thành CLR/mã gốc.Quy tắc ở trên ngụ ý rằng trong trường hợp được bỏ ghim, nếu khi ở mã gốc bạn
nhận con trỏ tới một khối bộ nhớ được chuyển cho bạn dưới dạng [out] từ
CLR, bạn cần giải phóng nó. Mặt khác, nếu CLR nhận được
một con trỏ được chuyển thành [out] từ mã gốc, CLR cần phải
miễn phí nó. Rõ ràng, trong trường hợp đầu tiên, mã gốc cần phải thực hiện việc xóa phân bổ
và trong trường hợp thứ hai, mã được quản lý cần phải thực hiện
không phân bổ.

Vì vậy, CLR tuân thủ các quy tắc COM về quyền sở hữu bộ nhớ. QED.

+1

Câu trả lời này không liên quan gì đến những gì CLR tự động thực hiện cho interop, đó là tất cả các OP đang hỏi về. – ildjarn

+0

@ildjarn: ngược lại, nó trả lời chính xác câu hỏi của OP. –

+0

@Alf: Nói đúng câu trả lời vì lý do sai và ngữ cảnh sai và liên kết không thực sự "đúng". – ildjarn

0

Bạn có ý nghĩa từ quan điểm của nhà phát triển C# hoặc từ nhà phát triển C++.

Nhà phát triển C# không phải lo lắng về bất kỳ quản lý bộ nhớ nào khi xử lý COM +.

Tạo thành phần COM + trong C++, bạn sẽ không phải biết ai đang gọi bạn, ngữ nghĩa bộ nhớ giống nhau. Nếu đó là tham số, người gọi có trách nhiệm quản lý bộ nhớ, bất kể đó là C++ hay C#. Trong C#, CLR sẽ xử lý nó cho chúng.

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