"Batch-Only" Programm

Hello,

i'm trying to write a tool in VB.NET which only converts a specific reference set into a step file (and either with visible or with hidden parts).

Now i am looking for a way without using the NX Journal Playback. I have a .net author license but i dont know how to set up the code for a batch-programm.
I don't want to use an interactive NX session, just start a tool from console and let the step translator do his job (unfortunately, i have to select some parts with the API)

I think my problem is the "Session"-Part:

theSession = Session.GetSession()
workPart = theSession.Parts.Work
displayPart = theSession.Parts.Display

Whats the correct way to initialize them when using batch? Is there a "full sample"? I couldn't find any tutorials for this... (Remoting is the wrong thing i guess?)

Thanks in Advance!

Best Regards,
Ery

I don't think that you will need remoting to do what you are describing. You will compile your code to an .exe file; it will need to have access to the NXOpen dll files. I have not created such a batch program, but it is my understanding that to give the exe access to the dll files, you can add the path to the dll files to the "PATH" environment variable, or you can copy the dll files to the working directory of the exe (or similarly, move the exe to the appropriate NX directory).

When your program starts in batch mode and gets the session object, it will then need to load a part to work on. I would suggest passing the path to one or more files as string arguments to your exe file. Your program can then validate the path to the file, open it, and do its work.

Also, check out the NX customization help files:
https://docs.plm.automation.siemens.com/tdoc/nx/10/nx_api/#uid:index_nxo...

Hello, thanks for your answer!

I already pass some arguments (also the "inputfile") to my programm, i can access all DLLs etc, but unfortunately i dont have a valid session because i don't know how to declare the things i quoted/code-highlighted (without using the active/opened session).

I think Session.GetSession() is not working because i don't have an running NX process/loaded part (and i dont know how to say "Use the part i passed in the arguments).

I really dont like the documentation, it looks like the main document is written in c++?

You will need to add references to the NXOpen dll files in your project before compiling. If your project has the proper references before compiling and has access to the dll files after compiling, it should start an NX process (there will not be a visible NX GUI in batch mode). The call to .GetSession should not need to be changed.

To use the argument(s) passed to your program, it will be similar to what is shown here:
http://nxjournaling.com/comment/1406#comment-1406
You might also want to do a websearch on using command line arguments in a compiled exe program. I'll bet there is some good tutorials or sample code available.

Hello,

that sample (especially the OpenPart Sub) you linked was exactly what i was looking for. Thank you very much!
Once im finished with my code i'll post it here (though im not sure if everything is working fine)

It's been a while but finally i finished the batch-programm.
The Problem above was because of wrong NXOpen Libraries - i needed to reference the Libraries with the exact same Version number as of NX itself (while this doesnt affect NX Journaling it does affect an batch program). For example NX10.0.2.6 needs the reference (in VS) to the Libraries of this version - it doesnt help when you change the files.

Anyway, with the following code i am able to convert a specific reference set to STP with a argument to also convert hidden bodies (by default off).


Option Strict On
Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports NXOpen
Imports NXOpen.Features

Module NXCODE
Public modus As String = ""
Public inputfile As String = ""
Public outputfile As String = ""
Public definitionfile As String = ""
Public logfile As String = ""
Public hidden As Boolean = False
Public theSession As Session = Session.GetSession()
Public workPart As Part
Public displayPart As Part
Public refMembers(-1) As NXObject

Const REFSETNAME As String = "NAMEOFTHEREFSETGOESHERE"

Sub Main(ByVal startparam() As String)
If CheckStartParameter(startparam) = False OrElse ValidateArguments() = False Then
Console.WriteLine("Konvertierung aufgrund eines Fehlers beendet...")
Environment.ExitCode = 1
Exit Sub
End If
LoadPart()
GetVisibleBodies()
End Sub

Sub LoadPart()
Dim basePart1 As BasePart
Dim partLoadStatus1 As PartLoadStatus
basePart1 = theSession.Parts.OpenBaseDisplay(inputfile, partLoadStatus1)
displayPart = theSession.Parts.Display
workPart = theSession.Parts.Work
partLoadStatus1.Dispose()
End Sub

Function ValidateArguments() As Boolean

If Not IO.File.Exists(definitionfile) OrElse Not IO.File.Exists(inputfile) Then
Console.WriteLine("Definitions- oder Inputdatei nicht gefunden")
Return False
End If
Try
If IO.File.Exists(outputfile) Then
IO.File.Delete(outputfile)
End If
Catch ex As Exception
Console.WriteLine("Überschreiben der STEP Datei fehlgeschlagen. " & ex.Message)
Return False
End Try
Return True
End Function

Sub GetVisibleBodies()

Dim theBodies As New List(Of DisplayableObject)
Dim myReferenceSets As ReferenceSet() = workPart.GetAllReferenceSets()

For Each myRefSet As ReferenceSet In myReferenceSets
If myRefSet.Name.ToUpper() = REFSETNAME Then
refMembers = myRefSet.AskAllDirectMembers()
For Each myObject As DisplayableObject In refMembers
If hidden = True Then
theBodies.Add(myObject)
Else
If myObject.IsBlanked = False Then
theBodies.Add(myObject)
End If
End If
Next
End If
Next

If theBodies.Count > 0 Then
StepExport(theBodies)
Else
Console.WriteLine("Nichts zu exportieren...")
Environment.ExitCode = 1
Exit Sub
End If
End Sub

Sub StepExport(ByVal theBodies As List(Of DisplayableObject))

Console.WriteLine("Starte Konvertierung...")

Dim step214Creator1 As Step214Creator
step214Creator1 = theSession.DexManager.CreateStep214Creator()
Try

With step214Creator1
.SettingsFile = definitionfile
.ExportSelectionBlock.SelectionScope = ObjectSelector.Scope.SelectedObjects
.ObjectTypes.Solids = True
.ObjectTypes.Structures = True
.ObjectTypes.Surfaces = True
.ObjectTypes.Csys = True
.ObjectTypes.Curves = True
.OutputFile = outputfile
.FileSaveFlag = False
.LayerMask = "1-256"
.ProcessHoldFlag = True
Dim added1 As Boolean
added1 = .ExportSelectionBlock.SelectionComp.Add(theBodies.ToArray)
End With

Dim nXObject1 As NXObject
nXObject1 = step214Creator1.Commit()
Catch ex As NXException
Console.WriteLine("Fehler... " & ex.Message)
Environment.ExitCode = 1
Exit Sub
Finally
Console.WriteLine("Beende Konvertierung...")
step214Creator1.Destroy()
End Try

End Sub

Function CheckStartParameter(ByVal startparam As Array) As Boolean
If startparam.Length < 4 Then
Console.WriteLine("Es wurden nur " & startparam.Length.ToString & " von 4 benötigten Startparametern übergeben")
Return False
Else
Dim lastloop As Integer = startparam.Length - 1
For Each value As String In startparam
If value.ToLower.Contains("d=") And value.ToLower.Contains(".def") Then
definitionfile = value.Substring(value.IndexOf(Chr(61)) + 1, value.Length - 1 - value.IndexOf(Chr(61)))
ElseIf value.ToLower.Contains("m=") And value.ToLower.Contains("online") Or value.ToLower.Contains("offline") Then
modus = value
ElseIf value.ToLower.Contains("o=") And value.ToLower.Contains(".stp") Then
outputfile = value.Substring(value.IndexOf(Chr(61)) + 1, value.Length - 1 - value.IndexOf(Chr(61)))
ElseIf value.ToLower.Contains("h=") Then
If value.ToLower.Contains("h=true") Then
hidden = True
End If
ElseIf lastloop <= 0 And value.ToLower.Contains(".prt") Then
inputfile = value
Else
Console.WriteLine("Falscher Kommandozeilen-Parameter übergeben, beende Konvertierung...")
Environment.ExitCode = 1
Return False
End If
lastloop -= 1
Next
End If
Return True
End Function

Public Function GetUnloadOption(ByVal dummy As String) As Integer
GetUnloadOption = NXOpen.Session.LibraryUnloadOption.Immediately
End Function
End Module

Thanks for your help!

Glad to see that you got it working and thanks for posting your finished code!

Hello,
im trying to adjust the above code a little bit, it seems that it doesnt process an assembly. "No input part found"
Is there an easy way to adjust the above code so i can either process a part or assembly with it? I cant loop through all the parts because i need one single step file.
thanks..

You can get all the occurrence bodies in an assembly with code similar to that in thread:
http://nxjournaling.com/content/select-all-bodies-current-displayed-asse...

Im trying to rewrite this journal and finally implement the assembly function... Unfortunately i dont get it to work. What im trying to do is this:

Cycle through the Child-Components of the root Assembly. Set the workpart to the current child and run basically the "Select the bodies with Reference Set" snippet from above. This seems to work i guess, at least in theory, but im unable to re-set the workpart. Im trying to do it with
theSession.Parts.SetWorkComponent(child, NXOpen.PartCollection.RefsetOption.Entire, NXOpen.PartCollection.WorkComponentOption.Visible, partLoadStatus1)
but it doesnt work... Whats the correct way to do so?
Or even better: Is that even an viable way to make my code from above work assembly wide?..

thanks

Ok, that was stupid. Im using two different workpart classes, obvious it wont work.
Though, still would like to know wheter this is an good way to solve the problem. :)
Thanks

I see that your code is exporting geometry to a STP file. What is your goal when run on an assembly file? Do you want a single STP file with bodies representing the components, do you need the assembly structure, or maybe you want individual STP files for the components?

Also, I'm not sure what type of trouble you are having with the .SetWorkComponent method. Is it not setting the specified component as the work part? Or perhaps you are having trouble setting the main assembly as the work part after processing the components?

The goal is to only convert specific reference sets. I want one STP files with the bodies inside. But in the meantime i already got it working.
I tried to use the .SetWorkComponent method but used another instance of an workpart which, of course, didn't use the changed workpart - obvious stupidity :)

Ok, glad to hear that you got it working.

I just saw that i still have issues with this code... when converting the step, it seems the selected solids loose the position, so in the step file they appear in each other...
Do you know what might cause this? I dont see any difference between my code and the one recorded by the journal (except maybe "Dim component104 As NXOpen.Assemblies.Component = CType(component103.FindObject("COMPONENT 1000054717-031-000_04 1"), NXOpen.Assemblies.Component)" also reports its location?

I suspect that your code is finding and exporting the prototype bodies; what you want to do is find the occurrence bodies in the assembly and export those. The assembly controls the positioning of the occurrence bodies; if you export the occurrence bodies from the assembly, the positioning should be correct.

The following thread has some code that will find the occurrence bodies of the given assembly:
http://nxjournaling.com/content/select-all-bodies-current-displayed-asse...

Basically im looping through all DisplayableObjects in each workpart.

Sub CheckRootComp(ByVal comp as Component)
for each child as Component in comp.Getchildren
if child.GetChildren.Length <> 0 then
'not checking for solids in assemblies (should not occur), therefor only checking recursively for subparts.
CheckRootComp(child)
else
Dim partLoadStatus1 As NXOpen.PartLoadStatus = Nothing
thesession.parts.SetWorkComponent(child, NXOpen.PartCollection.RefsetOption.Entire, NXOpen.PartCollection.WorkComponentOption.Visible, partLoadStatus1)
workpart = thesession.Parts.Work
dim attributeInfo as NXObject.AttributeInformation = workpart.getuserattribute("NOMENCLATURE", NXObject.AttributeType.String, -1)
LW.WriteLine("Nomenclature: " & attributeInfo.StringValue)
AddObjects()
end if
next
End Sub

Sub AddObjects()
Dim myReferenceSets As ReferenceSet() = workPart.GetAllReferenceSets()
For Each myRefSet As ReferenceSet In myReferenceSets
If myRefSet.Name.ToUpper() = REFSETNAME Then
refMembers = myRefSet.AskAllDirectMembers()
For Each myObject As DisplayableObject In refMembers
If hidden.ToUpper = "TRUE" Then
theBodies.Add(myObject)
Else
If myObject.IsBlanked = False Then
theBodies.Add(myObject)
End If
End If
Next
End If
Next
End Sub

I think your solution is not possible in this case because i need to check for reference sets. Unfortunately, mine is neither?

If your load options are set correctly, the desired reference set will be used when the assembly is loaded. You can loop through the components and verify/change the reference set of each as desired. Once the assembly is set the way you want, use the previous code to get the occurrence bodies from the assembly and export them to the STP file.

Thats a really good direction you pointed me to (didn't know the step exporter only uses the loaded solids)...
Im now converting the entire part, trying to set the load options:
When exporting via ugraf.exe, it uses the load options set in the load_options.def - it doesnt care wheter i change it manually in the load options dialog. If no load_options.def is available, it seems to use the default value (model or as saved, dont know the difference) even though there is something set via the dialog.
When converting with the journal, it doesnt work with at all, it always seems to use the default values first?

Here is the code to it:

Dim referenceSets1(5) As String
referenceSets1(0) = "123"
referenceSets1(2) = "Use Model"
referenceSets1(3) = "As Saved"
referenceSets1(4) = "Entire Part"
referenceSets1(5) = "Empty"
theSession.Parts.LoadOptions.SetDefaultReferenceSets(referenceSets1)
Dim partLoadStatus1 As PartLoadStatus = Nothing
Dim basePart1 As BasePart
basePart1 = theSession.Parts.OpenBaseDisplay(PRTFile, partLoadStatus1)

and

With stepCreator1
.SettingsFile = definitionfile
.exportfrom = NXOpen.StepCreator.ExportFromOption.DisplayPart
.ObjectTypes.Solids = True
.ObjectTypes.Structures = False
.ObjectTypes.Surfaces = False
.ObjectTypes.Csys = False
.ObjectTypes.Curves = False
.InputFile = inputfile
.OutputFile = outputfile
.FileSaveFlag = False
.LayerMask = "1-256"
.ProcessHoldFlag = True

End With

This doesnt overwrite the load_options.def file in my script. when using it in the journal directly everything works just fine (=the load options update and work when opening new files).
Of course i run my code before i load the file.

Am i doing something wrong?

I just run the code directly in ugraf journal (instead of run_journal). It loads the part correctly, so the load_option code works, but the step exporter doesnt use them and uses one of the default values i guess?

I set the UGII_LOAD_OPTIONS in the code now, seems to work for whatever reason (it was an system variable before, so idk)...