日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > C# >内容正文

C#

在C#里调用C++的dll时需要注意的一些问题转

發(fā)布時(shí)間:2024/4/17 C# 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 在C#里调用C++的dll时需要注意的一些问题转 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
原文來(lái)自:http://hi.baidu.com/cityhacker/blog/item/419ed50af30a9e1595ca6b9d.html 2009-11-19 12:21 在c#里調(diào)用C++的dll,遇到了一些頭疼的問(wèn)題:

C++里頭文件定義形勢(shì)如下:

typedef void (*CALLBACKFUN1W)(wchar_t*, void* pArg);
typedef void (*CALLBACKFUN1A)(char*, void* pArg);

bool BIOPRINT_SENSOR_API dllFun1(CALLBACKFUN1 pCallbackFun1, void* pArg);

在其中一個(gè)導(dǎo)入的dll方法里,有一個(gè)回調(diào)函數(shù)的參數(shù)

[DllImport("test.dll", EntryPoint = "dllFunc1", CharSet = CharSet.Unicode)]
?? public static extern bool dllFunc1([MarshalAs(UnmanagedType.FunctionPtr)] CallbackFunc1 pCallbackFunc1 , IntPtr pArg);

回調(diào)函數(shù)在C#里定義成委托如下:
public delegate void CallbackFunc1(StringBuilder strName, IntPtr pArg);

調(diào)試運(yùn)行,報(bào)錯(cuò)。
有時(shí)是直接出錯(cuò)退出,信息如下:
Buffer overrun detected!

Program:
...

A buffer overrun has been detected which has corrupted the program's internal state. The program cannot safely continue execution and must now be terminated.

有時(shí)則能運(yùn)行起來(lái),但會(huì)拋出異常:
System.AccessViolationException: 嘗試讀取或?qū)懭胧鼙Wo(hù)的內(nèi)存。這通常指示其他內(nèi)存已損壞。

幾經(jīng)周折,覓得答案,原來(lái)是要指定 調(diào)用方式,如下就OK了:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
?? public delegate void CallbackFunc1(IntPtr hWnd, IntPtr pArg);

而系統(tǒng)默認(rèn)方式為 CallingConvention.StdCall。


程序終于不報(bào)錯(cuò)了,但是又出現(xiàn)結(jié)果不對(duì)了
定義成如下時(shí),strName在方法中的值,只有一個(gè)字符,
public delegate void CallbackFunc1(StringBuilder strName, IntPtr pArg);

后來(lái)改為:
public delegate void CallbackFunc1([MarshalAs(UnmanagedType.LPWStr)] StringBuilder strName, IntPtr pArg);

OK了,strName帶出來(lái)的值完整了,參數(shù)類型定義成 string 或者 StringBuilder 都無(wú)所謂

還可以用 IntPtr ,或者 char* 都行(用char* 得加 unsafe)

char* 類型的,得到值后,可循環(huán)至'\0'得到整個(gè)字符串
IntPtr 類型的,可以用Marshal.Copy出來(lái),如:
Marshal.Copy(IntPtr_source, toBytes, 0, 1024);



如果報(bào)
“嘗試讀取或?qū)懭胧鼙Wo(hù)的內(nèi)存。這通常指示其他內(nèi)存已損壞。”
異常,
還有可能是因?yàn)镃++和C#的參數(shù)類型對(duì)應(yīng)問(wèn)題,

如:
bool __declspec(dllimport) getImage(unsigned char** ppImage, int& nWidth, int& nHeight);

對(duì)應(yīng)成
[DllImport("test.dll")]
public static extern bool getImage(IntPtr ppImage, ref int nWidth, ref int nHeight);

時(shí),
則該方法在調(diào)用前,要對(duì)傳入的ppImage分配空間,如下
IntPtr pImage = Marshal.AllocHGlobal(iWidth * iHeight);
這種方法不推薦,因?yàn)槭菐С鼋Y(jié)果來(lái),一般這種指針不確定需要分配多大空間的。

正確的要對(duì)應(yīng)成下面這樣:
[DllImport("test.dll")]
public static extern bool getImage(ref IntPtr ppImage, ref int nWidth, ref int nHeight);

調(diào)用時(shí)只要定義就行了:
IntPtr pImage = new IntPtr();
int refWidth = 0, refHeight = 0;

getImage(ref pImage, ref refWidth, ref refHeight);

總結(jié),凡是雙針指類型參數(shù),可以用 ref IntPtr
而對(duì)于 int*, int&, 則都可用 ref int 對(duì)應(yīng)


另外,提一下自定義消息的響應(yīng)

?? public const int WM_USER = 0x0400;
?? public const int WM_TEST_MSG = (WM_USER + 0x100);


C# 要響應(yīng) dll 的自定義 消息,則要重寫 WinForm的DefWndProc方法。

protected override void DefWndProc(ref Message m)

{

switch (m.Msg)
??? {

????? case WM_TEST_MSG:
????? {

?????? }
????? break;

default:
????? base.DefWndProc(ref m);
????? break;
??? }

}


消息發(fā)送是通過(guò) Windows 提供的 API 函數(shù) SendMessage 來(lái)實(shí)現(xiàn)的,它的原型定義:

[DllImport("User32.dll",EntryPoint="SendMessage")]
private static extern int SendMessage(
?????? IntPtr hWnd,????? // handle to destination window
?????? uint Msg,???????? // message
?????? uint wParam,????? // first message parameter
?????? uint lParam?????? // second message parameter
);



再轉(zhuǎn)貼一篇相關(guān)文章:

C#中調(diào)用Windows API的要點(diǎn)

在.Net Framework SDK文檔中,關(guān)于調(diào)用Windows API的指示比較零散,并且其中稍全面一點(diǎn)的是針對(duì)Visual Basic .net講述的。本文將C#中調(diào)用API的要點(diǎn)匯集如下,希望給未在C#中使用過(guò)API的朋友一點(diǎn)幫助。另外如果安裝了Visual Studio .net的話,在C:\Program Files\Microsoft Visual Studio .NET\FrameworkSDK\Samples\Technologies\Interop\PlatformInvoke\WinAPIs\CS目錄下有大量的調(diào)用API的例子。
  一、調(diào)用格式
  using System.Runtime.InteropServices; //引用此名稱空間,簡(jiǎn)化后面的代碼
  ...
  //使用DllImportAttribute特性來(lái)引入api函數(shù),注意聲明的是空方法,即方法體為空。
  [DllImport("user32.dll")]
  public static extern ReturnType FunctionName(type arg1,type arg2,...);
  //調(diào)用時(shí)與調(diào)用其他方法并無(wú)區(qū)別
  可以使用字段進(jìn)一步說(shuō)明特性,用逗號(hào)隔開,如:
  [ DllImport( "kernel32", EntryPoint="GetVersionEx" )]
  DllImportAttribute特性的公共字段如下:
  1、CallingConvention 指示向非托管實(shí)現(xiàn)傳遞方法參數(shù)時(shí)所用的 CallingConvention 值。
  CallingConvention.Cdecl : 調(diào)用方清理堆棧。它使您能夠調(diào)用具有 varargs 的函數(shù)。
  CallingConvention.StdCall : 被調(diào)用方清理堆棧。它是從托管代碼調(diào)用非托管函數(shù)的默認(rèn)約定。
  2、CharSet 控制調(diào)用函數(shù)的名稱版本及指示如何向方法封送 String 參數(shù)。
  此字段被設(shè)置為 CharSet 值之一。如果 CharSet 字段設(shè)置為 Unicode,則所有字符串參數(shù)在傳遞到非托管實(shí)現(xiàn)之前都轉(zhuǎn)換成 Unicode 字符。這還導(dǎo)致向 DLL EntryPoint 的名稱中追加字母“W”。如果此字段設(shè)置為 Ansi,則字符串將轉(zhuǎn)換成 ANSI 字符串,同時(shí)向 DLL EntryPoint 的名稱中追加字母“A”。
  大多數(shù) Win32 API 使用這種追加“W”或“A”的約定。如果 CharSet 設(shè)置為 Auto,則這種轉(zhuǎn)換就是與平臺(tái)有關(guān)的(在 Windows NT 上為 Unicode,在 Windows 98 上為 Ansi)。CharSet 的默認(rèn)值為 Ansi。CharSet 字段也用于確定將從指定的 DLL 導(dǎo)入哪個(gè)版本的函數(shù)。
  CharSet.Ansi 和 CharSet.Unicode 的名稱匹配規(guī)則大不相同。對(duì)于 Ansi 來(lái)說(shuō),如果將 EntryPoint 設(shè)置為“MyMethod”且它存在的話,則返回“MyMethod”。如果 DLL 中沒(méi)有“MyMethod”,但存在“MyMethodA”,則返回“MyMethodA”。
  對(duì)于 Unicode 來(lái)說(shuō)則正好相反。如果將 EntryPoint 設(shè)置為“MyMethod”且它存在的話,則返回“MyMethodW”。如果 DLL 中不存在“MyMethodW”,但存在“MyMethod”,則返回“MyMethod”。如果使用的是 Auto,則匹配規(guī)則與平臺(tái)有關(guān)(在 Windows NT 上為 Unicode,在 Windows 98 上為 Ansi)。如果 ExactSpelling 設(shè)置為 true,則只有當(dāng) DLL 中存在“MyMethod”時(shí)才返回“MyMethod”。
  3、EntryPoint 指示要調(diào)用的 DLL 入口點(diǎn)的名稱或序號(hào)。
  如果你的方法名不想與api函數(shù)同名的話,一定要指定此參數(shù),例如:
  [DllImport("user32.dll",CharSet="CharSet.Auto",EntryPoint="MessageBox")]
  public static extern int MsgBox(IntPtr hWnd,string txt,string caption, int type);
  4、ExactSpelling 指示是否應(yīng)修改非托管 DLL 中的入口點(diǎn)的名稱,以與 CharSet 字段中指定的 CharSet 值相對(duì)應(yīng)。如果為 true,則當(dāng) DllImportAttribute.CharSet 字段設(shè)置為 CharSet 的 Ansi 值時(shí),向方法名稱中追加字母 A,當(dāng) DllImportAttribute.CharSet 字段設(shè)置為 CharSet 的 Unicode 值時(shí),向方法的名稱中追加字母 W。此字段的默認(rèn)值是 false。
  5、PreserveSig 指示托管方法簽名不應(yīng)轉(zhuǎn)換成返回 HRESULT、并且可能有一個(gè)對(duì)應(yīng)于返回值的附加 [out, retval] 參數(shù)的非托管簽名。
  6、SetLastError 指示被調(diào)用方在從屬性化方法返回之前將調(diào)用 Win32 API SetLastError。 true 指示調(diào)用方將調(diào)用 SetLastError,默認(rèn)為 false。運(yùn)行時(shí)封送拆收器將調(diào)用 GetLastError 并緩存返回的值,以防其被其他 API 調(diào)用重寫。用戶可通過(guò)調(diào)用 GetLastWin32Error 來(lái)檢索錯(cuò)誤代碼。

?

?

轉(zhuǎn)載于:https://www.cnblogs.com/khler/archive/2010/01/12/1645436.html

總結(jié)

以上是生活随笔為你收集整理的在C#里调用C++的dll时需要注意的一些问题转的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。