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

2024-04-29 14:48

本文主要是介绍关于GetActiveObject失败的灵异现象的解决,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

最近做一个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/
 

 

这篇关于关于GetActiveObject失败的灵异现象的解决的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/946389

相关文章

Spring的RedisTemplate的json反序列泛型丢失问题解决

《Spring的RedisTemplate的json反序列泛型丢失问题解决》本文主要介绍了SpringRedisTemplate中使用JSON序列化时泛型信息丢失的问题及其提出三种解决方案,可以根据性... 目录背景解决方案方案一方案二方案三总结背景在使用RedisTemplate操作redis时我们针对

SpringBoot整合Dubbo+ZK注册失败的坑及解决

《SpringBoot整合Dubbo+ZK注册失败的坑及解决》使用Dubbo框架时,需在公共pom添加依赖,启动类加@EnableDubbo,实现类用@DubboService替代@Service,配... 目录1.先看下公共的pom(maven创建的pom工程)2.启动类上加@EnableDubbo3.实

nginx中端口无权限的问题解决

《nginx中端口无权限的问题解决》当Nginx日志报错bind()to80failed(13:Permissiondenied)时,这通常是由于权限不足导致Nginx无法绑定到80端口,下面就来... 目录一、问题原因分析二、解决方案1. 以 root 权限运行 Nginx(不推荐)2. 为 Nginx

解决1093 - You can‘t specify target table报错问题及原因分析

《解决1093-Youcan‘tspecifytargettable报错问题及原因分析》MySQL1093错误因UPDATE/DELETE语句的FROM子句直接引用目标表或嵌套子查询导致,... 目录报js错原因分析具体原因解决办法方法一:使用临时表方法二:使用JOIN方法三:使用EXISTS示例总结报错原

Windows环境下解决Matplotlib中文字体显示问题的详细教程

《Windows环境下解决Matplotlib中文字体显示问题的详细教程》本文详细介绍了在Windows下解决Matplotlib中文显示问题的方法,包括安装字体、更新缓存、配置文件设置及编码調整,并... 目录引言问题分析解决方案详解1. 检查系统已安装字体2. 手动添加中文字体(以SimHei为例)步骤

nginx 负载均衡配置及如何解决重复登录问题

《nginx负载均衡配置及如何解决重复登录问题》文章详解Nginx源码安装与Docker部署,介绍四层/七层代理区别及负载均衡策略,通过ip_hash解决重复登录问题,对nginx负载均衡配置及如何... 目录一:源码安装:1.配置编译参数2.编译3.编译安装 二,四层代理和七层代理区别1.二者混合使用举例

Java中读取YAML文件配置信息常见问题及解决方法

《Java中读取YAML文件配置信息常见问题及解决方法》:本文主要介绍Java中读取YAML文件配置信息常见问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要... 目录1 使用Spring Boot的@ConfigurationProperties2. 使用@Valu

SQL Server配置管理器无法打开的四种解决方法

《SQLServer配置管理器无法打开的四种解决方法》本文总结了SQLServer配置管理器无法打开的四种解决方法,文中通过图文示例介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录方法一:桌面图标进入方法二:运行窗口进入检查版本号对照表php方法三:查找文件路径方法四:检查 S

Redis出现中文乱码的问题及解决

《Redis出现中文乱码的问题及解决》:本文主要介绍Redis出现中文乱码的问题及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 问题的产生2China编程. 问题的解决redihttp://www.chinasem.cns数据进制问题的解决中文乱码问题解决总结

Python中Tensorflow无法调用GPU问题的解决方法

《Python中Tensorflow无法调用GPU问题的解决方法》文章详解如何解决TensorFlow在Windows无法识别GPU的问题,需降级至2.10版本,安装匹配CUDA11.2和cuDNN... 当用以下代码查看GPU数量时,gpuspython返回的是一个空列表,说明tensorflow没有找到