2012-08-15 56 views
13

Tôi đã tìm kiếm trên internet xa và rộng nhưng không tìm thấy giải thích tốt.Tôi có thể sử dụng SafeHandle thay vì IntPtr không?

Câu hỏi của tôi khá đơn giản.

Tôi có một DLL có chức năng được gọi là Khởi tạo và một trong các tham số là một con trỏ sẽ nhận được một xử lý được sử dụng với các cuộc gọi tiếp theo. Tham số khác là một chuỗi mà tôi sẽ liệt kê để hoàn thành. Chữ ký Tôi đang sử dụng là (theo mẫu đơn giản của nó):

[DllImport(MyDll)] 
static extern bool Initialize([In] string name, out IntPtr handle); 

chữ ký trong DLL tự nó được viết như sau: Initialize(LPTSTR name, HANDLE handle) với lời nhận xét "HANDLE: Con trỏ trỏ tới một vị trí đó sẽ nhận được xử lý".

Và tiếp theo các cuộc gọi đang ở trong hình thức

[DllImport(MyDll)] 
static extern bool DoSomething(IntPtr handle, uint randomParameter); 

Tôi đã được đọc về SafeHandle và tôi đã tự hỏi nếu tôi có thể sử dụng nó để substite cho xử lý IntPtr tôi. Và nếu tôi có thể, làm thế nào để tôi làm điều đó? Mở rộng lớp SafeHandle trừu tượng không phải là một vấn đề, nhưng tôi có thể trực tiếp thay thế IntPtr của tôi cho SafeHandle (và sử dụng mặc định Marshalling) hay tôi cần phải làm gì đó thêm?

+0

lợi ích gì 'SafeHandle' cung cấp cho bạn mà chỉ lưu trữ các' IntPtr' không làm? –

+4

@ScottChamberlain - 'SafeHandle' là' IDisposable' và đảm bảo rằng các tài nguyên được giới thiệu bởi các xử lý được phát hành.'IntPtr' chỉ đơn giản là một giá trị kích thước con trỏ có thể được truyền xung quanh - nó không có ngữ nghĩa xử lý. – LBushkin

+0

Giả sử bạn được phép tính phí bộ nhớ, trừ khi bạn có thể de-cấp phát bộ nhớ con trỏ bằng cách sử dụng 'Marshal.FreeBSTR',' Marshal.FreeCoTaskMem', hoặc 'Marshal.FreeHGlobal', tôi không nghĩ rằng bạn có thể an toàn - phân bổ bộ nhớ từ C#. Sử dụng 'IntPtr', C# sẽ không tìm cách giải phóng bộ nhớ tự động. – Pooven

Trả lời

10

Bạn có thể tìm một câu trả lời đầy đủ hơn về sự khác biệt giữa SafeHandleIntPtr đây: IntPtr, SafeHandle and HandleRef - Explained

Tuy nhiên, để tóm tắt, IntPtr nên được sử dụng khi đối số thực sự là một con trỏ máy có kích thước-SafeHandle nên được sử dụng nơi đối số thực sự là một tay cầm Win32. Những loại này thường không thể hoán đổi cho nhau; kích thước của IntPtr sẽ thay đổi trên các kiến ​​trúc khác nhau (32 bit trên x86 và 64 bit trên x64 và amd64). LƯU Ý: Dưới bìa tôi tin rằng SafeHandle cũng sử dụng một số IntPtr).

Ngoài ra, không giống như IntPtr, SafeHandle thực sự thực hiện xử lý tài nguyên khi loại rác được thu thập. Điều này đảm bảo rằng tài nguyên hệ thống không bị rò rỉ khi chương trình của bạn đang chạy (mặc dù bạn nên Dispose() trong số SafeHandle trường hợp sớm nhất có thể). Lưu ý rằng SafeHandle thực sự trừu tượng vì có nhiều loại xử lý khác nhau yêu cầu các cách tiếp cận khác nhau để xử lý và xử lý thích hợp.

Trong trường hợp cụ thể của bạn, bạn cần xem tài liệu về DLL bạn đang gọi. Nếu nó là một Win32 DLL, có thể đã có một loại SafeHandle cho nó. Nếu đó là một bên thứ ba DLL, sau đó bạn có thể cuộn thực hiện SafeHandle của riêng bạn - giả sử rằng ngoài Initialize() có một số phiên bản của Release() (hoặc tương đương).

Một số mẩu tin thú vị bổ sung về IntPtr vs SafeHandle thể được tìm thấy tại địa chỉ:

Use SafeHandle to encapsulate native resources

SafeHandle Class Reference

SafeHandles and Critical Finalization

+0

Chắc chắn 'IntPtr' là 64 bit không 65? Tôi đã chỉnh sửa - vui lòng hoàn nguyên và giải thích thêm (Tôi đã chuẩn bị cho điều này để trở thành "của tôi" tìm hiểu điều gì đó mới mẻ mỗi ngày) – sblom

+0

Vâng, việc tạo ra sự che giấu SafeHandle của riêng tôi như tôi đã nói là không có vấn đề lớn, có rất nhiều ví dụ Những gì tôi muốn biết là nếu tôi có thể sử dụng SafeHandle và IntPtr hoán đổi cho nhau, do đó tôi có thể làm: 'static extern bool Initialize ([In] string name, out SafeHandle)' thay cho 'static extern bool Initialize 'hiện tại ([In] tên chuỗi, ra IntPtr) '? – Davio

+0

@ sblom: Không, đó chỉ là một lỗi đánh máy trên một phần của tôi. Cảm ơn bạn đã đánh bắt nó – LBushkin

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