NET调用Com组件事例

http://blog.csdn.net/shizhiyingnj/article/details/1507948

在程序设计中,往往通过键盘的某个按键来完成相关操作!

下面就来说明如何实现:

1.引入名称空间;

using
System.Runtime.InteropServices;

(由于使用到API(user32.dll)

2.使用API

[DllImport("user32.dll", CharSet =
CharSet.Auto)]
  private static extern Int32 GetKeyState(long
nVirtKey);

3.测试

private void
button1_Click(object sender, System.EventArgs
e)
  {
   if(GetKeyState(Convert.ToInt32
(Keys.Capital))==0)
   {
        
MessageBox.Show("Caps
Lock为开状态!");
   }
  }

作者:刘铁猛
日期:2005-12-20
关键字:C# .NET
Win32 API

版权声明:本文章受知识产权法保护,如果阁下想转载,在转载的时候烦劳阁下连同在下的姓名一起转载,并向[email protected]发一个Mail,我很想知道我的文章都去哪里了.谢谢.

小序
       
Win32 API可以直接控制Microsoft Windows的核心,因为API(Application Programming
Interface)本来就是微软留给我们直接控制Windows的接口。想玩儿吗?呵呵,太难了。
       
C#使用非常简单,写程序就像打拱猪,Sorry  -_-!
,搭积木一样简单。想玩儿吗?呵呵,没办法直接控制Windows的核心。
        难道就没有两全其美的办法吗?当然不是!要不微软的产品早就没人买了。其实从C#(或者说.NET平台)调用Win32
API还是非常简单滴~~~~今天偶们大家就一起来研究研究。

一.   
基础知识
        Win32
API是C语言(注意,不是C++语言,尽管C语言是C++语言的子集)函数集。C#语言与C语言是完全不同的(除了语法上比较像),所以,要想用C#语言调用C语言的Win32
API,要费上一番周折。首先我们就要准备一些基础知识。
1. Win32
API函数放在哪里?
        Win32
API函数是Windows的核心,比如我们看到的窗体、按钮、对话框什么的,都是依靠Win32函数“画”在屏幕上的,由于这些控件(有时也称组件)都用于用户与Windows进行交互,所以控制这些控件的Win32
API函数称为“用户界面”函数(User Interface Win32
API),简称UI函数;还有一些函数,并不用于交互,比如管理当前系统正在运行的进程、硬件系统状态的监视等等……这些函数只有一套,但是可以被所有的Windows程序调用(只要这个程序的权限足够高),简而言之,API是为程序所共享的。为了达到所有程序能共享一套API的目的,Windows采用了“动态链接库”的办法。之所以叫“动态链接库”,是因为这样的函数库的调用方式是“随用随取”而不是像静态链接库那样“用不用都要带上”。
       
这里不太好理解,不要紧,我们举个小例子。我们把Windows比做一个游乐场,而把在游乐场里玩儿的小孩比做一个一个程序。小孩在玩的过程中可能要喝水。我们有两个办法让小家伙们想喝水的时候就有水喝:1.给每个小家伙配一个水壶,小家伙们喝了的话就喝自己带的水;2.给游乐场配一个饮水机,谁渴了谁来喝。显然,第二个方法要好得多,这体现在三个地方。第一,带着水壶,小家伙身体不灵活、玩不爽(影响程序的速度),况且这只是带了一个水壶,要是再带上饭盒呢?还有轮滑、头盔、创可贴、纱布……AK-47
My
God,如果带全了就赶上美国大兵了。所以游乐园里还是有个公用“仓库”要来的方便,让大家随用随取(动态链接)。第二,小家伙们带了那么多东西,占了游乐场很多地方,让游乐场拥挤不堪,别的小朋友就进不来了(程序体积大,影响程序和系统的性能)。第三,如果某件物品升级了,比如水壶从一升的改为二升的,那么每个小家伙就必须go
home去换新的(重新编译程序,由编译器把新的静态库链接进程序主体里),而第二种情况里,只要游乐场把自己仓库里的水壶换个型号,那么所有小家伙就都在同一时间拥有了大容量的水壶。(悟空!我就一会儿不在,你怎么就乱丢东西?!打到小朋友多不好~~~~~)
       
悟空已经急了,我就不再叽叽歪歪了……呃……Win32
API函数是放在Windows系统的核心库文件中的,这些库在硬盘里的存储形式是.dll文件。我们常用到的dll文件是user32.dllkernel32.dll两个文件,还有其它一些dll文件也非常重要,大家要在实践中多积累经验。
       
我们知道Win32
API函数是放在dll文件中了,但新问题又来了——我们怎么调用它们呢?这些dll文件是用C语言写的,源代码经C语言编译器编译之后,会以二进制可执行代码形式存放在这些dll文件中,就好像苹果被打碎机打成果酱后装在罐子里一样——你再也分不清哪个是你GF给你的,哪个是你老妈给你的一样。为了能让程序使用这些函数,微软在发布每个新的操作系统的时候,也会放出这个系统的SDK,目前最新的是Win2003
SP1
SDK,据说Vista的马上就要放出来,而且已经把UI的API从核心库中分离出去以提高系统的稳定性了。SDK里有一些C语言的头文件(.h文件),这些文件里描述了核心dll文件里都有哪些Win32
API函数,在写程序的时候,把这些.h文件用#include"....."指令包含进你的程序里,你就可以使用这些Win32
API了。至于程序是怎样链接的,超出了本文的范围——也超出了本人的知识范围:D
        
至此,如果你是C语言高手,已经可以使用Windows SDK去调教Windows了!不过,今天我们讨论的是C#语言调用Win32
API的问题。我们现在已经知道API函数放在dll动态链接库文件里,也知道C语言怎么调用它们了,那么C#语言怎么办呢?C#语言是不能使用C语言的.h文件的。C#语言也使用dll动态链接库,不过这些dll都是.NET版本的,具有“自描述性”,也就是自己肚子里都有哪些函数都已经写在自己的metadata里了,不用再附加一个.h文件来说明。现在,我们已经找到了问题的关键点:如何用.NET平台上的C#语言来调用Win32平台上的dll文件。答案非常简单:使用DllImport特性
二. 
小试牛刀

       
下面,就让我们写一个小程序,试一试如何用C#语言和DllImport特性来调用Win32 API。

using
System;
using
System.Runtime.InteropServices;
class Program
{
     [DllImport("User32.dll")]
     public static
extern int
MessageBox(int h, string m, string
c, int type);

    
static int
Main()
    
{
         MessageBox(0, "Hello
Win32 API", "水之真谛",
4);
         Console.ReadLine();
        
return 0;
    
}
}

       
新建一个C#的控制台程序,把VS自动生成的代码清空,把上面的代码Copy过去就可以编译执行了。让我们剖析一下这个程序:
1.
要使用DllImport这个特性(特性也是一种类),必须使用这一句using
System.Runtime.InteropServices;
,导入“运行时->交互服务”。喔~~~~运行时的交互服务不就是“动态链接”吗?感谢Microsoft!
2.
然后我们就可以制造一个DllImport类的实例,并把这个实例绑定在我们要使用的函数上了。“特性类”这种类非常怪——制造类实例的时候不使用MyClass mc
= new
MyClass();这种形式,而是使用[特性类(参数列表)]这种形式;特性类不能独立存在,一定要用作修饰其它目标上(本例是修饰后面的一个函数),不同的特性可以用来修饰类、函数、变量等等;特性类实例在被编译的时候也不产生可执行代码,而是被放进metadata里以备检索。总之,你记住特性类很怪就是了,想了解更多就查查MSDN,懒得查就先这么记——不懂惯性定律不影响你学骑自行车。[DllImport("User32.dll")]是说我们要使用的Win32
API函数在User32.dll这个文件里。问题又来了:我怎么知道那么多API函数都在哪个dll文件里呢?这个你可以在MSDN里查到,位置是Root->Win32 and COM
Development->Development Guides->Windows API->Windows API->Windows
API Reference->Functions by
Category
。打开这页,你会看到有很多API的分类,API全在这里了。打开一个分类,比如Dialog
Box,在Functions段,你会看到很多具体的函数,其中就有上面用到的MessageBox函数,点击进入。你将打开MessageBox的详细解释和具体用法。它的名字、返回值、参数类型尽收眼底、一览无余!而且很练英文哦~~~~在这一页的底部,你可以看到一个小表格,里面有一项“Minimum
DLL Version   user32.dll”就是说这个函数在user32.dll里。
3.
接下来就是我们的函数了。在C#里调用Win32函数有这么几个要点。第一:名字要与Win32
API的完全一样。第二:函数除了要有相应的DllImport类修饰外,还要声明成public
static extern类型的。第三:也是最变态的一点,函数的返回值和参数类型要与Win32
API完全一致!这可难煞我们这群初学者——Win32的数据类型比较搞怪,比如什么LPSTR、什么HINSTANCE都是些虾米东东呢?给大家一个小参考,我的Blog里有《Windows数据类型探幽——千回百转你是谁?》系列拙文,可以查一下。另外在此,我从MSDN里摘出一张表来,是常用Win32数据类型与.NET平台数据类型的对应表:
Figure 2 Non-Pointer Data
Types

















































Win32 Types Specification CLR Type
char, INT8, SBYTE, CHAR 8-bit signed integer System.SByte
short, short int, INT16,
SHORT
16-bit signed integer System.Int16
int, long, long int, INT32, LONG32,
BOOL, INT
32-bit signed integer System.Int32
__int64, INT64, LONGLONG 64-bit signed integer System.Int64
unsigned char, UINT8, UCHAR,
BYTE
8-bit unsigned integer System.Byte
unsigned short, UINT16, USHORT, WORD,
ATOM, WCHAR, __wchar_t
16-bit unsigned integer System.UInt16
unsigned, unsigned int, UINT32,
ULONG32, DWORD32, ULONG, DWORD, UINT
32-bit unsigned integer System.UInt32
unsigned __int64, UINT64, DWORDLONG,
ULONGLONG
64-bit unsigned integer System.UInt64
float, FLOAT Single-precision floating
point
System.Single
double, long double, DOUBLE Double-precision floating
point
System.Double
In Win32 this type is an
integer with a specially assigned meaning; in contrast, the CLR provides a
specific type devoted to this meaning.

有了这些东西,我们就能把一个Win32
API函数转成C#函数了。还拿MessageBox函数为例(看刚才给出的函数表),它的Win32原形如下:

int MessageBox(  HWND hWnd,   LPCTSTR lpText,    LPCTSTR lpCaption,  UINT uType
);

函数名:MessageBox将保持不变。
返回值:int
将保持不变(无论是Win32还是C#,int都是32位整数)
参数表:H开头意味着是Handle,一般情况下Handld都是指针类型,Win32平台的指针类型是用32位来存储的,所以在C#里正好对应一个int整型。不过,既然是指针,就没有什么正负之分,32位都应该用来保存数值——这样一来,用uint(无符号32位整型)来对应Win32的H类型更合理。不过提醒大家一点,int是受C#和.NET
CLR双重支持的,而uint只受C#支持而不受.NET
CLR支持,所以,本例还是老老实实地使用了int型。(肚子饿了……再坚持坚持……)
至于LPCTSTR是Long Pointer to Constant
String的缩写,说白了就是——字符串。所以,用C#里的string类型就对了。
修饰符:要求有相应的DllImport和public
static
extern

经过上面一番折腾,Win32的MessageBox函数就包装成C#可以调用的函数了:

    
[DllImport("User32.dll")]
     public static
extern int
MessageBox(int h, string m, string
c, int
type);

       
好人做到底,我把四个参数的用处也说一下:
第一个:弹出的MessageBox的父窗口是谁。本例中没有,所以是0,也就是“空指针”。
第二个:MessageBox的内容。本例中是“Hello
Win32
API”。
第三个:MessageBox的标题。本例中用的是本人Blog的名字——水之真谛——请大家不要忘记。
第四个:MessageBox上的按钮是什么,如果是0,那就只有一个OK,MessageBox太短了,你将看不全“水之真谛”四个字,于是偶改成了4,这样就有两个按钮了。这些在MSDN的函数用法里都有。不过,我还是非常推荐您阅读一下本人的另一篇拙作《一个Win32程序的进化》 。
       
至此,一个麻雀虽小、五毒俱全~~~Sorry  -_-! 五脏俱全的C#调用Win32
API的程序就分析完了。原理并不难吧!应届生拿去蒙HR足够了!真正见功底的地方是你使用MSDN、SDK、.NET
Framework类库VC/VC#的熟练程度。相信我——MSDN+SDK+VC/C#绝对足够把Windows收拾得服服帖帖了:D
三.
真的有必要吗?
        
嘿嘿嘿嘿……看我的表情,我在坏坏地笑哦!你们都上当啦!操作Windows的底层不一定都要调用Win32
API滴~~~~(哪儿来的砖头!!!)
        
我想说的是:.NET Framework是对Win32 API的良好封装,大部分Win32 API函数都已经封装在了.NET
Framework类库的各个类里了。如果说Win32 API函数是散落在地上的珍珠的话,那么.NET
Framework就是把这些珍珠按种类分放到了各个抽屉里——让我想起我妈来了——我的书放得满地满床的时候我总是能找到,她一收拾我就再也找不到了,郁闷。唉……没办法,我们还是仔细把.NET
Framework类库好好翻翻吧,会有很多惊喜哦!
       
最后,用一个例子结束我们的文章吧!
        例子是这样滴~~~~~
       
那是在很久很久以前,我给一个公司写程序用来控制用户登录,在登录之前,用户不能把鼠标移出登录窗体,因为要控制鼠标,所以我首先想起了调用Win32
API中与Cursor相关的函数来——于是不管三七二十一、花了九牛二虎之力调用了Win32
API中的ClipCursor()这个函数,效果还不错。
       
结果前两天翻.NET Framework类库的时候,发现System.Windows.Forms.Cursor类的Clip属性就是专门做这个用的!差点没把鼻子气歪了……请大家自己动手创建一个C#的Windows程序,把下面的核心代码贴到主窗体的双击事件里,试一试。做这个例子的目的就是要告诉大家:1.对类库的了解程序直接决定了你编程的效率和质量——用类库里的组件比我们“从轮子造起”要快得多、安全得多。2.不到万不得已,不要去直接调Win32
API函数——那是不安全的。

         private void
Form1_DoubleClick(object sender, EventArgs
e)
        
{
             
Rectangle r = new Rectangle(this.Left, this.Top, this.Width, this.Height);
             
System.Windows.Forms.Cursor.Clip =
r;
        
}

        最后,大家一定非常想知道,.NET
Framework都为我们封装好了哪些Win32 API,OK,MSDN里有一篇文章,专门列出了这些。文章的名字是《Microsoft
Win32 to Microsoft .NET Framework API Map》请感兴趣的朋友自己阅读。
四.  感恩
       
新年快到了,这篇文章也做为一份小小的礼物,一是博大家一乐,二是让我们永远铭记这幸福的时刻。
       
送给对我有着知遇之恩的陆经理;
       
送给刘莹Lead感谢在工作中给予的指导和支持;
       
送给我的Team伙伴乐莲、王勇(Worksoft),没有你们的帮助,我是不可能开始工作的!
       
送给我宿舍的兄弟张雄,没有你,我可能要睡在城铁站了。
       
送给段玮和陈宁,感谢你们组织的活动和培训。
       
送给陈曦、陈建、王勇、常勇、舜贤、挺挺、对面的女孩李芳,还有本组的JJMM,还有小朱……与你们共事是我最大的快乐!

       
文章写完鸟~~~~倾城MM大概也把饭做好鸟~~~~回家鸟~~~~

我们可以使用Declare语句调用外部DLL中的过程。但VB.NET给我们提供了另外一种更加先进的-----
Dllimport特性。

如:

Imports System.Runtime.InteropServices

<DllImport("user32")>
_

Function Findwindow(ByVal lpClassName As String, ByVal lpWindowName As String) As Integer

End Function

<DllImport("user32")>
_

Function MoveWindow(ByVal hWnd As
String, ByVal x As Integer, ByVal y
As Integer,
ByVal nWidth As Integer, ByVal nHeight As
Integer, ByVal bRepaint As
Integer) As
Integer

End Function

Sub
Test()

Dim hWnd As
Integer = Findwindow(Nothing,
"Untitled-Nodepad")

If hWnd <> 0 Then MoveWindow(hWnd, 0, 0, 600, 300,
1)

End Sub

这样就可以不任何代码实现便可以调用外部的Dll,即使我们改变方法名为FindwindowA,也可以顺利的实现调用,因为使用Dllimport特性编译器可以自动追踪实际的过程以及方法!

另外,Dllimport特性海支持几种可选的参数,来精确定义调用外部过程的方式,以及外部过程的返回值方式.

CharSet
参数:用于说明字符串传递给外部过程的方式,可以是CharSet.Ansi(默认),CharSet.Unicode.CharSet.Auto.

ExactSpelling参数:用于指定方法名是否和DLL中的名称完全一致,默认值为True.

EntryPoint参数:用于指定DLL中的实际函数名称.

CallingConvention参数:为入口点指定调用的约定,值有WinApi(默认       
               
值),CDecl,FastCallStdCall和ThisCall.

SetLastError参数:判断被调用函数是否设置了最近一次Win32错误代码,如果设置为True    
      
则可以通过Err.LastDllError方法或Marshal.GetLastWin32Error方法     
       读取这些代码.

PreServeSig参数:为一个Boolean值,如果为True ,则将告诉编译器,方法不应被转换为一   
         个返回HRESULT值函数.

下面使用Dllimport特性来调用myFunction.dll中的名为friend(friend为vb保留名称)的方法.Dllimport特性带有Unicode字符串,并影响Win32错误代码:

<DllImport("myFunction.dll",
EntryPoint:="Friend", CharSet:=CharSet.Unicode, SetLastError:=True)>
_

Function MakeFriends(ByVal sl As String, ByVal s2
As String)
As Integer

End Function

NET调用Com组件事例,布布扣,bubuko.com

时间: 2024-10-06 00:43:08

NET调用Com组件事例的相关文章

C#调用htmlfile组件,并执行js函数

前一篇我测试了vba调用htmlfile做反混淆,并执行js函数的代码.本文换成C#实现. 本文地址:http://www.cnblogs.com/Charltsing/p/CSharpEval.html 联系QQ:564955427 C#调用com组件需要使用CreateInstance,当然,我们也可以通过反编译vb.net里面的CreatObject来修改成C#代码.我从网上下载了一个 [SecurityPermission(SecurityAction.Demand, Unmanaged

Jacob调用COM组件总结,实例

转自:http://blog.csdn.net/whw6_faye/article/details/5418506 最近做了一个Java Jacob调用COM组件的东西,其中遇到了不少问题,现在把经验总结一下和大家分享. 1.Jacob安装 Google一下,下载Jacob最新版.我这里用的是Jacob-1.15 把Jacob.jar放到你Java工程的lib目录下,引入项目 Jacob自带了两个dll, jacob-1.15-M3-x64.dll 和jacob-1.15-M3-x86.dll,

Titanium中调用ios组件时语言不是本地化的解决方法

用Titanium开发的ios应用中,当调用系统组件时,尽管手机已经设置了系统语言为中文,但那些组件的界面却仍为英文.比如调用iphone中的相册组件,其界面为: 那么怎么让它跟系统语言保持一致呢? 在原生的ios开发中,只需要在info.plist中把 CFBundleAllowMixedLocalizations 设置为 true 就行了,代表Localized resources can be mixed,就是允许库使用本地语言资源. 那么在Titanium中该怎么做呢? 其实也很简单,T

VS2010调用Com组件

Com组件开发过程中用的不多,资料也不多,故记录开发Com组件中的部分问题. 在这一篇文章里,讲解了如何使用VS2010创建Com组件.现在基于该文章创建的Com组件接口,创建VC++项目来调用该接口. 使用流程 新建win32控制台项目. 主文件代码如下: #include "stdafx.h" #include "../testCom/testCom_i.h" #include "../testCom/testCom_i.c" int _tm

C语言调用COM组件

调用COM组件最简单的语言当然是C++,但在某些情况下,不得不用C语言.本文介绍用C语言调用COM组件的方法. 为了更好的理解C的做法,我们要先看一看C++调用COM组件是怎么做的. 一.C++方式 从 Windows 7 开始,任务栏可以显示进度条,就以这个接口为例吧. ITaskbarList4 *pTaskbar = nullptr; HRESULT hResult = ::CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_INPROC

vue组件之间的通信以及如何在父组件中调用子组件的方法和属性

在Vue中组件实例之间的作用域是孤立的,以为不能直接在子组件上引用父组件的数据,同时父组件也不能直接使用子组件的数据 一.父组件利用props往子组件传输数据 父组件: <div> <child v-bind:my-message="parentMsg"></child>//注意传递参数时要用-代替驼峰命名,HTML不区分大小写 </div> 子组件: Vue.component('child', { // camelCase in Ja

java调用com组件操作word使用总结(jacob)

ava调用com组件操作word使用总结(jacob) 简单描述 在此处输入简单摘要 特别声明:使用java-com技术可以完成任何VBA可以完成的office文档操作; 一.准备工作 先了解一下概念,JACOB 就是 JAVA-COM Bridge的缩写,提供自动化的访问com的功能,也是通过JNI功能访问windows平台下的com组件或者win32系统库的.这是一个开始于 1999年的开源项目的成果,有很多使用者对该项目进行了修改,做出了自己的贡献. Jacob下载地址: http://s

[转]C# 互操作性入门系列(四):在C# 中调用COM组件

传送门 C#互操作系列文章: C#互操作性入门系列(一):C#中互操作性介绍 C#互操作性入门系列(二):使用平台调用调用Win32 函数 C# 互操作性入门系列(三):平台调用中的数据封送处理 C#互操作性入门系列(四):在C# 中调用COM组件 本专题概要: 引言 如何在C#中调用COM组件--访问Office 互操作对象 在C# 中调用COM组件的实现原理剖析 错误处理 小结 一.引言 COM(Component Object Modele,组件对象模型)是微软以前推崇的一个开发技术,所以

.NET通过调用Office组件导出Word文档

.NET通过调用Office组件导出Word文档 最近做项目需要实现一个客户端下载word表格的功能,该功能是用户点击"下载表格",服务端将该用户的数据查询出来并生成数据到Word模板中,再反馈给客户端下载. 实现思路如下: 利用微软提供的Office的组件来完成,在服务器端指定目录放置一个word模板(该模板中需要替换的数据信息用书签标记好),当请求过来的时候,读取模板信息并将书签内容替换成从数据库获得的信息在返回给客户端下载即可,代码如下: #region 根据申请单ID号和模板生