近期研究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;
}