PInvoke
来源:互联网 发布:cf一键领取软件 编辑:程序博客网 时间:2024/04/28 13:54
PInvoke
If you want to call one of the many Win32 API functions that are not available directly from the .NET framework, you should be able to call them using PInvoke (Platform Invoke). (PInvoke is not supported with classes. To call an interface method in a COM dll use COM Interop.) There are excellent tutorials on the Microsoft Developers Network on using PInvoke, so I will not belabor this technique. Here is a snippet of code that plays a sound from Eric Gunnerson's tutorial Using Win32 and Other Libraries. The class WrapK32 encapsulates or hides the call to InteropServices. To the user of the Wrap32 class, the Beep function appears as managed code.
using System;using System.Runtime.InteropServices;
namespace TestPInvoke{/// <summary>/// Summary description for Class1./// </summary>class WrapK32{[DllImport("kernel32.dll")]public static extern bool Beep(int frequency, int duration);/// <summary>/// The main entry point for the application./// </summary>[STAThread]static void Main(string[] args){//// TODO: Add code to start application here//Random random = new Random();
for (int i = 0; i < 10000; i++){Beep(random.Next(10000), 100);}}}}
To invoke the Beep Win32 function, you declare the C# prototype as public static extern as in:
public static extern bool Beep(int frequency, int duration);
The Beep function is in the kernal32 dll so you tell the runtime using the DllImport attribute directive.
[DllImport("kernel32.dll")]public static extern bool Beep(int frequency, int duration);
String Stuff
Strings are confusing. Under Win9x, strings are ANSI single byte (8 bit) or double byte (8 _or_ 16 bit aka multi-byte) characters. Under NT, W2K and WXP, strings are 16 bit WIDE characters (Unicode). The LPTSTR type is both! It acts as ANSI on Win9x and as WIDE on WinNT. COM uses BSTR which is just a typedef to a WIDE string:
typedef wchar_t *BSTR;
However, a BSTR must adhere to a very specific set of rules that differs from a LPWSTR:
typedef wchar_t *LPWSTR;
The default marshaling type for strings in PInvoke is LPTSTR. This differs from COM Interop where the default marshaling type for strings is BSTR. If the actual parameter type differs from the PInvoke default then you will need to use the MarshalAs attribute in the function prototype declaration. For instance, it is an error to pass an immutable C# String as an out parameter. Instead, you will need to pass a StringBuffer and use the MarshalAs attribute. Here again is a sample from Eric Gunnerson's tutorial:
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]public static extern int GetShortPathName( [MarshalAs(UnmanagedType.LPTStr)] string path, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder shortPath, int shortPathLength);
The CharSet= CharSet.Auto attribute is used to tell the CLR to automatically use the type of string supported by the OS, which is either ANSI or WCHAR (Unicode). If you do not declare the CharSet, the default is CharSet.Ansi which could cause performance problems under Win NT. You should declare CharSet as Auto unless the Win32 API call exist only as ANSI or WCHAR.
Calling Convention
The default calling convention is CallingConvention.StdCall which puts the function's last parameter on the stack first and the callee cleans the stack. You may need to set the CallingConvention to CallingConvention.Cdecl if the caller cleans the stack (Cdecl supports a variable number of arguments in a function, but C# does not support VARARG). The enum CallingConvention.Winapi automates the calling convention to StdCall on Windows and Cdecl on Windows CE .NET.
Creating and Calling a C++ Win32 DLL
You can create your own C++ Win32 dll using the Visual Studio Project Wizard. If you tell the wizard to create a dll and export the dll functions, you can see the exported functions using the DUMPBIN tool (You may need to modify the system path to include the dumpbin.exe and mspdb71.dll). Once you have the path set up correctly, run DUMPBIN with the /EXPORTS option. For example, if you use Visual Studio 2003 to create a C++ Win32 dll project named Win32Test and choose to export your functions, the wizard will create a sample exported function
int fnWin32Test(){return 42;}
Change the return type to long and then look at the exported function using dumpbin.
>dumpbin /exports Win32Test.dll
This outputs the exported fnWin32Test function as "?fnWin32Test@@3HA". To look at the undecorated name use the undname tool as in:
>undname ?fnWin32Test@@3HA
This converts the decorated name to "long fnWin32Test".
It may be easier to use the undecorated name when calling from C#. You can do this by exporting the function using "C" linkage in your Win32 dll using the syntax:
extern "C" long declspect(dllexport)fnWin32Test() {...}
or
#ifdef WIN32TEST_EXPORTS#define WIN32TEST_API __declspec(dllexport)#else#define WIN32TEST_API __declspec(dllimport)#endif
extern "C" WIN32TEST_API long fnWin32Test();
You can now call this function from C# as:
class Class1{[DllImport("Win32Test.dll")]public static extern int fnWin32Test();/// <summary>/// The main entry point for the application./// </summary>[STAThread]static void Main(string[] args){//// TODO: Add code to start application here//System.Console.WriteLine(fnWin32Test());System.Console.ReadLine();}}
Output: 42.
Note: The C++ return type long has been mapped to the C# type int.
Using the EntryPoint DllImportAttribute
You can rename an unmanaged dll function call from within C# using the EntryPoint attribute. To call a function using its fully decorated name "?fnWin32Test2@@YAJXZ" as "Win32Test2" you can specify the static entry point as "?fnWin32Test2@@YAJXY":
[DllImport("Win32Test.dll", EntryPoint= "?fnWin32Test2@@YAJXZ")]
public static extern int fnWin32Test2();And call it as:
System.Console.WriteLine(fnWin32Test2());
- PInvoke
- PInvoke
- PInvoke 白话文
- PInvoke In C# -- Preparing
- .net gotachas,pinvoke
- Pinvoke with const char *
- Win32 API PInvoke
- GetSecurityInfo DACL pinvoke advapi32
- Reflector、PInvoke.NET、XP&ADHelper
- PInvoke.NET Visual Studio 插件
- 关于PInvoke 和COM Interop
- PInvoke调用导致堆栈不对称
- PInvoke调用导致堆栈不对称
- .Net互操作之PInvoke
- PInvoke调用导致堆栈不对称
- PINVOKE.NET: Do interop the wiki way!
- PINVOKE.NET: Do interop the wiki way!
- 无法找到 PInvoke DLL“sqlceme35.dll”
- 今天又是一个全新的开始...
- WinCE下对数据库的操作
- 首次使用
- [转] 香港流行乐坛三十年
- 分享经验,让更多的人受益
- PInvoke
- 软件开发的隐喻
- Consuming Unmanaged C++ Class Libraries from .NET Clients
- 多表相连时求出正确的COUNT
- 人活着是为什么啊?
- 刚注册CSDN一个多星期,等级已经三角了
- 我们自杀吧!(贴图)_8:卧轨
- (转)FTP的协议命令字和标准FTP信息
- WinCE下隐藏系统任务栏的方法