获取COM调用中服务器进程的ID

近期研究UWP程序,内部大量使用COM组件。研究过程中有一点是如何知道为其提供COM服务的进程ID,查了资料说大概有三种方法,这里摘取一种,调试可用。该方法的原理是,在QueryInterface到接口指针后,通过CoMarshalInteface获取初始化Proxy对象所需要的信息,从中提取进程ID。上代码:

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shlobj.h>
#include <stdio.h>
#include <shobjidl.h>
#include <objidlbase.h>
#include <objbase.h>
#include <atlbase.h>
#include <string>

#define OBJREF_SIGNATURE 0x574f454d

#define OBJREF_STANDARD	1
#define OBJREF_HANDLER	2
#define OBJREF_CUSTOM	4
#define OBJREF_EXTENDED	8

typedef unsigned __int64 OXID;
typedef unsigned __int64 OID;
typedef GUID           IPID;

struct tagSTDOBJREF
{
	unsigned long flags;
	unsigned long cPublicRefs;
	OXID oxid;
	OID oid;
	IPID ipid;
};

typedef struct tagDUALSTRINGARRAY
{
	unsigned short wNumEntries;
	unsigned short wSecurityOffset;
	unsigned short aStringArray[1];
} DUALSTRINGARRAY;

typedef struct tagOBJREF
{
	unsigned long signature;
	unsigned long flags;
	struct _GUID iid;
	union
	{
		struct
		{
			struct tagSTDOBJREF std;
			struct tagDUALSTRINGARRAY saResAddr;
		}u_standard;
		struct
		{
			struct tagSTDOBJREF std;
			struct _GUID clsid;
			struct tagDUALSTRINGARRAY saResAddr;
		}u_handler;
		struct
		{
			struct _GUID clsid;
			unsigned long cbExtension;
			unsigned long size;
			unsigned char * pData;
		}u_custom;
		struct
		{
			struct tagSTDOBJREF std;
			struct tagOBJREFDATA * pORData;
			struct tagDUALSTRINGARRAY saResAddr;
		}u_extended;
	} u_objref;
}OBJREF, *LPOBJREF;

DWORD GetCOMServerPID(LPUNKNOWN pInterface)
{
	static const int COM_SERVER_PID_OFFSET = 4;
	DWORD dwPid = 0;
	CComPtr<IStream> marshalStream;
	CreateStreamOnHGlobal(NULL, TRUE, &marshalStream);

	CoMarshalInterface(
		marshalStream,	// Where to write the marshaled interface
		IID_IUnknown,	//ID of the marshaled interface
		pInterface,		// The interface to be marshaled
		MSHCTX_INPROC,	// Unmarshaling will be done in the same process
		NULL,			// Reserved and must be NULL
		MSHLFLAGS_NORMAL// The data packet produced by the marshaling process will be unmarshaled in the destination process
	);

	HGLOBAL memoryHandleFromStream = NULL;
	GetHGlobalFromStream(marshalStream, &memoryHandleFromStream);

	LPOBJREF objef = reinterpret_cast <LPOBJREF> (GlobalLock(memoryHandleFromStream));
	if (objef && objef->signature == OBJREF_SIGNATURE)
	{
		IPID ipid;

		if (objef->flags == OBJREF_STANDARD)
		{
			ipid = objef->u_objref.u_standard.std.ipid;
			dwPid = *reinterpret_cast<LPWORD>(reinterpret_cast<LPBYTE>(&ipid) + COM_SERVER_PID_OFFSET);
		}
		else if (objef->flags == OBJREF_HANDLER)
		{
			ipid = objef->u_objref.u_handler.std.ipid;
			dwPid = *reinterpret_cast<LPWORD>(reinterpret_cast<LPBYTE>(&ipid) + COM_SERVER_PID_OFFSET);
		}
		else if (objef->flags == OBJREF_EXTENDED)
		{
			ipid = objef->u_objref.u_extended.std.ipid;
			dwPid = *reinterpret_cast<LPWORD>(reinterpret_cast<LPBYTE>(&ipid) + COM_SERVER_PID_OFFSET);
		}
	}

	return dwPid;
}