문제

누구든지 Excel.Application가로드 된 Excel 프로세스와 관련된 IDispatch* dll Pointer를 보유하는 방법을 알고 있습니까?

여기서 중요한 것은 프로세스가 excel.exe이고 가 필요로하는 포인터는 해당 프로세스에 속해야합니다.Excel만이 첫 번째 인스턴스 만 등록하기 때문에 실행중인 오브젝트 테이블을 사용하지 않습니다.

저는 저수준의 Com 트릭이 있기를 바랍니다. 그러나 저는 그 분야의 전문가가 아닙니다.

도움이 되었습니까?

해결책

edited II 코드는 wtfpl 라이센스 버전에 속해 있습니다. 2.

편집 된 : @ericbrown의 주석 제안에 따라 현재 여러 개의 Excel 프로세스가 실행 중일 때 필터링을 허용 할 PID 매개 변수를 추가합니다.

ROT를 사용하지 않고 Excel "Application"객체로 작업 IDispatch*를 얻을 수있었습니다. 트릭은 MSAA를 사용하는 것입니다. 내 코드는 독립형 콘솔 응용 프로그램으로 작동하지만 코드가 Excel 프로세스에서 실행되는 경우 DLL 주입을 통해 잘 작동 할 수 있다고 생각합니다. 전용 스레드에 있어야 할 수도 있습니다. 내가 DLL 주입 수준으로 혐의를 밀어 내기를 원한다면 알려주세요.

유니 코드 빌드 (32 비트 및 64 비트)가있는 Window7 64B에서 확인했습니다. Excel 버전 2010 64 비트 (버전 "14")

"워크 시트"개체에서 "응용 프로그램"속성을 통해 IDispatch를 얻습니다. 결과 : 열린 워크 시트가 있어야합니다. 좋은 MSSA 창을 찾으려면 최상위 Excel 프레임 창의 클래스 이름이 필요합니다. Excel 2010에서는 "Xlmain"입니다. 워크 시트의 클래스 이름은 "Excel7"이며 "표준"인 것으로 보입니다.

메인 Excel 창에서 WorkerOcodiceTag 코드를 직접 얻을 수 없었지만 매우 열심히 노력하지 않았습니다. 이는 MSAA가 주 창을 제공하는 iDispatch (Idispatch가 응용 프로그램 개체에 대한 것이 아닌 경우) isISPATCH를 쿼리하기 위해 Excel에서 자동화 DLL을 사용하여 #import를 포함 할 수 있습니다.

#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;
}
.

다른 팁

exceldna 에서 코드를 검토 하여이 작업을 수행하는 방법을 찾아야합니다.이 프로젝트에는 확장 라이브러리에서 Excel로 다시 연결되는 코드가 들어 있습니다.코드는 필요한 것이 더 정교해질 가능성이 있지만 필요한 참조를 구현합니다.

이것은 내가 어떻게하는지입니다 : (@manuell 인정).dispatch_wrapper는 클래스이며, 다음은 m_disp_application를 설정하는 생성자입니다.

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;
}
.

getProcessName()는 소문자를 반환합니다.

Office 응용 프로그램이 문서를 썩음에 등록하기 때문에 썩은 의 문서에 IDispatch를 얻는 다음 document.application.hwnd (VBA이므로 번역 todispatch :: getIDSOFNAMES 및 IDispatch :: Dispatch_PropertyGet 가있는 invoke 윈도우 핸들을 얻으려면 인스턴스.

이제 모든 Excel 인스턴스의 IDispatch와 Windows 핸들 사이에 매핑이 있으므로 사용자가 자신의 Excel 인스턴스를 찾을 시간입니다. 창 핸들에서 GetWindowThreadProcessID를 호출하여 프로세스 ID를 가져온 다음 GetCurrentProcessID가 리턴 한 사용자 자신의 프로세스 ID와 비교하여 현재 프로세스에 속한 Excel 창이 속한 Excel 창을보고 현재 Excel 응용 프로그램을 찾기 위해 iDispatch 매핑을 찾습니다. IDispatch 인터페이스.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top