2011-12-21 29 views
11

Tôi đang cố gắng đi qua các mâu thuẫn của các định nghĩa interop COM chúng tôi đã phân tán trên các dự án khác nhau và thu thập chúng thành một vị trí duy nhất nhóm dev có thể có lợi. Một phần của nỗ lực này bao gồm làm sạch các định nghĩa đã được tích lũy qua nhiều năm.Khi nào nó cần thiết/thích hợp để sử dụng InAttribute và OutAttribute cho COM Interop

Một số trong số này được mượn từ mã nguồn khác, một số được sao chép đúng nguyên văn từ pinvoke.net và một số được dịch trực tiếp từ tiêu đề SDK. Một điều tôi nhận thấy là không có sự nhất quán về thời điểm sử dụng các thuộc tính marshalling khác nhau, (ngay cả trong số các ví dụ về pinvoke.net, điều này là khá hay bị bỏ lỡ). Một phần của vấn đề là, tôi không nghĩ rằng bất cứ ai ở đây (bao gồm cả bản thân mình) hoàn toàn hiểu được khi các thuộc tính khác nhau là cần thiết hay không, hoặc những gì họ thực sự làm. Cho đến thời điểm này, nhận được những quyền này có vẻ là một sự kết hợp của phỏng đoán và thay đổi ngẫu nhiên cho đến khi COMExceptions ngừng xảy ra, nhưng tôi muốn nhiều bản dịch là đúng vì ai đó thực sự nhìn vào chúng và tuyên bố chúng như vậy.

Vì vậy, tôi bắt đầu với [In][Out]. Tôi biết hai thuộc tính đó có ý nghĩa gì: chúng thông báo cho marshaller biết hướng dữ liệu phải đi. Ví dụ: tôi giả sử trình so khớp, sẽ không làm phiền sao chép dữ liệu [In] trở lại người gọi hoặc biết rằng dữ liệu có thể cần được giải phóng ở phía bên lề, v.v. Những điều tôi không biết là:

  1. Khi nào thì cần thiết để sử dụng các thuộc tính này? Đó là, khi nào thì hành vi marshalling mặc định sai sao cho các thuộc tính làm cho nó đúng?
  2. Khi nào thì an toàn để sử dụng các thuộc tính này? Nghĩa là, sẽ xác định những gì đã được các hành vi mặc định thay đổi cách marshaller hoạt động?
  3. Khi nào thì nguy hiểm để sử dụng các thuộc tính này? Tôi giả định rằng một cách rõ ràng đánh dấu một tham số đầu ra [In] là xấu, nhưng là đánh dấu một tham số đầu vào [In, Out] thực sự sẽ phá vỡ bất cứ điều gì?

Vì vậy, được đưa ra một phương pháp giao diện COM giả thuyết mà IDL trông như thế này:

HRESULT Foo(
    [in] ULONG a, 
    [out] ULONG * b 
    [in, out] ULONG * c); 

tôi có thể thấy điều này được dịch là bất kỳ những điều sau đây:

void Foo(
    uint cb, 
    out uint b, 
    ref uint c); 

void Foo(
    uint cb, 
    [Out] out uint b, 
    [In, Out] ref uint c); 

void Foo(
    [In] uint cb, 
    [Out] out uint b, 
    [In, Out] ref uint c); 

Có sự khác biệt chức năng giữa ba người đó? Có ai trong số họ được coi là "tốt hơn" so với những người khác vì lý do ngoài tính chính xác kỹ thuật?

+2

Hãy cẩn thận ở đây, bạn đang so sánh táo và cam. Các thuộc tính [in] và [out] trong một tệp IDL chỉ được sử dụng bởi midl.exe khi nó tạo ra mã proxy/stub. Chỉ được sử dụng khi cuộc gọi COM cần được sắp xếp giữa các căn hộ hoặc quy trình. Các thuộc tính .NET [In] và [Out] chỉ được sử dụng bởi marshaller pinvoke. Mà chạy trong một môi trường thời gian chạy rất khác nhau, luôn luôn trong quá trình và không có bất kỳ liên quan đến căn hộ. Ý định của họ chắc chắn là như nhau, tối ưu hóa cuộc gọi. –

+1

Vâng, tôi (nghĩ rằng tôi) hiểu phần này. Đối với mục đích của tôi, khi dịch IDL thành C#, tôi chỉ sử dụng các thuộc tính IDL như một gợi ý về cách các phương thức được "nghĩa vụ" hành xử như thế nào. IOW, thuộc tính [out] trong IDL có nghĩa là người viết giao diện dự định tham số này sẽ quay lại từ người gọi với một giá trị được lưu trữ trong đó, vì vậy tôi cần đảm bảo mã C# hoạt động theo cùng một cách. Nơi tôi đang rơi ngắn là sự hiểu biết hành vi mặc định của NET marshaller và khi tôi cần phải nói với nó phải làm gì so với khi nó làm điều đúng trên riêng của mình. –

+2

Chúng cần thiết trong IDL vì nó hoàn toàn không rõ ràng hướng dữ liệu là gì khi bạn sử dụng con trỏ. Không phải là vấn đề trong C# với các từ khóa * ref * và * out *. Trường hợp tốt 99% chỉ đơn giản là bỏ qua các thuộc tính trong C#. 100% nếu bạn đang thực sự thay thế mã COM bằng C#. –

Trả lời

14

Không, bạn không cần phải áp dụng bất kỳ thuộc tính nào trong số các thuộc tính này trong mã của riêng bạn. Tất cả đều tùy chọn và tự động áp dụng cho mã của bạn tùy thuộc vào loại thông số.

Về cơ bản, họ có từ khóa tương đương C# sau:

  • Bạn nhận được [In] theo mặc định.
  • Từ khóa ref giúp bạn [In, Out].
  • Từ khóa out giúp bạn [Out].

Tất cả được ghi lại trong một bảng đẹp here.

Bạn chỉ cần sử dụng chúng khi bạn muốn thay đổi ngữ nghĩa ngụ ý hoặc thay đổi hành vi mặc định của trình so khớp. Ví dụ, bạn có thể đánh dấu một tham số được khai báo ref với thuộc tính [In] chỉ để ngăn chặn phần "ra" của marshaling.

Điều đó nói rằng, tôi thấy mình sử dụng chúng bởi vì chúng là một cách rất dễ dàng để làm cho mã tự tài liệu.

+0

Tôi thích ý tưởng tự tài liệu! Và chỉ cần thêm: Việc sử dụng MarshalAs cho Bool và Strings có liên quan nhiều hơn, hãy kiểm tra chúng ... – eFloh

+0

Vâng, tôi quen thuộc hơn với thuộc tính MarshalAs, mặc dù có một số chi tiết mà tôi vẫn chưa rõ (chủ yếu là với mảng). Tôi đã bắt đầu đơn giản :) –

+0

Ah, điều đó thực sự giải thích điều tôi thấy trên pinvoke.net rất nhiều! Ví dụ, nếu một phương thức có tham số REFIID, thông thường đó sẽ là một "refid". Nhưng nếu tham số được chỉ định là [trong] trong IDL, tôi có thể chỉ định nó là "[In] ref Guid refiid" và nó sẽ không bận tâm để sắp xếp cấu trúc Guid lại cho tôi vì tôi không cần nó, đúng ? –

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