歡迎來到人人文庫網! | 幫助中心 人人文檔renrendoc.com美如初戀!
人人文庫網

創(chuàng)建Win32 DLL--并在C#里面調用

這是三篇網上收集的技術文章的合集,分別講解了如何創(chuàng)建Win32 DLL,然后如何在C#里面調用這個DLL的教程。

首先是創(chuàng)建Win32 DLL的文章。講解這個的文章到處都有,這里給出一篇我看過的:http://www.flipcode.com/articles/article_creatingdlls.shtml。Win32 DLL的創(chuàng)建其實在Visual Studio里面已經給出了比較好的模板,只是需要注意的,有些XXX_API宏并沒有把extern "C"加進去,這樣會造成在C#里面找不到這個函數(shù)的錯誤。所以,請記住,一定要把函數(shù)定義extern "C"。




第二篇文章來之于http://edu.100down.com/it/program/Csharp/105256797.html,下面是轉貼內容:

平臺調用服務 (PInvoke) 允許托管代碼調用在 DLL 中實現(xiàn)的非托管函數(shù)。

本教程說明使用什么方法才能從 C# 調用非托管 DLL 函數(shù)。該教程所討論的屬性允許您調用這些函數(shù)并使數(shù)據(jù)類型得到正確封送。

教程

C# 代碼有以下兩種可以直接調用非托管代碼的方法:

  • 直接調用從 DLL 導出的函數(shù)。

  • 調用 COM 對象上的接口方法(有關更多信息,請參見 COM Interop 第一部分:C# 客戶端教程)。

對于這兩種技術,都必須向 C# 編譯器提供非托管函數(shù)的聲明,并且還可能需要向 C# 編譯器提供如何封送與非托管代碼之間傳遞的參數(shù)和返回值的說明。

該教程由下列主題組成:

  • 直接從 C# 調用 DLL 導出

  • 默認封送處理和為非托管方法的參數(shù)指定自定義封送處理

  • 為用戶定義的結構指定自定義封送處理

  • 注冊回調方法

該教程包括下列示例:

  • 示例 1 使用 DllImport

  • 示例 2 重寫默認封送處理

  • 示例 3 指定自定義封送處理

直接從 C# 調用 DLL 導出

若要聲明一個方法使其具有來自 DLL 導出的實現(xiàn),請執(zhí)行下列操作:

  • 使用 C# 關鍵字 static 和 extern 聲明方法。

  • 將 DllImport 屬性附加到該方法。DllImport 屬性允許您指定包含該方法的 DLL 的名稱。通常的做法是用與導出的方法相同的名稱命名 C# 方法,但也可以對 C# 方法使用不同的名稱。

  • 還可以為方法的參數(shù)和返回值指定自定義封送處理信息,這將重寫 .NET Framework 的默認封送處理。

示例 1

本示例顯示如何使用 DllImport 屬性通過調用 msvcrt.dll 中的 puts 輸出消息。

// PInvokeTest.cs
using System;
using System.Runtime.InteropServices;

class PlatformInvokeTest
{
    [DllImport("msvcrt.dll")]
    public static extern int puts(string c);
    [DllImport("msvcrt.dll")]
    internal static extern int _flushall();

    public static void Main() 
    {
        puts("Test");
        _flushall();
    }
}

輸出

Test

代碼討論

前面的示例顯示了聲明在非托管 DLL 中實現(xiàn)的 C# 方法的最低要求。PlatformInvokeTest.puts 方法用 static 和 extern 修飾符聲明并且具有 DllImport 屬性,該屬性使用默認名稱 puts 通知編譯器此實現(xiàn)來自msvcrt.dll。若要對 C# 方法使用不同的名稱(如 putstring),則必須在 DllImport 屬性中使用 EntryPoint 選項,如下所示:

[DllImport("msvcrt.dll", EntryPoint="puts")]

有關 DllImport 屬性的語法的更多信息,請參見 DllImportAttribute 類。

默認封送處理和為非托管方法的參數(shù)指定自定義封送處理

當從 C# 代碼中調用非托管函數(shù)時,公共語言運行庫必須封送參數(shù)和返回值。

對于每個 .NET Framework 類型均有一個默認非托管類型,公共語言運行庫將使用此非托管類型在托管到非托管的函數(shù)調用中封送數(shù)據(jù)。例如,C# 字符串值的默認封送處理是封送為 LPTSTR(指向 TCHAR 字符緩沖區(qū)的指針)類型。可以在非托管函數(shù)的 C# 聲明中使用 MarshalAs 屬性重寫默認封送處理。

示例 2

本示例使用 DllImport 屬性輸出一個字符串。它還顯示如何通過使用 MarshalAs 屬性重寫函數(shù)參數(shù)的默認封送處理。

// Marshal.cs
using System;
using System.Runtime.InteropServices;

class PlatformInvokeTest
{
    [DllImport("msvcrt.dll")]
    public static extern int puts(
        [MarshalAs(UnmanagedType.LPStr)]
        string m);
    [DllImport("msvcrt.dll")]
    internal static extern int _flushall();


    public static void Main() 
    {
        puts("Hello World!");
        _flushall();
    }
}

輸出

運行此示例時,字符串

Hello World!

將顯示在控制臺上。

代碼討論

在前面的示例中,puts 函數(shù)的參數(shù)的默認封送處理已從默認值 LPTSTR 重寫為 LPSTR。

MarshalAs 屬性可以放置在方法參數(shù)、方法返回值以及結構和類的字段上。若要設置方法返回值的封送處理,請將 MarshalAs 屬性與返回屬性位置重寫一起放置在方法上的屬性塊中。例如,若要顯式設置puts 方法返回值的封送處理:

...
[DllImport("msvcrt.dll")] 
[return : MarshalAs(UnmanagedType.I4)]
public static extern int puts( 
...

有關 MarshalAs 屬性的語法的更多信息,請參見 MarshalAsAttribute 類。

注意   In 和 Out 屬性可用于批注非托管方法的參數(shù)。它們與 MIDL 源文件中的 in 和 out 修飾符的工作方式類似。請注意,Out 屬性與 C# 參數(shù)修飾符 out 不同。有關 In 和 Out 屬性的更多信息,請參見 InAttribute 類和 OutAttribute 類。

為用戶定義的結構指定自定義封送處理

可以為傳遞到非托管函數(shù)或從非托管函數(shù)返回的結構和類的字段指定自定義封送處理屬性。通過向結構或類的字段中添加 MarshalAs 屬性可以做到這一點。還必須使用 StructLayout 屬性設置結構的布局,還可以控制字符串成員的默認封送處理,并設置默認封裝大小。

示例 3

本示例說明如何為結構指定自定義封送處理屬性。

請考慮下面的 C 結構:

typedef struct tagLOGFONT 
{ 
   LONG lfHeight; 
   LONG lfWidth; 
   LONG lfEscapement; 
   LONG lfOrientation; 
   LONG lfWeight; 
   BYTE lfItalic; 
   BYTE lfUnderline; 
   BYTE lfStrikeOut; 
   BYTE lfCharSet; 
   BYTE lfOutPrecision; 
   BYTE lfClipPrecision; 
   BYTE lfQuality; 
   BYTE lfPitchAndFamily; 
   TCHAR lfFaceName[LF_FACESIZE]; 
} LOGFONT;

在 C# 中,可以使用 StructLayout 和 MarshalAs 屬性描述前面的結構,如下所示:

// logfont.cs
// compile with: /target:module
using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]
public class LOGFONT 
{ 
    public const int LF_FACESIZE = 32;
    public int lfHeight; 
    public int lfWidth; 
    public int lfEscapement; 
    public int lfOrientation; 
    public int lfWeight; 
    public byte lfItalic; 
    public byte lfUnderline; 
    public byte lfStrikeOut; 
    public byte lfCharSet; 
    public byte lfOutPrecision; 
    public byte lfClipPrecision; 
    public byte lfQuality; 
    public byte lfPitchAndFamily;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=LF_FACESIZE)]
    public string lfFaceName; 
}

有關 StructLayout 屬性的語法的更多信息,請參見 StructLayoutAttribute 類。

然后即可將該結構用在 C# 代碼中,如下所示:

// pinvoke.cs
// compile with: /addmodule:logfont.netmodule
using System;
using System.Runtime.InteropServices;
 
class PlatformInvokeTest
{   
      [DllImport("gdi32.dll", CharSet=CharSet.Auto)]
      public static extern IntPtr CreateFontIndirect(
            [In, MarshalAs(UnmanagedType.LPStruct)]
            LOGFONT lplf   // characteristics
            );
 
      [DllImport("gdi32.dll")]
      public static extern bool DeleteObject(
            IntPtr handle
            );
 
      public static void Main() 
      {
            LOGFONT lf = new LOGFONT();
            lf.lfHeight = 9;
            lf.lfFaceName = "Arial";
            IntPtr handle = CreateFontIndirect(lf);
 
            if (IntPtr.Zero == handle)
            {
                  Console.WriteLine("Can't creates a logical font.");
            }
            else
            {
                  
                  if (IntPtr.Size == 4)
                        Console.WriteLine("{0:X}", handle.ToInt32());
                  else
                        Console.WriteLine("{0:X}", handle.ToInt64());         

                  // Delete the logical font created.
                  if (!DeleteObject(handle))
                       Console.WriteLine("Can't delete the logical font");
            }
      }
}

運行示例

C30A0AE5

代碼討論

在前面的示例中,CreateFontIndirect 方法使用了一個 LOGFONT 類型的參數(shù)。MarshalAs 和 In 屬性用于限定此參數(shù)。程序將由此方法返回的數(shù)值顯示為十六進制大寫字符串。

注冊回調方法

若要注冊調用非托管函數(shù)的托管回調,請用相同的參數(shù)列表聲明一個委托并通過 PInvoke 傳遞它的一個實例。在非托管端,它將顯示為一個函數(shù)指針。有關 PInvoke 和回調的更多信息,請參見平臺調用詳解。

例如,考慮以下非托管函數(shù) MyFunction,此函數(shù)要求 callback 作為其參數(shù)之一:

typedef void (__stdcall *PFN_MYCALLBACK)();
int __stdcall MyFunction(PFN_ MYCALLBACK callback);

若要從托管代碼調用 MyFunction,請聲明該委托,將 DllImport 附加到函數(shù)聲明,并根據(jù)需要封送任何參數(shù)或返回值:

public delegate void MyCallback();
[DllImport("MYDLL.DLL")]
public static extern void MyFunction(MyCallback callback);

同時,請確保委托實例的生存期覆蓋非托管代碼的生存期;否則,委托在經過垃圾回收后將不再可用。




 第三篇文章來之于http://www.njpro.cn/8918/ShowPost.aspx,一篇關于C/C++和C#中的數(shù)據(jù)類型的對應表。


Wtypes.h 中的非托管類型非托管 C 語言類型托管類名說明
HANDLEvoid*System.IntPtr32 位
BYTEunsigned charSystem.Byte8 位
SHORTshortSystem.Int1616 位
WORDunsigned shortSystem.UInt1616 位
INTintSystem.Int3232 位
UINTunsigned intSystem.UInt3232 位
LONGlongSystem.Int3232 位
BOOLlongSystem.Int3232 位
DWORDunsigned longSystem.UInt3232 位
ULONGunsigned longSystem.UInt3232 位
CHARcharSystem.Char用 ANSI 修飾。
LPSTRchar*System.String 或System.StringBuilder用 ANSI 修飾。
LPCSTRConst char*System.String 或System.StringBuilder用 ANSI 修飾。
LPWSTRwchar_t*System.String 或System.StringBuilder用 Unicode 修飾。
LPCWSTRConst wchar_t*System.String 或System.StringBuilder用 Unicode 修飾。
FLOATFloatSystem.Single32 位
DOUBLEDoubleSystem.Double64 位


關于我們 - 網站聲明 - 網站地圖 - 資源地圖 - 友情鏈接 - 網站客服 - 聯(lián)系我們

網站客服QQ:2881952447     

copyright@ 2020-2024  renrendoc.com 人人文庫版權所有   聯(lián)系電話:400-852-1180

備案號:蜀ICP備2022000484號-2       經營許可證: 川B2-20220663       公網安備川公網安備: 51019002004831號

本站為文檔C2C交易模式,即用戶上傳的文檔直接被用戶下載,本站只是中間服務平臺,本站所有文檔下載所得的收益歸上傳人(含作者)所有。人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對上載內容本身不做任何修改或編輯。若文檔所含內容侵犯了您的版權或隱私,請立即通知人人文庫網,我們立即給予刪除!