如何在C#中使用Win32和其他庫之三

具有內嵌字符數組的結構

某些函數接受具有內嵌字符數組的結構。例如,GetTimeZoneInformation() 函數接受指向以下結構的指針:

typedef struct _TIME_ZONE_INFORMATION {     LONG       Bias;     WCHAR      StandardName[ 32 ];     SYSTEMTIME StandardDate;     LONG       StandardBias;     WCHAR      DaylightName[ 32 ];     SYSTEMTIME DaylightDate;     LONG       DaylightBias; } TIME_ZONE_INFORMATION, *PTIME_ZONE_INFORMATION;

在 C# 中使用它需要有兩種結構。一種是 SYSTEMTIME,它的設置很簡單:

   struct SystemTime   {      public short wYear;      public short wMonth;      public short wDayOfWeek;      public short wDay;      public short wHour;      public short wMinute;      public short wSecond;      public short wMilliseconds;   }

這里沒有什么特別之處;另一種是 TimeZoneInformation,它的定義要復雜一些:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]struct TimeZoneInformation{    public int bias;   [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]   public string standardName;   SystemTime standardDate;   public int standardBias;   [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]   public string daylightName;   SystemTime daylightDate;   public int daylightBias;}

此定義有兩個重要的細節。第一個是 MarshalAs 屬性:

   [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]

查看 ByValTStr 的文檔,我們發現該屬性用于內嵌的字符數組;另一個是 SizeConst,它用于設置數組的大小。

我在第一次編寫這段代碼時,遇到了執行引擎錯誤。通常這意味著部分互操作覆蓋了某些內存,表明結構的大小存在錯誤。我使用 Marshal.SizeOf() 來獲取所使用的封送拆收器的大小,結果是 108 字節。我進一步進行了調查,很快回憶起用于互操作的默認字符類型是 Ansi 或單字節。而函數定義中的字符類型為 WCHAR,是雙字節,因此導致了這一問題。

我通過添加 StructLayout 屬性進行了更正。結構在默認情況下按順序布局,這意味著所有字段都將以它們列出的順序排列。CharSet 的值被設置為 Unicode,以便始終使用正確的字符類型。

經過這樣處理后,該函數一切正常。您可能想知道我為什么不在此函數中使用 CharSet.Auto。這是因為,它也沒有 A W 變體,而始終使用 Unicode 字符串,因此我采用了上述方法編碼。

具有回調的函數

當 Win32 函數需要返回多項數據時,通常都是通過回調機制來實現的。開發人員將函數指針傳遞給函數,然后針對每一項調用開發人員的函數。

在 C# 中沒有函數指針,而是使用“委托”,在調用 Win32 函數時使用委托來代替函數指針。

EnumDesktops() 函數就是這類函數的一個示例:

BOOL EnumDesktops(  HWINSTA hwinsta,            // 窗口實例的句柄  DESKTOPENUMPROC lpEnumFunc, // 回調函數  LPARAM lParam               // 用于回調函數的值);

HWINSTA 類型由 IntPtr 代替,而 LPARAM 由 int 代替。DESKTOPENUMPROC 所需的工作要多一些。下面是 MSDN 中的定義:

BOOL CALLBACK EnumDesktopProc(  LPTSTR lpszDesktop,  // 桌面名稱  LPARAM lParam        // 用戶定義的值);

我們可以將它轉換為以下委托:

delegate bool EnumDesktopProc(   [MarshalAs(UnmanagedType.LPTStr)]   string desktopName,   int lParam);

完成該定義后,我們可以為 EnumDesktops() 編寫以下定義:

[DllImport("user32.dll", CharSet = CharSet.Auto)]static extern bool EnumDesktops(   IntPtr windowStation,   EnumDesktopProc callback,   int lParam);

這樣該函數就可以正常運行了。

在互操作中使用委托時有個很重要的技巧:封送拆收器創建了指向委托的函數指針,該函數指針被傳遞給非托管函數。但是,封送拆收器無法確定非托管函數要使用函數指針做些什么,因此它假定函數指針只需在調用該函數時有效即可。

結果是如果您調用諸如 SetConsoleCtrlHandler() 這樣的函數,其中的函數指針將被保存以便將來使用,您就需要確保在您的代碼中引用委托。如果不這樣做,函數可能表面上能執行,但在將來的內存回收處理中會刪除委托,并且會出現錯誤。

其他高級函數

迄今為止我列出的示例都比較簡單,但是還有很多更復雜的 Win32 函數。下面是一個示例:

DWORD SetEntriesInAcl(  ULONG cCountOfExplicitEntries,           // 項數  PEXPLICIT_ACCESS pListOfExplicitEntries, // 緩沖區  PACL OldAcl,                             // 原始 ACL  PACL *NewAcl                             // 新 ACL);

前兩個參數的處理比較簡單:ulong 很簡單,并且可以使用 UnmanagedType.LPArray 來封送緩沖區。

但第三和第四個參數有一些問題。問題在于定義 ACL 的方式。ACL 結構僅定義了 ACL 標頭,而緩沖區的其余部分由 ACE 組成。ACE 可以具有多種不同類型,并且這些不同類型的 ACE 的長度也不同。

如果您愿意為所有緩沖區分配空間,并且愿意使用不太安全的代碼,則可以用 C# 進行處理。但工作量很大,并且程序非常難調試。而使用 C++ 處理此 API 就容易得多。

屬性的其他選項

DLLImport StructLayout 屬性具有一些非常有用的選項,有助于 P/Invoke 的使用。下面列出了所有這些選項:

DLLImport

CallingConvention

您可以用它來告訴封送拆收器,函數使用了哪些調用約定。您可以將它設置為您的函數的調用約定。通常,如果此設置錯誤,代碼將不能執行。但是,如果您的函數是 Cdecl 函數,并且使用 StdCall(默認)來調用該函數,那么函數能夠執行,但函數參數不會從堆棧中刪除,這會導致堆棧被填滿。

CharSet

控制調用 A 變體還是調用 W 變體。

EntryPoint

此屬性用于設置封送拆收器在 DLL 中查找的名稱。設置此屬性后,您可以將 C# 函數重新命名為任何名稱。

ExactSpelling

將此屬性設置為 true,封送拆收器將關閉 AW 的查找特性。

PreserveSig

COM 互操作使得具有最終輸出參數的函數看起來是由它返回的該值。此屬性用于關閉這一特性。

SetLastError

確保調用 Win32 API SetLastError(),以便您找出發生的錯誤。

StructLayout

LayoutKind

結構在默認情況下按順序布局,并且在多數情況下都適用。如果需要完全控制結構成員所放置的位置,可以使用 LayoutKind.Explicit,然后為每個結構成員添加 FieldOffset 屬性。當您需要創建 union 時,通常需要這樣做。

CharSet

控制 ByValTStr 成員的默認字符類型。

Pack

設置結構的壓縮大小。它控制結構的排列方式。如果 C 結構采用了其他壓縮方式,您可能需要設置此屬性。

Size

設置結構大小。不常用;但是如果需要在結構末尾分配額外的空間,則可能會用到此屬性。

從不同位置加載

您無法指定希望 DLLImport 在運行時從何處查找文件,但是可以利用一個技巧來達到這一目的。

DllImport 調用 LoadLibrary() 來完成它的工作。如果進程中已經加載了特定的 DLL,那么即使指定的加載路徑不同,LoadLibrary() 也會成功。

這意味著如果直接調用 LoadLibrary(),您就可以從任何位置加載 DLL,然后 DllImport LoadLibrary() 將使用該 DLL。

由于這種行為,我們可以提前調用 LoadLibrary(),從而將您的調用指向其他 DLL。如果您在編寫庫,可以通過調用 GetModuleHandle() 來防止出現這種情況,以確保在首次調用 P/Invoke 之前沒有加載該庫。

P/Invoke 疑難解答

如果您的 P/Invoke 調用失敗,通常是因為某些類型的定義不正確。以下是幾個常見問題:

  • long != long。在 C++ 中,long 是 4 字節的整數,但在 C# 中,它是 8 字節的整數。
  • 字符串類型設置不正確。

轉載于:https://www.cnblogs.com/kevinGao/archive/2011/11/09/2243452.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/387531.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/387531.shtml
英文地址,請注明出處:http://en.pswp.cn/news/387531.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

unity3d 預制體

首先要說明一下什么是預制體? 在Unity3D里面我們叫它Prefab;我們也可以這樣理解:當制作好了游戲組件(場景中的任意一個gameobject ),我們希望將它制作成一個組件模版,用于批量的套用工作,例如說…

Python小數據池,代碼塊

今日內容一些小的干貨 一. id is 二. 代碼塊三. 小數據池四. 總結python小數據池,代碼塊的最詳細、深入剖析 一. id is 二. 代碼塊三. 小數據池四. 總結一,id,is, 在Python中,id是什么?id是內存地址…

【Wax】使用Wax (framework方式,XCode 4.6)

前情提示:【Wax】使用Wax (非framework方式,XCode 4.6) 這次,將以framework的方式來使用Wax 那么,讓我們開始吧!!! 準備工作: 下載wax.framework:…

unity3d 簡單動畫

1,動畫系統配置 創建游戲對象并添加Animation組件,然后將動畫文件拖入組件。 進入動畫文件的Debug屬性面板 選中Legacy屬性 選中游戲對象,打開Animation編輯窗口 添加動畫變化屬性 需改關鍵幀的屬性值 配置完成后運行即可得到動畫效果 2&…

人月神話閱讀筆記(二)

今天對人月神話的正文部分進行了閱讀,從人月神話這一部分中了解到缺乏合理的時間進度控制是造成滯后的主要原因,比其他任何事情影響的和還大,書中也對造成這種這種普遍災難的原因進行了并進行了詳細列舉。 首先,我們對估算技術缺乏…

3dmax導出到unity3d下分割動畫

1、在3dmax 導出時候,要導出FBX文件,同時包含動畫,骨骼,皮膚等內容 2、把FBX文件導入到Unity3d后會默認有一個超長的大動畫,就是一個整體的動畫,如圖Take001,這個時候要分割哪部分是跑&#xf…

華碩首款平板電腦周五開售

新浪科技訊北京時間3月21日晚間消息,華碩周一宣布,將于本周開售首款平板電腦EeePadTransformer。本周五,臺灣地區用戶將可以率先預定這款平板電腦,隨后還將在全球其他國家和地區推出,悠語yoryu化妝品玻尿酸水潤彈力面膜120ml補水保…

(2)頁面標簽解析

<!--規定文檔類型的指令&#xff1a;html,以h5的語法來書寫html文件--><!DOCTYPE html><!--頁面根標簽&#xff0c;什么是根標簽&#xff0c;就是一個頁面空間可以理解成全局&#xff0c;所有內容都在這個頁面空間內--><!--langen就是定義頁面的默認語言&…

Unity3d之AssetBundle打包與讀取

一、創建Assetbundle 在unity3d開發的游戲中&#xff0c;無論模型&#xff0c;音頻&#xff0c;還是圖片等&#xff0c;我們都做成Prefab&#xff0c;然后打包成Assetbundle&#xff0c;方便我們后面的使用&#xff0c;來達到資源的更新。 一個Assetbundle可以打包一個模型&…

Android代碼抄襲Java曝猛料 新證據出現

Oracle最初告Android代碼里侵犯了他們旗下Java知識產權的時候,大多數不明真相的圍觀群眾都是站在Google這一邊的,畢竟Oracle蠻橫不講理慣了嘛. 但是,這次我們還真是當了不明真相的圍觀群眾了,美國專利博 ... Oracle最初告Android代碼里侵犯了他們旗下Java知識產權的時候,大多數…

JS之數據類型v(** v**)v個人筆記

<body> <!-- 單詞記憶 argument&#xff1a;實參 assignment&#xff1a;賦值 instance&#xff1a;實例 1.JS中的數據類型分為以下類型 *值類型&#xff08;基本類型&#xff09;*String&#xff1a;可以為任何字符串*Number&#xff1a;可以為任何數字*boolean&…

unity3d 各個目錄的意思

1.首先&#xff0c;你得理解Unity中各個目錄的意思&#xff1f; 我這里說的是移動平臺&#xff08;安卓舉例&#xff09;&#xff0c;讀&#xff0c;寫。所謂讀&#xff0c;就是你出大版本的包之后&#xff0c;這個只讀的話&#xff0c;就一輩子就這些東西了&#xff0c;不會改…

WordPress Option API(數據庫儲存 API)

WordPress Option API 是提供給開發者的數據庫存儲機制&#xff0c;通過調用函數&#xff0c;可以快速、安全的把數據存儲到數據庫里&#xff08;都在 wp_options 表&#xff09;。 每個設置的模式是 key – value&#xff0c;利于擴展。Option API 不僅僅給主題和插件開發者用…

asp.net core根據用戶權限控制頁面元素的顯示

asp.net core根據用戶權限控制頁面元素的顯示 Intro 在 web 應用中我們經常需要根據用戶的不同允許用戶訪問不同的資源&#xff0c;顯示不同的內容&#xff0c;之前做了一個 AccessControlHelper 的項目&#xff0c;就是解決這個問題的。 asp.net core 支持 TagHelper 和 基于 …

Please let us know in case of any issues

Please let us know in case of any issues轉載于:https://www.cnblogs.com/zhangchenliang/archive/2010/05/18/1738117.html

Java面向對象(二)

source:http://blog.java1234.com/index.html?typeId1 Java類的繼承 1&#xff0c;繼承定義以及基本使用 定義&#xff1a;子類能夠繼承父類的屬性和方法&#xff1b; 注意點&#xff1a;Java中只支持單繼承&#xff1b; 私有方法不能繼承&#xff1b; 2&#xff0c;方法重寫 …

游戲通訊方式

農藥自從上線以來&#xff0c;依靠著強大的產品力以及騰訊的運營能力&#xff0c;在游戲市場上表現可謂是風生水起&#xff0c;根據第三方的調研數據顯示&#xff0c;《王者榮耀》滲透率達到22.3%&#xff0c;用戶規模達到2.01億人&#xff0c;每日的日活躍用戶&#xff08;DAU…

小小c#算法題 - 3 - 字符串語句反轉

題目&#xff1a;反轉語句。 如I love Beijing! 反轉后輸出 !Beijing love I 特點是指反轉單詞的順序&#xff0c;其他字符&#xff08;這個可以自己指定&#xff09;不反轉。且不能用內置函數&#xff0c;如Split和Substring。 分析&#xff1a;我們需要保證一個單詞的字…

unity5.4.3p2里面的AssetBundle打包流程

unity5.4.3p2里面的AssetBundle打包流程&#xff0c;相比之前unity4.x的打包簡單了許多&#xff0c;Unity4.X中打包的時候需要自己去管理依賴關系&#xff0c;各種BuildPipeline.PushAssetDependencies()和BuildPipeline.PopAssetDependencies()&#xff0c;一不小心手一抖&…

靜態查找表的實現

#ifndef SSTABLE_H #define SSTABLE_H#include <iostream> using namespace std;/************************************************************* SSTable&#xff1a;stastic search table 靜態查找表的模板類實現 順序存儲結構 ************************************…