Hello! everyone!
It's AutoCAD program,Now I want to automate it by COM in my app.
Now the problem is GetActiveObject(clsid, NULL, &pUnk); I cann't get more control on it.
i.e
IF the user have several AutOCAD instances running . And How I can guarantee that always get the most newly created one?
And if my app startup the autocad by ShellExecuteEX then I can get the Hanlde of it.
By this Handle, May I get it's corresponding Com's object?
use the ROT
http://stackoverflow.com/questions/11835617/understanding-the-running-object-table
thanks for you reply!
I have read the link -page, But I still cann't find a way to accomplish it.
I use C++ ,Can you give more instance in detais ?
I have google and look up MSDN,But I don't get more useful info to realize it.\
regards!
no problem - search for ROT and AutoCAD e.g. http://adndevblog.typepad.com/autocad/2012/12/dumping-the-com-running-object-table-rot-in-objectarx....
yes~!
But I have accomplish similar function.
Now I can get the IMonike of the acad.exe. And by pMoniker->IsSystemMoniker() I know both(I start 2 acad instances)
IMonikes are Item moniker. They GetDispName is the same. So pMoniker->isEqual() is return Yes!
So Now I just don't know How to distinguish this 2 CAD instances?
I have tried using IMonike::GetTimeOfLastChange() but failed.
BTW,Actually I start CAD using a stand-alone exe by shellExcuteEx() Then I know the process handle and it's process's ID. I just want my app to start CAD as a companion,and do some communication by IPC.
But the user may have start 1 or more CAD instance even after my app started,the user still may start another CADs,So I want to my app always can attach to the CAD instance as my app's companion by COM.
(GetActiveObject() always attach to the first CAd instance)
Thanks !
there are many posts online about how to obtain the command line parameters from an external exe... From .NET you can do this
using (ManagementObjectSearchersearcher = newManagementObjectSearcher("SELECT * FROM Win32_Process"))
{
ManagementObjectCollectioncollection = searcher.Get();
foreach (ManagementObject @object in collection)
{
try
{
objectcommandLine = @object["CommandLine"];
OK!
For now ,assume I have get the acad.exe's that match.
I know it's processId and clsid(AutoCAD.Application),And How can i get the Com's IUnknow interface that match my processID?
I'm not sure, I have never done it. I would play around with Marshal.GetActiveObject() or at least research the methods in the Marshal namepsace.
Here is some code I wrote in C# to access the ROT, if useful to anyone...
[DllImport("ole32.dll")] static extern int CreateBindCtx(uint reserved, out IBindCtx ppbc); [DllImport("ole32.dll")] public static extern void GetRunningObjectTable( int reserved, out IRunningObjectTable prot); //Requires Using System.Runtime.InteropServices.ComTypes //Get all running AutoCAD instance by querying ROT private List<object> GetAcadInstances(string[] progIds) { List<string> clsIds = new List<string>(); //get the autocad clsid foreach (string progId in progIds) { Type type = Type.GetTypeFromProgID(progId); if(type != null) clsIds.Add(type.GUID.ToString().ToUpper()); } //Get Running Object Table ... IRunningObjectTable Rot = null; GetRunningObjectTable(0, out Rot); if (Rot == null) return null; //get enumerator for ROT entries IEnumMoniker monikerEnumerator = null; Rot.EnumRunning(out monikerEnumerator); if (monikerEnumerator == null) return null; monikerEnumerator.Reset(); List<object> instances = new List<object>(); IntPtr pNumFetched = new IntPtr(); IMoniker[] monikers = new IMoniker[1]; //Go through all entries and identifies ACAD instances while (monikerEnumerator.Next(1, monikers, pNumFetched) == 0) { IBindCtx bindCtx; CreateBindCtx(0, out bindCtx); if (bindCtx == null) continue; string displayName; monikers[0].GetDisplayName(bindCtx, null, out displayName); foreach (string clsId in clsIds) { if (displayName.ToUpper().IndexOf(clsId) > 0) { object ComObject; Rot.GetObject(monikers[0], out ComObject); if (ComObject == null) continue; instances.Add(ComObject); break; } } } return instances; } private void TestROT() { //look for acad 2009 & 2010 & 2011 string[] progIds = { "AutoCAD.Application.17.2", "AutoCAD.Application.18", "AutoCAD.Application.19.1" }; List<object> instances = GetAcadInstances(progIds); foreach (object acadObj in instances) { try { //Late bind property "AcadApplication.Preferences.Profiles.ActiveProfile" object Preferences = acadObj.GetType().InvokeMember("Preferences", System.Reflection.BindingFlags.GetProperty, null, acadObj, null, null, null, null); object Profiles = Preferences.GetType().InvokeMember("Profiles", System.Reflection.BindingFlags.GetProperty, null, Preferences, null, null, null, null); string ActiveProfile = Profiles.GetType().InvokeMember("ActiveProfile", System.Reflection.BindingFlags.GetProperty, null, Profiles, null, null, null, null) as string; //... } catch { continue; } } }