Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/135.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在';它已加载到Excel中_C++_Dll_Com_Xll - Fatal编程技术网

C++ 在';它已加载到Excel中

C++ 在';它已加载到Excel中,c++,dll,com,xll,C++,Dll,Com,Xll,有人知道如何获取与加载了dll的Excel进程相关联的Excel.ApplicationIDispatch*指针吗 这里的一个关键点是进程是excel.exe,我需要的指针必须属于该进程。使用正在运行的对象表将无法运行,因为Excel仅向该表注册其第一个实例 我希望有一些低级的COM欺骗,但我不是该领域的专家。编辑的II代码在许可证版本2下 已编辑:根据@EricBrown的评论建议,添加PID参数以允许在多个Excel进程当前正在运行时进行筛选 我设法在不使用ROT的情况下将一个工作的IDis

有人知道如何获取与加载了
dll
的Excel进程相关联的
Excel.Application
IDispatch*
指针吗

这里的一个关键点是进程是
excel.exe
,我需要的指针必须属于该进程。使用正在运行的对象表将无法运行,因为Excel仅向该表注册其第一个实例


我希望有一些低级的COM欺骗,但我不是该领域的专家。

编辑的II代码在许可证版本2下

已编辑:根据@EricBrown的评论建议,添加PID参数以允许在多个Excel进程当前正在运行时进行筛选

我设法在不使用ROT的情况下将一个工作的
IDispatch*
添加到Excel“应用程序”对象中。诀窍是使用MSAA。我的代码作为一个独立的控制台应用程序工作,但我认为如果代码是在Excel进程中通过DLL注入执行的,它可能工作得很好。您可能必须处于专用线程中。如果您想让我将实验推送到DLL注入级别,请告诉我

在Windows7 64b上测试正常,具有UNICODE版本(32位和64位)。 Excel版本2010 64位(版本“14”)

我通过“工作表”对象的“应用程序”属性获取IDispatch。结果:必须有一个打开的工作表。为了找到好的MSSA窗口,我需要顶级Excel框架窗口的类名。在Excel 2010中,它是“XLMAIN”。工作表的类名是“EXCEL7”,这似乎是一个“标准”

我无法从Excel主窗口直接获取一个正在工作的
IDispatch*
,但我没有尽力。这可能涉及#使用自动化DLL从Excel导入,以便查询接口MSAA为主窗口提供的IDispatch(IDispatch不适用于应用程序对象)

#包括
#pragma注释(lib,“Oleacc.lib”)
HRESULT GetExcelAppDispatch(CComPtr&spIDispatchExcelApp,DWORD dwExcelPID){
结构电子战{
结构ep{
_TCHAR*pszClassName;
德沃德·德皮德;
HWND-HWND;
};
静态BOOL回调ewp(HWND-HWND,LPARAM-LPARAM){
TCHAR szClassName[64];
if(GetClassName(hWnd,szClassName,64)){
ep*pep=重新解释铸件(lParam);
如果(_tcscmp(szClassName,pep->pszClassName)==0){
如果(pep->dwPID==0){
pep->hWnd=hWnd;
返回FALSE;
}否则{
德沃德·德皮德;
if(GetWindowThreadProcessId(hWnd和dwPID)){
如果(dwPID==pep->dwPID){
pep->hWnd=hWnd;
返回FALSE;
}
}
}
}
}
返回TRUE;
}
};
ew::ep;
ep.pszClassName=_TEXT(“XLMAIN”);
ep.dwPID=dwPID;
ep.hWnd=NULL;
枚举窗口(ew::ewp,重新解释强制转换(&ep));
HWND hWndExcel=ep.HWND;
如果(ep.hWnd==NULL){
printf(“无法使用EnumWindows找到主Excel窗口\n”);
返回-1;
}
ep.pszClassName=_TEXT(“EXCEL7”);
ep.dwPID=0;
ep.hWnd=NULL;
EnumChildWindows(HwnExcel、ew::ewp、重新解释强制转换(&ep));
HWND HWND工作表=ep.HWND;
如果(hwndsheet==NULL){
printf(“找不到带有EnumChildWindows的工作表\n”);
返回-1;
}
CComPtr spIDispatchWorkSheet;
HRESULT hr=窗口中的可访问对象(HWND工作表、对象本机、IID_IDispatch、,
重新解释cast(&SPIDISPATCHWORKS));
如果(失败(hr)| |(spIDispatchWorkSheet==0)){
printf(“AccessibleObjectFromWindow失败\n”);
返回人力资源;
}
c变异向量机;
hr=spIDispatchWorkSheet.GetPropertyByName(CComBSTR(“应用程序”),&vExcelApp);
如果(成功(hr)&(vExcelApp.vt==vt_调度)){
spIDispatchExcelApp=vExcelApp.pdispVal;
返回S_OK;
}
返回人力资源;
}
int _tmain(int argc,_TCHAR*argv[]
{
DWORD dwExcelPID=0;
如果(argc>1)dwExcelPID=_ttol(argv[1]);
HRESULT hr=协同初始化(NULL);
bool bCoUnInitializeTodo=false;
如果(成功(hr)){
bCoUnInitializeTodo=true;
CComPtr spDispatchExcelApp;
hr=GetExcelAppDispatch(spDispatchExcelApp,dwExcelPID);
if(成功(hr)和spDispatchExcelApp){
c变异向量机;
hr=spDispatchExcelApp.GetPropertyByName(CComBSTR(“版本”),&vExcelVer);
如果(成功(hr)和(vExcelVer.vt==vt\u BSTR)){
wprintf(L“Excel版本为%s\n”,vExcelVer.bstrVal);
}
}
}
if(bCoUnInitializeTodo)conInitialize();
返回0;
}

编辑的II代码在许可证版本2下

已编辑:根据@EricBrown的评论建议,添加PID参数以允许在多个Excel进程当前正在运行时进行筛选

我设法在不使用ROT的情况下将一个工作的
IDispatch*
添加到Excel“应用程序”对象中。诀窍是使用MSAA。我的代码作为一个独立的控制台应用程序工作,但我认为如果代码是在Excel进程中通过DLL注入执行的,它可能工作得很好。您可能必须处于专用线程中。如果您想让我将实验推送到DLL注入级别,请告诉我

在Windows7 64b上测试正常,具有UNICODE版本(32位和64位)。 Excel版本2010 64位(版本“14”)

我通过“工作表”对象的“应用程序”属性获取IDispatch。结果:必须有一个打开的工作表。为了找到好的MSSA窗口,我需要顶级Excel框架窗口的类名。在Excel 2010中,它是“
#include <atlbase.h>

#pragma comment( lib, "Oleacc.lib" )

HRESULT GetExcelAppDispatch( CComPtr<IDispatch> & spIDispatchExcelApp, DWORD dwExcelPID ) {

   struct ew {
      struct ep {
         _TCHAR* pszClassName;
         DWORD dwPID;
         HWND hWnd;
      };
      static BOOL CALLBACK ewp( HWND hWnd, LPARAM lParam ) {
         TCHAR szClassName[ 64 ];
         if ( GetClassName( hWnd, szClassName, 64 ) ) {
            ep* pep = reinterpret_cast<ep*>( lParam );
            if ( _tcscmp( szClassName, pep->pszClassName ) == 0 ) {
               if ( pep->dwPID == 0 ) {
                  pep->hWnd = hWnd;
                  return FALSE;
               } else {
                  DWORD dwPID;
                  if ( GetWindowThreadProcessId( hWnd, &dwPID ) ) {
                     if ( dwPID == pep->dwPID ) {
                        pep->hWnd = hWnd;
                        return FALSE;
                     }
                  }
               }
            }
         }
         return TRUE;
      }
   };

   ew::ep ep;

   ep.pszClassName = _TEXT( "XLMAIN" );
   ep.dwPID = dwExcelPID;
   ep.hWnd = NULL;
   EnumWindows( ew::ewp, reinterpret_cast<LPARAM>( &ep ) );
   HWND hWndExcel = ep.hWnd;
   if ( ep.hWnd == NULL ) {
      printf( "Can't Find Main Excel Window with EnumWindows\n" );
      return -1;
   }

   ep.pszClassName = _TEXT( "EXCEL7" );
   ep.dwPID = 0;
   ep.hWnd = NULL;
   EnumChildWindows( hWndExcel, ew::ewp, reinterpret_cast<LPARAM>( &ep ) );
   HWND hWndWorkSheet = ep.hWnd;
   if ( hWndWorkSheet == NULL ) {
      printf( "Can't Find a WorkSheet with EnumChildWindows\n" );
      return -1;
   }

   CComPtr<IDispatch> spIDispatchWorkSheet;
   HRESULT hr = AccessibleObjectFromWindow( hWndWorkSheet, OBJID_NATIVEOM, IID_IDispatch,
                                            reinterpret_cast<void**>( &spIDispatchWorkSheet ) );
   if ( FAILED( hr ) || ( spIDispatchWorkSheet == 0 ) ) {
      printf( "AccessibleObjectFromWindow Failed\n" );
      return hr;
   }
   CComVariant vExcelApp;
   hr = spIDispatchWorkSheet.GetPropertyByName( CComBSTR( "Application" ), &vExcelApp );
   if ( SUCCEEDED( hr ) && ( vExcelApp.vt == VT_DISPATCH ) ) {
      spIDispatchExcelApp = vExcelApp.pdispVal;
      return S_OK;
   }
   return hr;

}
int _tmain(int argc, _TCHAR* argv[])
{

   DWORD dwExcelPID = 0;
   if ( argc > 1 ) dwExcelPID = _ttol( argv[ 1 ] );

   HRESULT hr = CoInitialize( NULL );
   bool bCoUnInitializeTodo = false;
   if ( SUCCEEDED( hr ) ) {
      bCoUnInitializeTodo = true;
      CComPtr<IDispatch> spDispatchExcelApp;
      hr = GetExcelAppDispatch( spDispatchExcelApp, dwExcelPID );
      if ( SUCCEEDED( hr ) && spDispatchExcelApp ) {
         CComVariant vExcelVer;
         hr = spDispatchExcelApp.GetPropertyByName( CComBSTR( "Version" ), &vExcelVer );
         if ( SUCCEEDED( hr ) && ( vExcelVer.vt == VT_BSTR ) ) {
            wprintf( L"Excel Version is %s\n", vExcelVer.bstrVal );
         }
      }
   }
   if ( bCoUnInitializeTodo ) CoUninitialize();
   return 0;
}
dispatch_wrapper(void)
{
    DWORD target_process_id = ::GetProcessId(::GetCurrentProcess());

    if (getProcessName() == "excel.exe"){
        HWND hwnd = ::FindWindowEx(0, 0, "XLMAIN", NULL);
        while (hwnd){
            DWORD process_id;
            ::GetWindowThreadProcessId(hwnd, &process_id);
            if (process_id == target_process_id){
                HWND hwnd_desk = ::FindWindowEx(hwnd, 0, "XLDESK", NULL);
                HWND hwnd_7 = ::FindWindowEx(hwnd_desk, 0, "EXCEL7", NULL);
                IDispatch* p = nullptr;
                if (SUCCEEDED(::AccessibleObjectFromWindow(hwnd_7, OBJID_NATIVEOM, IID_IDispatch, (void**)&p))){
                    LPOLESTR name[1] = {L"Application"};
                    DISPID dispid;
                    if (SUCCEEDED(p->GetIDsOfNames(IID_NULL, name, 1U, LOCALE_SYSTEM_DEFAULT, &dispid))){
                        CComVariant v;
                        DISPPARAMS dp;
                        ::memset(&dp, NULL, sizeof(DISPPARAMS));
                        EXCEPINFO ei;
                        ::memset(&ei, NULL, sizeof(EXCEPINFO));
                        if (SUCCEEDED(p->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &dp, &v, &ei, NULL))){
                            if (v.vt == VT_DISPATCH){
                                m_disp_application = v.pdispVal;
                                m_disp_application->AddRef();
                                return;
                            }
                        }
                    }
                }
            }
            hwnd = ::FindWindowEx(0, hwnd, "XLMAIN", NULL);
        }
    }
    m_disp_application = nullptr;
}