COM和套间(Apartments) 1 - 基本知识

COM笔记-CoCreateInstance COM笔记-CoCreateInstance 很有用的 开发参考 比如 CoCreateInstance(CLSID_VideoRenderer,0,CLSCTX_ALL,IID_IBaseFilter,(void**)&pPreview);这里面的参数是什么意思 ?这个文档可以告诉你。。 欢迎联系:393877568 立即下载
Overview
COM技术过时了吗?这句话也对也不对。从技术上讲,确实COM的使用率在下降,但是从思想上来说,COM的面向接口的思想正在被Java和.NET发扬光大。那我们还需要和COM打交道吗?这取决于你工作的领域。虽然现在微软的平台在慢慢向着.NET迁移,不过,在维护原有非托管代码,编写和Windows系统组件打交道的程序,以及使用CLR调用非托管代码的时候,COM或多或少都是不可避免的。与COM打交道就没法不谈到套间(Apartments)。套间是COM中一个非常有用然而也非常难以理解的一个概念,可以说COM中的很多问题都和套间有关,理解了套间,离完全理解COM就更近了一步,本文将分若干次讨论套间的基础知识以及在.NET中的应用。
 
什么是套间(Apartments)
套间是COM为了简化对象对多线程的支持而推出的一套机制,用于指定线程和COM对象的多线程特性,并且对不同特性的套间之间的调用提供同步支持,保证不同多线程特性的对象之间可以互相正确调用而不会引入同步问题,简化编程(实际上可能搞得更复杂了)。比如,如果某个对象编写的时候忘记考虑多线程,或者没有时间考虑,或者没有必要提供实现多线程的支持,这个时候可以将对象指定为STA,让COM自动管理对该对象的调用,保证对象可以被正确调用,即使是多线程的调用也会被串行化(依次调用,而非同时调用)。反之,如果一个对象支持多线程调用,那么它可以被标记为MTA,COM会允许对其进行多线程的调用。
对于套间需要注意下面几点:
<!--[if !supportLists]-->1.     <!--[endif]-->套间并不是一个真实存在的一个区域,而是一个逻辑的概念
<!--[if !supportLists]-->2.     <!--[endif]-->套间表明了位于套间的代码的多线程特性,决定了以下几点
<!--[if !supportLists]-->a.     <!--[endif]-->代码本身允许单线程调用还是多线程调用
<!--[if !supportLists]-->b.     <!--[endif]-->代码创建COM对象拿到的是Proxy还是原始的指针(关于Proxy请参见后面的Proxy一节)
<!--[if !supportLists]-->c.     <!--[endif]-->代码调用同一套间的COM对象是通过原始指针,不同套间则通过Proxy
<!--[if !supportLists]-->3.     <!--[endif]-->线程必须属于某个套间,这表明了线程本身的多线程特性,也就是线程会对COM对象进行多线程的调用还是单线程的调用。比如,一个线程位于STA中,那么该线程只适合直接调用支持单线程调用的、同一套间的COM对象,其他COM对象则需要通过Proxy来间接调用,什么是Proxy后面会讲到。同时,线程所处的套间还决定了创建对象的时候所获得的对象是对象本身还是Proxy。线程在同一时间内只能属于一个套间或者不属于某个套间,但是线程可以在不同时间内属于不同的套间。典型的例子有,线程调用了CoInitialize,然后再调用CoUninitialize退出套间,之后又调用了CoInitialize进入了另外一个套间,此外,线程临时进入NTA也是一个例子。下面会讲到。
<!--[if !supportLists]-->4.     <!--[endif]-->COM对象也必须属于某个套间,同样的这决定了COM对象的多线程特性,和上面类似。COM对象不会从一个套间迁移到另外一个套间,如果这个套间被释放,那么这个对象也同时被释放,这个事实对于STA套间尤为重要。
<!--[if !supportLists]-->5.     <!--[endif]-->跨套间必须要通过Proxy,这是COM保证套间能够工作的基础。后面Proxy一节会谈到为什么是这样
 
套间(Apartments)的类型
常见的套间有STA和MTA,此外Win2000中引入了一种新的套间NTA。STA用于单线程,MTA用于多线程。而NTA则被称为线程无关(Thread-Neutral)的多线程。简单来讲,STA,MTA,NTA的区别请见下表:
 
跨套间可以在任意线程上执行
线程可以属于该套间
多线程特性?
需要消息循环?
进程中套间个数
套间中线程个数
STA
No
Yes
单线程
Yes
无限制
1
MTA
No
Yes
多线程
No
1
无限制
NTA
Yes
No
多线程
No
1
无限制
 
在文章后面将详细解释各个套间的特点、区别以及编程的有关注意事项。
 
线程和套间
线程通过调用CoInitialize/CoInitializeEx进入套间,然后通过CoUninitialize退出套间。进入套间可能会导致套间被创建,同样CoUninitialize调用会导致套间被释放。CoInitialize和CoUninitialize的调用次数必须Match,类似AddRef/Release。
CoInitialize只能进入STA套间,而CoInitializeEx可以通过传入参数进入不同的套间,传入COINIT_APARTMENTHREADED进入STA,而传入COINIT_MULTITHREADED则进入MTA。当调用了CoInitialize/CoUnintiialize之后,线程便属于了这个套间,如果指定STA,那么新的STA总会被创建,如果指定的是MTA,那么如果MTA不存在的话将创建一个新的MTA。细心的朋友可能已经注意到了,上面提到了3种套间,那么NTA跑哪去了呢?其实一个线程并不能属于NTA,线程只可以临时进入NTA,NTA中只可以存在对象。
 
对象和套间
COM对象总是属于某个套间的。COM对象在注册表里面可以通过ThreadingModel属性指定对象所期望的套间类型,有效的值有:
属性值
含义
Main (缺省值)
主STA,也就是第一个创建的STA
Apartment
STA
Both
STA或者MTA都可以
Free
MTA
Neutral
NTA
需要说明的是,从套间角度来讲主STA和其他非主STA没有区别,只是特别指定是主STA而已。
 
线程套间和对象套间的关系
大家可以看到,线程也有套间,同时对象也有套间,那么这两者有何关系呢?这是一个比较Confusing的一个问题。事实上,简单来讲,对象的套间设置决定了对象所处的套间,而线程的套间决定了线程的套间。OK,看到这里你可能会说,这不是等于没说吗?呵呵,这确实是最本质的区别,然而,另外这两个套间的设置还决定了另外一点,即套间和对象是否兼容,是否处于同一套间。这很重要,因为这决定的了CoCreateInstance所返回的对象的指针是原始指针还是Proxy(这里讨论进程内的情况,进程外则总是Proxy)。举例来讲,如果线程的套间是STA,并且对象的套间也是STA,那么这个对象就被创建在线程所位于的STA中,反之,如果线程的套间是STA,而对象的套间是MTA,那么对象则被创建到唯一的MTA套间中,线程拿到的是对象的Proxy(代理),而非原始指针。代理的概念后面会讲到。
MSDN中有一张表,这里稍作修改,列在下面:
 
对象套间=Main
对象套间=Apartment
对象套间=Both
对象套间=Free
对象套间=Neutral
线程套间=主STA
主STA
当前线程套间
当前线程套间
MTA
NTA
线程套间=STA
当前线程套间
当前线程套间
当前线程套间
MTA
NTA
线程套间=MTA
主STA
STA
当前线程套间
MTA (当前线程的套间)
NTA
线程套间=NTA
主STA
STA
NTA
MTA
NTA
 
跨套间(Cross-Apartment),Proxy/Stub以及Marshalling
套间调用本套间内的对象不需要Proxy,则是直接调用,和普通C++的虚函数调用并无区别。COM强大的地方(也是不太容易理解的地方)在于可以通过Proxy来实现线程安全。我们还是用一个实际的例子来考虑这个问题,假如两个MTA线程同时调用一个STA中的对象A,这个对象因为位于STA中,因此它编写的时候没有考虑到多线程问题,因此需要保护。如果两个MTA线程同时通过A的指针pA来调用A的方法,显然这个时候是无法提供线程安全的保护的。COM的解决方案是,让这两个MTA线程拿到的对象A并非对象A本身,而是A的Proxy。所谓Proxy,指的是该对象并非是实际对象,而是一个代理,负责将调用转发到它所代理的对象A,代理本身并不执行实际操作。而在服务器端,有一段代码称之为Stub,负责接受Proxy发来的请求,并实际执行这个请求。换句话说,Proxy总是在客户端,而Stub则是在服务器端。

<!--[if !vml]--><!--[endif]--> 

SmartFusion从FPGA到ARM(八)——CoreUARTapb的使用 文章目录1.CoreUARTapb简介2.添加CoreAPB3总线IP核3.添加CoreUARTapb4.驱动代码实现5.库函数简介6.串口printf函数实现7.串口接收轮询和中断方式 系列教程:SmartFusion从FPGA到ARM系列教程 1.CoreUARTapb简介 对于SmartFusion2来说,MSS_UART的管脚可以任意分配,但是对于SmartFusion来说,MSS_UART的管脚是固定的不能分配: 109-UART0_RX 110-UART0_TX 111-UART1_RXD 11 阅读详情

相关推荐

Windows下QT5.15.2安装MQTT模块全攻略(附分支选择避坑指南)

本文详细介绍了在Windows环境下为QT5.15.2安装MQTT模块的完整流程,包括环境准备、源码获取、编译配置及项目集成等关键步骤。特别针对分支选择、依赖项处理和常见错误提供了实用解决方案,帮助开发者高效完成MQTT模块的安装与调试,适用于物联网开发场景。

weixin_29224589的博客 466

CoCreateInstance具体内部实现

CoCreateInstance(....)     {     //.......     IClassFactory *pClassFactory=NULL;     CoGetClassObject(CLSID_Object, CLSCTX_INPROC_SERVER, NULL, IID_IClassFactory, (void **)&pClassFactory);     p

IT民工 7760

Xilinx PL端DP显示接口开发实战(一)——环境搭建与硬件选型

本文详细介绍了Xilinx PL端DP显示接口开发的环境搭建与硬件选型实战经验。从Vivado和Vitis 2021.1版本的软件安装要点,到DP141和MCDP6000芯片的选型建议,再到DP1.4接口的RX/TX方向开发关键点,为开发者提供了全面的技术指导。文章还分享了IP核配置、BD原理图设计以及常见问题排查的实用技巧,帮助开发者高效完成Xilinx DP接口开发项目。

weixin_29250573的博客 174

CoCreateInstance 解析

CoCreateInstance 创建组件的最简单的方法是使用CoCreateInstance函数。 在COM库中包含一个用于创建组件的名为CoCreateInstance的函数。此函数需要一个CLSID参数,在此基础上创建相应组件的一个实例,并返回此组件的某个接口。   CoCreateInstance 的声明 HRESULT _stdcall  CoCreateInstance(

雄鹰 工作室 3221

从零搭建VGGNet

在 forward 方法中实现了前向传播过程,包括卷积、激活、池化和平铺操作,最后通过全连接层得到分类结果。使用 torch.onnx.export 将模型导出为 ONNX 格式的文件 vgg.onnx。导出 ONNX:将模型导出为 ONNX 格式,便于在其他平台或框架中使用。定义 VGG 网络:构建了一个包含多个卷积层、池化层和全连接层的网络。使用 torch.save 将整个模型保存为 vgg.pth 文件。前向传播:对输入数据进行前向传播,得到输出结果。保存模型:将模型保存为 .pth 文件。

开源驱动,创造价值;坦诚清晰,快速失败;让复杂可计算。 521

RC模型车多电机驱动方案:从电调PWM原理到四电机安全连接实战

在电机控制领域,PWM(脉冲宽度调制)是实现精确调速的核心技术。其原理是通过调节固定周期内高电平的脉宽来编码控制指令,进而驱动电子调速器(电调)改变输出功率。这项技术对于需要多电机协同工作的场景,如RC模型车的差速转向或重型负载驱动,具有关键价值。它能实现动力的精细分配与同步,提升车辆的可控性与通过性。在实际应用中,为确保系统稳定,必须关注电流分配与信号同步问题。例如,通过为每个电机配备独立电调并采用信号并联(Y线)的方式,可以构建可靠的四电机驱动系统。这种方案能有效避免因单个电调过载或电机反电动势不一致导

weixin_30664615的博客 381

关于C++调用::CoCreateInstance创建对象提示没有注册类的问题的解决

关于C++调用::CoCreateInstance创建对象提示没有注册类的问题的解决

Whoo_的博客 3729

IPSec Over GRE和GRE Over IPSec技术

IPSec Over GRE 和 GRE Over IPSec 一. 技术介绍 IPsec     主要作用是对数据进行加密,因为他能提供所有有时候被单独用作实现加密的一种方法!IPsec建立的是一个逻辑隧道,并不是真正意义上的隧道!并且不能提供路由功能,因为IPsec不支持非ip流量,也不支持广播(组播)! GRE     (通用路由封装)能很好的提供一个真正意义上的点对点的隧道,GRE是一种三层VPN封装技术。GRE可以对某些网络层协议(如IPX、Apple Talk、IP等)的报文进行封装,使封装后

qq_56228347的博客 9870

CoCreateInstance 跟踪笔记

CoCreateInstance用于创建一个COM Class Object,我从0开始分析这个函数并且解释一个个参数,让你对COM对象的创建有一个根本性的全面认识。 程序传入OBJECT的CLSID和IID再call CoCreateInstance后(为什么需要CLSID和IID,等下再说),CoCreateInstance从注册表里面根据CLSID找到对应的dll文件,并使用LoadL

a1875566250的专栏 4656

无人机:DJI Matrice 600 Pro_(8).DJI_Matrice_600_Pro_负载能力

在一些高级应用场景中,可能需要自定义开发负载设备。

zhubeibei168的博客 1341

什么是 SAP ABAP AMDP?

SAP HANA是SAP开发的一种内存数据库管理系统,它具有出色的性能和处理大规模数据的能力。为了充分利用SAP HANA的性能,SAP引入了AMDP技术,以便将数据库操作推送到数据库服务器执行,从而减少数据传输和处理时间。AMDP方法通常需要输入参数和输出参数。输入参数用于传递数据到SQLScript代码,而输出参数用于接收SQLScript代码的结果数据。ENDMETHOD.ENDCLASS.我们定义了一个输入参数来传递销售订单数据,以及一个输出参数来接收计算结果。ENDMETHOD.

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 908

COM笔记-类厂

CoCreateInstance实际上并没有直接创建COM组件 ,而是创建了一个被称作是类厂的组件。而所需的组件正是由些类厂创建的。类厂组件的唯一功能就创建其他的组件。创建组件的标准接口是IClassFactory,用CoCreateInstnce创建的组件实际上是通过IClas

http://www.softwareace.cn 王牌软件 1525

后悔没早点知道!用AI只需四步,一次性讲清高质量论文引言写法(附公式+AI指令)

帮我写SCI 论文撰写引言的“研究背景与重要性”,要求从本研究所属领域的小背景切入,使用现在时态描述该领域的总体状况与发展趋势,突出其在学术研究、实际应用或社会层面的重要价值,并通过一个吸引人的钩子开头,如关键事实、现实问题或学术热点,引导读者关注本主题的重要性。梳理你所在领域和你研究相关的关键成果,但不能罗列所有文献,重点抓核心脉络,这部分最重要的实际上是让你了解别人的研究脉络,然后在每个关键的节点上,引用几篇关键参考文献作支撑,来体现你对领域的熟悉度就可以了。3)研究缺口模糊,没法突出问题的真实价值;

qq_64378896的博客 116
上一篇: 指针与引用的区别
下一篇: 2006年全球顶级杀毒软件排名 BitDefender居首
Devillyd
博客等级 码龄23年 58粉丝 101原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值