参考&&引用
起因
看来人总是健忘的,只能隐约的记得是因为一个关于C#封装的COM接口的问题。于是自己动手封装实现了一下,接着就引发了下面一系列的问题。
一场因为想偷懒引发的那些事——COM的那些事1
一场因为想偷懒引发的那些事——COM的那些事2
一场因为想偷懒引发的那些事——WinDbg的简单用法
一场因为想偷懒引发的那些事——记C# Com接口调用的相关姿势
一场因为想偷懒引发的那些事——C#调用COM的一个进阶使用方式
一场因为想偷懒引发的那些事番外——结构体的一些事
这是一个开头
上一篇大概写了一下COM 接口的结构、布局,这次就简短的说一下怎么创建一个COM的对象。
创建一个COM 对象主要有两种方式:
- 使用公开的方法。
- 使用
CoCreateInstance
这个通用创建方法。
因为我喜欢吃柚子 ,所以就拿水果来举个例子,例如叫IFruit
。下面就可以开始创建水果这个对象的过程了。
使用方法一
一般来说使用这种方式都会有一个方法 例如本次的叫做
HRESULT CreateFruit(IFruit** iFruit)
在C++中调用方式就可以是这样
IFruit* fruit=nullptr;
auto result=CreateFruit(&fruit);
if(SUCCEEDED(hr))
{
std::cout<<"get a fruit"<<std::endl;
}
else
{
std::cout<<" fail "<<std::endl;
}
结合上一篇可以得知, CreateFruit
这个方法 开辟了一块内存空间,这里方式IFruit的一个函数表,传入 IFruit*
的地址,则是CreateFruit
让 IFruit*
指向了该地址。
Windows 中有不少这样的函数,例如:
SHSTDAPI SHCreateItemFromParsingName(_In_ PCWSTR pszPath, _In_opt_ IBindCtx *pbc, _In_ REFIID riid, _Outptr_ void **ppv);
//这里SHSTDAPI为宏, 定义为 #define SHSTDAPI EXTERN_C DECLSPEC_IMPORT HRESULT STDAPICALLTYPE
//展开即为 extern "C" __declspec(dllimport) HRESULT __stdcall
C# 中想要调用这个方法就需要对其进行封装, 简单的封装可以为这样
[DllImport("Shell32.dll")]
public extern static int SHCreateItemFromParsingName([In][MarshalAs(UnmanagedType.LPWStr)] string pszPath, [In] IntPtr pbc,
[In][MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IntPtr ppv);
然后对其调用,即可以根据传入的riid得到不同的COM接口对象。
使用方法二
在使用CoCreateInstance
这个方法之前,先看看其定义:
HRESULT CoCreateInstance(
REFCLSID rclsid, //要创建对象的guid
LPUNKNOWN pUnkOuter, //表示这个对象是不是属于aggregate,Null代表不是 ps:aggregate这里指COM重用方式的一种,其他的还有Containment
DWORD dwClsContext, // 指定对象运行的上下文,例如:CLSCTX_INPROC_SERVER 同一进程.CLSCTX_LOCAL_SERVER不同进程但是同一台电脑
REFIID riid, // 这个对象实现的接口
LPVOID *ppv //接收指向这个接口的指针,因为改方法是通用方法所以此类型不能为强类型,只能是void**
);
例如,如果要创建一个名为柚子
的对象,使用即为:
IFruit* fruit=nullptr;
CoCreateInstance(CLSID_Pomelo,NULL,CLSCTX_INPROC_SERVER,IID_IFruit,(void**)&fruit)
至此,就可以拿着这个IFruit 进行榨汁
、做罐头
等水果相应的操作了。
结束
这篇只是大致介绍了一下COM对象的创建方式,很多相关的细节没有写,以后有空(等我学习完)再来补充细节吧😅
接下来就是此偷懒系列的终篇了,终于要结尾了。