对象也可以,所有的成员函数深明为dllexport然后memcpy( sharemem, &obj, sizeof(obj))不过最好还是用结构比较好。
解决方案 »
- ActiveX 激活父窗体
- 调用GetDC()返回的HDC一般用来干什么? 绘图不行吧?
- Url编码针对TCHAR类型,给个例子吧,最好不要用MFC,不熟悉
- 用CDC画个矩形,怎么改变矩形边框的颜色呢?
- 请问在VC++中怎么访问dbf文件中的数据?
- 给出盘符 H:,如何得到他属于第几个硬盘(HarddiskX)? 在线等
- [菜鸟求助]自考书上的题:用new操作为一个包含20个整数的数组分配内存,输入若干个值到数组中,分别统计其中整数和负数的个数后再用delet
- 为什么GetSaveFileName函数在98下不能显示
- 我的几个盘都有12兆的空间被占了。找也找不到,也不是隐藏文件,为什么?
- 为什么GetClientRect() 所取得的区域不准确?
- ***********************菜鸟问题,在VC中如何动态实现控制文本框?
- 汇编啊,汇编
我昨天试图用共享对象指针的方式达到共享内存目的,但失败了。
class A{
int a;
int b;
}
class B{
A a;
}
一样的简单。
如果是:
Class B{
A *pa;
}
就比较繁了。
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 );
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 1996Download 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 [email protected] 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(天天) :希望能继续得到你的帮助,赫赫