[DllImport("user32.dll", EntryPoint="MessageBoxA")]
static extern int MsgBox(int hWnd, string msg, string caption, int type);
|
MsgBox(0," 這就是用 DllImport 調用 DLL 彈出的提示框哦! "," 挑戰杯 ",0x30); |
// 導出函數,使用「 _stdcall 」 標準調用
extern "C" _declspec(dllexport)int _stdcall count(int init);
|
int _stdcall count(int init)
{//count 函數,使用參數 init 初始化靜態的整形變量 S ,並使 S 自加 1 後返回該值
static int S=init;
S++;
return S;
}
|
[DllImport("Count.dll")]
static extern int count(int init);
|
MessageBox.Show(" 用 DllImport 調用 DLL 中的 count 函數, \n 傳入的實參爲 0 ,獲得的結果是: "+count(0).ToString()," 挑戰杯 ");
MessageBox.Show(" 用 DllImport 調用 DLL 中的 count 函數, \n 傳入的實參爲 10 ,獲得的結果是: "+count(10).ToString()+"\n 結果可不是想要的 11 哦!!! "," 挑戰杯 ");
MessageBox.Show(" 所得結果代表: \n 用 DllImport 調用 DLL 中的非託管 \n 函數是全局的、靜態的函數!!! "," 挑戰杯 ");
|
using System.Runtime.InteropServices; // 用 DllImport 需用此 命名空間
using System.Reflection; // 使用 Assembly 類需用此 命名空間
using System.Reflection.Emit; // 使用 ILGenerator 需用此 命名空間
|
/// <summary>
/// 參數傳遞方式枚舉 ,ByValue 表示值傳遞 ,ByRef 表示址傳遞
/// </summary>
public enum ModePass
{
ByValue = 0x0001,
ByRef = 0x0002
}
|
/// <summary>
/// 原型是 :HMODULE LoadLibrary(LPCTSTR lpFileName);
/// </summary>
/// <param name="lpFileName">DLL 文件名 </param>
/// <returns> 函數庫模塊的句柄 </returns>
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
/// <summary>
/// 原型是 : FARPROC GetProcAddress(HMODULE hModule, LPCWSTR lpProcName);
/// </summary>
/// <param name="hModule"> 包含需調用函數的函數庫模塊的句柄 </param>
/// <param name="lpProcName"> 調用函數的名稱 </param>
/// <returns> 函數指針 </returns>
[DllImport("kernel32.dll")]
static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
/// <summary>
/// 原型是 : BOOL FreeLibrary(HMODULE hModule);
/// </summary>
/// <param name="hModule"> 需釋放的函數庫模塊的句柄 </param>
/// <returns> 是否已釋放指定的 Dll</returns>
[DllImport("kernel32",EntryPoint="FreeLibrary",SetLastError=true)]
static extern bool FreeLibrary(IntPtr hModule);
/// <summary>
/// Loadlibrary 返回的函數庫模塊的句柄
/// </summary>
private IntPtr hModule=IntPtr.Zero;
/// <summary>
/// GetProcAddress 返回的函數指針
/// </summary>
private IntPtr farProc=IntPtr.Zero;
|
/// <summary>
/// 裝載 Dll
/// </summary>
/// <param name="lpFileName">DLL 文件名 </param>
public void LoadDll(string lpFileName)
{
hModule=LoadLibrary(lpFileName);
if(hModule==IntPtr.Zero)
throw(new Exception(" 沒有找到 :"+lpFileName+"." ));
}
|
public void LoadDll(IntPtr HMODULE)
{
if(HMODULE==IntPtr.Zero)
throw(new Exception(" 所傳入的函數庫模塊的句柄 HMODULE 爲空 ." ));
hModule=HMODULE;
}
|
/// <summary>
/// 得到函數指針
/// </summary>
/// <param name="lpProcName"> 調用函數的名稱 </param>
public void LoadFun(string lpProcName)
{ // 若函數庫模塊的句柄爲空,則拋出異常
if(hModule==IntPtr.Zero)
throw(new Exception(" 函數庫模塊的句柄爲空 , 請確保已進行 LoadDll 操做 !"));
// 取得函數指針
farProc = GetProcAddress(hModule,lpProcName);
// 若函數指針,則拋出異常
if(farProc==IntPtr.Zero)
throw(new Exception(" 沒有找到 :"+lpProcName+" 這個函數的入口點 "));
}
/// <summary>
/// 得到函數指針
/// </summary>
/// <param name="lpFileName"> 包含需調用函數的 DLL 文件名 </param>
/// <param name="lpProcName"> 調用函數的名稱 </param>
public void LoadFun(string lpFileName,string lpProcName)
{ // 取得函數庫模塊的句柄
hModule=LoadLibrary(lpFileName);
// 若函數庫模塊的句柄爲空,則拋出異常
if(hModule==IntPtr.Zero)
throw(new Exception(" 沒有找到 :"+lpFileName+"." ));
// 取得函數指針
farProc = GetProcAddress(hModule,lpProcName);
// 若函數指針,則拋出異常
if(farProc==IntPtr.Zero)
throw(new Exception(" 沒有找到 :"+lpProcName+" 這個函數的入口點 "));
}
|
/// <summary>
/// 卸載 Dll
/// </summary>
public void UnLoadDll()
{
FreeLibrary(hModule);
hModule=IntPtr.Zero;
farProc=IntPtr.Zero;
}
|
/// <summary>
/// 調用所設定的函數
/// </summary>
/// <param name="ObjArray_Parameter"> 實參 </param>
/// <param name="TypeArray_ParameterType"> 實參類型 </param>
/// <param name="ModePassArray_Parameter"> 實參傳送方式 </param>
/// <param name="Type_Return"> 返回類型 </param>
/// <returns> 返回所調用函數的 object</returns>
public object Invoke(object[] ObjArray_Parameter,Type[] TypeArray_ParameterType,ModePass[] ModePassArray_Parameter,Type Type_Return)
{
// 下面 3 個 if 是進行安全檢查 , 若不能經過 , 則拋出異常
if(hModule==IntPtr.Zero)
throw(new Exception(" 函數庫模塊的句柄爲空 , 請確保已進行 LoadDll 操做 !"));
if(farProc==IntPtr.Zero)
throw(new Exception(" 函數指針爲空 , 請確保已進行 LoadFun 操做 !" ) );
if(ObjArray_Parameter.Length!=ModePassArray_Parameter.Length)
throw(new Exception(" 參數個數及其傳遞方式的個數不匹配 ." ) );
// 下面是建立 MyAssemblyName 對象並設置其 Name 屬性
AssemblyName MyAssemblyName = new AssemblyName();
MyAssemblyName.Name = "InvokeFun";
// 生成單模塊配件
AssemblyBuilder MyAssemblyBuilder =AppDomain.CurrentDomain.DefineDynamicAssembly(MyAssemblyName,AssemblyBuilderAccess.Run);
ModuleBuilder MyModuleBuilder =MyAssemblyBuilder.DefineDynamicModule("InvokeDll");
// 定義要調用的方法 , 方法名爲「 MyFun 」,返回類型是「 Type_Return 」參數類型是「 TypeArray_ParameterType 」
MethodBuilder MyMethodBuilder =MyModuleBuilder.DefineGlobalMethod("MyFun",MethodAttributes.Public| MethodAttributes.Static,Type_Return,TypeArray_ParameterType);
// 獲取一個 ILGenerator ,用於發送所需的 IL
ILGenerator IL = MyMethodBuilder.GetILGenerator();
int i;
for (i = 0; i < ObjArray_Parameter.Length; i++)
{// 用循環將參數依次壓入堆棧
switch (ModePassArray_Parameter[i])
{
case ModePass.ByValue:
IL.Emit(OpCodes.Ldarg, i);
break;
case ModePass.ByRef:
IL.Emit(OpCodes.Ldarga, i);
break;
default:
throw(new Exception(" 第 " +(i+1).ToString() + " 個參數沒有給定正確的傳遞方式 ." ) );
}
}
if (IntPtr.Size == 4) {// 判斷處理器類型
IL.Emit(OpCodes.Ldc_I4, farProc.ToInt32());
}
else if (IntPtr.Size == 8)
{
IL.Emit(OpCodes.Ldc_I8, farProc.ToInt64());
}
else
{
throw new PlatformNotSupportedException();
}
IL.EmitCalli(OpCodes.Calli,CallingConvention.StdCall,Type_Return,TypeArray_ParameterType);
IL.Emit(OpCodes.Ret); // 返回值
MyModuleBuilder.CreateGlobalFunctions();
// 取得方法信息
MethodInfo MyMethodInfo = MyModuleBuilder.GetMethod("MyFun");
return MyMethodInfo.Invoke(null, ObjArray_Parameter);// 調用方法,並返回其值
}
|
/// <summary>
/// 調用所設定的函數
/// </summary>
/// <param name="IntPtr_Function"> 函數指針 </param>
/// <param name="ObjArray_Parameter"> 實參 </param>
/// <param name="TypeArray_ParameterType"> 實參類型 </param>
/// <param name="ModePassArray_Parameter"> 實參傳送方式 </param>
/// <param name="Type_Return"> 返回類型 </param>
/// <returns> 返回所調用函數的 object</returns>
public object Invoke(IntPtr IntPtr_Function,object[] ObjArray_Parameter,Type[] TypeArray_ParameterType,ModePass[] ModePassArray_Parameter,Type Type_Return)
{
// 下面 2 個 if 是進行安全檢查 , 若不能經過 , 則拋出異常
if(hModule==IntPtr.Zero)
throw(new Exception(" 函數庫模塊的句柄爲空 , 請確保已進行 LoadDll 操做 !"));
if(IntPtr_Function==IntPtr.Zero)
throw(new Exception(" 函數指針 IntPtr_Function 爲空 !" ) );
farProc=IntPtr_Function;
return Invoke(ObjArray_Parameter,TypeArray_ParameterType,ModePassArray_Parameter,Type_Return);
}
|
/// <summary>
/// 建立一個 dld 類對象
/// </summary>
private dld myfun=new dld();
|
myfun.LoadDll("Count.dll"); // 加載 "Count.dll"
myfun.LoadFun("_count@4"); // 調入函數 count, "_count@4" 是它的入口,可經過 Depends 查看
|
object[] Parameters = new object[]{(int)0}; // 實參爲 0
Type[] ParameterTypes = new Type[]{typeof(int)}; // 實參類型爲 int
ModePass[] themode=new ModePass[]{ModePass.ByValue}; // 傳送方式爲值傳
Type Type_Return = typeof(int); // 返回類型爲 int
// 彈出提示框,顯示調用 myfun.Invoke 方法的結果,即調用 count 函數
MessageBox.Show(" 這是您裝載該 Dll 後第 "+myfun.Invoke(Parameters,ParameterTypes,themode,Type_Return).ToString()
+" 次點擊此按鈕。 "," 挑戰杯 ");
|
myfun.UnLoadDll();
|
// 因爲 static 不能修飾方法體內的變量,因此需放在這裏,且初始化值爲 int.MinValue
static int S=int.MinValue;
public int count(int init)
{// 判斷 S 是否等於 int.MinValue ,是的話把 init 賦值給 S
if(S==int.MinValue) S=init;
S++; //S 自增 1
return S; // 返回 S
}
|
private object Invoke(string lpFileName,string Namespace,string ClassName,string lpProcName,object[] ObjArray_Parameter)
{
Try { // 載入程序集
Assembly MyAssembly=Assembly.LoadFrom(lpFileName);
Type[] type=MyAssembly.GetTypes();
foreach(Type t in type)
{// 查找要調用的命名空間及類
if(t.Namespace==Namespace&&t.Name==ClassName)
{// 查找要調用的方法並進行調用
MethodInfo m=t.GetMethod(lpProcName);
if(m!=null)
{
object o=Activator.CreateInstance(t);
return m.Invoke(o,ObjArray_Parameter);
}
else MessageBox.Show(" 裝載出錯 !");
}
}
}//try
catch(System.NullReferenceException e)
{
MessageBox.Show(e.Message);
}//catch
return (object)0;
}// Invoke
|
// 顯示 count(0) 返回的值
MessageBox.Show(" 這是您第 "+Invoke("CsCount.dll","CsCount","Class1","count",new object[]{(int)0}).ToString()+" 次點擊此按鈕。 "," 挑戰杯 ");
|
using System.IO; // 對文件的讀寫須要用到此命名空間
using System.Reflection; // 使用 Assembly 類需用此命名空間
using System.Reflection.Emit; // 使用 ILGenerator 需用此命名空間
|
// 記錄要導入的程序集
static Assembly MyAssembly;
|
private byte[] LoadDll(string lpFileName)
{
Assembly NowAssembly = Assembly.GetEntryAssembly();
Stream fs=null;
try
{// 嘗試讀取資源中的 DLL
fs = NowAssembly.GetManifestResourceStream(NowAssembly.GetName().Name+"."+lpFileName);
}
finally
{// 若是資源沒有所需的 DLL ,就查看硬盤上有沒有,有的話就讀取
if (fs==null&&!File.Exists(lpFileName)) throw(new Exception(" 找不到文件 :"+lpFileName));
else if(fs==null&&File.Exists(lpFileName))
{
FileStream Fs = new FileStream(lpFileName, FileMode.Open);
fs=(Stream)Fs;
}
}
byte[] buffer = new byte[(int) fs.Length];
fs.Read(buffer, 0, buffer.Length);
fs.Close();
return buffer; // 以 byte[] 返回讀到的 DLL
}
|
public void UnLoadDll()
{// 使 MyAssembly 指空
MyAssembly=null;
}
|
public object Invoke(string lpFileName,string Namespace,string ClassName,string lpProcName,object[] ObjArray_Parameter)
{
try
{// 判斷 MyAssembly 是否爲空或 MyAssembly 的命名空間不等於要調用方法的命名空間,若是條件爲真,就用 Assembly.Load 加載所需 DLL 做爲程序集
if(MyAssembly==null||MyAssembly.GetName().Name!=Namespace)
MyAssembly=Assembly.Load(LoadDll(lpFileName));
Type[] type=MyAssembly.GetTypes();
foreach(Type t in type)
{
if(t.Namespace==Namespace&&t.Name==ClassName)
{
MethodInfo m=t.GetMethod(lpProcName);
if(m!=null)
{// 調用並返回
object o=Activator.CreateInstance(t);
return m.Invoke(o,ObjArray_Parameter);
}
else
System.Windows.Forms.MessageBox.Show(" 裝載出錯 !");
}
}
}
catch(System.NullReferenceException e)
{
System.Windows.Forms.MessageBox.Show(e.Message);
}
return (object)0;
}
|
// 添加一個 ldfs 實例 tmp
private ldfs tmp=new ldfs();
|
// 調用 count(0), 並使用期提示框顯示其返回值
MessageBox.Show(" 這是您第 "+tmp.Invoke("CsCount.dll","CsCount","Class1","count",new object[]{(int)0}).ToString()+" 次點擊此按鈕。 "," 挑戰杯 ");
|
// 卸載 DLL
tmp.UnLoadDll();
|