IV2010, Vista 64, CreateObject / CreateInstance, and Killing Processes

IV2010, Vista 64, CreateObject / CreateInstance, and Killing Processes

Anonymous
Not applicable
886 Views
9 Replies
Message 1 of 10

IV2010, Vista 64, CreateObject / CreateInstance, and Killing Processes

Anonymous
Not applicable
I'm writing a program to launch Inventor for the user, and I'm stumbling across a strange COM oddity. Perhaps I'm just overlooking something.

I use the following code to launch Inventor:
{code}
Dim t As Type = Type.GetTypeFromProgID("Inventor.Application")
m_objInventorApplication = CType(Activator.CreateInstance(t), Inventor.Application)
{code}

This starts Inventor just fine. The problem comes with closing it down. The process won't actually shut down if you go File-> Exit Inventor or click the X in the title bar. However, if I use my Application object, I can use .Quit and the process dies. Interestingly, I can also kill the process by invoking a different addin that I wrote that calls the .Quit function.

Telling Inventor itself to close will not end its process.

I believe this to be similar to the case in this thread:
http://discussion.autodesk.com/forums/thread.jspa?messageID=5792813
(I'm running Vista 64 Ultimate.)

I have tried running my activator method then using FinalReleaseCOMObject on the Application object, and then going File->Exit Inventor. But this won't work either.

{code}

Private Sub ReleaseApplicationCOMReference()
If m_objInventorApplication IsNot Nothing Then
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(m_objInventorApplication)
m_objInventorApplication = Nothing
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
End If
End Sub
{code}

Now, if I open Inventor first, then use GetObject / GetActiveObject to hook onto it, closing it inside Inventor will ends its process, irregardless of whether I release the COM object.

{code}
m_objInventorApplication = _
CType(System.Runtime.InteropServices.Marshal.GetActiveObject("Inventor.Application"), Inventor.Application)
{code}

Is this some sort of Inventor bug or is it COM related?
0 Likes
887 Views
9 Replies
Replies (9)
Message 2 of 10

Anonymous
Not applicable
Inventor is actually following the standard COM rules in this case and the
behavior you're seeing is what's expected. The main thing in your case is
that because Inventor knows it was started through COM, it waits to be shut
down through COM.

There is a fairly easy workaround though. Instead of using COM to start
Inventor you can start the Inventor process directly and then use COM to
connect to it and get the Application object. This is the same as the user
starting it and it will shut down when the user exits Inventor.

I've attached some code I wrote a while ago to do this. I spent a few
minutes on it just now to more fully update it to use the .Net Framework and
took out Windows API calls that I had previously. It worked on some simple
tests I did but you'll want to do some more testing.

I wrote this initially to work around a timeout problem that occurs when
starting an application through COM. COM has a defined period of time that
it waits for the application to become available. If the application takes
longer than than COM will give up on it and fail. In this funciton I have
control over how long I want to wait. In the attached code it's waiting 90
seconds for Inventor to start. If Inventor is still running after 90
seconds but hasn't become available yet I assume it's hung up for some
reason so this kills it.
--
Brian Ekins
Autodesk Inventor API Product Designer
http://blogs.autodesk.com/modthemachine

"peter.townsend" wrote in message news:6279153@discussion.autodesk.com...
I'm writing a program to launch Inventor for the user, and I'm stumbling
across a strange COM oddity. Perhaps I'm just overlooking something.

I use the following code to launch Inventor:
{code}
Dim t As Type = Type.GetTypeFromProgID("Inventor.Application")
m_objInventorApplication = CType(Activator.CreateInstance(t),
Inventor.Application)
{code}

This starts Inventor just fine. The problem comes with closing it down.
The process won't actually shut down if you go File-> Exit Inventor or click
the X in the title bar. However, if I use my Application object, I can use
.Quit and the process dies. Interestingly, I can also kill the process by
invoking a different addin that I wrote that calls the .Quit function.

Telling Inventor itself to close will not end its process.

I believe this to be similar to the case in this thread:
http://discussion.autodesk.com/forums/thread.jspa?messageID=5792813
(I'm running Vista 64 Ultimate.)

I have tried running my activator method then using FinalReleaseCOMObject on
the Application object, and then going File->Exit Inventor. But this won't
work either.

{code}

Private Sub ReleaseApplicationCOMReference()
If m_objInventorApplication IsNot Nothing Then
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(m_objInventorApplication)
m_objInventorApplication = Nothing
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
End If
End Sub
{code}

Now, if I open Inventor first, then use GetObject / GetActiveObject to hook
onto it, closing it inside Inventor will ends its process, irregardless of
whether I release the COM object.

{code}
m_objInventorApplication = _
CType(System.Runtime.InteropServices.Marshal.GetActiveObject("Inventor.Application"),
Inventor.Application)
{code}

Is this some sort of Inventor bug or is it COM related?
0 Likes
Message 3 of 10

Anonymous
Not applicable
That'll certainly work, but I'm leery of using GetObject. I don't want to interrupt a user's current Inventor session if it's already running. I'd like to start a brand new session of Inventor in this case, but GetObject will hook onto the older one. Is there something that can workaround this?
0 Likes
Message 4 of 10

Anonymous
Not applicable
CreateObject
0 Likes
Message 5 of 10

Anonymous
Not applicable
Sorry sir, but CreateObject is the main problem.
0 Likes
Message 6 of 10

Anonymous
Not applicable
Good point. In my case where I was using this it was guaranteed that the
Inventor I was starting up was the only one. The other thing to investigate
is the Running Object Table (ROT). That's what GetObject is using to find
Inventor and hook up, but it's just connecting to the first instance in the
table. I haven't investigated this in detail to know exactly what to do.
I'm hoping you could check the table and then start Inventor and be able to
look for the new instance and connect to it. Good luck.
--
Brian Ekins
Autodesk Inventor API Product Designer
http://blogs.autodesk.com/modthemachine
0 Likes
Message 7 of 10

Anonymous
Not applicable
I did poke at the ROT a bit before. I'll see what I can come up with.

Thanks for the assistance!
0 Likes
Message 8 of 10

nmunro
Collaborator
Collaborator
Have you looked into the System.Diagnostics.Process class?

Neil

        


https://c3mcad.com

0 Likes
Message 9 of 10

Anonymous
Not applicable
>>Have you looked into the System.Diagnostics.Process class?

Yep. Had no problem implementing this approach. I start the process on a second thread then have it enter a sleeping pattern until GetActiveObject works. I can also make it enter another one until the Application.Ready property comes true. When it's done it launches an event so my program knows.

I did poke with the ROT a bit. I'm no COM expert by any means. I can get the list of all running objects and iterate through the monikers. I opened up two Inventor instances side by side, and I saw two entries corresponding to the application CLSID.

However, attempting to bind either moniker gives back the older instance. I had an addin running that modified the status bar and popped up a message box dialog so I would know which was being talked too. Both times it appeared on the older instance.

Here's the code I used to test with:

DLLImports (change the attribute's curly braces to less than and greater than as the message board doesn't like them):
{code}

{DllImport("ole32.dll")} _
Private Shared Function GetRunningObjectTable(ByVal reserved As UInt32, ByRef pprot As System.Runtime.InteropServices.ComTypes.IRunningObjectTable) As Integer
End Function

{DllImport("ole32.dll")} _
Private Shared Function CreateBindCtx(ByVal reserved As UInt32, ByRef pprot As System.Runtime.InteropServices.ComTypes.IBindCtx) As Integer
End Function
{code}

ROT looping code:
{code}

Dim objTable As System.Runtime.InteropServices.ComTypes.IRunningObjectTable = Nothing
Dim objEnumMoniker As ComTypes.IEnumMoniker = Nothing
GetRunningObjectTable(0, objTable)
objTable.EnumRunning(objEnumMoniker)
objEnumMoniker.Reset()
Dim intNumFetched As IntPtr
Dim objIMoniker(0) As ComTypes.IMoniker
Dim i As Integer = 0
Dim s As String = ""
While objEnumMoniker.Next(1, objIMoniker, intNumFetched) = 0
Dim ctx As ComTypes.IBindCtx = Nothing
CreateBindCtx(0, ctx)
Dim objGUID As System.Guid = Nothing
Dim objBind As Object = Nothing
Dim objFiletime As ComTypes.FILETIME = Nothing
Dim strRunningName As String = Nothing

objTable.GetObject(objIMoniker(0), objBind)
If objBind IsNot Nothing AndAlso TypeOf objBind Is Inventor.Application Then
s += "objBind is Inventor.Application | "
Dim appInventor As Inventor.Application = CType(objBind, Inventor.Application)
CType(appInventor.ApplicationAddIns.ItemById("{00000000-dc92-4f9b-b9b2-2ebd30dea8f9}").Automation, TestAddin.ITestAddin).Zort(i.ToString)
ElseIf objBind Is Nothing Then
s += "objBind is Nothing | "
End If
objTable.GetTimeOfLastChange(objIMoniker(0), objFiletime)
s += "Filetime: " + objFiletime.dwHighDateTime.ToString + " . " + objFiletime.dwLowDateTime.ToString + " | "

objIMoniker(0).GetDisplayName(ctx, Nothing, strRunningName)
objIMoniker(0).GetClassID(objGUID)
s += strRunningName + " | " + objGUID.ToString() + " | "
s += vbCrLf
i += 1
End While
ShowMessageBox(s)
{code}
0 Likes
Message 10 of 10

Anonymous
Not applicable
I can't say that I've done anything similar, but did find the following
quote which may similar to how IV is treated in the ROT.

"Theoretically, you can iterate the ROT for each individual instance, but
Office applications do not register themselves if another instance is
already in the ROT because the moniker for itself is always the same, and
cannot be distinguished. This means that you cannot attach to any instance
except for the first. However, because Office applications also register
their documents in the ROT, you can successfully attach to other instances
by iterating the ROT looking for a specific document, attaching to this
document, and then getting the Application object from this document. For a
code example of iterating the ROT and looking for a document name, click the
article number below to view the article in the Microsoft Knowledge Base:
190985 (http://support.microsoft.com/kb/190985/ ) How To Get IDispatch of
an Excel or Word Document from an OCX"

If so, perhaps you could open and save a specific document and look up the
instance that way?





"peter.townsend" wrote in message news:6280868@discussion.autodesk.com...
>>Have you looked into the System.Diagnostics.Process class?

Yep. Had no problem implementing this approach. I start the process on a
second thread then have it enter a sleeping pattern until GetActiveObject
works. I can also make it enter another one until the Application.Ready
property comes true. When it's done it launches an event so my program
knows.

I did poke with the ROT a bit. I'm no COM expert by any means. I can get
the list of all running objects and iterate through the monikers. I opened
up two Inventor instances side by side, and I saw two entries corresponding
to the application CLSID.

However, attempting to bind either moniker gives back the older instance. I
had an addin running that modified the status bar and popped up a message
box dialog so I would know which was being talked too. Both times it
appeared on the older instance.
0 Likes