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]--> 

SWIFT报文实战指南:从MT700到MT799的信用证操作全解析 本文深入解析了国际贸易中信用证操作的核心SWIFT报文流程,从开证的MT700到各类通知、修改及结算报文(如MT707、MT730、MT754、MT732/734等)。通过实战案例与关键字段拆解,指导外贸与银行从业者精准处理报文,规避风险,并探讨了利用自动化工具提升处理效率的方法,助力保障跨境交易顺畅。 阅读详情

相关推荐

银河麒麟桌面操作系统V10(SP1)ssh服务安装与配置

在国产化的大背景下,各种国产操作系统逐步进入运维人员的视野,ssh作为linux远程连接工具,是运维人员必需的工具之一。本文主要介绍在银河麒麟桌面操作系统V10(SP1)上安装和配置ssh服务。

zhengshaolin128的博客 7806

CoCreateInstance具体内部实现

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

IT民工 7760

iTerm2+oh-my-zsh最全配置

iTerm2+oh-my-zsh最全配置安装前先看效果图一.安装[iTem2](https://iterm2.com/)二.安装[oh-my-zsh](https://ohmyz.sh/)三.安装[Powerline](https://powerline.readthedocs.io/en/latest/installation.html)四.安装 [Meslo](https://github.com/powerline/fonts) 字体库五.安装agnoster主题六.安装语法高亮七.安装代码补全插件八

xinximo的博客 2610

CoCreateInstance 解析

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

雄鹰 工作室 3221

px3 有感分析

px3 后续分析

qq_39707917的博客 3115

宋浩线性代数笔记

Miao-A-SongHao-Linear-Algebra-Notes bilibili 宋浩老师 “惊叹号” 系列 《线性代数》网课 笔记及时间点目录 Github项目地址:https://github.com/cy69855522/Miao-A-SongHao-Linear-Algebra-Notes ???? 前言 我发现吧,线代没记笔记真不行。 浩浩学习,天天向上。数学网课推荐????宋浩老师的免...

Knife丶小刀博客 4万+

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

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

Whoo_的博客 3729

SOC设计必看!Tessent DRC检查中最容易踩的5个坑(附解决方案)

本文针对SOC设计中Tessent DRC检查的常见问题,详细分析了5个最易忽视的陷阱,包括时钟域交叉、扫描链虚连、多电压域规则等,并提供专业解决方案。特别针对芯片设计中的DFT验证难点,分享了经过验证的调试方法和Tessent工具使用技巧,帮助工程师提升DRC检查效率。

weixin_29280657的博客 496

CoCreateInstance 跟踪笔记

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

a1875566250的专栏 4656

NVIDIA Isaac Lab 入门教程(一)

Isaac Lab 是一个用于机器人学习的统一模块化框架,旨在简化机器人研究中的常见工作流程(如 RL、从演示中学习和运动规划)。它建立在英伟达 Isaac Sim 的基础上,利用最新的仿真功能实现逼真的场景和快速高效的仿真。该框架的核心目标是Isaac Lab 的主要功能包括:由 PhysX 提供的快速准确的物理模拟、用于矢量化渲染的平铺渲染 API、用于提高鲁棒性和适应性的域随机化,以及对在云中运行的支持。有关该框架的更多信息,请参阅论文[MYY+23]。

机器人控制与仿真应用 8217

搬运机器人系列编程:KUKA KR QUANTEC_(2).KUKA KRL语言编程基础

定义一个函数END!调用函数PRINT "结果: ", result!定义一个过程PRINT msgEND!调用过程printMessage("欢迎使用 KUKA 机器人")!定义搬运零件的起始位置和目标位置!定义焊接路径的各个点!定义喷涂路径的各个点KUKA Robot Language (KRL) 是一种专门为工业机器人设计的编程语言,具有结构化编程、丰富的库函数、实时性以及集成性等特点。

zhubeibei168的博客 1246

COM笔记-类厂

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

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

运行codex时出现登录失败:failed to start login server: 以一种访问权限不允许的方式做了一个访问套接字的尝试。 (os error 10013) 解决方案

本文主要介绍了运行codex时出现登录失败:failed to start login server: 以一种访问权限不允许的方式做了一个访问套接字的尝试。 (os error 10013) 解决方案,希望能对使用xx的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案

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

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值