上一篇《Silverlight5通過P/Invoke調用系統win32的三個示例》展示了silverlight5通過P/Invoke調用系統win32的三個示例,本篇給出自定義win32 dll及其在Silverlight5中調用的代碼。
注1:為了確保silverilght5在瀏覽器或桌面上成功調用win32 DLL,必須在項目屬性中勾選相應的權限:
勾選Enable running application out of the browser及其Require elevated trust when running in-browser
勾選Require elevated trust when running in-browser
注2:win32 dll文件編譯后放在\windows\system32或\windows\system目錄下,win7 x64的系統放在后者。
注3:winform/wpf中調用類似
.h
// The following ifdef block is the standard way of creating macros which make exporting // from a DLL simpler. All files within this DLL are compiled with the MYDLL_EXPORTS // symbol defined on the command line. This symbol should not be defined on any project // that uses this DLL. This way any other project whose source files include this file see // MYDLL_API functions as being imported from a DLL, whereas this DLL sees symbols // defined with this macro as being exported. #ifdef MYDLL_EXPORTS #define MYDLL_API __declspec(dllexport) #else #define MYDLL_API __declspec(dllimport) #endif
struct HHFC_SET
{
;char* UID;
int code;
};
// This class is exported from the MyDLL.dll class MYDLL_API CMyDLL { public: CMyDLL(void); // TODO: add your methods here. }; //extern MYDLL_API int nMyDLL; extern "C" MYDLL_API int nMyDLL; extern "C" MYDLL_API float fnMyDLL(float x ,float y);// 注意得加上extern "C",否則無法P/Invoke
.cpp
#include "stdafx.h" #include "MyDLL.h"
#include <iostream>
#include "LuaPlus.h"
#include "LuaPlusHelper.h"
#pragma comment(lib,"LuaPlusLib.lib")
using namespace LuaPlus;
using namespace std;
// This is an example of an exported variable MYDLL_API int nMyDLL=0; // This is an example of an exported function. MYDLL_API float fnMyDLL(float x ,float y) { //調用Lua腳本並計算 string str; str.append("function Add(x, y)\n"); str.append(" return x*y;\n"); str.append("end\n"); int iret = state->DoString(str.c_str());// state->DoFile("a.lua"); LuaFunction Add = state->GetGlobal("Add"); float myret = Add(x,y); return myret; } extern "C" __declspec(dllexport) int WINAPI add() { return 101; }
extern "C" __declspec(dllexport) int WINAPI add2(HHFC_SET* stru )
{
stru->UID="this is a win32 test about struct";
stru->code=3;
return 1;
}
extern "C" __declspec(dllexport) float* WINAPI add3()
{
float* num=(float*)malloc(4);
num[0]=11.2f;
num[1]=21.3f;
num[2]=33.5f;
num[3]=46.2f;
return num;
}
// This is the constructor of a class that has been exported. // see MyDLL.h for the class definition CMyDLL::CMyDLL() { return; }
.xaml
<Grid x:Name="LayoutRoot" Background="White"> <StackPanel Orientation="Horizontal" VerticalAlignment="Top" Margin="24,24,0,0"> <TextBlock Name="textBlock1" Text="add 函數結果:" Height="23" /> <TextBox Name="textBox1" Width="120" Height="23" /> </StackPanel> <StackPanel Orientation="Horizontal" VerticalAlignment="Top" Margin="24,64,0,0"> <TextBlock Name="textBlock2" Text="fnMyDLL函數結果:" Height="23"/> <TextBox Name="textBox2" VerticalAlignment="Top" Width="120" Height="23"/> </StackPanel> <Button Content="Button" Height="32" Margin="120,101,202,0" Name="button1" VerticalAlignment="Top" Width="78" Click="button1_Click" /> </Grid>
.cs
public partial class MainPage : UserControl { [DllImportAttribute("user32.dll", EntryPoint = "MessageBoxW")] public static extern int MessageBoxW(int hWnd, [In][MarshalAs(UnmanagedType.LPWStr)] string lpText, [In][MarshalAs(UnmanagedType.LPWStr)] string lpCaption, int uType); [DllImport("MyDll.dll", EntryPoint = "add", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = false)] public static extern int add(); [DllImport("MyDll.dll", EntryPoint = "fnMyDLL", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi, SetLastError = false)] public static extern float fnMyDLL(float x,float y); [DllImport("MyDLL.dll", EntryPoint = "add2", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi, SetLastError = false)] public static extern int add2(ref HHFC_SET stru);
[DllImport("MYDLL.dll", EntryPoint = "add3", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi, SetLastError = false)]
public static extern IntPtr add3();
//EntryPoint: 指定要調用的 DLL 入口點。默認入口點名稱是托管方法的名稱 。 //CharSet: 控制名稱重整和封送 String 參數的方式 (默認是UNICODE) //CallingConvention指示入口點的函數調用約定(默認WINAPI) //SetLastError 指示被調用方在從屬性化方法返回之前是否調用 SetLastError Win32 API 函數 (C#中默認false ) public MainPage() { InitializeComponent(); } private void button1_Click(object sender, RoutedEventArgs e) { this.textBox1.Text = add().ToString(); this.textBox2.Text = fnMyDLL(12,2).ToString(); MessageBoxW(0, "提交成功", "溫馨提示", 0);
HHFC_SET stru = new HHFC_SET();
stru.Uid = "";
Console.WriteLine(stru.Uid);
int a = add2(ref stru);
Console.WriteLine(stru.Uid);
IntPtr d = add3();
float[] bytes2 = new float[Marshal.SizeOf(d)];
Marshal.Copy(d, bytes2, 0, 4);
}
}
[StructLayout(LayoutKind.Sequential)]
public struct HHFC_SET
{
[MarshalAs(UnmanagedType.LPStr)]
public String Uid;
[MarshalAs(UnmanagedType.I4)]
public int code;
}
-----------------------------------------------------------------------------------------
.net調用C DLL
編寫C程序如下:
#include "stdio.h"
__declspec(dllexport) void MyFun() { printf("this is a dll\n"); }
保存,取名為My.C
運行 VS 命令提示,Cl /c 路徑/My.c
運行以后會生成 My.Obj,默認在vs安裝文件夾的VC目錄下
再運行 link/dll 路徑/My.obj
在同一個目錄會生成My.dll
在C#中調用:
將dll復制到bin目錄,編寫如下C#代碼:
static void Main(string[] args)
{
MyFun();
}
[DllImport("My.dll")]
public extern static void MyFun();
-----------------------------------------------------------------------------------------
C#傳委托給C的函數指針調用問題
C代碼如下:
#include "stdio.h" __declspec(dllexport) int Call(int (*qq)(int num),char * str) { printf(str); return qq(123); }
多次驗證發現在C#中傳委托給C中的函數指針,如果委托不帶參數則都能成功運行,但是委托一帶參數不管是int參數還是string參數或者其他參數,都會報“ 嘗試讀取或寫入受保護的內存。這通常指示其他內存已損壞”的錯誤,找了一天才找到解決方法,既在C#的委托聲明上加[UnmanagedFunctionPointer(CallingConvention.Cdecl)],正確調用如下:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int MyDeg(int num); class Program { static void Main(string[] args) { try { MyDeg myd = new MyDeg(FF); Console.WriteLine(Call(myd, "helloworld")); } catch (Exception ex) { Console.WriteLine(ex.Message); } } static int FF(int num) { Console.WriteLine(num); return num + 1; } [DllImport("my.dll", EntryPoint = "Call")] public extern static int Call(MyDeg mm ,string str); }