1、COM调用
COM应该是非托管组件重用最重要的方式,特别是调用微软的COM组件。
可以用VS添加引用的方式自动生成包装类,也可以用Tlbimp.exe实用工具包装COM对象生成包装类。
COM对象需要在本机注册,这个程序部署带来一定的麻烦,如果调用简单的功能,包装COM有点大材小用。
如果只简单的调用非托管函数,可以用接下来介绍的DllImprot等方式。
- using System;
- using OLEPRNLib;
-
- namespace PrinterStatus
- {
- class Class1
- {
- [STAThread]
- static void Main(string[] args)
- {
- string[] ErrorMessageText = new string[8];
-
- ErrorMessageText[0] = "service requested";
- ErrorMessageText[1] = "offline";
- ErrorMessageText[2] = "paper jammed";
- ErrorMessageText[3] = "door open";
- ErrorMessageText[4] = "no toner";
- ErrorMessageText[5] = "toner low";
- ErrorMessageText[6] = "out of paper";
- ErrorMessageText[7] = "low paper";
-
- int DeviceID = 1;
- int Retries = 1;
- int TimeoutInMS = 2000;
- string CommunityString = "public";
- string IPAddressOfPrinter = "10.3.0.93";
-
-
- OLEPRNLib.SNMP snmp = new OLEPRNLib.SNMP();
-
-
- snmp.Open(IPAddressOfPrinter, CommunityString, Retries, TimeoutInMS);
-
-
- uint WarningErrorBits = snmp.GetAsByte(String.Format("25.3.5.1.2.{0}", DeviceID));
-
-
- uint StatusResult = snmp.GetAsByte(String.Format("25.3.2.1.5.{0}", DeviceID));
-
-
-
- string Result1Str = "";
- switch (StatusResult)
- {
- case 2: Result1Str = "OK";
- break;
- case 3: Result1Str = "Warning: ";
- break;
- case 4: Result1Str = "Being Tested: ";
- break;
- case 5: Result1Str = "Unavailable for any use: ";
- break;
- default: Result1Str = "Unknown Status Code : " + StatusResult;
- break;
- }
-
- string Str = "";
- if ((StatusResult == 3 || StatusResult == 5))
- {
- int Mask = 1;
- int NumMsg = 0;
- for (int i = 0; i < 8; i++)
- {
- if ((WarningErrorBits & Mask) == Mask)
- {
- if (Str.Length > 0)
- Str += ", ";
- Str += ErrorMessageText[i];
- NumMsg = NumMsg + 1;
- }
- Mask = Mask * 2;
- }
- }
- Console.WriteLine(Result1Str + Str);
- }
- }
- }
2、DllImport
DllImport是在"System.Runtime.InteropServices"命名空间中定义的特性。
- [DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "MessageBox")]
- public static extern int InvokeMessageBox(IntPtr hWnd, String text, String caption, uint type);
-
- static void Main()
- {
- InvokeMessageBox(new IntPtr(0), "对话框内容", "对话框标题", 0);
- }
3、加载非托管动态链接库
Win32中,有个LoadLibrary(string file)函数,加载动态链接库;GetProcAddress函数动态调用导出函数。
.NET类库的 Marshal.GetDelegateForFunctionPointer 方法能将非托管函数指针转换为委托。
- public delegate int MsgBox(int hwnd,string msg,string cpp,int ok);
- [DllImport("Kernel32")]
- public static extern int GetProcAddress(int handle, String funcname);
- [DllImport("Kernel32")]
- public static extern int LoadLibrary(String funcname);
- [DllImport("Kernel32")]
- public static extern int FreeLibrary(int handle);
-
- private static Delegate GetAddress(int dllModule, string functionname, Type t)
- {
- int addr = GetProcAddress(dllModule, functionname);
- if (addr == 0)
- return null;
- else
- return Marshal.GetDelegateForFunctionPointer(new IntPtr(addr), t);
- }
-
- private void button1_Click(object sender, EventArgs e)
- {
- int huser32 = 0;
- huser32 = LoadLibrary("user32.dll");
- MsgBox mymsg = (MsgBox)GetAddress(huser32, "MessageBoxA", typeof(MsgBox));
- mymsg(this.Handle.ToInt32(), txtmsg.Text, txttitle.Text , 64);
- FreeLibrary(huser32);
- }
4、DynamicMethod
可以使用 DynamicMethod 类在运行时生成和执行方法,而不必生成动态程序集和动态类型来包含该方法。动态方法是生成和执行少量代码的最有效方式。
- using System;
- using System.Collections.Generic;
- using System.Text;
- using Zealic.Windows;
-
- namespace ConsoleApplication1
- {
- class Program
- {
- static void Main(string[] args)
- {
-
- DynamicLibrary hilib = new DynamicLibrary("hi.dll");
- NativeMethodBuilder hiBuilder = new NativeMethodBuilder();
- NativeMethod method = hiBuilder.MakeMethod(hilib, "func");
- Console.WriteLine("请关闭弹出的对话框 'Hille'");
- method.Invoke();
- hilib.Free();
-
-
- DynamicLibrary krnlib = new DynamicLibrary("kernel32.dll");
- NativeMethodBuilder beepBuilder = new NativeMethodBuilder();
- beepBuilder.ParameterLength = 2;
- beepBuilder.SetParameterInfo(0, typeof(int));
- beepBuilder.SetParameterInfo(1, typeof(int));
- method = beepBuilder.MakeMethod(krnlib,"Beep");
- Console.WriteLine("听,你的机器在尖叫!");
- method.Invoke(1000, 1000);
- Console.WriteLine("按任意键退出!");
- Console.ReadKey(true);
- }
- }
- }
5、直接调用执行机器码
机器码是最原始的程序代码,或称指令,把这些指令装载到内存,Marshal.GetDelegateForFunctionPointer方法转换为对应的委托,调用即可。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- namespace NShellNativeCode
- {
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Runtime.InteropServices;
- using System.IO;
- using System.Diagnostics;
- using System.Reflection;
-
- delegate int AddProc(int p1, int p2);
- class Program
- {
-
-
- static void Main(string[] args)
- {
-
-
-
-
- byte[] codeBytes = {
- 0x8B, 0x44, 0x24, 0x08
- , 0x8B, 0x4C, 0x24, 0x04
- , 0x03, 0xC1
- , 0xC3
- };
-
-
-
-
-
-
-
-
-
- IntPtr handle = IntPtr.Zero;
- handle = Marshal.AllocHGlobal(codeBytes.Length);
- try
- {
-
- Marshal.Copy(codeBytes, 0, handle, codeBytes.Length);
-
- AddProc add
- = Marshal.GetDelegateForFunctionPointer(handle, typeof(AddProc)) as AddProc;
-
- int r = add(1976, 1);
-
- Console.WriteLine("本机代码返回:{0}", r);
-
-
- }
- finally
- {
- Marshal.FreeHGlobal(handle);
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
-
-
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- public class NativeCodeHelper:IDisposable
- {
-
- private bool _disposed = false;
- private byte[] _codeBytes = {};
- private IntPtr _handle = IntPtr.Zero;
-
- public NativeCodeHelper(byte[] codeBytes)
- {
- this._codeBytes = codeBytes;
- }
-
-
-
-
- private void CreateHandle()
- {
- if (_handle == IntPtr.Zero)
- {
- _handle = Marshal.AllocHGlobal( this._codeBytes.Length);
- Marshal.Copy(_codeBytes, 0, _handle, _codeBytes.Length);
- }
- }
-
-
-
-
-
- public T ToDelegate<T>() where T:class
- {
- this.CreateHandle();
-
-
- T result = Marshal.GetDelegateForFunctionPointer(_handle, typeof(T)) as T;
-
- return result;
-
- }
-
- #region IDisposable 成员
-
- ~NativeCodeHelper()
- {
- Dispose(false);
- }
-
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
-
- }
-
-
-
- private void Dispose(bool disposing)
- {
- if (disposing)
- {
-
- MethodBase mb = System.Reflection.MethodBase.GetCurrentMethod();
- Type t = mb.DeclaringType;
-
- Trace.WriteLine("not Dispose"
- , "" + t + "." + mb );
- }
-
-
- if (!this._disposed)
- {
- if (disposing)
- {
-
- }
-
- Marshal.FreeHGlobal(this._handle);
- _handle = IntPtr.Zero;
- }
- _disposed = true;
- }
-
- #endregion
- }
- }