SegeX Automation:VC调用Golden Surfer自动化失败(VC调用Automation失败)原因详解

news2024/10/2 1:27:41

----哆啦刘小洋 原创,转载需说明出处 2022-12-29

SegeX Automation:Surfer自动化(Automation)失败原因

    • 1 简介
    • 2 初始化Surfer对象不成功
      • 2.1 一般代码
      • 2.1 改进代码
    • 3 Windows系统原因
    • 4 Surfer原因
    • 5 其他问题

1 简介

在工程领域,Golden Surfer普遍使用,为了提高成图效率,经常使用自动化(Automation)技术调用Surfer完成自动绘制。但网上一般提供的调用方式会有一定机会失败,从而大大影响了用户的体验并给工作带来困难。本文来源于SegeX Automation组件中的技术,旨在分析Surfer调用失败的原因,并给出解决办法。本文中的一些方法也适用于其他软件如AutoCAD、Office等软件的Automation使用。本文的代码基于VC2012及以上。

2 初始化Surfer对象不成功

2.1 一般代码

VC中初始化Surfer对象的一般代码如下(这里使用的是Automation包装类的方法,用接口的调用方法也是一样的。另外里面返回的错误号是SegeX内定,看的时候可直接忽略):

...
#include "CSurferApplication.h"

long InitSurfer()
{
		CoInitialize(NULL);
		
		CSurferApplication	SurfApp;
		CLSID clsid;
		HRESULT   h=NOERROR;
		IUnknown* pUnknown;
		LPDISPATCH pDispatch;
		BOOL bSuccessget_Object = FALSE;
            
		//获取Surfer的Class ID
		h = ::CLSIDFromProgID(OLESTR("Surfer.Application"), &clsid); 
		if(!SUCCEEDED(h))
			return ERR_AUTOMATION_CAN_NOT_GET_CLSID;
		
		//获取正在运行的Surfer对象
		h = ::GetActiveObject(clsid, NULL, &pUnknown);
		if(SUCCEEDED(h))
		{
			h = pUnknown->QueryInterface(IID_IDispatch, (void**)&pDispatch);
			if(SUCCEEDED(h))
			{
				bSuccessget_Object = TRUE;
				pDispatch->Release();
				SurfApp.AttachDispatch(pDispatch);
			}
		}

    	 //没有正在运行的Surfer对象,就创建一个
		if(!bSuccessget_Object)
			h=SurfApp.CreateDispatch(clsid);

		if(!SUCCEEDED(h) || SurfApp.m_lpDispatch == NULL)
			return ERR_AUTOMATION_CAN_NOT_CREATE_OBJECT;
}

这里使用的是Automation包装类的方法,用接口的调用方法也是一样的(关于两种方法详解,可参考我的另一篇文章“SegeX Automation:VC调用AutoCAD自动化的两种方法(包装类、接口)使用详解”)。CSurferApplication是Surfer Automation包装类CApplication重新改了个名字,至于如何得到Surfer Automation的包装类,网上有很多文章,这里不赘述了。运气好的话,上述代码就可以获取或打开Surfer,后面就好办了。但是!往往这里就会失败。咋办?听我道来。

2.1 改进代码

很多时候(在不同的计算机、不同的Windows版本,表现是不一样),我们在获取Surfer的Class ID就失败了!这是失败的一大主因,但问题是不同的计算机反应不同,所以很多时候我们编程人员不知道是哪里出了问题,因为在编程的计算机上是没有问题的。这是微软自动化技术很大的一个弱点,不强壮!不强壮!(重要的事情说两遍),专业术语讲,不鲁棒!别以为我瞎说,作为SegeX的开发人员,任何一句话、一个细节都是很认真的。言归正传,这里失败的原因出在Windows系统函数::CLSIDFromProgID身上。这个函数我认为不完善,为什么这么讲,必须要多啰嗦两句。
首先,你换个平台,别在VC上折腾,先打开Surfer(切记!),然后用Excel的Vba,你试试Excel中的代码,在Excel中随便写个宏,如果没有Excel,用Word、AutoCAD…,实在不行,就用Surfer中的VbScript也行。如下:

Sub a()
	set app = GetObject(, "Surfer.Application")
End Sub

调试运行,我哇!竟然成功(严格讲是大概率会成功,或者说成功率大大高于上面VC中的代码)!为什么?我们MFC洋洋洒洒数十行比不上人家一行,MFC不没落才怪。所以我说::CLSIDFromProgID是有缺陷的,到了这一步,也可以肯定的讲Vba中绝不是简单的使用::CLSIDFromProgID来获取对象CLSID的。

翻开注册表吧!regedit,点开HKEY_CLASSES_ROOT,直接快速打两个字母“su”,会跳到入下图所示的位置:
在这里插入图片描述

看到了吗?明明有Surfer.Application对应的CLSID。可::CLSIDFromProgID就是视而不见,非要到后面很远的地方去读,不知道微软怎么弄的,咱也不敢乱说。解决方法也呼之欲出了,改进代码如下(为节省篇幅,只写::CLSIDFromProgID相关的地方):

		h = ::CLSIDFromProgID(OLESTR("Surfer.Application"), &clsid); 
		if(!SUCCEEDED(h))
		{
			//尝试从注册表读入
			HKEY hStartKey = HKEY_CLASSES_ROOT;
			TCHAR buf[256] = { 0 };
			BOOL b = GetRegKeyValue(hStartKey, _T("Surfer.Application\\CLSID"), NULL, REG_SZ, (LPBYTE)buf, 256, NULL);
			if (b)
				h = CLSIDFromString(buf, &clsid);
			else
			{
				hStartKey = HKEY_CURRENT_USER;
				b = GetRegKeyValue(hStartKey, _T("SOFTWARE\\Classes\\Surfer.Application\\CLSID"), NULL, REG_SZ, (LPBYTE)buf, 256, NULL);
				if (b)
					h = CLSIDFromString(buf, &clsid);
			}

			if (h != S_OK)
				return ERR_AUTOMATION_CAN_NOT_GET_CLSID;
		}

代码里有个函数GetRegKeyValue,是专门用来读取注册表的,代码如下:

BOOL IsWow64()
{
	BOOL bIsWow64 = FALSE;
	typedef BOOL(WINAPI* LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
	LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process");
	if (NULL != fnIsWow64Process)
	{
		fnIsWow64Process(GetCurrentProcess(), &bIsWow64);
	}

	return bIsWow64;
}
BOOL GetRegKeyValue(HKEY hKey, LPCTSTR lpszSubKey, LPCTSTR lpszItem, DWORD dwType, LPBYTE pRetData, UINT uRetDataBufSize, LPDWORD pRetSize)
{
	HKEY hKeyResult;
	LONG retval;

	if (IsWow64())
		retval = RegOpenKeyEx(hKey, lpszSubKey, 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &hKeyResult);
	else
		retval = RegOpenKeyEx(hKey, lpszSubKey, 0, KEY_QUERY_VALUE, &hKeyResult);

	if (retval == ERROR_SUCCESS || retval == ERROR_MORE_DATA)
	{
		DWORD size = uRetDataBufSize;
		retval = RegQueryValueEx(hKeyResult, lpszItem, 0, &dwType, pRetData, &size);
		if (retval == ERROR_SUCCESS || retval == ERROR_MORE_DATA)
		{
			if (pRetSize != NULL)
				*pRetSize = size;
			if (dwType == REG_SZ)
				pRetData[size] = 0;
		}
		RegCloseKey(hKeyResult);

		return (retval == ERROR_SUCCESS || retval == ERROR_MORE_DATA);
	}
	return (retval == ERROR_SUCCESS || retval == ERROR_MORE_DATA);
}

3 Windows系统原因

我们下了这么多功夫,应该没问题了吧!呵呵,那你太小看MFC了,它总是会时不时的跳起来,突然出其不意的给你一击。“MFC,永远在路上!”,我给MFC的墓志铭。

不多说了,首先你的程序最好设置为系统管理员权限。在哪里设置?呃。。。,我找找,唉,实在是找不到!还有一句想送的话:”永远别低估VC的难度!“。好了,在”链接器/清单文件/UAC执行级别“,选则:“requireAdministrator”。
这下有预感了吧!事情没有结束,这时我已经没有什么别的好办法了,让用户先打开Surfer,打开方式尝试两种:普通运行和管理员身份运行。可能总有一种适合他的计算机。

4 Surfer原因

事情是没有结束。我们一味指责MFC、Windows也不全对,因为Surfer本身也有问题。不然,为什么你用自动化技术打开Excel、AutoCAD很少出问题呢?第一个问题就是Surfer在注册自动化组件时不完善,也就是注册表中关于自动化项不完善,导致VC调用失败。但这里要说的不是这个。而是你不要安装多个不同的Surfer版本。安装了不同版本之后,可能时之间有冲突,也会导致失败。这时候,请你请求你的用户,让他们删除多余的Surfer,留一个就够了。

这时候就又双叒引申了新的Surfer问题,Surfer删除不干净!也就是说,用户只留了一个Surfer也仍然不行了。这时候已经不是代码问题了, 也不是VC、VB或C#能解决的问题了。请让用户不要嫌麻烦,也不要怪罪开发人员,直接按下面方法干就完了:
1)删除所有的Surfer,重新启动计算机。
2)打开注册表,搜索“Surfer.Application”,见一个删一个,看都不要看。
3)打开Execel的Vba开发代码窗口,别的微软的Vba开发代码窗口也行,在菜单“工具/引用”弹出的对话框中,看看有没有Surfer的影子:
在这里插入图片描述

如果有,看一下下面它定位的位置,比如“C:\Program Files\Golden Software\Surfer 12\Surfer.exe”。回到注册表,从头开始,搜索这个字符串,还是见一个删一个。
4)重新安装一个Surfer。

如果又双叒叕不成功,最后的最后,去建议用户安装一个相对低版本的Surfer,我的建议是11~14。

5 其他问题

在使用surfer接口函数时,也要注意:
1)要考虑到中英文版的区别。这个Surfer也是奇葩,汉化的时候,内核也全部汉化了!!简直就是简直了!内核你去汉化它是个什么鬼思路,想让用户看你里面穿的什么马甲吗?关键是汉化之后,开发人员麻烦了,比如预设的颜色值红色,本来英文版就是“red”,代码中也用字符串“red”读取,但汉化后,这个常量变成“红色”了,也就是你代码中要放两套,我去!而且,而且还有不同的汉化版,一个颜色的汉语两个汉化版用的不是一个词语!更别说还有湾湾的繁体字!坚决让你的用户用英文版!
2)要考虑后续Surfer版本接口函数的参数变化以及执行的差别,否则会导致程序崩溃或调用提前终止。

不说了,如果想更详细了解Surfer自动化处理的细节代码,请看我的另一篇文章“SegeX Automation:VC VB(VBA) C# 调用Golden Surfer自动化(Automation)方法详解”,当然这篇文章还没有写,希望你看这篇文章的时候,那篇文章也写好了。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

国产无线耳机什么牌子好?国产真无线蓝牙耳机排行

随着近几年蓝牙耳机市场的快速发展,蓝牙耳机依旧占据着半个行业的份额,在人们的日常生活中出现的频率也越来越高。叫得上名的国产蓝牙耳机牌子也越来越多,那么,国产无线耳机什么牌子好?下面,我来给大家推荐…

无代码资讯 | Gartner 预测明年低代码市场规模;微软推出低代码学习平台;AWS 推出开发无服务器应用的低代码平台

栏目导读:无代码资讯栏目从全球视角出发,带您了解无代码相关最新资讯。 TOP3 大事件 1、Gartner 预测到 2023 年,全球低代码市场预计达到269亿美元 根据 Gartner 的最新预测,到 2023 年全球低代码开发技术市场规模预计将达到 269…

hnu计网实验三-应用层和传输层协议分析(PacketTracer)

前言:难度适中的一个实验 一、实验目的 通过本实验,熟悉PacketTracer的使用,学习在PacketTracer中仿真分析应用层和传输层协议,进一步加深对协议工作过程的理解。 二、实验内容 研究应用层和传输层协议 从 PC 使用 URL 捕获 W…

多道程序与分时多任务--rCore[3]

概念 协作式操作系统 计算机硬件在快速发展,内存容量在逐渐增大,处理器的速度也在增加,外设 I/O 性能方面的进展不大。于是就想到,让应用在执行 I/O 操作或空闲时,可以主动 释放处理器 ,让其他应用继续执行…

Linux- 系统随你玩之--grep查找文件内容

1、前言 我们在使用过程中经常需要对当前获取的文件进行过滤、提取和分析,以便快速查找到含有指定内容的文件或指定信息的那些行。本章我们继续深入了解有关文本检索的内容。 2、grep 查找文件内容 Linux系统中grep命令是一种强大的文本搜索工具,它能…

使用Loki收集网络设备日志

新钛云服已累计为您分享716篇技术干货前言Loki是Grafana Labs团队的开源项目,是一个水平可扩展,高可用性,多租户的日志聚合系统,它的设计非常简洁易于操作。受Prometheus启发的,可以水平扩展、高可用以及支持多租户的日…

S-HUB如何实现数据库对接WEBSERVICE API

近几年SAAS被大家逐步认可,越来越多的企业购买SAAS服务,但是仍然有很多自建各种业务系统,这些系统建设时一般都只考虑自身业务,而不是特别注重与别的系统之间的互联互通。而企业为了提升效率,又需要将这些业务与别的系…

Java开发 - 双向链表不可怕

前言 说起链表,那还是当初上学的时候学习的,印象里就觉得像锁链一样一环扣一环,后来工作后就几乎没实际接触过链表,每当遇到链表,总是不知道该怎么讲,因为对链表的本质一无所知。也是在学习了Java后&#…

剑指offer----C语言版----第三天

目录 1. 替换空格 1.1 题目描述 1.2 题目背景 1.3 必要的思考 1.4 思路一 1.5 思路二 1.6 思路三(学方法) 1.7 小试牛刀 1. 替换空格 原题链接:剑指 Offer 05. 替换空格 - 力扣(LeetCode)https://leetcode.cn/p…

回首2022,展望2023(年度总结)

回首2022,展望2023 热爱技术的伙计们: 哈喽,这篇文章经过一周左右的写写改改,在2022最后的工作日与大家见面,有人说总结是为了更好的开始。是的,一年的时间真的很快,马上就是2023了&#xff0…

k-mean聚类的python实现

文章目录介绍KMeans()函数介绍实例导入相关包整理数据手肘法确定分类个数创建模型绘制结果分为3类的结果作者:张双双介绍 sklearn.cluster模块提供了常用的非监督聚类算法。 该模块中每一个聚类算法都有两个变体: 一个是类(class)另一个是函数(function)。 类实现了…

day06 Debug基础练习

1.Debug模式 1.1 什么是Debug模式 是供程序员使用的程序调试工具,它可以用于查看程序的执行流程,也可以用于追踪程序执行过程来调试程序。 1.2 Debug介绍与操作流程 如何加断点 选择要设置断点的代码行,在行号的区域后面单击鼠标左键即可 …

刷题记录:牛客NC24858Job Hunt [最长路+两种不同判环详解]

传送门:牛客 题目描述: 奶牛们正在找工作。农场主约翰知道后,鼓励奶牛们四处碰碰运气。而且他还加了一条要求:一头牛在一个城市 最多只能赚D(1≤D≤1000)美元,然后它必须到另一座城市工作。当然,它可以在…

2自由度陀螺仪滑模控制和PID控制跟踪目标轨迹

目录 前言 1.陀螺仪模型 2.滑模跟踪控制 3.PID控制 4.总结 前言 不为别的,这篇小文章只为内涵某人,问候一下他:不是有手就行,哈哈~ 1.陀螺仪模型 2.滑模跟踪控制 对于2自由度陀螺仪有两个方向x、y跟踪,所以需要…

对于软件测试认识的几大误区,看看你有没有?

对于软件开发来说,软件测试可能还不被大众了解,很多开发人员,包括很多软件高层管理人员,由于缺乏软件测试的知识和实践经验,对软件测试的认识还有很多的误区: 误区一:如果软件发布后有质量问题…

我们一起来谈谈高并发和分布式系统的幂等如何处理!

什么是幂等性 幂等是一个数学与计算机学概念,在数学中某一元运算为幂等时,其作用在任一元素两次后会和其作用一次的结果相同。 在计算机中编程中,一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。 幂等函数或幂等…

Codeforces Round #841 (Div. 2)

题目链接 A. Joey Takes Money 题目描述 input output 题意: 有一个长度为n的数组,你可以进行一步操作,选择两个i,j,然后再选择两个数x,y,使得a[i]a[j] xy,然后将a[i] x,a[j] y,问任意步操…

Spring 中运用的 9 种设计模式

Spring中涉及的设计模式总结,在面试中也会经常问道 Spring 中设计模式的问题。本文以实现方式、实质、实现原理的结构简单介绍 Sping 中应用的 9 种设计模型,具体详细的刨析会在后面的文章发布,话不多说,来个转发、在看、收藏三连…

京东软件测试岗:惨不忍睹的三面,幸好做足了准备,月薪17k,已拿offer

我今年25岁,专业是电子信息工程本科,19年年末的时候去面试,统一投了测试的岗位,软件硬件都有,那时候面试的两家公司都是做培训的,当初没啥钱,他们以面试为谎言再推荐去培训这点让我特别难受。 …

Unity 搭建ILRuntime开发环境

Unity热更新目前主流的方案有: Lua, ILRuntime, puerts, huatuo方案。前两个大家都比较熟悉了,puerts 是基于TypeScript开发的热更新,huatuo是基于C#的方案。后两个大家会比较陌生。本系列分享基于ILRuntime来做热更新。 对啦!这里有个游戏开…