ATL揭秘之“对象创建”篇
程 化
1 问题
当我们用VC++ ATL工程创建了一个COM工程,实现了一个自己的COM对象,又在另一个程序中CoCreateInstance这个COM对象时,不知你是否想过这样的问题:COM对象是用C++类对象实现的,但是,我们从来没有在自己的代码中创建这些C++类对象——比如,“new”这些对象。那么,实现COM对象的C++对象是由谁,何时,以及如何创建的呢?
当然,简单而且正确的回答是:ATL在幕后帮助我们完成了这些工作。如果你不想了解ATL的工作细节,这样的回答应该是足够了。然而,ATL本身的思想就是“白盒”操作,想要用好ATL,就应该尽量多地了解ATL的工作细节。所以,搞清楚这个问题还是很有必要的。
想到这个问题后,出于懒惰的天性,我首先上网,试图找到别人对于这个问题的讲述,然而,大家要么讨论C++对象,要么讨论ATL其他的机制,似乎没有人特别关注ATL COM对象的创建过程,更比较少有人留心ATL如何将COM对象创建过程转换到C++对象创建过程上。
在研究这个问题的过程中,我逐渐发现这个问题很有意思,对这个问题的完整回答涉及了ATL相当多的基础结构。弄清楚了这个问题,对ATL的了解也会加深不少。
下面,我们就一起开始ATL对象创建揭秘之旅。
2 “对象”探讨
既然谈“对象创建”,则有必要对“对象”这个概念作一点讨论。在实际工作中,我感觉不少人对“对象”这个概念有不少误解;对“COM对象”也没有清晰的认识。
2.1 对象性质
这似乎是老生常谈了。对象性质,不就是“封装、继承、多态”这三个陈词滥调吗?然而,孔老夫子教导我们说:“温故而知新”。真理往往就蕴含在陈词滥调中。经过这些年的软件生涯,我对这句“陈词滥调”似乎有了更多地理解:
首先,“对象性质”是个独立的概念,也就是说,凡是具备了这个性质的东西就可以被称作对象。因此,一来“对象”不一定要用面向对象的语言编写,二来“对象”也可以具备各种环境下的语义——面向对象语言生成的对象是“编程语言”语义下的对象,如“C++对象”; 面向组件的开发生成的对象是“组件环境”语义下的对象,如“COM对象”。
其次,对象性质中的“继承”、“多态”需要好好斟酌。
什么是“继承”?是不是一定要用“CMyObject::CBaseObject”这样的语法才叫继承?当然不是,“继承”应该是对“对象层次结构”的有效处理。只要能够有效地处理对象层次结构,使低层对象能够自动具备高层对象的特性、行为,就应该可以被叫做“继承”。“CMyObject::CBaseObject”干的是什么事?不就是把CBaseObject的成员变量复制给了CMyObject,并且使CMyObject的对象能够调用CBaseObject的公有和保护方法吗?
再说“多态”。C++语言说“多态”就是支持虚函数调用,这样讲对,但是局限在C++语言本身上。“虚函数调用”是某些语言的特性,难道没有虚函数的语言就无法支持多态了?其实“多态”这个词本身译得很好,直抒其意——“多姿多态”。“多态”本质上是“运行时决定行为”。只要能够在运行时才决定如何行动,而不是在编译时决定,就是“多态”。
综合看来,“继承”和“多态”都不是面向对象语言的专利,其他的语言,只要能够通过某种机制实现这些特性,就可以实现“对象”。
2.2 COM对象
COM规范对于COM对象如何做到“封装、继承、多态”有自己的规定。该规定不依赖具体语言,不依赖具体的操作系统环境,所以,我们说COM规范是语言中立和平台中立的(当然,提供平台的人并不中立,这和规范的中立是两码事)。
-
“封装”:COM对象只处理行为封装,其工具是“接口”;
-
“继承”:COM的继承不是源代码级别,是二进制代码级别。COM对象提供了两种方式来继承对象的二进制代码——“包容”和“聚合”;
-
“多态”:COM的“运行时决定行为”能力来自不同对象实现同一接口。使用COM的统一方式——QueryInterface,我们可以找到不同COM对象对同一接口的实现,从而实现“运行时决定行为”。
当然,COM对象除了这老三样之外,还要其他性质,其中最重要的就是对象的“生命周期管理”。“生命周期管理”通过AddRef和Release这两个“引用计数”函数实现。
3 ATL COM对象
ATL实现COM对象的基本思路是:针对不同的COM对象性质,分层处理。不同的ATL类层次处理特定的COM对象特性。
ATL COM对象的层次结构如下图所示:

<shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 117pt; HEIGHT: 4in" fillcolor="window" type="#_x0000_t75"><imagedata o:title="Class_diagram_Object" src="file:///C:%5CDOCUME~1%5Choward%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image001.png"></imagedata></shape>
从上图可以看到:
-
最基础的类是CComObjectRootBase。该类除了提供InternalQueryInterface方法外,还实现了若干帮助方法可供最终派生类CComObject调用;
-
CComObjectRootEx是个模板类。该类根据不同的线程模型生成足够线程安全的InternalAddRef和InternalRelease函数。为什么只提供一个CComObjectRootEx类呢?我觉得主要的原因是:CComObjectRootBase实现的InternalQueryInterface不涉及对类成员数据的线程保护,不涉及线程安全因素;CComObjectRootEx的InternalAddRef和InternalRelease方法则和线程安全密切相关,故CComObjectRootEx有必要作为模板类实现。将这两个类揉到一起实现反而显得不清晰;
-
我们自己定义的类直接从CComObjectRootEx继承,根据需要选择不同的线程模型;
-
ATL最后实际创建的COM对象是CComObject、CComAggObject等类的实例。这些类负责真正实现QueryInterface、AddRef和Release方法,具体选择哪个类根据宏定义来决定。具体在哪里定义什么宏在4.3节会讲到。
4 ATL COM对象创建——内部机制
所谓内部机制,指的是类厂创建COM对象的过程。由于类厂也在COM对象的实现类中实现,所以,类厂对象创建相应COM对象的过程可以看作是COM对象的内部过程。
正是在这个内部机制中,“COM对象创建”这个动作被转换到“C++对象创建”这个动作上。
下图是对内部机制的简单勾勒:

<shape id="_x0000_i1026" style="WIDTH: 277.5pt; HEIGHT: 190.5pt" fillcolor="window" type="#_x0000_t75"><imagedata o:title="Class_diagram_Object_Creation" src="file:///C:%5CDOCUME~1%5Choward%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image003.png"><font size="3"></font></imagedata></shape>
从这幅图中可以看到,内部创建主要涉及三个类的交互作用,它们是:CComCreator,CComClassFactory和CComCoClass。下面就对这三个类分别讲述。
4.1 CComCreator——COM对象创建器
COM规范要求用类厂来创建COM对象,其目的是使COM对象能够控制自己的创建过程(“类厂”设计模式的典型应用)。由于类厂对象本身也是一个COM对象,所以,ATL为了统一COM对象的创建过程,封装了一个CComCreator类。ATL CComCreator这个类的作用很单纯,正如其名字所表示的——创建COM对象。该类包装了一个CreateInstance静态方法(之所以是静态方法,因为该方法要放到_ATL_OBJMAP_ENTRY中,后面会讲到),正是在CComCreator的CreateInstance方法中,ATL COM对象创建被转换到具体的C++对象创建上。由于这个类如此重要,因此有必要列出这个类的实现:
template <class T1>
class CComCreator
{
public:
static HRESULT WINAPI CreateInstance(void* pv, REFIID riid,
LPVOID* ppv)
{
ATLASSERT(*ppv == NULL);
HRESULT hRes = E_OUTOFMEMORY;
T1* p = NULL;
ATLTRY(p = new T1(pv))
if (p != NULL)
{
p->SetVoid(pv);
p->InternalFinalConstructAddRef();
hRes = p->FinalConstruct();
p->InternalFinalConstructRelease();
if (hRes == S_OK)
hRes = p->QueryInterface(riid, ppv);
if (hRes != S_OK)
delete p;
}
return hRes;
}
};
其中,底色是黄色的那句代码就是实际创建C++对象的代码。看到熟悉的“new”了。
从这个类是模板类也可以看出,ATL中所有的COM对象创建,最终其实都是由CComCreator类负责。比如,创建COM对象可以用CComCreator<CComObject>的形式;创建类厂类可以用CComCreator<CComClassFactory>的形式。后面那个CComCreator的CComClassFactory就是我们说的类厂类。
4.2 CComClassFactory
每个COM对象类都有一个自己的类厂类,专门负责创建该类的类对象。在ATL中,缺省的类厂类是CComClassFactory。类厂类也有一个CreateInstance方法,该方法调用类厂类保存的COM对象类的CComCreator的静态CreateInstance函数指针,创建相应的COM对象。
4.3 CComCoClass
CComCoClass是一个非常重要的ATL实现类。基本上我们自己的类都要从CComCoClass继承。为什么?因为CComCoClass定义了两个宏:
DECLARE_CLASSFACTORY()
DECLARE_AGGREGATABLE(T)
前一个宏定义了_ClassFactoryCreatorClass——类厂类的创建者,该创建者可以使用不同的类厂类作为模板参数,为COM对象的创建过程提供了灵活性;后一个宏定义了_CreatorClass——COM对象类的创建者,该创建者使用CComObject类族的不同类作为模板参数,为COM对象QueryInterface、AddRef和Release函数的实现方式提供了不同选择。
通过继承CComCoClass,我们自己的类就继承了CComCoClass对类厂和最后生成类的实现。
CComCoClass也有一个CreateInstance方法。该方法纯粹是对_CreatorClass::CreateInstance方法的包装。因为我们的类继承自CComCoClass,经过这个包装后,就可以直接以CUserClass::CreateInstance的方式来调用CComCreator::CreateInstance了。
上图看到的三个CreateInstance方法,各有各的意义,这里总结一下:
CComCreator::CreateInstance
|
真正创建C++对象的所在
|
CComClassFactory::CreateInstance
|
调用_CreatorClass::CreateInstance
|
CComCoClass::CreateInstance
|
调用_CreatorClass::CreateInstance
|
至此,估计大家一定有一个疑问:_CreatorClass::CreateInstance由类厂对象的CreateInstance调用;_ClassFactoryCreatorClass::CreateInstance又由谁来调用呢?这就是我们要进入的下一个论题:ATL COM对象创建的外部机制。
5 ATL COM对象创建——外部机制
所谓“外部机制”,指的是应用程序创建ATL COM对象类厂的过程。应用程序并不关心COM对象是MFC实现方式的还是ATL实现方式的,它永远使用CoCreateInstance这类API函数,通过类厂创建COM对象。在ATL下,应用程序对CoCreateInstance的调用,是如何转换到对ATL COM对象类厂CreateInstance方法的调用的呢?
5.1 COM服务器
COM对象不能凭空存在,它必须存在于操作系统的某种可执行文件中。由于只有Windows操作系统支持COM规范,很自然地,COM对象存在于Windows操作系统的可执行文件中。
Windows操作系统的可执行文件,其格式主要有两种:EXE和DLL。这里就不必要说这两种文件格式的区别了吧。如果不知道,这篇文章你估计也看不懂了。
能够生成COM对象的可执行程序叫COM服务器。EXE是进程外服务器,DLL是进程内服务器。这里只讨论DLL的情况。由于DLL本身只能通过对外输出的函数与外界交互,所以,DLL作为COM服务器也是通过四个输出函数来体现其服务器的作用。这就是著名的四个函数:
-
DllRegisterServer;
-
DllUnregisterSever;
-
DllGetClassObject;
-
DllCanUnloadNow;
<wrapblock><shape id="_x0000_s1026" style="MARGIN-TOP: 28.5pt; Z-INDEX: 1; MARGIN-LEFT: -36pt; WIDTH: 7in; POSITION: absolute; HEIGHT: 284.65pt; mso-position-horizontal: absolute; mso-position-horizontal-relative: text; mso-position-vertical: absolute; mso-position-vertical-relative: text" type="#_x0000_t75" o:allowincell="f"><font size="3"><imagedata o:title="COM Server" src="file:///C:%5CDOCUME~1%5Choward%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image005.png"></imagedata><wrap type="topAndBottom"></wrap></font></shape></wrapblock>
COM服务器的工作机制可以用下图来表示:

COM服务器的重要功能可以归纳为三个:
-
管理服务器的生命周期;
-
管理服务器和对象的注册;
-
获得COM对象的类厂;
我们可以看到,作为COM服务器的DLL,用四个函数来完成这三个方面的功能。四个输出函数的调用时机分别如下:
-
DllRegisterServer、DllUnregisterServer:使用regsvr32程序注册和反注册服务器时;
-
DllCanUnloadNow:当调用CoFreeUnusedLibraries系统函数时;
-
DllGetClassObject:从函数的字面意思来理解,应该是创建COM对象时该函数被调用。而我们知道创建COM对象的API函数是CoCreateInstance。CoCreateInstance是个封装函数,它包装了对CoGetClassObject,以及相应类厂的CreateInstance函数的调用。CoGetClassObject通过注册表机制,找到相应的服务器,并且调用服务器的DllGetClassObject函数来获得类厂。一旦获得类厂对象,就可以调用类厂对象的CreateInstance方法来创建COM对象了。
5.2 ATL COM服务器
前面讲的是所有COM服务器都应该遵循的工作流程。不同的COM实现,实现这个流程的方式也不同。对于ATL来说,其具体的实现可以用下图简略体现:

<shape id="_x0000_i1027" style="WIDTH: 6in; HEIGHT: 90pt" fillcolor="window" type="#_x0000_t75"><imagedata o:title="Class_diagram_Server" src="file:///C:%5CDOCUME~1%5Choward%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image007.png"><font size="3"></font></imagedata></shape>
ATL COM服务器主要通过CComModule类和_ATL_OBJMAP_ENTRY结构来实施服务器管理。前面讲过,COM服务器的主要职能是三个:管理服务器生命周期、注册组件、获得COM对象的类厂,所以,CComModule的成员函数也围绕这三个方面。同样,_ATL_OBJMAP_ENTRY数据结构中的内容也紧紧围绕着这三个方面。由于本文讨论COM对象创建,所以,对服务器管理的讨论也局限在“获得COM对象的类厂”上。ATL COM服务器实现“获得COM对象的类厂”的步骤如下:
1、 所有的ATL工程都会生成一个全局变量,其类型为CComModule,名字固定为_Module。
2、 DLL的四个输出函数内部都是调用_Module的成员函数来实现其功能。
3、 CComModule提供了一系列成员函数来管理COM服务器,这些方法基本都工作在_ATL_OBJMAP_ENTRY结构数组上。
4、 _ATL_OBJMAP_ENTRY结构内的成员基本上都是一些静态成员函数指针。最重要的函数指针是两个:pfnGetClassObject和pfnCreateInstance,它们都指向CComCreator的静态成员函数CreateInstance。
5、 _ATL_OBJMAP_ENTRY结构数组由三个宏配合定义:BEGIN_OBJ_MAP、OBJECT_ENTRY和END_OBJ_MAP。其中,OBJECT_ENTRY宏比较重要,有必要在下面列出其定义:
#define OBJECT_ENTRY(clsid, class) \
{&clsid, class::UpdateRegistry, \
class::_ClassFactoryCreatorClass::CreateInstance, \
class::_CreatorClass::CreateInstance, NULL, 0, \
class::GetObjectDescription, class::GetCategoryMap, \
class::ObjectMain },
注意黄底色部分。该宏用class的数据成员_ClassFactoryCreatorClass的CreateInstance静态函数指针填充到pfnGetClassObject位置。用_CreatorClass的CreateInstance静态函数指针填充到pfnCreateInstance位置。
要找到一个特定的类厂,DllGetClassObject 将调用CComModule的成员函数GetClassObject。GetClassObject遍历结构数组,找到相应的CLSID对应的_ATL_OBJMAP_ENTRY结构。ATL会先检查结构中的pCF,这是ATL缓存的类厂对象指针,如果不为空,则可以直接利用该指针来创建COM对象,如果为空,则调用结构中的pfnGetClassObject函数指针,创建相应的类厂对象并且把类厂对象的指针缓存到pCF成员数据中。
6 ATL COM对象创建——内外结合
本文中,先讲了ATL COM对象本身,接着讲了ATL COM对象创建的内部机制——ATL COM对象的类厂如何创建ATL COM对象;再接着讲了ATL COM对象创建的外部机制——ATL COM服务器如何创建ATL COM对象的类厂。有个这几方面的了解之后,我们再把相关的知识结合起来,看一看ATL COM对象创建的统一场景。图示如下:
<shape id="_x0000_i1028" style="WIDTH: 368.25pt; HEIGHT: 414.75pt" fillcolor="window" type="#_x0000_t75"><imagedata o:title="Class_diagram" src="file:///C:%5CDOCUME~1%5Choward%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image009.png"><font size="3"></font></imagedata></shape>

图中左上部分是ATL COM对象本身;右上部分是ATL COM对象的创建;中下部分是ATL COM服务器对COM对象的管理。
对每个部分的作用,本文各个部分已经有了具体描述,这里要强调的是图中标示为红色部分:_ATL_OBJMAP_ENTRY结构和CComCreator,正是通过它们,图中三个部分有机地联系到了一起,完成了ATL COM对象创建的任务。
通观本文,没有给什么“示范代码”,而是力求从本人理解的COM原理的角度探讨ATL的COM对象创建机制。有可能这样的讨论在理论真正精深者看来不值一哂,然而,本人希望那些觉得ATL不好理解的人有了这次ATL COM对象创建过程探索的经历,能够感觉ATL好把握一些了,不再是若干莫名其妙的模板类的组合了。
分享到:
相关推荐
### ATL揭秘之“对象创建”篇 当我们使用Visual C++的ATL框架创建了一个COM工程并实现了自己的COM对象,然后在另一个程序中通过`CoCreateInstance`调用这个COM对象时,你是否曾思考过这样的问题:我们知道COM对象是...
- `ATL揭秘.pdf`:这可能是一本详细介绍ATL的书籍,涵盖了ATL的基础到高级主题,有助于读者全面了解和掌握ATL。 - `ATLstudy`:这个名字暗示可能是一个包含ATL学习资料的文件夹,可能包含源代码、教程或其他实践...
在日常的工作和学习中,你是否常常为处理复杂的数据、生成高质量的文本或者进行精准的图像识别而烦恼?DeepSeek 或许就是你一直在寻找的解决方案!它以其高效、智能的特点,在各个行业都展现出了巨大的应用价值。然而,想要充分发挥 DeepSeek 的优势,掌握从入门到精通的知识和技能至关重要。本文将从实际应用的角度出发,为你详细介绍 DeepSeek 的基本原理、操作方法以及高级技巧。通过系统的学习,你将能够轻松地运用 DeepSeek 解决实际问题,提升工作效率和质量,让自己在职场和学术领域脱颖而出。现在,就让我们一起开启这场实用又高效的学习之旅吧!
在日常的工作和学习中,你是否常常为处理复杂的数据、生成高质量的文本或者进行精准的图像识别而烦恼?DeepSeek 或许就是你一直在寻找的解决方案!它以其高效、智能的特点,在各个行业都展现出了巨大的应用价值。然而,想要充分发挥 DeepSeek 的优势,掌握从入门到精通的知识和技能至关重要。本文将从实际应用的角度出发,为你详细介绍 DeepSeek 的基本原理、操作方法以及高级技巧。通过系统的学习,你将能够轻松地运用 DeepSeek 解决实际问题,提升工作效率和质量,让自己在职场和学术领域脱颖而出。现在,就让我们一起开启这场实用又高效的学习之旅吧!
ACM动态规划模板-区间修改线段树问题模板
# 踏入C语言的奇妙编程世界 在编程的广阔宇宙中,C语言宛如一颗璀璨恒星,以其独特魅力与强大功能,始终占据着不可替代的地位。无论你是编程小白,还是有一定基础想进一步提升的开发者,C语言都值得深入探索。 C语言的高效性与可移植性令人瞩目。它能直接操控硬件,执行速度快,是系统软件、嵌入式开发的首选。同时,代码可在不同操作系统和硬件平台间轻松移植,极大节省开发成本。 学习C语言,能让你深入理解计算机底层原理,培养逻辑思维和问题解决能力。掌握C语言后,再学习其他编程语言也会事半功倍。 现在,让我们一起开启C语言学习之旅。这里有丰富教程、实用案例、详细代码解析,助你逐步掌握C语言核心知识和编程技巧。别再犹豫,加入我们,在C语言的海洋中尽情遨游,挖掘无限可能,为未来的编程之路打下坚实基础!
在日常的工作和学习中,你是否常常为处理复杂的数据、生成高质量的文本或者进行精准的图像识别而烦恼?DeepSeek 或许就是你一直在寻找的解决方案!它以其高效、智能的特点,在各个行业都展现出了巨大的应用价值。然而,想要充分发挥 DeepSeek 的优势,掌握从入门到精通的知识和技能至关重要。本文将从实际应用的角度出发,为你详细介绍 DeepSeek 的基本原理、操作方法以及高级技巧。通过系统的学习,你将能够轻松地运用 DeepSeek 解决实际问题,提升工作效率和质量,让自己在职场和学术领域脱颖而出。现在,就让我们一起开启这场实用又高效的学习之旅吧!
本项目为Python语言开发的PersonRelationKnowledgeGraph设计源码,总计包含49个文件,涵盖19个.pyc字节码文件、12个.py源代码文件、8个.txt文本文件、3个.xml配置文件、3个.png图片文件、2个.md标记文件、1个.iml项目配置文件、1个.cfg配置文件。该源码库旨在构建一个用于表示和查询人物关系的知识图谱系统。
在日常的工作和学习中,你是否常常为处理复杂的数据、生成高质量的文本或者进行精准的图像识别而烦恼?DeepSeek 或许就是你一直在寻找的解决方案!它以其高效、智能的特点,在各个行业都展现出了巨大的应用价值。然而,想要充分发挥 DeepSeek 的优势,掌握从入门到精通的知识和技能至关重要。本文将从实际应用的角度出发,为你详细介绍 DeepSeek 的基本原理、操作方法以及高级技巧。通过系统的学习,你将能够轻松地运用 DeepSeek 解决实际问题,提升工作效率和质量,让自己在职场和学术领域脱颖而出。现在,就让我们一起开启这场实用又高效的学习之旅吧!
rtsp实时预览接口URL:/evo-apigw/admin/API/MTS/Video/StartVideo HLS、FLV、RTMP实时预览接口方式 :接口URL/evo-apigw/admin/API/video/stream/realtime 参数名 必选 类型 说明 data true string Json串 +channelId true string 视频通道编码 +streamType true string 码流类型:1=主码流, 2=辅码流,3=辅码流2 +type true string 协议类型:hls,hlss,flv,flvs,ws_flv,wss_flv,rtmp hls:http协议,m3u8格式,端口7086; hlss:https协议,m3u8格式,端口是7096; flv:http协议,flv格式,端口7886; flvs:https协议,flv格式,端口是7896; ws_flv:ws协议,flv格式,端口是7886; wss_flv:wss协议,flv格式,端口是7896; rtmp:rtmp协议,端口是1975;
Simulink永磁风机飞轮储能系统二次调频技术研究:频率特性分析与参数优化,Simulink永磁风机飞轮储能二次调频技术:系统频率特性详解及参数优化研究参考详实文献及两区域系统应用,simulink永磁风机飞轮储能二次调频,系统频率特性如下,可改变调频参数改善频率。 参考文献详细,两区域系统二次调频。 ,核心关键词: 1. Simulink 2. 永磁风机 3. 飞轮储能 4. 二次调频 5. 系统频率特性 6. 调频参数 7. 改善频率 8. 参考文献 9. 两区域系统 以上关键词用分号(;)分隔,结果为:Simulink;永磁风机;飞轮储能;二次调频;系统频率特性;调频参数;改善频率;参考文献;两区域系统。,基于Simulink的永磁风机与飞轮储能系统二次调频研究:频率特性及调频参数优化
MATLAB驱动的ASR防滑转模型:PID与对照控制算法对比,冰雪路面条件下滑移率与车速轮速对照展示,MATLAB驱动的ASR防滑转模型:PID与对照控制算法对比,冰雪路面条件下滑移率与车速轮速对照图展示,MATLAB驱动防滑转模型ASR模型 ASR模型驱动防滑转模型 ?牵引力控制系统模型 选择PID控制算法以及对照控制算法,共两种控制算法,可进行选择。 选择冰路面以及雪路面,共两种路面条件,可进行选择。 控制目标为滑移率0.2,出图显示车速以及轮速对照,出图显示车辆轮胎滑移率。 模型简单,仅供参考。 ,MATLAB; ASR模型; 防滑转模型; 牵引力控制系统模型; PID控制算法; 对照控制算法; 冰路面; 雪路面; 控制目标; 滑移率; 车速; 轮速。,MATLAB驱动的ASR模型:PID与对照算法在冰雪路面的滑移率控制研究
芯片失效分析方法介绍 -深入解析芯片故障原因及预防措施.pptx
4131_127989170.html
内容概要:本文提供了一个全面的PostgreSQL自动化部署解决方案,涵盖智能环境适应、多平台支持、内存与性能优化以及安全性加强等重要方面。首先介绍了脚本的功能及其调用方法,随后详细阐述了操作系统和依赖软件包的准备过程、配置项的自动生成机制,还包括对实例的安全性和监控功能的强化措施。部署指南给出了具体的命令操作指导,便于新手理解和执行。最后强调了该工具对于不同硬件条件和服务需求的有效应对能力,特别是针对云计算环境下应用的支持特点。 适合人群:对PostgreSQL集群运维有一定基础并渴望提高效率和安全性的数据库管理员及工程师。 使用场景及目标:本脚本能够帮助企业在大规模部署时减少人工介入时间,确保系统的稳定性与高性能,适用于各类需要稳定可靠的数据库解决方案的企业或机构,特别是在大数据量和高并发事务处理场合。 其他说明:文中还提及了一些高级功能如自动备份、流复制等设置步骤,使得该方案不仅可以快速上线而且能满足后续维护和发展阶段的要求。同时提到的技术性能数据也为用户评估其能否满足业务需求提供了直观参考。
房地产开发合同[示范文本].doc
在日常的工作和学习中,你是否常常为处理复杂的数据、生成高质量的文本或者进行精准的图像识别而烦恼?DeepSeek 或许就是你一直在寻找的解决方案!它以其高效、智能的特点,在各个行业都展现出了巨大的应用价值。然而,想要充分发挥 DeepSeek 的优势,掌握从入门到精通的知识和技能至关重要。本文将从实际应用的角度出发,为你详细介绍 DeepSeek 的基本原理、操作方法以及高级技巧。通过系统的学习,你将能够轻松地运用 DeepSeek 解决实际问题,提升工作效率和质量,让自己在职场和学术领域脱颖而出。现在,就让我们一起开启这场实用又高效的学习之旅吧!
在日常的工作和学习中,你是否常常为处理复杂的数据、生成高质量的文本或者进行精准的图像识别而烦恼?DeepSeek 或许就是你一直在寻找的解决方案!它以其高效、智能的特点,在各个行业都展现出了巨大的应用价值。然而,想要充分发挥 DeepSeek 的优势,掌握从入门到精通的知识和技能至关重要。本文将从实际应用的角度出发,为你详细介绍 DeepSeek 的基本原理、操作方法以及高级技巧。通过系统的学习,你将能够轻松地运用 DeepSeek 解决实际问题,提升工作效率和质量,让自己在职场和学术领域脱颖而出。现在,就让我们一起开启这场实用又高效的学习之旅吧!
工程技术承包合同[示范文本].doc
蓝桥杯开发赛【作品源码】