在一个QQ群里,有人在问如何“在C# 中调用非托管DLL”。
俺脑子抽抽了一下,就回了一句“你喜欢用那种声明方式,就用那种方式去调用。”
然后就有人说:“参数声明要和DLL的声明完全一致”。
俺脑子又抽抽了一下,又回了一句“可以不一致,反正就是两种 一种是byref 一种是byval。注意一些,这个就OK”。
然后就被怼了。俺就写了一个例子,用三种不同的声明方式进行演示,发在了群里。然后俺就被 踢出群了。
下面的代码中:
第一种声明方式 : private static extern uint GetWindowsDirectoryA(StringBuilder lpBuffer, uint uSize ) ; 这种方式用的比较多,也是 大家推荐的一种写法。
第二种声明方式: private static extern uint GetWindowsDirectoryA_ref( ref byte lpBuffer, uint uSize); 这个其实就个bug。但是它确实可以得到正确的结果。虽然参数声明中 的 ref byte lpBuffer 是错误的,但是这不妨碍执行结果的正确。
第三种方式:private static extern uint GetWindowsDirectoryA_IntPtr(IntPtr lpBuffer, uint uSize);这种方式比较原始,但是俺喜欢这种方式。如果一定要给个理由的话,那就是情怀。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
//function GetWindowsDirectoryA(lpBuffer: PAnsiChar; uSize: UINT): UINT; stdcall;
//
[DllImport("kernel32.dll", EntryPoint = "GetWindowsDirectoryA", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall) ]
private static extern uint GetWindowsDirectoryA(StringBuilder lpBuffer, uint uSize ) ;
private void button1_Click(object sender, EventArgs e)
{
StringBuilder sb = new StringBuilder();
GetWindowsDirectoryA(sb, 255);
MessageBox.Show(sb.ToString());
}
//
[DllImport("kernel32.dll", EntryPoint = "GetWindowsDirectoryA", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
private static extern uint GetWindowsDirectoryA_ref( ref byte lpBuffer, uint uSize);
private void button2_Click(object sender, EventArgs e)
{
byte[] lpBuffer = new byte[255];
uint c= GetWindowsDirectoryA_ref(ref lpBuffer[0], (uint)lpBuffer.Length);
MessageBox.Show(Encoding.GetEncoding("gb2312").GetString(lpBuffer, 0, (int)c));
//此方法不稳定
}
//
[DllImport("kernel32.dll", EntryPoint = "GetWindowsDirectoryA", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
private static extern uint GetWindowsDirectoryA_IntPtr(IntPtr lpBuffer, uint uSize);
private void button3_Click(object sender, EventArgs e)
{
IntPtr ptr = Marshal.AllocHGlobal(255);
uint c = GetWindowsDirectoryA_IntPtr(ptr,255);
byte[] lpBuffer = new byte[c];
Marshal.Copy(ptr, lpBuffer,0,(int)c);
MessageBox.Show(Encoding.GetEncoding("gb2312").GetString(lpBuffer, 0, (int)c));
Marshal.FreeHGlobal(ptr);
}
}