⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 subject_36155.htm

📁 一些关于vc的问答
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<p>
序号:36155 发表者:xiongli 发表日期:2003-04-12 14:50:56
<br>主题:关于CRT和com的一些个人猜想,请指正thanks
<br>内容:先说CRT (C RUN-TIME LIBRARY)<BR>CRT分为两种类型.两种类型是动态连接的crt和静态连接的crt.<BR>先说这两种类型的差别。差别主要是在用动态crt连接的应用程序,在使用c函数的时候,是通过调用系统dll的方式实现的,当用静态crt连接程序的时候,是通过把c函数函数体编码到exe文件中,当调用c函数的时候,实际上是调用的exe内部代码段的函数。<BR>这里面有一个很大的陷阱:动态crt是在作为一个dll映射到所有使用crt进程的空间的,作为一个dll,他做的很多工作是全局的,也就是说,对所有映射动态crt的进程来说是"通用"的.举个例子:c里面的堆分配(heap,malloc/free)实际上是调用windows api HeapCreate() HeapAlloc()来实现的.作为动态dll来说,他只需要在初始化时调用一次HeapCreate(),然后所有的malloc都是在这一次HeapCreate()建立的堆里面通过HeapMalloc()分配.所以说所有连接到动态crt的用malloc分配的堆内存,都是来自于同一次的HeapCreate().对于静态的crt来说,该crt作为进程全局函数,只在该进程内部有效.所以静态crt分配的堆内存,是同一个进程里面的所有堆来自同一次HeapCreate(),不同进程的堆来自不同的HeapCreate().这样就引出一个问题:如果你的程序包含多个模块,这些模块如果都是通过动态dll连接的,那么这些模块之间可以"相互malloc/free",也就是说,你可以free一个来自其他模块里面通过malloc分配的内存而没有问题,因为他们是动态crt连接,都来自同一个HeapCreate(),但是如果你的模块里面不全是动态crt连接的话,就很容易出问题,比如你在动态crt里面malloc的内存拿到静态crt里面的free去释放就会出问题,因为他们来自不同的HeapCreate<BR><BR>以上是个人猜想.我考虑的是作为动态crt分配的堆应该是归谁所有.也就是说第一次是谁调用HeapCreate().我想应该是系统,然后系统保留这个HeapCreate()返回的handle.然后系统应该想办法让所有进程都能够访问到这个handle,以作为以后HeapAlloc的参数.因为虽然dll只有一个,但是映射到进程空间以后,dll内的所有变量都是分配到每个进程独立空间里面的(先不讨论copy on write等等).所以这个handle是不能作为dll全局变量自己保存的,那么这个handle就因该是系统初始化,然后crt dll去使用.但是The HeapCreate function creates a heap object that can be used by the calling process.HeapCreate建立的堆是给一个具体的process使用的,而不能共享的,所以上面的理解肯定有问题.<BR><BR><BR><BR>在说COM/STA<BR>reguall dll只能导出全局变量和函数.不适合面向对象编程.如果用extended dll可以在vc下导出class,但因为编译器符号问题,这种class只能在一个编译器下面使用.那怕解决了符号问题,如果对dll中class没有一定保准的话,当dll因为升级,class内部成员变量等等发生改变的时候,客户端也需要重新联接才能正常使用.那么解决的办法是:不导出含有变量的class,只导出函数,那么客户端就不需要重新连接.那么只导出函数如何实现面向对象呢,这就要求到处的函数全部是虚函数,通过虚函数实现多态.实现的办法有很多,可以通过传统c来实现,但这要求通过复杂的function ptr array等等,比较麻烦.而c++是直接支持面向对象的,但c++却也有某些部分在二进制上的不同需要避免使用,比如vi/exception handing.那么建立的办法就是<BR><BR>1,定义虚基类(interface)<BR>2,实现虚基类<BR>3,在dll全局函数中实现这个类的object,不管是static member还是heap member<BR>4,把这个object通过static_cast转换成虚基类指针返回给客户<BR>5,客户通过这个指针操作object<BR><BR>好,只要虚基类(inerface)不改变,那么客户永远不需要重新编译.<BR>现在来解决剩下的问题:<BR>1,如何扩充这个组件.如果我想支持新的函数怎么办?<BR>如果要支持新的函数,可以再定义一个虚基类(interface) ,然后实现类中通过多继承.最后返回虚基类指针的时候,返回新的接口,这样新接口老接口同时存在,新版本的client和老的client都可以使用<BR>2,如何方便地返回新接口?<BR>在所有的基类(interface)都支持一个函数quearyinterface.客户在这个函数中传递进去需要的接口类型,queryinteraface根据客户要求的类型把this指针static_cast成相应的interface返回<BR>3,如果控制这个object的生命期?<BR>要求所有interface都支持addref/releace.通过这两个函数来通知object改变内部引用计数,方便object在引用计数为0的时候delete this.<BR>4,如何在一个dll或者exe里面通过一个入口得到里面包含的不相关联的组件?<BR>一个dll/exe其实可以包含多个不相关联的组件,要想得到不同的类型,需要在这些dll/exe里面实现类工厂(class factory),类工厂也是一个组件,导出的IFactory接口.一般把需要的组件类型告诉类工厂,类工厂返回这个组件,然后根据这个组件的queryinterface得到这个组件的其他相关接口.因为组件的作用是返回不同类型,所以一般可做成static member.<BR>5,如何得到classfactory?<BR>需要dll导出全局函数dllgetclassobject(),com api通过这个函数返回class object<BR>6,如何控制dll生命期?<BR>这个我也不清楚.我认为当dll没有进程引用的时候会自己unload的,但是dllcanunloadnow这个dll 全局函数却提供一些功能.正在研究<BR>7,系统如何知道我需要的classfactory对应的dll放在那里?<BR>通过注册表.dll要注册自己的,系统查表得到dll路径<BR>8,如何实现多语言支持?<BR>首先在定义上,使用idl定义,方便生成各种语言的需要文件.其次,每种语言在使用接口上应该使用一个默认接口,支持这种语言的组件都应该实现这个接口,比如IDispatch<BR>9,接口的远程调用跨进程调用通过什么来实现的?<BR>通过rpc等等.<BR><BR><BR>然后讨论一下sta:<BR>首先考虑,如果得到了一个interface,然后把这个interface保存为全局变量,很多线程都并发访问这个变量,使用这个接口,会怎么样?答案是,就跟你写一个函数,很多线程都来访问这个函数一样.如果你的函数支持多线程,那么ok,没问题.如果你当初设计这个函数没考虑到这个问题,那么就有可能死掉(crt的动态版本都支持多线程,静态版本有两种支持方式供用户选择).<BR>既然我的一个组件希望发布后很多语言都可以使用到,那么我不能保证用户到底会不会多线程调用它,所以我应该设计成多线程安全的com.但是这样做无疑增加了程序员负担,所以系统提供了sta模型,允许我们编写单线程安全的com,在多线程模式下也不会出问题.方法是:系统保证每次只有一个线程访问这个com接口中的一个方法.必须等一个方法完成返回后,其他的线程才可以进入这个com相应的方法.<BR>在sta中得到的interface要通过列集才可以给其他线程使用.其他现成得到列集后的一个handle,把handle反列集后再得到interface.反列集后的interface通过代理访问原来的对象.也就是说,访问的时候不是直接访问,而是发送windows message给一个系统建立的隐含窗口,这个窗口根据发送过来的消息对列一次一个地访问原来的object来实现多线程安全.<BR><BR>我觉得class factory可以返回不同的类型的object,内聚可以在得到object后再返回不具有is-a关系的object,这两者有什么具体用途和差别?
<br><a href="javascript:history.go(-1)">返回上页</a><br><a href=http://www.copathway.com/cndevforum/>访问论坛</a></p>
<hr size=1>
<blockquote><p>
回复者:bottle_fish 回复日期:2003-04-12 15:17:05
<br>内容:厉害,这么细致
<br>
<a href="javascript:history.go(-1)">返回上页</a><br><a href=http://www.copathway.com/cndevforum/>访问论坛</a></p></blockquote>
<hr size=1>
<blockquote><p>
回复者:xiongli 回复日期:2003-04-12 21:48:34
<br>内容:先说关于crt的,是我弄复杂了<BR>我先整理一下再解释
<br>
<a href="javascript:history.go(-1)">返回上页</a><br><a href=http://www.copathway.com/cndevforum/>访问论坛</a></p></blockquote>
<hr size=1>
<blockquote><p>
<font color=red>答案被接受</font><br>回复者:dr0 回复日期:2003-04-12 22:04:18
<br>内容:reguall dll只能导出全局变量和函数.不适合面向对象编程.<BR>// Who tell u this ? when u talk about COM, try NOT to wear a MFC glass to see<BR>// the world. <BR><BR>那么解决的办法是:不导出含有变量的class,只导出函数,那么客户端就不需要重新连接.那么只导出函数如何实现面向对象呢,这就要求[到处]的函数全部是虚函数<BR>// NO. COM dll only exports DllGetClassObject() etc. <BR>// The interface (your virtual function set) is used with *.h file or typelib.<BR>// Because a method of the COM interface is called by the offset into the <BR>// method pointer table (or u can call VTable in c++)<BR>// So u can not call it : [export virtual functions]<BR>// the concept is confused.<BR><BR>3, 在dll全局函数中实现这个类的object<BR>// What do u mean that ? i guess u mean u will create the object in the dll<BR>// global function, NOT implement it. the 2 words are different, mean different<BR>// operation.<BR><BR>
<br>
<a href="javascript:history.go(-1)">返回上页</a><br><a href=http://www.copathway.com/cndevforum/>访问论坛</a></p></blockquote>
<hr size=1>
<blockquote><p>
回复者:xiongli 回复日期:2003-04-12 22:13:54
<br>内容:作为com载体的dll不过是一个普通的有一个DllGetClassObject() 全局导出函数的dll,至于这个dll跟对象有什么关系是因为:<BR>虽然写dll的时候用到class,但是编译后的的到的二进制代码是看不出什么面向对象面向过程的.但是通过client得到的接口指针和头文件可以获得dll内部没有导出的函数的offset,从而调用这些函数.
<br>
<a href="javascript:history.go(-1)">返回上页</a><br><a href=http://www.copathway.com/cndevforum/>访问论坛</a></p></blockquote>
<hr size=1>
<blockquote><p>
回复者:dr0 回复日期:2003-04-12 22:14:19
<br>内容:然后讨论一下sta:<BR>首先考虑,如果得到了一个interface,然后把这个interface保存为全局变量,很多线程都并发访问这个变量,使用这个接口,会怎么样?答案是,就跟你写一个函数,很多线程都来访问这个函数一样.如果你的函数支持多线程,那么ok,没问题.如果你当初设计这个函数没考虑到这个问题,那么就有可能死掉(crt的动态版本都支持多线程,静态版本有两种支持方式供用户选择).<BR>既然我的一个组件希望发布后很多语言都可以使用到,那么我不能保证用户到底会不会多线程调用它,所以我应该设计成多线程安全的com.但是这样做无疑增加了程序员负担,所以系统提供了sta模型,允许我们编写单线程安全的com,在多线程模式下也不会出问题.方法是:系统保证每次只有一个线程访问这个com接口中的一个方法.必须等一个方法完成返回后,其他的线程才可以进入这个com相应的方法.<BR>在sta中得到的interface要通过列集才可以给其他线程使用.其他现成得到列集后的一个handle,把handle反列集后再得到interface.反列集后的interface通过代理访问原来的对象.也就是说,访问的时候不是直接访问,而是发送windows message给一个系统建立的隐含窗口,这个窗口根据发送过来的消息对列一次一个地访问原来的object来实现多线程安全.<BR><BR>我觉得class factory可以返回不同的类型的object,内聚可以在得到object后再返回不具有is-a关系的object,这两者有什么具体用途和差别?<BR><BR>when u talk about the COM topic, especially about Threading Model, a clear way is to list your complete information or environment, for e.g. :<BR><BR>Assume A is a STA Server, thread B enters a STA apartment.<BR>B call CoCreateInstance() to create an instance of A. <BR><BR>The above is a clear statement, else u will make puzzled the peers listening to u.<BR><BR>
<br>
<a href="javascript:history.go(-1)">返回上页</a><br><a href=http://www.copathway.com/cndevforum/>访问论坛</a></p></blockquote>
<hr size=1>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -