Community
Inventor Programming - iLogic, Macros, AddIns & Apprentice
Inventor iLogic, Macros, AddIns & Apprentice Forum. Share your knowledge, ask questions, and explore popular Inventor topics related to programming, creating add-ins, macros, working with the API or creating iLogic tools.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Is there a way to pass a variable from VBA to an iLogic Rule?

29 REPLIES 29
Reply
Message 1 of 30
Gruff
4231 Views, 29 Replies

Is there a way to pass a variable from VBA to an iLogic Rule?

We are using Inventor 2011.

 

I have found a rouind about way to display document thumbnails in VBA in 64 bit windows 7 inventor.

 

The only piece of the puzzle I am missing is for a way to push a document object or a document file name into an iLogic Rule from VBA.

 

Any Ideas on how one can do that?

 

 

 

Below is a 64 bit thumbnail solution for VBA sans the input.

 

Essentially I am launching an iLogic Rule from VBA that pushes an inventor document object into a VB.NET dll.

The dll converts the iPictureDisp into a VB.NET image object, reduces the size then converts it into a byte array.

The byte array is passed back to VBA through the same iLogic Rule.

Once the byte array is received it is converted back into an iPictureDisp object.

 

' ----------------------------------------

' --- VBA Project Form Code ---

' ----------------------------------------

Option Explicit

 

Private Sub Command1_Click()

 

End Sub

 

 

' -------------------------------------------

' --- VBA Project Module Code ---

' -------------------------------------------

Option Explicit

 

Public Sub SetPic(ByRef bBuffer() As Byte)
  Set UserForm1.Pic.Picture = PictureFromRes(bBuffer)
End Sub

 

Public Sub RuniLogic(ByVal DLL_Name As String)
  Dim iLogicAuto As Object
  Dim oDoc As Document
 
  Set oDoc = ThisApplication.ActiveDocument
  If oDoc Is Nothing Then
    MsgBox "Missing Inventor Document"
    Exit Sub
  End If
 
  Set iLogicAuto = GetiLogicAddin(ThisApplication)
  If (iLogicAuto Is Nothing) Then Exit Sub

  iLogicAuto.RunExternalRule oDoc, DLL_Name
End Sub

Function GetiLogicAddin(oApplication As Inventor.Application) As Object
  Dim addIns As ApplicationAddIns
  Set addIns = oApplication.ApplicationAddIns

  Dim addIn As ApplicationAddIn
  Dim customAddIn As ApplicationAddIn
  For Each addIn In addIns
    If (addIn.ClassIdString = "{3BDD8D79-2179-4B11-8A5A-257B1C0263AC}") Then
      Set customAddIn = addIn
    Exit For
    End If
  Next

  If (customAddIn Is Nothing) Then Exit Function

  customAddIn.Activate
  Set GetiLogicAddin = customAddIn.Automation
End Function

 

' -------------------------------------------------------

' --- iLogic External Rule "SaveThumb"  ---

' -------------------------------------------------------

 ' Add reference to ThumbNailFix.Dll
AddReference "ThumbNailFix" 

Sub Main()
 Dim oFix As New ThumbNailFix.Fixer
 oFix.Doc = ThisApplication.ActiveDocument
    oFix.SaveThumb
 
 ' Call VBA Sub Routine
 InventorVb.RunMacro("ApplicationProject", "basSandBox", "SetPic", oFix.bBuffer)
End Sub

 

' -------------------------------------------------------

' --- VB.NET Compiled ThumbNailFixer Dll Library ---

' -------------------------------------------------------

Imports Inventor
Imports System.Drawing
Imports Microsoft.VisualBasic.Compatibility.VB6
Imports System.IO

Public Class Fixer
  Public Property Doc As Inventor.Document = Nothing
  Public Property bBuffer As Byte() = Nothing

  Public Sub SaveThumb()
    Dim imgMemoryStream As MemoryStream = New MemoryStream()
    Dim img As Image = IPictureDispToImage(Doc.Thumbnail)
    Dim imgOut As Image = CType(img.GetThumbnailImage(100, 100, Nothing, New IntPtr), Bitmap)

    imgOut.Save(imgMemoryStream, System.Drawing.Imaging.ImageFormat.Bmp)
    bBuffer = imgMemoryStream.GetBuffer()
  End Sub
End Class

 

29 REPLIES 29
Message 2 of 30
MjDeck
in reply to: Gruff

If you have to use .NET code from VBA, I think it would be easier to use Visual Studio to create make a .NET class that exposes a COM interface.  You can put all the .NET thumbnail code in that class.  Then you can use that class directly in VBA, and you don't have to go through iLogic.  Here's a link:

http://support.microsoft.com/kb/817248

 

 But alternatively, it is possible to provide arguments to an iLogic rule, and return values from the rule.  Here's a sample based on your code.  It provides a String argument to the rule, and the rule returns a Byte array. 

 The VBA code is in the attached file RuniLogicRule.txt

 The external rule GetThumbnail.txt is also attached.  It uses the predefined RuleArguments object to access the rule arguments.


Mike Deck
Software Developer
Autodesk, Inc.

Message 3 of 30
MjDeck
in reply to: MjDeck

Defining a COM class in .NET probably wouldn't work for the thumbnail, because it would be running from VBA outside the Inventor process.

So if the iLogic method works, that's good.


Mike Deck
Software Developer
Autodesk, Inc.

Message 4 of 30
Gruff
in reply to: MjDeck

Made your suggested changes and It ran well on my 32bit development machine

 

Transfered the VBA project and iLogic rule to the  64bit machine.

 

it failed to run there.  Got the following errors from the iLogic engine (I assume).

 

--------------

Error in rule: ConvertThumbNail, in document: ConvertThumbNail.vb

Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))

--------------

System.Runtime.InteropServices.COMException (0x8000FFFF): Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))
   at System.RuntimeType.ForwardCallToInvokeMember(String memberName, BindingFlags flags, Object target, Int32[] aWrapperTypes, MessageData& msgData)
   at Inventor.Document.get_Thumbnail()
   at ThumbNailFix.Fixer.ConvertThumb() in C:\Users\TGroff\Documents\Visual Studio 2010\Projects\_DLL_Libraries\ThumbNailFix\ThumbNailFix\Fixer.vb:line 17
   at LmiRuleScript.Main()
   at Autodesk.iLogic.Exec.AppDomExec.ExecRuleInAssembly(Assembly assem)
   at p.b(String A_0)

--------------

 

LIne 17 of my Referenced Dll from the iLogic Rule is :

Dim img AsImage = IPictureDispToImage(Doc.Thumbnail)

So basically I think it is telling me pretty much what you said.about running outside the Inventor process

Darn!

 

Does this mean that iLogic Rules also run 32 bit outside the Inventor Process?

 

 

 

Message 5 of 30
Gruff
in reply to: Gruff

Okay. I'm Looking at creating an Addin that exposes a function through automation to convert the thumb to a byte array.

 

I set the VB.NET Standard 2010 compiler option to AnyCPU and Framework 3.5.

I could use some help as I have never made an automation addin before.  Here is what I have so far (That does not work)

 

---

--- Inside 64BitThumbNailConverter Inventor Addin Project ----

'   Class to Expose

Imports Inventor
Imports System.Drawing
Imports Microsoft.VisualBasic.Compatibility.VB6
Imports stdole
Imports System.IO

Public Class ConvertThumb
  Private oApp As Inventor.Application

  Public Sub New(ByRef App As Inventor.Application)
    oApp = App
  End Sub

  Public Function ConvertThumbToByteArray(ByVal sFullFileName As String, ByRef bBuffer As Byte()) As Boolean
    Dim oDoc As Inventor.Document = Nothing
    Dim img As Image = Nothing
    Dim imgMemoryStream As MemoryStream = New MemoryStream()
    Try
      oDoc = oApp.Documents.ItemByName(sFullFileName)
    Catch e As Exception
      Return False
    End Try

    Try
      img = IPictureDispToImage(oDoc.Thumbnail)
    Catch e As Exception
      Return False
    End Try

    If img Is Nothing Then
      Return False
    Else
      Dim imgOut As Image = CType(img.GetThumbnailImage(128, 128, Nothing, New IntPtr), Bitmap)
      imgOut.Save(imgMemoryStream, System.Drawing.Imaging.ImageFormat.Bmp)
      bBuffer = imgMemoryStream.GetBuffer()
      Return True
    End If
  End Function
End Class

----

 --- Inside  StandardAddInServer.vb ---

    Public ReadOnly Property Automation() As Object Implements Inventor.ApplicationAddInServer.Automation

      ' This property is provided to allow the AddIn to expose an API
      ' of its own to other programs. Typically, this  would be done by
      ' implementing the AddIn's API interface in a class and returning
      ' that class object through this property.

      Get
        'Return Nothing
        Dim oConvert = New ConvertThumb(m_inventorApplication)
        Return oConvert
      End Get

    End Property

 

--- Inside VBA ---

 

Inside the main menu tools | References | I selected 64BitThumbNailConverter

Then wrote this Function...

 

Public Function Get64BitPicture(ByVal sFileName As String) As StdPicture
 
 'look for out addin that has the custom interface
  Dim oApp As Inventor.Application
  Dim oConverter As [64BitThumbNailConverter].ConvertThumb
  Dim oAddIn As ApplicationAddIn
  Dim i As Long
 
  Set oApp = ThisApplication
  Dim oAddins As Inventor.ApplicationAddIns
  Set oAddins = oApp.ApplicationAddIns
 
  For i = 1 To oAddins.Count
    Dim sName As String
    sName = oAddins.Item(i).ShortDisplayName
    If sName = "64BitThumbNailConverter" Then
      Set oAddIn = oApp.ApplicationAddIns.Item(i)
      Exit For
    End If
  Next
 
  'make sure addin is loaded and activated
  If oAddIn Is Nothing Then
    MsgBox "The test Add-In was not found"
  ElseIf Not oAddIn.Activated Then
    MsgBox "The test Add-In is not running"
  Else
 
    'get the custom interface from the addin
    Set oConverter = oAddIn.Automation
 
    Dim bBuffer() As Byte
    If oConverter.ConvertThumbToByteArray(sFileName, bBuffer) Then
      Set Get64BitPicture = PictureFromRes(bBuffer)
    Else
      Set Get64BitPicture = Nothing
    End If
  End If
End Function

-----

 

It crashes big time when  I try to use:

 

oConverter.ConvertThumbToByteArray(sFileName, bBuffer)

 

on my 32 bit development machine.

Can you show me where i am going wrong?

 

Message 6 of 30
MjDeck
in reply to: Gruff

> Does this mean that iLogic Rules also run 32 bit outside the Inventor Process?

No, an iLogic rule will always run within the Inventor process.  However, when a rule is being run from VBA or another out-of-process caller, it will not run in the main Inventor thread.  It runs in a separate thread.  I think this separate thread has the same problem with reading the document thumbnail.

 There is a way to get around this, and make a rule run in the main thread.  The way to do this is to change a parameter that triggers the rule to run.  But in that situation, you can't pass arguments to the rule.  But your method using  InventorVb.RunMacro should work to send the data back to VBA.  Alternatively, you could write the data to a temporary file and then read it in VBA.

 But this method has a big drawback: it requires a dedicated rule in the document.  You can't use it with an external rule.  So it's not a general solution that will work in any document.

 Since you're developing an add-in, you could do something like this yourself: add code to react to the ModelingEvents.OnParameterChange event and run the thumbnail code on that event.  I think you have to use that (or some other event).  I don't think you can get to the thumbnail through an Automation interface on the add-in by calling it directly from VBA.  You will get the same "separate thread" behavior as iLogic.

  Do you have a lot of VBA code that requires thumbnails?

 If you want advice on the add-in, it would be good if you can zip up your whole VB.NET solution and attach it as a file, rather than posting the code as text.  Same for the VBA project.


Mike Deck
Software Developer
Autodesk, Inc.

Message 7 of 30
Gruff
in reply to: MjDeck

Thanks for the response.  I will zip my projects in the future.

 

I have many corporate VBA applications that shiow thumbnails in image controls.  All of them are driven by listbox click or mousedown events.  their purpose is always to allow a user to recognize a part or assembly when working with large numbers of inventor documents.  Most of the VBA apps are quite extensive.  Here are just a few.

 

Custom upgrading of all documents to current requirements.

Custom creation of material exports lists for assembly components

Custom FX manipulation of assembly components

Custom file property editing for assembly components

Custom printing of all assembly drawings

Custom material swapping for multiple components at once.

Custom Pack & Go tools

Custom setting of BOM attributes for multiple components at once.

Custom export of DXF files from top level assemblies.

 

Attached are a few screen shots zipped that shows how we are using thumbs

 

I am confused as to how I could implement your parameter on event scenario in an addin with the above type of applications.  The firing event needs to be user controlled by selecting from lists.

 

If what you say about the thread being the problem here then what good would writing a VB.NET app that automates Inventor do?  Wouldn't that thread also be 32 bit?  Same with an external iLogic right?

 

 

Message 8 of 30
MjDeck
in reply to: Gruff

When called from out-of-process, an iLogic rule (and API calls) will run in a 64-bit thread.  But it's not the main 64-bit thread.  It's a secondary thread, created specifically for the out-of-process caller.  As a separate thread, it can't access some of the objects on the main thread.

 But when an addin runs code in response to an event that is raised by Inventor (on the main thread), that addin code will also run in the main thread.

 So the trick is: instead of calling an API function (such as Document.Thumbnail) directly, call another unrelated API function that causes an event to be fired.  You have already installed an event handler for this event.  Your event handler code will run in the main thread, so it can call the API fuction that you really want (Document.Thumbnail).  You have to get your required inputs to that event handler, and retrieve outputs.  All the handling code will execute during the original API call that fired the event.  So once that call has finished, your VBA code should be able to read the output.

 The parameter change event is not really a good event for this purpose, because it will modify the document.  Although your code could create a new "scratch" document whose only purpose is to host these events.  Here's a workflow:

- Create the scratch document (with Documents.Add), and add a trigger parameter.  If your thumbnail function only requires the name of the file as input, then this could be a Text parameter that holds the filename.

- When the user selects a file from the list, your VBA code assigns this new name to the parameter in the scratch document.

- This fires the ModelingEvents.OnParameterChange event.  Your event handler code for this event (in your add-in) checks the name of the document and parameter, so that it ignores all other parameter changes and only reacts to this particular parameter.

- Your event handler code reads the thumbnail for the document and saves the data to a file, or runs a VBA macro to send it back to VBA.

- Control returns to your VBA code, with the thumbnail data available.

 

Another alternative would be to do this with an iLogic rule in the scratch part.  In that case you don't need a custom add-in.  You could either create the scratch part "from scratch" (using the API) every time you need it, or have it saved and ready to be opened.  It would contain a rule that does what I described above, triggered by a parameter change.


Mike Deck
Software Developer
Autodesk, Inc.

Message 9 of 30
Gruff
in reply to: MjDeck

Followed your advice and created a scratch file.

 

1) Put the iLogic Rule in it.

2) Created a User Parameter Called ThumbFile. Saved the scratch file to disk.

 

3) In my VBA program on a button click I get the scratch document.

then programmically change the User Parameter to a part part.

UserParameters.Item(1).Value = FileName

 

From what I can determine the Rule is not firing.when I change the Parameter.

 

I added back the code that runs the Rule: i.e.  Call RuniLogic(oPrt, "ThumbNailToByteArray")

ThumbNail is returned.  Works fine.

Removed the Run Code nothing happens, but the Parameter is definitely changed. 

 

What else must I do to cause the Rule to run?

 

I will check back on Monday.

Message 10 of 30
Gruff
in reply to: Gruff

Forgot to attach the VBA code module and Scratch part file.

Message 11 of 30
MjDeck
in reply to: Gruff

To make the rule fire, you have to use the parameter directly as a variable, instead of using the Parameter function.  Like this:

Dim sFullFileName As String = ThumbFileName

 


Mike Deck
Software Developer
Autodesk, Inc.

Message 12 of 30
Gruff
in reply to: MjDeck

Thank you Mike,

 

Wasn't sure what you meant by that last remark until I realized you were talking about the iLogic code.  🙂

 

Yeah!  That did it.  It works on the 64 bit machine!.

 

I could wish for better speed though. 

It looks like there is some overhead with using iLogic from a file that you have to make a reference to.

I'm loading the Scratch file on form initialize and closing it on deactivate then creating a ref to the open file when a thumbnail is required.

 

I will take a second look at using an add in according to your suggestions.  I had some success with using the Windows clipboard for input and output in earlier versions .Perhaps I can capture the stdPicture in 64 bit and push it onto the clipboard for pasting in 32 bit.  If not then perhaps pasting the byte array or a string.

 ---

 

For the future.  Can I suggest that the Document Class ThumbNail method be iPictureDisp by default but take an enumerated argument that allows the return of: iPictureDisp, VB.NET Image Class, or an inert byte array?

 

Seems like a no brainer to me. 😉

Message 13 of 30
MjDeck
in reply to: Gruff

Glad to hear it works. 

How do you create the reference to the open document?  You should be able to re-use the same Document object that you got from the Documents.Open call.

The API is COM, so I don't think it can return a .NET object.    But it should be possible to return a byte array.


Mike Deck
Software Developer
Autodesk, Inc.

Message 14 of 30
Gruff
in reply to: MjDeck

As I stated above. I am opening the Scratch file  on form open and closing it on form close.

I defined the part doc variable as Public in a module so it is global and available for the thumbnail function.

 

I created the scratch document as a template on our network so it can be added to any users Inventor session.

In any case I'd perfer a cleaner solution. 

 

RE: Add in.

One Idea would be to use VBA to push oDoc.FullFilename & ",Create64BitThumbNail" onto the Windows Clipboard then in the Addin Event check the clipboard for EndingWith(",Create64BitThumbNail").  If true get the filename substring and process it.  For output I was thinking about either the clipboard again or maybe getting a controldef from the command manager and run a VBA sub.  Do they support aruments?  Another thought was using VBE.

 

I am not sure what event would be best to fire the code.  What about something like and EnvironmentalEvent.

Handles.m_Browser.OnEnvironmentChange.  Toggling the Browser Active or not from VBA would fire it correct?  Since it doesn't happen often wouldn't it be a better choice?

 

Message 15 of 30
MjDeck
in reply to: Gruff

The performance problem might be mainly due to using VBA in 64-bit.
The clipboard might work for input and output.
I don't think using the CommandManager to load a VBA macro would allow you to specifiy arguments.

I don't know if toggling the Browser active would trigger an OnEnvironmentChange event.  You might need to do more than that.


Mike Deck
Software Developer
Autodesk, Inc.

Message 16 of 30
Gruff
in reply to: MjDeck

Ran into an issue with the scratch part template.  The users stress and crash inventor routinely.  There could be a scratch doument or multiple scratch docs  left in the queue ....

 

This is why I am leaning toward an addin.  There would be fewer problems with maintanence.

Message 17 of 30
Gruff
in reply to: Gruff

Ran a proof of concept for the Addn in a VBA Class.  Looks like it will work.

 

Still cannot create an Addin that loads in Addins.  I check the loaded/Unloaded box and it is unchecked when I look again.

The Addin Compiles but does not load.

 

Is there an Updated SDK for Inventor 2011?

The version I had would not work with MS VS.NET 2010.

 

I installed the 2012 SDK and in the VB.NET template changed the version check from 12.. to 11 in:

subKey.SetValue("SupportedSoftwareVersionGreaterThan", "11..")

Changed the Reference to the Inventor interop from 2012 to 2011.

 

Set the Framework to 3.50 under the Advanced Compile options.

 

Still the Addin doesn't appear to load.  I've rebuilt it numerous times.

The Add in Code is attached.  Basically the only interface I am using is an Inventor event.

Any Ideas?  My frustration level is off the charts.  Haven't been able to create a viable Inventor Addin since VB6.

 

Message 18 of 30
MjDeck
in reply to: Gruff

If you installed the Inventor 2012 SDK, you should be able to create a registration-free addin.  I would recommend doing it that way.  It will work in Inventor 2011 as long as you install the dll to the C:\Program Files\Autodesk\Inventor 2011\Bin directory.  You also need a .addin file.  This is created by the wizard in your project.  You have install the .addin file to C:\ProgramData\Autodesk\Inventor 2011\Addins (on Vista or Windows 7).

 Is the wizard creating a registration-free addin?  If not, maybe you have to uninstall the 2011 SDK and reinstall the 2012 SDK.

 


Mike Deck
Software Developer
Autodesk, Inc.

Message 19 of 30
Gruff
in reply to: MjDeck

[quote] It will work in Inventor 2011 as long as you install the dll to the C:\Program Files\Autodesk\Inventor 2011\Bin directory [/quote]

Which dll are you speaking of?

 

[quote] You also need a .addin file.  This is created by the wizard in your project.  You have install the .addin file to C:\ProgramData\Autodesk\Inventor\2011\Addins [/quote] 

Again it is unclear as to what file you are talking about.  Is this the same dll as above?

 

[quote] Is the wizard creating a registration-free addin? [/quote]

How do I know?  Is it missingt he COM section in the template?

 

Is there a step by step tutorial that walks through installation and creating a simple registration free addin you can recommend?

Message 20 of 30
MjDeck
in reply to: Gruff

If you are using the Inventor 2012 SDK wizard to create an add-in, it will build a dll with the name you provide as the project name.  That's the dll I'm talking about.  It will also create a file with the extension .addin in your VB.NET project.  That .addin file is used for registry-free COM.   There will be no code dealing with the Windows registry in the template or in your code.

 Sorry, I can't find a step-by-step tutorial.  I'll keep looking.

 It's registry-free COM.  You're still using COM, but not through the Windows registry.


Mike Deck
Software Developer
Autodesk, Inc.

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report