※ 引述《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