其中要使用兩個未公開的Win32 API函數來存取控制台窗口,這就需要使用動態調用的方法,動態調用中使用的Windows API函數主要有三個,即:Loadlibrary,GetProcAddress和Freelibrary。步驟如下:
1. Loadlibrary: 裝載指定DLL動態庫
2. GetProcAddress:獲得函數的入口地址
3. Freelibrary: 從內存中卸載動態庫
但是C#中是沒有函數指針,無法直接使用GetProcAddress返回的入口地址。后來找到資料,其實.NET 2.0新增了Marshal.GetDelegateForFunctionPointer 方法可以滿足這個要求,MSDN里的解釋是:將非托管函數指針轉換為委托。
后面的事就簡單啦,我把它編成了一個類來方便調用。
using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; namespace feiyun0112.cnblogs.com { public class DllInvoke { Win API#region Win API [DllImport("kernel32.dll")] private extern static IntPtr LoadLibrary(string path); [DllImport("kernel32.dll")] private extern static IntPtr GetProcAddress(IntPtr lib, string funcName); [DllImport("kernel32.dll")] private extern static bool FreeLibrary(IntPtr lib); #endregion private IntPtr hLib; public DllInvoke(String DLLPath) { hLib = LoadLibrary(DLLPath); } ~DllInvoke() { FreeLibrary(hLib); } //將要執行的函數轉換為委托 public Delegate Invoke (string APIName,Type t) { IntPtr api = GetProcAddress(hLib, APIName); return (Delegate)Marshal.GetDelegateForFunctionPointer(api, t); } } }
下面是使用代碼
using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; using feiyun0112.cnblogs.com; namespace ConsoleApplication1 { class Program { public delegate string Test(string a); static void Main(string[] args) { DllInvoke dll = new DllInvoke("test2.dll"); Test test = (Test)dll.Invoke("testC", typeof(Test)); string s = test("ss"); Console.WriteLine(s); Console.WriteLine("****************************************"); Console.ReadLine(); } } }
DllImport會按照順序自動去尋找的地方:
1、exe所在目錄
2、System32目錄
3、環境變量目錄
所以只需要你把引用的DLL 拷貝到這三個目錄下 就可以不用寫路徑了