转载:http://www.it1352.com/534235.html

问题:

I am writing a Windows Form application in .Net to list all running instances of a third-party CAD/CAM software (in this case CATIA) and let user to choose one of them to perform couple of automated tasks. For performing automated tasks, I need to get the specific instance of COM objects - compared to Getobject() which gives me a non-specific COM instance. Is there a way to get a specific COM instance using window handle or any other methods?

UPDATE: As Raymond said there is no single solution for all COM objects; however I managed to get CATIA COM objects using following code (Which uses ROT to fill a list with all CATIA COM Instances name):

<DllImport("user32.dll", CharSet:=CharSet.Auto)> Private Shared Sub GetClassName(ByVal hWnd As System.IntPtr, ByVal lpClassName As System.Text.StringBuilder, ByVal nMaxCount As Integer) End Sub
<DllImport("ole32.dll", ExactSpelling:=True, PreserveSig:=False)> Private Shared Function GetRunningObjectTable(ByVal reserved As Int32) As IRunningObjectTable End Function
<DllImport("ole32.dll", CharSet:=CharSet.Unicode, ExactSpelling:=True, PreserveSig:=False)> Private Shared Function CreateItemMoniker(ByVal lpszDelim As String, ByVal lpszItem As String) As IMoniker End Function
<DllImport("ole32.dll", ExactSpelling:=True, PreserveSig:=False)> Private Shared Function CreateBindCtx(ByVal reserved As Integer) As IBindCtx End Function Try Dim ROTObject As Object = Nothing
Dim runningObjectTable As IRunningObjectTable
Dim monikerEnumerator As IEnumMoniker = Nothing
Dim monikers(1) As IMoniker runningObjectTable = GetRunningObjectTable(0)
runningObjectTable.EnumRunning(monikerEnumerator)
monikerEnumerator.Reset() Dim numFetched As IntPtr = New IntPtr()
While (monikerEnumerator.Next(1, monikers, numFetched) = 0)
Dim ctx As IBindCtx
ctx = CreateBindCtx(0) Dim runningObjectName As String = ""
monikers(0).GetDisplayName(ctx, Nothing, runningObjectName) runningObjectName = runningObjectName.ToUpper
If (Not runningObjectName.Equals("")) Then
Dim runningObjectIns As Object = Nothing
runningObjectTable.GetObject(monikers(0), runningObjectIns) 'Check if object is a Catia object
Try
Dim catiaIns As INFITF.Application = Nothing
catiaIns = DirectCast(runningObjectIns, INFITF.Application)
ListCATIA.Items.Add(catiaIns.Windows.Count)
Catch Exc As Exception
MessageBox.Show(Exc.ToString())
End Try
End If
End While Catch Exc As Exception
Throw Exc
End Try

However, all CATIA instances refer to first CATIA application loaded. No idea why, anybody?

解决方案

The "problem" in your code is that calling GetObject always returns the first active server that it finds in the Running Object Table (ROT). Enumerating the ROT doesn't change that behavior and is a little frustrating because it does show that there is more than one server in the ROT. Note that some of the items returned in the enumeration may not actually be running: GetObject returns the first active server -- not necessarily the first one returned by the enumeration.

However, in the case of CATIA in particular it is possible to get a specific instance. I suspect it is possible with many applications if you can get the particular instance of interest to run some code, on demand, before you actually get a pointer to the COM instance.

For CATIA, this is a rough outline of the process I use:

1. Make a dll with two functions:
HRESULT __stdcall CoMarshalToFile(IUnknown* punk, const char* const filePath)
/* uses `::CreateStreamOnHGlobal`, `::CoMarshalInterface`, `::CoGetMarshalSizeMax`,
and `::GetHGlobalFromStream` to marshal the IUnknown to the specified file.
*/
HRESULT __stdcall CoMarshalFromFile(IUnknown** ppunk, const char* const filePath)
/* uses `::CreateStreamOnHGlobal` and `::CoUnmarshalInterface` to marshal
from the file to an IUnknown pointer.
*/ 2. In CATIA:
Note: this only needs to be done on the development computer.
Make a new "VBA projects" macro library.
Add "declare" statements for:
"LoadLibrary" (Windows API)
"CoMarshalToFile" (DLL specified above)
Add a function
Public Function MarshalCatiaToFile _
(marshalInstanceFilePath As String, _
marshalDllFolder As String) As Long MarshalCatiaToFile calls "LoadLibrary" to load the C++ DLL
and then calls CoMarshalToFile (in DLL) to marshal the CATIA instance
to a file. Remove the macro library from CATIA's list of macro libraries. 3. Create a file:
"C:\Temp\CatiaOnTheFlyCatScripts\OnTheFlyCatScript.catvbs"
The file can be empty. 4. In CATIA:
Note: this must be done for *each* user of CATIA on *each* computer used.
It may be possible to make this available to all users without individual
setup required: it is saved in "FrameUserAliases.CATSettings"
It may also be possible to reverse engineer the settings file and set up
the needed data from outside CATIA. Add "C:\Temp\CatiaOnTheFlyCatScripts\" as a new "Directories" macro library.
Make the added library "current"
Use "Tools --> Customize --> Commands --> Macros" to assign a
"User Alias:" to the "OnTheFlyCatScript.catvbs" script file.
Name the alias "ExecuteOnTheFlyCatScript".
Remove the macro library from CATIA's list of macro libraries.
Close CATIA at this point to force the changes to be saved. 5. VB.net / C# program:
Add the DLL (from step 1) and the CatVBA macro library (from step 2) as
"Embedded Resource" to the project. During program execution:
Extract the DLL and macro library to an appropriate location.
Load the DLL into session using "LoadLibrary".
Create the file:
"C:\Temp\CatiaOnTheFlyCatScripts\OnTheFlyCatScript.catvbs" The "OnTheFlyCatScript.catvbs" will be executed in CATIA. It
uses CATIA.SystemService.ExecuteScript to execute the
"MarshalCatiaToFile" function in the CatVBA macro library.
Add method of choice to this file to indicate success/failure.
I use a dialog box with the appropriate title. To execute the "OnTheFlyCatScript.catvbs":
Using the Windows API functions, get the window handle for the
"Power Input" box at the bottom right of the "desired"
CATIA window.
Using the Windows API functions (*NOT* "SendKeys") send
"c:ExecuteOnTheFlyCatScript" + {Enter} to the "Power Input".
Wait for the "completion" signal from the script. If you used
a dialog box, use the Windows API function to close it. Assuming the script succeeded in marshaling the CATIA instance to
a file, call the DLL function CoMarshalFromFile to get the CATIA
instance.

It's a lot of work with many "moving" parts but it does allow you to automate multiple CATIA sessions "simultaneously". Works well for my purposes: automated extraction of data from a set of CATIA models and automated creation of a set of CATIA models using more than one CATIA session at a time. The bottleneck for my application is the individual CATIA session -- not CPU resources (using a dual processor 4 or 6 core per processor machine); adding more sessions improves throughput.

[转载]在VB.Net中获取COM对象的特定实例(Getting a specific instance of COM object in VB.Net)的更多相关文章

  1. 在SpringMVC中获取request对象

    1.注解法 @Autowired private  HttpServletRequest request; 2. 在web.xml中配置一个监听 <listener> <listen ...

  2. 在SpringMVC中获取request对象的几种方式

    1.最简单的方式(注解法) @Autowired private HttpServletRequest request; 2.最麻烦的方法 a. 在web.xml中配置一个监听 <listene ...

  3. js中获取事件对象的方法小结

    原文地址:http://jingyan.baidu.com/article/d8072ac4594d6cec95cefdac.html 事件对象 的获取很简单,很久前我们就知道IE中事件对象是作为全局 ...

  4. 如何在SpringMVC中获取request对象

    1.注解法 @Autowired private HttpServletRequest request; <listener> <listener-class> org.spr ...

  5. 9.Struts2在Action中获取request-session-application对象

    为避免与Servlet API耦合在一起,方便Action类做单元测试. Struts2对HttpServletRequest.HttpSession.ServletContext进行了封装,构造了三 ...

  6. 在spring中获取代理对象代理的目标对象工具类

    昨天晚上一哥们需要获取代理对象的目标对象,查找了文档发现没有相应的工具类,因此自己写了一个分享给大家.能获取JDK动态代理/CGLIB代理对象代理的目标对象. 问题描述:: 我现在遇到个棘手的问题,要 ...

  7. 如何在spring中获取request对象

    1.通过注解获取(很简单,推荐): public class Hello {@Autowired  HttpServletRequest request; //这里可以获取到request} 2.在w ...

  8. 3.jquery在js文件中获取选择器对象

    一.常用的选择器有一下几种: 1.标签选择器 2.类选择器 3.id选择器 4.并集选择器 5.层级选择器 二.如何获取选择器对象: <!DOCTYPE html> <html la ...

  9. Lucene.Net 3.0.3如何从TokenStream中获取token对象

    Lucene.Net最高版本为3.0.3,并且apache已经不再提供Lucene.Net的更新,没仔细研究过Lucene.Net的所有版本,Lucene.Net3.0.3遍历TokenStream获 ...

随机推荐

  1. c#生产/消费RabbitMQ

    public sealed class JsonSerializer { public static byte[] Serialize(object message) { return Encodin ...

  2. MVC中Cookies的简单读写操作

    写入 public static void WriteCookie(string cn, string cv, DateTime Time) { HttpCookie cookie = new Htt ...

  3. Python读写操作Excel模块_xlrd_xlwt_xlutils

    Python 读写操作Excel -- 安装第三方库(xlrd.xlwt.xlutils.openpyxl) 如果仅仅是要以表单形式保存数据,可以借助 CSV 格式(一种以逗号分隔的表格数据格式)进行 ...

  4. mgo01_window server 2012上安装mongo4.0

    目前mongo最新版为4.0(2018-07-18),下载地址 https://fastdl.mongodb.org/win32/mongodb-win32-x86_64-2008plus-ssl-4 ...

  5. vue入门----------路由配置

    在使用脚手架搭建好项目后要配置路由 1.首先要安装vue-router,你可以在项目的package.json文件中的dependencies项目中添加"vue-route": & ...

  6. thinkPHP5.0使用form表单提交数据和删除文章,不用TP的提示页面,使用弹出提示信息

    form表单提交数据和删除文章时,TP的默认信息提示页面的看起来不是很好看,想要实现弹窗提示怎么做呢? 前端:可以使用前端的一个知识--iframe,iframe元素会创建包含另外一个文档的内联框架: ...

  7. Python + Selenium 基础篇 - 打开和关闭浏览器

    1.首先要下载浏览器对应的driver,并放到你的python安装目录 Chrome浏览器(chromedriver): http://npm.taobao.org/mirrors/chromedri ...

  8. Django orm查询操作

    基于双下划线查询切记!!!!正向查询按字段,反向查询按表名的小写 正向:在Book表里设置关联Obj表,Book------>Obj就是正向查询 反向:在Book表里设置关联Obj表,Obj-- ...

  9. 利用Serv-U搭建FTP服务器

    以前在学校的时候,学校的整个宿舍楼都是在一个局域网中,经常有人用个人电脑搭个网站或者FTP啊什么的,主要是进行一些影视资源的传播活动.不乏 有些资源充沛的有志青年利用业余时间翻译某岛国影视资源,利用局 ...

  10. pat1043. Is It a Binary Search Tree (25)

    1043. Is It a Binary Search Tree (25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN ...