看板 C_Sharp 關於我們 聯絡資訊
※ 引述《proach (pazroach)》之銘言: : 問題一: : VC#需要將上述兩個檔案加入專案內嗎?是的話是加入 reference內? 在C#內, 只需將.DLL加入reference內,並且在要呼叫的CLASS內最前面用 using ThirdPartyDllNamespace之類的。 : 問題二: : 以前在 VC++內寫的程式碼要呼叫以下 function : short openDevice( &Handle ); : 我之前寫的程式碼是這樣的 : HANDLE handle; ┌─────────────────┬──────────────────┐ │MS$ C/C++ │MS$ C# │ ├─────────────────┼──────────────────┤ │HANDLE, LPDWORD, LPVOID, void* │IntPtr │ ├─────────────────┼──────────────────┤ │LPCTSTR, LPCTSTR, LPSTR, char* │String [in] │ │const char*, Wchar_t*, LPWSTR │StringBuilder [in, out] │ ├─────────────────┼──────────────────┤ │DWORD, unsigned long, Ulong │UInt32,[MarshalAs(UnmanagedType.U4)]│ ├─────────────────┼──────────────────┤ │bool │bool │ ├─────────────────┼──────────────────┤ │LP<struct> │[In] ref <struct> │ ├─────────────────┼──────────────────┤ │SIZE_T │uint │ ├─────────────────┼──────────────────┤ │LPDWORD │out uint │ ├─────────────────┼──────────────────┤ │LPTSTR │[Out] StringBuilder │ ├─────────────────┼──────────────────┤ │PULARGE_INTEGER │out ulong │ ├─────────────────┼──────────────────┤ │WORD │uInt16 │ ├─────────────────┼──────────────────┤ │Byte, unsigned char │byte │ ├─────────────────┼──────────────────┤ │Short │Int16 │ ├─────────────────┼──────────────────┤ │Long, int │Int32 │ ├─────────────────┼──────────────────┤ │float │single │ ├─────────────────┼──────────────────┤ │double │double │ ├─────────────────┼──────────────────┤ │NULL pointer │IntPtr.Zero │ ├─────────────────┼──────────────────┤ │Uint │Uint32 │ └─────────────────┴──────────────────┘ : short shortOpenSuccess = openDevice( &handle ); : 但是在 VC#內找不到 HANDLE 這個關鍵字,我要怎麼呼叫呢? 在C#內用IntPtr 類別代替C++內的HANDLE。 : 我最後有個奇怪的想法不知是否可行。因為此周邊其實都是傳回一些byte array而已, : 如果用 VC++ 寫個簡單的 Wrapper.dll,以處理 "HANDLE" 這東西的問題。 : VC# 去呼叫 Wrapper.dll,Wrapper.dll 再去呼叫 DriverLib.dll,只要 : 回傳一堆 byte就好,HANDLE 留在 Wrapper.dll 內不用回傳,這樣可行嗎? HANDLE其實只是一個Integer罷了, 給您看一篇文如下: DllImport介紹 在這篇文章中,我將概述幾點關於PInvoke的用法 . PInvoke是.Net程式語言能夠呼叫傳統 DLL內的函式的機制. 特別有用的地方於它可以呼叫Windows API, 而這些API是未收錄在 .Net類別庫中的, 以及一些第三方軟體業者提供的DLL內的函式也可以用PInvoke呼叫。 PInovke在C#和C++.NET中的用法和VB比較起來大不相同, 因為傳統的C++語言之類的內建 有指標或是可以指定unsafe code, 然而VB無法作到。 在VB.NET中使用PInvoke 在VB.Net中主要有兩種使用PInoke方式: 1. 使用 Declare 敘述 Declare Auto Function MyMessageBox Lib “user32.dll” Alias _ “MessageBox” (ByVal hWnd as Integer, ByVal msg as String, _ ByVal Caption as String, ByVal Tpe as Integer) As Integer Sub Main() MyMessageBox(0, "Hello World !!!", "Project Title", 0) End Sub Auto/Ansi/Unicode:字元的編碼. 用Auto就好, 讓編譯器自己去偵測編碼的型態。 Lib: DLL函式庫名稱。一定要用雙引號括起來。 Alias 函式的名稱和別名: 如果DLL內的函式名稱和VB的關鍵字一樣, 那麼一定要使用別 名。 2. 或使用DLLImport Imports System.Runtime.InteropServices <DllImport("User32.dll")> Public Shared Function _ MessageBox(ByVal hWnd As Integer, _ ByVal txt As String, ByVal caption As String, _ ByVal typ As Integer) As Integer End Function Sub Main() MessageBox(0, "Imported Hello World !!!", "Project Title", 0) End Sub Declare 敘述主要是用來提供和VB6的回溯相容性。其實VB.NET編譯器將Declare敘述自動 轉成DllImport, 但如果你用到了一些較進階的選項, 就非得用DllImport不可。 當你使用DllImport時, DLL內的函式是被實作成並帶有名稱和引數及回傳值型態空函式, 它是用DllImport特徵項(Attribute)來指定含有此函式的DLL檔的名稱, CLR(Common Language Runtime)會在現行資料夾下搜尋此檔, 接著在Windows的System32資料夾下找, 最後才在PATH環境變數內設的目錄去找。如果名稱和VB.NET的關鍵字相同, 那麼您必須將 名稱用中括號括起來。 下表是DllImport用到的參數列表 Parameter Description BestFitMapping 包裝轉換程式(Marshaler)將會為無法在ANSI和Unicode之間找到正確對 映的字元找出一個最佳匹配字元, 如果此參數設為True的話(此參數預設為True) 。 CallingConvention DLL進入點的呼叫慣例。 預設為 stdcall. CharSet 表示如何包裝轉換字串資料以及當同時有ANSI和Unicode兩種版本函式可用時該 選哪一個, 預設為Charset.Auto。 EntryPoint 該參數指定DLL進入點的名稱或值, 若未指定, 將使用函式名稱為進入點。 ExactSpelling 該參數控制了包裝轉換程式是否將會作名稱對映。 PreserveSig 該參數用來指定當正在包裝轉換時是否保留函式簽名。 SetLastError 該參數用來表示是否在呼叫完DLL內的函式時自動呼叫Win32的 SetLastError API。可用Marshal.GetLastWin32Error方法取代之。 ThrowOnUnmappableChar 該參數如果設為false, 那麼無法對映的字元將會用問號取代之 , 該參數如果設為true, 那麼當遇到無法對映的字元時, 將會丟出一個例外。 Using PInvoke in C# Unlike VB, C# does not have the Declare keyword, so we need to use DllImport in C# and Managed C++. [DllImport(“user32.dll”] public static extern int MessageBoxA( int h, string m, string c, int type); Here the function is declared as static because function is not instance dependent, and extern because C# compiler should be notified not to expect implementation. C# also provides a way to work with pointers. C# code that uses pointers is called unsafe code and requires the use of keywords: unsafe and fixed. If unsafe flag is not used, it will result in compiler error. Any operation in C# that involves pointers must take place in an unsafe context. We can use the unsafe keyword at class, method and block levels as shown below. public unsafe class myUnsafeClass { //This class can freely use unsafe code. } public class myUnsafeClass { //This class can NOT use unsafe code. public unsafe void myUnsafeMethod { // this method can use unsafe code } } public class myUnsafeClass { //This class can NOT use unsafe code. public void myUnsafeMethod { // this method too can NOT use unsafe code unsafe { // Only this block can use unsafe code. } } } stackalloc The stackalloc keyword is sometimes used within unsafe blocks to allow allocating a block of memory on the stack rather than on the heap. fixed & pinning GC moves objects in managed heap when it compacts memory during a collection. If we need to pass a pointer to a managed object to an unmanaged function, we need to ensure that the GC doesn’t move the object while its address is being used through the pointer. This process of fixing an object in memory is called pinning, and it’s accomplished in C# using the fixed keyword. MarshalAs MarshalAs attribute can be used to specify how data should be marshaled between managed and unmanaged code when we need to override the defaults. When we are passing a string to a COM method, the default conversion is a COM BSTR; when we are passing a string to a non-COM method, the default conversion is C- LPSTR. But if you want to pass a C-style null-terminated string to a COM method, you will need to use MarshalAs to override the default conversion. So far we have seen simple data types. But some of the functions need structures to be passed, which we have to handle differently from simple data types. StructLayout We can define a managed type that is the equivalent of an unmanaged structure. The problem with marshaling such types is that the common language runtime controls the layout of managed classes and structures in memory. The StructLayout Attribute allows a developer to control the layout of managed types. Possible values for the StructLayout are Auto, Explicit and Sequential. Charset, Pack and Size are the optional parameters which can be used with the StructLayout attribute. Callback functions and passing arrays as parameters involve some more complications and can be the subject for the next article. Parameter type mapping One of the severe problems with using Platform Invoke is deciding which .NET type to use when declaring the API function. The following table will summarize the .NET equivalents of the most commonly used Windows data types. Windows Data Type .NET Data Type BOOL, BOOLEAN Boolean or Int32 BSTR String BYTE Byte CHAR Char DOUBLE Double DWORD Int32 or UInt32 FLOAT Single HANDLE (and all other handle types, such as HFONT and HMENU) IntPtr, UintPtr or HandleRef HRESULT Int32 or UInt32 INT Int32 LANGID Int16 or UInt16 LCID Int32 or UInt32 LONG Int32 LPARAM IntPtr, UintPtr or Object LPCSTR String LPCTSTR String LPCWSTR String LPSTR String or StringBuilder* LPTSTR String or StringBuilder LPWSTR String or StringBuilder LPVOID IntPtr, UintPtr or Object LRESULT IntPtr SAFEARRAY .NET array type SHORT Int16 TCHAR Char UCHAR SByte UINT Int32 or UInt32 ULONG Int32 or UInt32 VARIANT Object VARIANT_BOOL Boolean WCHAR Char WORD Int16 or UInt16 WPARAM IntPtr, UintPtr or Object *As the string is an immutable class in .NET, they aren't suitable for use as output parameters. So a StringBuilder is used instead. All the English Text above is quoted from the following web site: http://www.codeproject.com/KB/dotnet/PInvoke.aspx -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 112.105.218.191
proach:這些資訊實在是太棒了,非常感謝 <(_,_)> 04/23 10:59
※ 編輯: horngsh 來自: 112.105.218.191 (04/23 11:22)
deuter:比較好的做法是用C# SafeHandle class 來存取 C++ HANDLE 04/23 11:57
deuter:而不是用IntPtr, MSDN有詳細解釋 04/23 11:57
horngsh:推D大說的 04/23 12:59
cogod:很實用的文章,thanks 04/25 23:27
TroyLee:推!! 04/25 23:37