#ifndef __COGETSERVERPID_H__
#define __COGETSERVERPID_H__

#include <atlbase.h>

HRESULT CoGetServerPID(IUnknown* punk, DWORD* pdwPID)
{
	HRESULT hr;

	if(pdwPID == NULL) return E_POINTER;
	if(punk == NULL) return E_INVALIDARG;

	// This structure represents the OBJREF
	// up to the pid at offset 52 bytes
	typedef struct tagOBJREFHDR
	{
		DWORD	signature;	// Should be 'MEOW'
		BYTE	padding[48];
		USHORT	pid;
	} OBJREFHDR;

  CComPtr<IUnknown> spProxyManager;
  hr = punk->QueryInterface(IID_IProxyManager, (void**)&spProxyManager);
  if(FAILED(hr))
  {
    // No standard proxy, we can't make any assumptions about remote PID
    return hr;
  }

	// Marshal the interface to get a new OBJREF
	CComPtr<IStream> spMarshalStream;
	hr = ::CreateStreamOnHGlobal(NULL, TRUE, &spMarshalStream);
	if(FAILED(hr)) return hr;

	hr = ::CoMarshalInterface(spMarshalStream, IID_IUnknown, punk, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
	if(FAILED(hr)) return hr;
	
	// We just created the stream, so go back to a raw pointer
	HGLOBAL hg = NULL;
	hr = ::GetHGlobalFromStream(spMarshalStream, &hg);
	if(SUCCEEDED(hr))
	{
		// Start out pessimistic
		hr = RPC_E_INVALID_OBJREF;

		OBJREFHDR *pObjRefHdr = (OBJREFHDR*)GlobalLock(hg);
		if(pObjRefHdr != NULL)
		{
			// Verify that the signature is MEOW
			if(pObjRefHdr->signature == 0x574f454d)
			{
				// We got the remote PID
				*pdwPID = pObjRefHdr->pid;
				hr = S_OK;
			}

			GlobalUnlock(hg);
		}
	}

	// Rewind stream and release marshal data to keep refcount in order
	LARGE_INTEGER li = {0};
	spMarshalStream->Seek(li, SEEK_SET, NULL);
  CoReleaseMarshalData(spMarshalStream);
  
  return hr;
}

#endif //__COGETSERVERPID_H__
