[原创]讨论一下VB下面的2个关键字
文章标题:[原创]讨论一下VB下面的2个关键字顶部 softbug 发布于:2005-06-2909:44 [楼主][原创]讨论一下VB下面的2个关键字
文章作者:Softbug[E.S.T]
信息来源:邪恶八进制信息安全团队(www.eviloctal)
PS:本文参考了PatrickSteele的<COMInteropExposed>
1.interface
2.implements
interface的意思就是接口的意思,implements的意思就是实现的意思。当你要用vb6开发windows外壳程序或者IE插件的时候用的最多了。
微软在开发程序的时候就意识到程序必须要和过去我们用了8年时间来开发程序的COM一起结合。丢掉了毕竟是浪费。直接入题吧,最关键的一个概念就是:COM总是通过接口被调用。再也没什么简单的
办法可以直接创建COM来调用COm的函数,必须通过接口来完成这些操作。有的时候,很多人用惯了vb,很多操作都是vb帮你代劳了。不是吗?:_)~~
打个比方,当你创建一个公共的类的时候,vb6在后台已经为你准备好了使用这些公共类的接口了。
大家注意:类----COM的包容性。
例子我就照搬PatrickSteele的了:
OptionStrict
PublicSubMoveForward()
...
EndSub
PublicSubFindCar()
...
EndSub
一个公共类,编译成DLL后,用oleview查看一下这个类型库,你将会看到vb创建了接口:"_Robot",同时还有个类:”Robot“,其实这个Robot类就是实现_Robot接口的类,是外部可以真正创建对象的类。
查看右边的IDL语句区:
interface_Robot:IDispatch{
...
HRESULTMoveForward();
...
HRESULTFindCar();
};
coclassRobot{
[default]interface_Robot;
};
我们看到,IDISpatch里面有2个接口定义,这个正是我们的公共类定义的函数。大家注意一下,COM里面的返回类型必须是HRESULT!为什么呢?我也很糊涂,希望知道的朋友能说一下。上面的IDL的第一个语句指出存在某个接口:_Robot。这个接口是vb帮我们创建的。紧接着看下面的叫Robot的coclass,既然是用类来实现接口,coclass里面实际上就列出了他能支持和实现的interface名字,当只有一个接口被实现的时候,我们需要加个[default]在前面。呵呵,多了嘛,总要有个默认值吧。
有心的朋友可能注意到了 [default]关键字了,既然这样我们能实现多个接口吗?答案是可以的。在activedll里面我们再添加一个类模块,加入下面的代码:
OptionExplicit
PublicSubCleanKitchen()
...
EndSub
PublicSubWashCar()
...
EndSub
再把ImplementsIMaid这个东东加到robot这个类文件里面,如下:
OptionExplicit
ImplementsIMaid
PublicSubMoveForward()
EndSub
PublicSubFindCar()
EndSub
PrivateSubIMaid_CleanKitchen()
EndSub
PrivateSubIMaid_WashCar()
EndSub
用oleview查看iDL:
interface_Robot:IDispatch{
...
HRESULTMoveForward();
...
HRESULTFindCar();
};
coclassRobot{
[default]interface_Robot;
interface_IMaid;
};
interface_IMaid:IDispatch{
..
HRESULTCleanKitchen();
..
HRESULTWashCar();
};
coclassIMaid{
[default]interface_IMaid;
};
注意和前面的IDL对比一下,发现了什么了吗。有启发吧。
"_XXX形式的接口都是vb6自动为XXX生成的类"
通过上面的分析我们可以知道,当你要把你的这些东西用到脚本环境当中,比如:aspdll当中,vbscript里面,你就只能存取MoveForward,FindCarmethods这2个方法,不能存取Imail方法,以为default的coclass:IDispath标记到了Robot对象上。
下面我们将探索里面的东东,在离开vb6之前我们还是来总结一下在vb6里面com被创建的时候发生了什么事情:
1.COm是基于接口的东西,任何com里面的调用都必须通过接口。
2.vb6不要你必须在class里面用实现接口,反而,vb6还会在编译的时候自动为你用下划线_接口名的方式帮你在类里面定义。
3.用vb6创建的接口带有default标志的才能在asp里面作为dll函数被调用
里面会发生什么事情:
很多人都觉得把里面的对象暴露出来用到vb6里面,比如建立一个class程序。简单的看看下面的代码:
[VB.NET]
OptionStrictOn
OptionExplicitOn
NamespaceQuickNET
PublicClassBee
PublicSubFindFlowers()
EndSub
PublicSubMakeHoney()
EndSub
EndClass
EndNamespace
[C#]
usingSystem;
namespaceQuickNET
{
publicclassBee
{
publicvoidFindFlowers()
{
}
publicvoidMakeHoney()
{
}
}
}
呵呵,编译一下,看看他到底都做了些什么。注意了,并不是为他们注册为COM对象,反而是为他们创建一个类型库(COMtypelibrary)。跑到VisualStudio.NET的命令提示符下面用下面的命令:
TLBEXP.EXEQuickNET.dll/out:Com.QuickNET.tlb
TLBEXP.EXE是个很好的东西,能把的class输出tlb来。tlb就是类型列表库。换OLEView上场了,打开来看看吧:
coclassBee{
[default]interface_Bee;
interface_Object;
};
interface_Bee:IDispatch{
};
啊,是不是很vb6看到的少了些什么啊,我们可以看到_bee接口,它也是个默认接口。但我们却看到接口的具体声明都没了。如果你此时把这些东西加到vb6的引用窗口里面,你将看到一片空白,vb6总是去寻含有default标志的coclass.
_Objectinterface第一次进入我们的视线,既然在里面,object是任何类型的基类,那么_object接口也将暴露在你开发的任何类里面。反过来想想,TLBEXP.EXE为什么要生成这样一个人不人鬼不鬼的类呢,为什么不干脆就把_bee的所有方法都放进去了,留空做什么啊!
大胆的猜测一下估计是为了不频繁的变动调用方的COM类
型,使调用方采用后期绑定访问的方式。增加了更多的灵活性吧。
话说回来,怎么才能把里面写的方式交给VB6里面的东西来使用呢?大家开动思维,把你所知道的关于vb6和com的知识用到上面去,至少你该知道:
1。接口里面定义的是方法
2。把一个接口做成一个默认的接口
第一个好解决:直接在里面写个接口,加个方法就可以了:
[VB.NET]
PublicInterfaceIBee
SubFindFlower()
SubMakeHoney()
EndInterface
[C#]
publicinterfaceIBee
{
voidFindFlower();
voidMakeHoney();
}
然后简单的实现一个这个接口:
[VB.NET]
PublicClassBee
ImplementsIBee
PublicSubFindFlower()ImplementsIBee.FindFlower
EndSub
PublicSubMakeHoney()ImplementsIBee.MakeHoney
EndSub
EndClass
[C#]
publicclassBee:IBee
{
publicvoidFindFlower()
{
}
publicvoidMakeHoney()
{
}
}
老办法,编译----查看----oleview:
interfaceIBee:IDispatch{
...
HRESULTFindFlower();
...
HRESULTMakeHoney();
};
coclassBee{
[default]interface_Bee;
interface_Object;
interfaceIBee;
};
interface_Bee:IDispatch{
};
呵呵,怎么样,感觉很爽吧。
我靠,IBeeinterface变成了一个标准的COM接口了,它包含了该包含的方法,BeeCoclass实现了这个接口。
在vb6里面,我们引用了它,然后:
DimbeeAsIBee
Setbee=NewBee
bee.FindFlower
bee.MakeHoney
就可以用了。想用开发COM接口的同志有希望了。用为ASP开发组件也不错哟。
这里不得不提的一个问题是:属性。什么叫属性?简单的说:属性就是对声明的描述。我们常提到的types,fields,methods,classes等等啊,在属性里面都有对应的值来描述他们。自从有了属性信息,就连clr里面的代码信息我们都可以用属性来描述。CLR(CommonLanguageRuntime)
TLBEXP.EXE其实可以通过加个开关就能控制输出的COM是否带有默认属性这个玩意。ClassInterfaceAttribute中的ClassInterfaceType.None枚举类型也可以在写代码的时候加到代码中实现输出无default属性的类型来。
见下:
[VB.NET]
OptionStrictOn
OptionExplicitOn
ImportsSystem.Runtime.InteropServices
NamespaceQuickNET
<ClassInterface(ClassInterfaceType.None)>PublicClassBee
ImplementsIBee
PublicSubFindFlower()ImplementsIBee.FindFlower
EndSub
PublicSubMakeHoney()ImplementsIBee.MakeHoney
EndSub
EndClass
EndNamespace
[C#]
usingSystem;
usingSystem.Runtime.InteropServices;
namespaceQuickNET
{
[ClassInterface(ClassInterfaceType.None)]
publicclassBee:IBee
{
publicvoidFindFlower()
{
}
publicvoidMakeHoney()
{
}
}
}
看看oleview:
interfaceIBee:IDispatch{
...
HRESULTFindFlower();
...
HRESULTFindHoney();
};
coclassBee{
interface_Object;
[def
ault]interfaceIBee;
};
为什么还有个默认接口呢,因为虽然程序把_bee接口去掉了。(_XXX这样的接口都是编译器自动生成的),但TLBEXP.EXE会把它到的第一个接口标记为default接口。所以你打算把class暴露给COM用的时候,不妨考虑一下在源代码里面,哪个是第一个实现的接口(他将成为默认接口)。
对GUID的探索
COM的世界也就是GUID的世界。有点开发经验的人都知道,你开发的程序引用的是一个COm组件,这个COM的组件GUID一般是不变的,但如果变了程序必定出现不到组件错误。
我们开发的class虽然可以放到COM里面来用,但每次的更改反复生成TLBEXP.EXE都将为新生成的COM生成一个新的GUID。这对于COM程序来说是个噩耗。
通过下面的代码能使生成的COMguid保持不变。guid的得到不多说,用guidgen生成吧。
[VB.NET]
<Guid("0490E147-F2D2-4909-A4B8-3533D2F264D0")>PublicInterfaceIBee
SubFindFlower()
SubMakeHoney()
EndInterface
[C#]
[Guid("0490E147-F2D2-4909-A4B8-3533D2F264D0")]
publicinterfaceIBee
{
voidFindFlower();
voidMakeHoney();
}
接口有了GUID(UUID),那class也需要自己的GUID.(nnd,COM里面接口都有个自己的标识)。
[VB.NET]
<ClassInterface(ClassInterfaceType.None),_
Guid("03AD5D2D-2AFD-439f-8713-A4EC0705B4D9")>_
PublicClassBee
ImplementsIBee
PublicSubFindFlower()ImplementsIBee.FindFlower
EndSub
PublicSubMakeHoney()ImplementsIBee.MakeHoney
EndSub
EndClass
[C#]
[ClassInterface(ClassInterfaceType.None)]
[Guid("03AD5D2D-2AFD-439f-8713-A4EC0705B4D9")]
publicclassBee:IBee
{
publicvoidFindFlower()
{
}
publicvoidMakeHoney()
{
}
}
这下tblexp能按我们的要求搞定了。
发布COM组件:
通过TLBexp我们毕竟是了解到了组件到COM的转换过程,但真正要用到COM组件,我们必须得把它搞的跟其他COm组件一样,比如:可注册。
我相信你属于:regsvr32
这个东西是拿来注册和反注册com组件的。在世界里面regsvr32被取代了。哈哈。其实的功能更强大。比如/tlb开关就能实现tlbexp的功能。
REGASMmyassem.dll/assem.tlb
========================================
再探索:
.NETassembly现在变成了COM后,任何的COM对象调用都将造成NETruntime运行库被加载。
框架就会去定位框架集合。那么说,就算你运行在你的COM环境下,的法规你还是要被尊守的。
1。GlobalAssemblyCache(GAC)会被检查
2。本地目录会被检查。
看看上面的2个选项,第二个选项仿佛很容易,但不是很灵活,把需要的框架集copy到com的运行目录就可以了。但当你在vb6IDE环境里编译的时候这个目录又变成vb6的安装目录了。靠,拷贝来拷贝去的,麻烦
不麻烦啊。所以嘛,把框架集放到GAC里面是最好的解决办法。当把你的框架集放到GAC里面的时候要注意:
1。你必须知道你的这个框架集的固定版本号.
2。一对强命名的KEY
*号会使gac自动生成一个版本号
接下来我们来生成个强命名的key:
sn-kmykey.snk
到编译选项里面指定这个key,然后重编译,安装:
gacutil-Imyassembly.dll
ok!vb里面你可以自由的调用了,不要再去管什么框架集了!哈哈~~
该文有带翻译的性质,但也有自己的心得和体会。同时会发布在www.microie和EST的Vb版面上面。
[此贴被EvilOctal在06-29-200514:17重新编辑](c)Copyleft2003-2007,EvilOctalSecurityTeam.
ThisfileisdecompiledbyanunregisteredversionofChmDecompiler.
Regsiteredversiondoesnotshowthismessage.
贴吧vb是什么意思YoucandownloadChmDecompilerat:www.zipghost/
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论