获取COM接口CoCreateInstance启动的进程PID

Posted 尚书左仆射

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了获取COM接口CoCreateInstance启动的进程PID相关的知识,希望对你有一定的参考价值。

CoCreateInstance是一个让COM变得更加有趣和可用的工具。然而,它并没有让你知道一个非常重要的信息——新启动的进程的id。也没有其他的API可以告诉我们这一点。这就是微软所谓的设计。

当我们启动像Excel或者PowerPoint时,问题就出现了。当你需要它们提供服务的时候,他们做得很好。但去尝试让他们退出,你就要开始抓狂了。一些Excel流程是不可能消失的。然后你就会明白为什么你需要进程id。如果你有进程id,至少你可以强制关闭它。

现在,虽然没有任何官方的方法可以做到这一点,但是有一些专家已经为你做了这些艰苦的工作。他们发现进程id数据被封装到COM中的某个地方,只是处理的方式比较晦涩。

下面就展示一下具体如何来获取通过CoCreateInstance接口创建的进程PID。

需要的头文件如下:

//cogetserverpid.h
/*******************************************************************************
Copyright (c) 2012, Kim Gr鋝man
All rights reserved.

Released under the Modified BSD license. For details, please see LICENSE file.

*******************************************************************************/
#ifndef INCLUDED_COGETSERVERPID_H__
#define INCLUDED_COGETSERVERPID_H__

#include <objbase.h>

/* This structure represents the OBJREF up to the PID at offset 52 bytes.
   1-byte structure packing to make sure offsets are deterministic. */
#pragma pack(push, 1)
typedef struct tagCOGETSERVERPID_OBJREFHDR

  DWORD signature;  /* Should be 'MEOW'. */
  DWORD flags;
  BYTE padding[44];
  USHORT pid;
 COGETSERVERPID_OBJREFHDR;
#pragma pack(pop)

inline HRESULT CoGetServerPID(IUnknown* punk, DWORD* pdwPID)

  HRESULT hr;
  IUnknown* pProxyManager = NULL;
  IStream* pMarshalStream = NULL;
  HGLOBAL hg = NULL;
  COGETSERVERPID_OBJREFHDR *pObjRefHdr = NULL;
  LARGE_INTEGER zero = 0;

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

  /* Make sure this is a standard proxy, otherwise we can't make any
     assumptions about OBJREF wire format. */
  hr = punk->QueryInterface(IID_IProxyManager, (void**)&pProxyManager);
  if(FAILED(hr)) return hr;

  pProxyManager->Release();

  /* Marshal the interface to get a new OBJREF. */
  hr = ::CreateStreamOnHGlobal(NULL, TRUE, &pMarshalStream);
  if(SUCCEEDED(hr))
  
    hr = ::CoMarshalInterface(pMarshalStream, IID_IUnknown, punk,
      MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
    if(SUCCEEDED(hr))
    
      /* We just created the stream so it's safe to go back to a raw pointer. */
      hr = ::GetHGlobalFromStream(pMarshalStream, &hg);
      if(SUCCEEDED(hr))
      
        /* Start out pessimistic. */
        hr = RPC_E_INVALID_OBJREF;

        pObjRefHdr = (COGETSERVERPID_OBJREFHDR*)GlobalLock(hg);
        if(pObjRefHdr != NULL)
        
          /* Validate what we can. */
          if(pObjRefHdr->signature == 0x574f454d && /* 'MEOW' */
             pObjRefHdr->flags == 1 && /* OBJREF_STANDARD */
             pObjRefHdr->pid != 0xFFFF) /* PIDs are sometimes clamped at 64K */
          
            /* We got the remote PID! */
            *pdwPID = pObjRefHdr->pid;
            hr = S_OK;
          

          GlobalUnlock(hg);
        
      

      /* Rewind stream and release marshal data to keep refcount in order. */
      pMarshalStream->Seek(zero, SEEK_SET, NULL);
      CoReleaseMarshalData(pMarshalStream);
    

    pMarshalStream->Release();
  

  return hr;


#endif // INCLUDED_COGETSERVERPID_H__

接下来,我们只要导入该头文件,然后在需要的时候调用其中获取PID的接口即可。示例代码如下:

#include "cogetserverpid.h"
#include <atlbase.h>

int main(int argc, char* argv[])

  CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);

  
    CComPtr<IUnknown> word;
    HRESULT hr = word.CoCreateInstance(L"Word.Application", NULL, CLSCTX_LOCAL_SERVER);
    printf("Word.Application created: 0x%X\\n", hr);

    DWORD wordPID = 0;
    hr = CoGetServerPID(word, &wordPID);
    printf("Word.Application PID: %d (0x%X)\\n", wordPID, hr);
  

  CoUninitialize();

  return 0;

或者一些其他使用场景:

//创建进程	
hr = ::CoCreateInstance( clsid, NULL, CLSCTX_ALL, IID_IUnknown, (void**)&m_pIUnk );
	if( FAILED(hr) )
	
		//·····
	
	else
	
            //开始获取PID
		DWORD wordPID = 0;
		hr = CoGetServerPID(m_pIUnk , &wordPID);
		m_dwPIDInfo = wordPID;
        

看着熟悉的PID又出现在了面前,终于又可以愉快地继续工作了。

以上是关于获取COM接口CoCreateInstance启动的进程PID的主要内容,如果未能解决你的问题,请参考以下文章

COM笔记-CoCreateInstance

即使找到接口,CoCreateInstance 也会返回 E_NOINTERFACE

在 COM 中:我应该在 CoCreateInstance 之后调用 AddRef 吗?

执行 CoCreateInstance 时出现 COM 错误 0x8007002(找不到文件)

CoCreateInstance 返回 E_INVALIDARG

确认注册的 COM 对象 CoCreateInstance 返回 REGDB_E_CLASSNOTREG