本文实例讲述了从C#程序中调用非受管DLLs的方法。分享给大家供大家参考。具体方法如下:
前言:
从所周知,.NET已经渐渐成为一种技术时尚,那么C#很自然也成为一种编程时尚。如何利用浩如烟海的Win32API以及以前所编写的Win32代码已经成为越来越多的C#程序员所关注的问题。本文将介绍如何从C#代码中调用非受管DLLs。如果某个函数是一个带有串类型(char*)输出参数的Win32API或者是DLL输出函数,那么从C#中如何调用它呢?对于输入参数的情形问题到不大,但如何获取从参数中返回的串呢?此外,如何调用有结构(struct)和回调(callback)作为参数的函数,如GetWindowsRect和EnumWindows?那我们又如何将参数从C++和MFC中转换成C#所要的类型呢?下面就让我们来一一解决这些问题。
微软.NET的一个最主要的优势是它提供一个语言无关的开发系统。我们可以用VisualBasic、C++、C#等等语言来编写类,然后在其它语言中使用,我们甚至可以用不同的语言来派生类。但是如何调用以前开发的非受管DLL呢?方法是必须将.NET对象转化成结构、char*以及C语言的指针。用行话说就是参数必须被列集(marshal)。说到列集,用一两句话也说不清楚。所幸的是实现列集并不要我们知道太多的东西。
为了从C#中调用DLL函数,首先必须要有一个声明,就象长期以来使用VisualBasic的程序员所做的那样,只不过在C#中使用的是DllImport关键字:
代码如下:usingSystem.Runtime.InteropServices;//DllImport所在的免费精选名字大全空间
publicclassWin32{
[DllImport(“User32.Dll”)]
publicstaticexternvoidSetWindowText(inth,Strings);
}
在C#中,DllImport关键字作用是告诉编译器入口点在哪里,并将打包函数捆绑在一个类中。我们可以为这类取任何免费精选名字大全,这里不妨将类名取为Win32。我们甚至可以将这个类放到一个免费精选名字大全空间中,就象下面的代码这样:
Win32API.cs源代码
代码如下://Win32API:此为免费精选名字大全空间,打包所选的Win32API函数
//编译方法:
// csc/t:library/out:Win32API.dllWin32API.cs
//
usingSystem;
usingSystem.Drawing;
usingSystem.Text;
usingSystem.Runtime.InteropServices;
/////////////////////////////////////////////////////////////////
//包装Win32API函数的免费精选名字大全空间。想用哪个Win32API,往里添加即可。
//
namespaceWin32API{
[StructLayout(LayoutKind.Sequential)]
publicstructPOINT{
publicPOINT(intxx,intyy){x=xx;y=yy;}
publicintx;
publicinty;
publicoverridestringToString(){
Strings=String.Format(“({0},{1})”,x,y);
returns;
}
}
[StructLayout(LayoutKind.Sequential)]
publicstructSIZE{
publicSIZE(intcxx,intcyy){cx=cxx;cy=cyy;}
publicintcx;
publicintcy;
publicoverridestringToString(){
Strings=String.Format(“({0},{1})”,cx,cy);
returns;
}
}
[StructLayout(LayoutKind.Sequential)]
publicstructRECT{
publicintleft;
publicinttop;
publicintright;
publicintbottom;
publicintWidth() {returnright-left;}
publicintHeight() {returnbottom-top;}
publicPOINTTopLeft() {returnnewPOINT(left,top);}
publicSIZE Size() {returnnewSIZE(Width(),Height());}
publicoverridestringToString(){
Strings=String.Format(“{0}x{1}”,TopLeft(),Size());
returns;
}
}
publicclassWin32{
[DllImport(“user32.dll”)]
publicstaticexternboolIsWindowVisible(inthwnd);
[DllImport(“user32.dll”)]
publicstaticexternintGetWindowText(inthwnd,
StringBuilderbuf,intnMaxCount);
[DllImport(“user32.dll”)]
publicstaticexternintGetClassName(inthwnd,
[MarshalAs(UnmanagedType.LPStr)]StringBuilderbuf,
intnMaxCount);
[DllImport(“user32.dll”)]
publicstaticexternintGetWindowRect(inthwnd,refRECTrc);
[DllImport(“user32.dll”)]
//注意,运行时知道如何列集一个矩形
publicstaticexternintGetWindowRect(inthwnd,refRectanglerc);
}
}
用下面的命令行可以编译这段代码:csc/t:library/out:Win32API.dllWin32API.cs
成功编译后,我们就有了一个可以在C#工程中使用的动态库了(Win32API.dll)。
代码如下:usingWin32API;
inthwnd=//getit
Strings=”I””msocute.”;
Win32.SetWindowText(hwnd,s);
编译器知道在user32.dll中找到SetWindowText,并在调用前自动将串转换为LPTSTR(TCHAR*)。真是神奇!.NET是如何实现的呢?其实,每一个C#类型都有一个缺省的列集类型。对于串来说,它的列集类型就是LPTSTR。但如果调用的是GetWindowText,它的串参数是一个输出参数,而非输入参数,因为串是不变的,再象上面这样处理就行不通了。我们可能一点都没有注意到,不论什么时候处理一个串时,都会创建一个新串。要想修改这个串,必须用StringBuilder:
代码如下:usingSystem.Text;//StringBuilder所在的免费精选名字大全空间
publicclassWin32{
[DllImport(“user32.dll”)]
publicstaticexternintGetWindowText(inthwnd,
StringBuilderbuf,intnMaxCount);
}
StringBuilder缺省的列集类型是LPTSTR,但是GetWindowText现在可以修改实际的串。
代码如下:inthwnd=//getit
StringBuildersb=newStringBuilder(256);
Win32.GetWindowText(hwnd,sb,sb.Capacity);
所以我们第一个问题的答案就是:使用StringBuilder。前面讨论的方法固然可以行得通,但有一种情况没有考虑,那就是如果缺省的列集类型不是你想要的类型怎么办?例如想要调用GetClassName,Windows编程高手都知道,GetClassName的参数与大多数其它的API函数的参数有所不同,它的串参数是LPSTR(char*),甚至是Unicode串。如果传递一个串,公共语言运行时(CLR)将把它转换成TCHARs——是不是很糟啊!不用害怕,我们可以用MarshalAs来改写缺省的处理:
代码如下:[DllImport(“user32.dll”)]
publicstaticexternintGetClassName(inthwnd,
[MarshalAs(UnmanagedType.LPStr)]StringBuilderbuf,
intnMaxCount);
现在我们调用GetClassName,.NET将串作为ANSI字符传递,而不是宽字符,搞掂!上述就是C#学习教程:从C#程序中调用非受管DLLs的方法分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/905828.html