关于GetActiveObject失败的灵异现象的解决

来源:互联网 发布:python tempfile 删除 编辑:程序博客网 时间:2024/06/13 07:37
 

最近做一个WORD AUTOMATION的程序,封装成DLL来实现WORD的自动化。开始进行的很顺利,在中文系统下没有任何问题,可是当拿到俄文系统时,问题出现了。而且出现得很是灵异。现象是,当把程序做成EXE时,没有任何问题,封装成DLL时,GetActiveObject就取不到活动的WORD文档了。反复测试发现了非常非常灵异的情况,就是当打开两个以上的文档时,GetActiveObject就可用。这个问题困扰了我好几天,真是百思不解呀。GOOGLE,百度,CSDN,MSDN,国内外的资料翻了个遍,也没找到原因。受了几天的折磨,就在快要放弃的时候,突然峰回路转,在MS support网站上找到了原因。苍天呀,原来是被微软给玩了一把。不过也怪自己,这遍文章之前找资料的时候也曾经见到过,只是当时看的不是特别认真,以为自己遇到的问题不是一回事,结果在这个问题上浪费了很多的时间。

这个故事告诉我们,一定要坚持,更一定要认真~~~~~~

我的代码:

CLSID clsid;
HRESULT hr;
hr=::CLSIDFromProgID(L"Word.Application",&clsid);
if(FAILED(hr))
{
   AfxMessageBox(_T("NO OFFICE"));
   return;
}

IUnknown *pUnknown=NULL;
IDispatch *pDispatch=NULL;
_Application app=NULL;
Selection sel=NULL;

hr=::GetActiveObject(clsid,NULL,&pUnknown); //在俄文系统不可用
if(FAILED(hr))
{
   AfxMessageBox(_T("NO WORD"));
   return;
}

       下面是微软给出的原因:Although the Office application is running, it might not be registered in the Running Object Table (ROT). A running instance of an Office application must be registered in the ROT before it can be attached to using GetObject (Visual Basic) or GetActiveObject (Visual C++).

When an Office application starts, it does not immediately register its running objects. This optimizes the application's startup process. Instead of registering at startup, an Office application registers its running objects in the ROT once it loses focus. Therefore, if you attempt to use GetObject or GetActiveObject to attach to a running instance of an Office application before the application has lost focus, you might receive one of the errors above.

         简单的说就是,MS对OFFICE的启动进行了优化以提高OFFICE的启动速度(不过不知道为什么没有对中文OFFICE进行优化),即不是OFFICE一启动就在ROT表进行注册,而是在OFFICE失去一次焦点之后,才进行注册。这就是我遇到的为什么只有在打开两个以上的WORD文档时GetActiveObject才能取到。实际情况不是非要打开两个以上的文档,只要使打开的WORD文档失去一次焦点就可以了,即不让它激活,也就是WORD文档窗变成灰的,或是说让WORD不在最前面(我也不知道严格讲应该怎样表达),就相当于你打开一个WORD文档,然后用鼠标点一下其他的窗口。不知道这么说够不够通俗易懂。这样,OFFICE就会去ROT进行注册,你的GetActiveObject也就能取到了。就可以进行下面的工作了。呵呵。

       MS给出的解决方案:

Workaround for C++
If you are programming in C++, the following code sample demonstrates a similar workaround to that shown in the above Visual Basic sample. Notice that SetForegroundWindow is used to move focus away from Excel, allowing it to register its running objects.


//Store the handle of the currently active window...
HWND hwndCurrent = ::GetForegroundWindow();

//Launch Excel and wait until it is waiting for
//user input...
STARTUPINFO Start;
PROCESS_INFORMATION ProcInfo;
ZeroMemory(&Start,sizeof(STARTUPINFO));
Start.cb=sizeof(Start);
Start.dwFlags = STARTF_USESHOWWINDOW;
Start.wShowWindow = SW_SHOWMINIMIZED;

//Change the path to Excel as needed...
LPSTR pszExcelPath =
      "c:\\program files\\microsoft office\\office\\excel.exe";

::CreateProcess(NULL, pszExcelPath, 0, 0, 1,
       NORMAL_PRIORITY_CLASS, 0, NULL, &Start, &ProcInfo);

if((::WaitForInputIdle(ProcInfo.hProcess, 10000))==WAIT_TIMEOUT)
{
    ::MessageBox(NULL, "Timed out waiting for Excel.", NULL, 
                 MB_OK);
}

//Restore the active window to the foreground...
//  NOTE: If you comment out this line, the code will fail!
::SetForegroundWindow(hwndCurrent);

//Initialize COM library...
::CoInitialize(NULL);

//Attach to the running instance...
CLSID clsid;
CLSIDFromProgID(L"Excel.Application", &clsid); 
IUnknown *pUnk = NULL;
IDispatch *pDisp = NULL;

for(int i=1;i<=5;i++) //try attaching for up to 5 attempts
{
   HRESULT hr = GetActiveObject(clsid, NULL, (IUnknown**)&pUnk);
   if(SUCCEEDED(hr))
   {
       hr = pUnk->QueryInterface(IID_IDispatch, (void **)&pDisp);
       break;
   }
   ::Sleep(1000);
}
       
if (!pDisp) {
    ::MessageBox(NULL, "Failed to find instance!!", "Error",
                 MB_ICONHAND);
}
else {
    ::MessageBox(NULL, "Got instance of Excel!", "Success", MB_OK);
}

//Release the no-longer-needed IUnknown...
if (pUnk)
    pUnk->Release();

//... Add your automation code for Excel here ...

//Release pDisp when no longer needed...
if (pDisp)
    pDisp->Release();

//Cleanup COM...
CoUninitialize();
具体原因就看下面吧:
http://support.microsoft.com/kb/238610/en-us/
 

 

原创粉丝点击