// VCConsoleClient01.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
// Global event object handle that will be signalled when
// an interface of a custom marshaled object has been
// marshaled into a stream. This will signal a receiving
// thread that unmarshaling can now be performed.
HANDLE g_hInterfaceMarshaled = NULL;
// ThreadFunc_CustomMarshaledObject() is the entry point function
// of a thread that will create an immutable object, create a
// marshaled data packet for it and pass it to the creator of this
// thread.
//
// This thread will then remain alive until a WM_QUIT message
// is posted to it. The fact that this thread remains alive
// will enable the imutable object to also remain alive.
DWORD WINAPI ThreadFunc_CustomMarshaledObject(LPVOID lpvParameter)
{
MSG msg;
long lLong = 0;
LPSTREAM* ppStreamReceiver = (LPSTREAM*)lpvParameter;
// This thread will be thread of an STA.
::CoInitialize(NULL);
IImmutableObjectFactoryPtr spIImmutableObjectFactory = NULL;
IImmutablePtr spIImmutable = NULL;
IUnknown* pIUnknown = NULL;
// Initialize the receiver.
*ppStreamReceiver = NULL;
// Create an instance of the COM object which has ProgID
// "BasicSample01InterfacesImpl.ImmutableObjectFactoryImpl" and manage it
// via its IImmutableObjectFactory interface.
// Now, because the resultant object (spIImmutableObjectFactory) is an STA object,
// and this thread is an STA thread, spIImmutableObjectFactory will live in the
// same STA as this thread.
_CoCreateInstance("BasicSample01InterfacesImpl.ImmutableObjectFactoryImpl", spIImmutableObjectFactory);
// Get the immutable object from spIImmutableObjectFactory.
// Now because the immutable object is also an STA object,
// it will live in the same STA as this thread.
spIImmutableObjectFactory -> CreateObject(101, (IImmutable**)&spIImmutable);
// QI the original interface pointer for its IUnknown interface.
spIImmutable -> QueryInterface (IID_IUnknown, (void**)&pIUnknown);
if (pIUnknown)
{
// Create a Stream Object which will reside in global memory.
// We set the first parameter to NULL, hence indicating that
// we want CreateStreamOnHGlobal() to internally allocate
// a new shared memory block of size zero.
// The second parameter is set to TRUE so that when the returned
// stream object is Release()'d, the global memory will also be
// freed.
::CreateStreamOnHGlobal
(
0,
TRUE,
ppStreamReceiver
);
if (*ppStreamReceiver)
{
LARGE_INTEGER li = { 0 };
// We use the new stream object to store the marshal data
// packet of the immutable object.
//
// The use of MSHCTX_INPROC indicates that the unmarshaling
// of the data in the stream will be done in another apartment
// in the same process.
//
// When CoMarshalInterface() is called on spIImmutable,
// COM will attempt to get the CLSID of the proxy for the
// immutable object and then to get the marshaled data packet
// from it.
//
// The following sequence of function calls will take place :
//
// CImmutableImpl::GetUnmarshalClass()
// CImmutableImpl::GetMarshalSizeMax()
// CImmutableImpl::MarshalInterface()
//
::CoMarshalInterface
(
*ppStreamReceiver,
__uuidof(IImmutablePtr),
(IUnknown*)pIUnknown,
MSHCTX_INPROC,
NULL,
MSHLFLAGS_NORMAL
);
// We will need to reset the stream to the beginning.
// Otherwise a later call to the CoUnmarshalInterface()
// API will fail with error STG_E_READFAULT.
(*ppStreamReceiver) -> Seek(li, STREAM_SEEK_SET, NULL);
}
pIUnknown -> Release();
pIUnknown = NULL;
// Signal the situation that the immutable object
// has been marshaled by setting the g_hInterfaceMarshaled
// event.
if (g_hInterfaceMarshaled)
{
SetEvent(g_hInterfaceMarshaled);
}
}
// Dispatch all windows messages in queue.
// This windows message loop will not
// break until the WM_QUIT message is
// posted to this thread.
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage (&msg);
DispatchMessage(&msg);
}
::CoUninitialize();
return 0;
}
// ExamineStream() will take a stream object and cast it
// to a MarshaledDataPacket structure for examination.
void ExamineStream(LPSTREAM& lpStream)
{
LPBYTE lpbyStreamData = NULL;
STATSTG statstg;
memset (&statstg, 0, sizeof(statstg));
lpStream -> Stat
(
(STATSTG*)&statstg,
STATFLAG_DEFAULT
);
lpbyStreamData = new BYTE[(size_t)(statstg.cbSize.LowPart)];
memset (lpbyStreamData, 0, (size_t)(statstg.cbSize.LowPart));
if (lpbyStreamData)
{
MarshalDataPacket marshal_data_packet;
memset (&marshal_data_packet, 0, sizeof(marshal_data_packet));
lpStream -> Read
(
(void*)lpbyStreamData,
statstg.cbSize.LowPart,
NULL
);
memcpy((void*)&marshal_data_packet, (void*)lpbyStreamData, sizeof(marshal_data_packet));
delete [] lpbyStreamData;
lpbyStreamData = NULL;
}
LARGE_INTEGER li;
memset (&li, 0, sizeof(li));
lpStream -> Seek
(
li,
STREAM_SEEK_SET ,
NULL
);
}
// Demonstrate_Cross_Apartment_Call_Via_Stream() will show
// a complete rendition of importing an interface pointer
// from another apartment.
void Demonstrate_Cross_Apartment_Call_Via_Stream()
{
HANDLE hThread = NULL;
DWORD dwThreadId = 0;
// lpStream is an uninitialized pointer to a stream.
LPSTREAM lpStream = NULL;
long lLongValue = 0;
// spIImmutable will become a proxy to the immutable object.
IImmutablePtr spIImmutable = NULL;
// We create a thread which is started by the function
// ThreadFunc_CustomMarshaledObject(). We also pass the
// uninitialized IStream pointer to this thread function
// as a parameter.
hThread = CreateThread
(
(LPSECURITY_ATTRIBUTES)NULL,
(SIZE_T)0,
(LPTHREAD_START_ROUTINE)ThreadFunc_CustomMarshaledObject,
(LPVOID)(&lpStream),
(DWORD)0,
(LPDWORD)&dwThreadId
);
// We wait for the thread to initialize.
ThreadMsgWaitForSingleObject(g_hInterfaceMarshaled, INFINITE);
ResetEvent(g_hInterfaceMarshaled);
// By the time the thread is initialized, lpStream will
// be initialized to point to a stream object that contains
// a marshaled data packet.
if (lpStream)
{
// We can examine this stream.
ExamineStream(lpStream);
// Construct a proxy to the IImmutable interface from the stream.
//
// At this point in time, the Marshal Data Packet is contained
// inside the stream. All COM needs is a new Proxy object to which
// it passes the Marshal Data Packet (in the UnmarshalInterface()
// method call).
//
// When CoUnmarshalInterface() is called with our marshaled
// data packet stream, COM will create a proxy to the immutable
// object created inside the ThreadFunc_CustomMarshaledObject
// thread.
//
// COM will then pass the marshaled data packet stream to the
// proxy in order to initialize it.
//
// The following sequence of function calls will take place :
//
// CImmutableImpl() (part of proxy construction)
// CImmutableImpl::FinalConstruct() (part of proxy construction)
// CImmutableImpl::UnmarshalInterface()
//
::CoUnmarshalInterface
(
lpStream,
__uuidof(IImmutablePtr),
(void**)&spIImmutable
);
lpStream -> Release();
lpStream = NULL;
}
// At this time, spIImmutable has been initialized to be a proxy
// of the immutable object.
if (spIImmutable)
{
spIImmutable -> get_LongValue(&lLongValue);
}
PostThreadMessage(dwThreadId, WM_QUIT, 0, 0);
ThreadMsgWaitForSingleObject(hThread, INFINITE);
CloseHandle (hThread);
hThread = NULL;
}
int _tmain(int argc, _TCHAR* argv[])
{
::CoInitialize(NULL);
g_hInterfaceMarshaled = CreateEvent(NULL, TRUE, FALSE, NULL);
Demonstrate_Cross_Apartment_Call_Via_Stream();
if (g_hInterfaceMarshaled)
{
CloseHandle(g_hInterfaceMarshaled);
g_hInterfaceMarshaled = NULL;
}
::CoUninitialize();
return 0;
}