• 全部
  • VC综合技术
  • 互联网技术
  • MFC AppLauncher
  • .NET 技术
  • 界面
  • 进程
  • 算法
  • 硬件/系统
  • 数据库
  • VC++技术资源

小问题(80+70+70)分:如何将对象放入共享内存中?

blackstone 华为软件 开发组长/高级工程师/技术专家  2001-06-28 03:59:50
我在COM中建立了一个shared memory,现在需要将一个对象置于其中以方便多个应用程序使用它;BSTR是可以的,但对象可以吗?该如何做?提供分数80+70+70
...全文
201 点赞 收藏 16
写回复
16 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
blackstone 2001-07-02
可以实现,给你分!
回复
blackstone 2001-06-30
这样不能达到我的目的,我需要两个应用程序之间共享对象,写一个进程外组件并不能达到我的要求。
plato(天天) :希望能继续得到你的帮助,赫赫
回复
blackstone 2001-06-29
push
回复
Kevin_qing 2001-06-29
关注先
回复
blackstone 2001-06-29
plato(天天) 到http://www.csdn.net/expert/topic/173/173336.shtm贴里去,我在那给你先加70分。
回复
blackstone 2001-06-29
plato(天天):能不能说的更详细一点?有实例最好。当将对象拷贝到shared memory内后如何调用它呢?
我昨天试图用共享对象指针的方式达到共享内存目的,但失败了。
回复
plato 2001-06-29
在ATL COM AppWizard中选择Server Type为Executable类型的。
回复
plato 2001-06-29
如果用COM,你就不用管这么多了。

用ATL COM AppWizard生成一个进程外组件(EXE)的框架,然后Marshal的事情都不用管
回复
blackstone 2001-06-29
再追加200分!
回复
plato 2001-06-29
要引用COM对象啊?写一个进程外的组件不就可以了,不用共享内存啊
回复
blackstone 2001-06-29
我在msdn里面看到了一篇文章,提到如何实现这一目的,可惜我对COM不熟悉,谁能讲讲?






This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.


--------------------------------------------------------------------------------
February 1996





Download MSJFEB96.exe (31KB)

Don Box is a co-founder of DevelopMentor where he manages the COM curriculum. Don is currently breathing deep sighs of relief as his new book, Essential COM (Addison-Wesley), is finally complete. Don can be reached at http://www.develop.com/dbox/default.asp.


Q I'd like to put an object in shared memory to allow multiple processes to access it simultaneously. What is the best way to do this?
Posted Frequently to comp.object
A Before you attempt to place an object into shared memory, it is important to note that simply by implementing your class as an out-of-process server in COM, your objects will automatically be sharable across multiple processes, provided that all of the interfaces that your object exports have proxy/stub pairs installed on the user's machine. This is inherent in the standard marshaling architecture of COM. But there are still valid reasons for placing an object into shared memory, the most common being efficiency. As noted in the December 1995 OLE Q&A, the cost of invoking methods on out-of-process objects is considerable. This cost can be attributed to the overhead of context switching, parameter marshaling, and message queuing under Windows NT? and Windows? 95. Placing the data members of an object into shared memory allows them to be accessed directly from within the client process without context switching, marshaling, or queuing, as long as the code that implements the methods has been mapped into each client's address space. This is the role of object handlers in COM.
Before I explain how handlers work, let's review some terms. The act of passing an object (or anything) from one process to another is called marshaling. COM supports two types of marshaling: standard and custom. Standard marshaling refers to passing an object from process A to process B by reference. If the object resides in process A, a proxy is created in process B that refers to the object via an RPC channel that is connected to a stub in the object's process. Fortunately, if that proxy (reference) is later passed to yet another process, a new proxy is created in the target process that is directly connected to the stub (see Figure 1), avoiding the unnecessary level of indirection that would result in creating a proxy to a proxy. This is similar to the way object references and pointers behave in traditional C++.



Figure 1 Object Sharing Using Standard Marshaling


Ultimately, objects/proxies are passed from one process to another via marshaling packets that contain whatever state is required to connect the client to the object. These packets are created by the marshaling code used to remote a given method call, and are populated with object references by calling the COM API function CoMarshalInterface:


HRESULT CoMarshalInterface(IStream *pstm
REFIID riid,
IUnknown *pUnk,
DWORD dwDestContext,
void *pvDestContext,
DWORD mshlflags);

If the marshaled object uses standard marshaling, CoMarshalInterface first examines the object (referred to by pUnk) to verify that it is not a handler or proxy. If pUnk points to an actual object, CoMarshalInterface then uses CoGetStandardMarshal to create the stub that will be used to manage the object side of the connection and fills the marshaling packet referred to by pstm with the unique identifier of the stub. This identifier, along with the CLSID of the handler that knows how to interpret it (CLSID_StdMarshal), is then transmitted to the receiver where it is ultimately unmarshaled from the packet and used to initialize and connect the proxy in the client's address space to the new stub. The COM function CoUnmarshalInterface creates and unmarshals the proxy.


HRESULT CoUnmarshalInterface(IStream *pstm
REFIID riid,
void **ppvObject);

CoUnmarshalInterface is called by the remoting code in the client's address space. CoUnmarshalInterface first reads the CLSID of the handler to be instantiated (here, CLSID_ StdMarshal) from the stream and passes this value to CoCreateInstance to instantiate the handler (proxy) that will act as the client's reference to the object. CoUnmarshalInterface then instructs the handler to unmarshal what remains of the marshaling packet (in this example, the identifier of the stub) to establish the connection to the stub.
When the interface pointer that is passed to CoMarshalInterface points to a proxy and not an actual object implementation, the marshaling packet is formed by simply extracting the stub's unique identifier from the proxy. When this packet is unmarshaled in the remote process, it creates a second direct connection to the original stub, not an indirect connection through the original proxy.
To allow objects greater control over their distributional characteristics, COM allows an object to bypass the normal proxy/stub connection management used by standard marshaling. The object instead establishes a private subcontract for communications between the client and the object. To implement this private subcontract, the object must provide an inprocess handler that will be used in the client in lieu of the generic proxy used in standard marshaling. This is custom marshaling.
In contrast to standard marshaling, custom marshaling is implemented on an object-by-object basis, and must be implemented more or less by hand. The lack of tool support is due to the fact that when an object is custom marshaled from process A to process B, it is being passed by value. The actual value being passed is not necessarily a linear representation of the object's data members, but rather a serialized version of whatever state the object needs on the client side to "connect" to the object in the originating process. To give objects control over the transmission and reception of this state, COM specifies the IMarshal interface, which must be implemented by all objects that implement custom marshaling (see Figure 2). Given this, you can see in detail how objects are transmitted across marshaling contexts, and how to create and connect the handler based on the received packet (see Figure 3).
The implementations of CreatePacket and CreateHandler are very similar to the implementations of the COM API functions CoMarshalInterface and CoUnmarshalInterface. The fundamental difference is that if the initial QueryInterface for IMarshal fails, the API functions use CoGetStandardMarshal to attach the standard marshaler to the object, establishing a default proxy/stub connection.


Figure 4 Object Sharing Using Inproc Handlers


Now let's place an object into shared memory. A reasonable strategy is to place the shared data members into a Win32? section object, and protect it from concurrent access using a mutex. The shared data members can be defined in a separate struct or class, and the handles to the mutex and file mapping objects can be stored in the handler along with the pointer to the shared memory. Assuming that the object's lifetime does not need to be bound to any one process, you can safely implement only an InprocHandler for our object that will support custom marshaling (see Figure 4).


Figure 5 CoSharedObject Hierarchy


As much of the code for implementing the handler is boilerplate and not dependent on the shared state of the object (except for its size and CLSID), I chose to implement a generic shared object using templates, as is shown in Figure 5 and Figure 6. The class CoSharedObjectBase contains most of the core code and is where IMarshal is implemented. As is shown in Figure 7, the handler maintains a pointer to a shared memory section where the actual object state is kept. Prepended to this is a shared reference count that keeps track of how many handlers are currently connected. When the section is initially created (in AttachToSection), the reference count is set to one and a virtual function call is made (OnInitializeSection) to allow the derived class to initialize the user-area of the section. When the final handler goes away, it makes a different virtual function call (OnDestroySection) to allow the derived class to clean up any state that may be associated with the shared members. As this implementation does not assume that the process identity of the object is fixed, it is entirely possible that the section will be initialized in one process and destroyed in another. For some applications, this is preferable; for others, it is not. Note that the template class CoSharedObject provides default implementations of OnInitializeSection and OnDestroySection that use placement to construct and destroy the shared state in place.


Figure 7 Sharing State Between Handlers


To identify the section and the mutex that protects it, there needs to be a way to uniquely identify the Win32 kernel objects that the initial handler creates. Since you're fairly immersed in COM, it makes sense to use—you guessed it—a GUID. You can easily create GUIDs at run time by calling the API function CoCreateGuid. You can use the GUID as an object ID. As is shown in Figure 6, CoSharedObjectBase uses CoCreateGuid in AccessSharedData (from SHAREDOB.CPP) to generate the shared object's ID the first time the object is accessed prior to marshaling. CoSharedObjectBase's implementation of MarshalInterface simply transmits the object ID to the receiving client. CoSharedObjectBase's implementation of UnmarshalInterface then reads the object ID in the client's process and opens the section and mutex by calling AttachToSection.
Figure 8 demonstrates the CoSharedObject template by implementing a simple object that keeps two ints and a string in shared memory. Note that the implementation of each of the member functions defines an instance of a class SharedThis at the beginning of the method. SharedThis is a nested class in CoSharedObject that provides a typed pointer to the shared state. It also acquires the mutex in its constructor and releases it in its destructor. Declaring an instance of SharedThis in each method guarantees that at most one thread will be accessing the shared object at any time. Figure 9 shows several clients accessing a single shared object simultaneously.


Figure 9 Multiple clients access a single shared object simultaneously


The implementation described here achieves performance close to that of an inprocess server for method invocation, as no context switching or marshaling needs to be performed. However, there are some tradeoffs. First, this implementation is extremely memory hungry. While the handler is very small and lightweight, the shared section winds up consuming at least 4KB due to page size granularity. This could be minimized by implementing a shared memory allocator (perhaps using CoSharedObject) and implementing malloc and free on top of the section. A more problematic tradeoff is the fact that the template supports sharing objects that have only instance data members (no pointer members or handles). If you want to share a linked list or file handle as a shared data member, you can look forward to a nontrivial job using the TypingWizard in Visual C++ to implement the pointer chasing and/or handle duplication required to get things to work properly.



Have a question about programming with ActiveX or COM? Send your questions via email to Don Box at dbox@develop.com or http://www.develop.com/dbox/default.asp



From the February 1996 issue of Microsoft Systems Journal.



--------------------------------------------------------------------------------
Send feedback to MSDN.Look here for MSDN Online resources.
回复
plato 2001-06-29
继续:

在shared memory上分配好对象后,假设
LPVOID startaddress1 = MapViewOfFile(...); //startaddress1是起始地址
A *obj = buf; //buf是在shared memory中的一个地址。
memcpy( obj, &a, sizeof(A));
//计算差:
DWORD offset = DWORD(obj) - (DWORD)startaddress1;

在另外一个进程要使用,需要把filemapping的名字和offset传过来:
hmapping = OpenFileMapping(..);
LPVOID startaddress2 = MapViewOfFile( hmapping ...);
A *anotherobj = (A *)( (DWORD)startaddress2 + offset );

回复
blackstone 2001-06-29
a,我惨大了,要引用的正是COM对象
回复
plato 2001-06-29
我假设你所说的C++的对象,不是COM对象

首先,你的对象应该是比较简单的,如果对象内部还有指向其它对象的指针,就麻烦了,你要保证这些指针也指向共享内存的地址,你不能用new来初始化对象内部指向其它对象的指针,因为new的对象分配在堆上面,因此其它进程不能用的。你要小心得拷贝,让所有的引用到的对象都存在于Shared Memory之上,而且是同一个Shared Memory。而且这个指针,跨进程是不能直接用的。因为Shared Memory,映射到不同进程的时候,地址是不一样的。如果要用,还要进行处理。总之,这个对象最好是诸如:
class A{
int a;
int b;
}
class B{
A a;
}
一样的简单。
如果是:
Class B{
A *pa;
}
就比较繁了。

回复
plato 2001-06-28
忘了说,有静态成员变量也要dllexport
回复
plato 2001-06-28
对象也可以,所有的成员函数深明为dllexport

然后memcpy( sharemem, &obj, sizeof(obj))

不过最好还是用结构比较好。
回复
发帖
VC/MFC
创建于2007-09-28

1.5w+

社区成员

VC/MFC相关问题讨论
申请成为版主
帖子事件
创建了帖子
2001-06-28 03:59
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……