Community Tip - Learn all about PTC Community Badges. Engage with PTC and see how many you can earn! X
CRESON Beta-3 is Available!
CEOSON is OpenSource Automation for CREO Parametric using JSON Transactions!
The latest release of CREOSON contains some new commands for BOM Exports and Dimensions with additional commands for Feature, File and Geometry related operations in CREO Parametric. Here is a summary of the new commands by group:
The latest Pre-Packaged Distribution is located here!
If you have any questions, please post them here... Bugs and Feature Requests should go to the GitHub Project
The Help Documentation within CREOSON contains all the updated command/function information and examples.
Thanks for all the great feedback!
Hello,
i tested CREOSON JSON server and page playground and all works perfectly.
I have skills in Visual Basic for Application for Microsoft Office.
Is there a step by step guide to configure Visual Studio and .json file? Just a few sample applications. I need help to learn how to post and retrive JSON data. Unfortunately You Tube files are not useful.
Anyway thank you for this open source project.
Can't wait to see more of the Windchill connectivity APIs coming to CREOSON. Thank you for this awesome work.
I've started writing my own CreoSON class in AHK. Try running the example bellow without lines 20 to 31 first.
obj := new CreoSON() obj.creoSONUrl := "http://localhost:9056/creoson" asmName := "large_assy.asm" res1 := obj.connect(obj.creoSONUrl) arr1 := Utils.ParseJson(res1) sessionId := arr1["sessionId"] res2 := obj.getWorkDirPath(obj.creoSONUrl, sessionId) MsgBox, % "response 1:`n" . res1 . "`n`n" . "response 1 converted:`n" . Utils.BuildJson(arr1) . "`n`n" . "sessionId: " . sessionId . "`n`n" . "response 2:`n" . res2 . "`n`n" . "last status: " . obj.status res3 := obj.openCADFile(obj.creoSONUrl, sessionId, asmName) ; look for "error":true in the response string if inStr(res3, """""error"""":true") { MsgBox, % res3 } res4 := obj.getBOMPathsFromAsm(obj.creoSONUrl, sessionId, asmName) arr4 := Utils.ParseJson(res4) Utils.Array_Gui(arr4) ExitApp ;=================== classes ========================= class CreoSON { status := "N/A" creoSONUrl := "N/A" connect(creoSONUrl) { reqBody = (LTrim Join { "command": "connection", "function": "connect" } ) WinHTTP := ComObjCreate("WinHTTP.WinHttpRequest.5.1") WinHTTP.Open("POST", creoSONUrl, 0) WinHTTP.SetRequestHeader("Content-Type", "application/json") try { WinHTTP.Send(reqBody) this.status := WinHTTP.Status response := WinHTTP.ResponseText } catch e { MsgBox, % e.message ExitApp } return response } getWorkDirPath(creoSONUrl, sessionId) { reqBody = (LTrim Join { "sessionId": "%sessionId%", "command": "creo", "function": "pwd" } ) WinHTTP := ComObjCreate("WinHTTP.WinHttpRequest.5.1") WinHTTP.Open("POST", creoSONUrl, 0) WinHTTP.SetRequestHeader("Content-Type", "application/json") try { WinHTTP.Send(reqBody) this.status := WinHTTP.Status response := WinHTTP.ResponseText } catch e { MsgBox, % e.message ExitApp } return response } getBOMPathsFromAsm(creoSONUrl, sessionId, asmFileName := "plate_assy.asm") { reqBody = (LTrim Join { "sessionId": "%sessionId%", "command": "bom", "function": "get_paths", "data": { "file": "%asmFileName%" } } ) WinHTTP := ComObjCreate("WinHTTP.WinHttpRequest.5.1") WinHTTP.Open("POST", creoSONUrl, 0) WinHTTP.SetRequestHeader("Content-Type", "application/json") try { WinHTTP.Send(reqBody) this.status := WinHTTP.Status response := WinHTTP.ResponseText } catch e { MsgBox, % e.message ExitApp } return response } openCADFile(creoSONUrl, sessionId, asmFileName := "plate_assy.asm") { reqBody = (LTrim Join { "sessionId": "%sessionId%", "command": "file", "function": "open", "data": { "file": "%asmFileName%", "display": true, "activate": true } } ) WinHTTP := ComObjCreate("WinHTTP.WinHttpRequest.5.1") WinHTTP.Open("POST", creoSONUrl, 0) WinHTTP.SetRequestHeader("Content-Type", "application/json") try { WinHTTP.Send(reqBody) this.status := WinHTTP.Status response := WinHTTP.ResponseText } catch e { MsgBox, % e.message ExitApp } return response } } ; ============== libs and functions from ahk community ================== class Utils { /**************************************************************************************** Function: BuildJson(obj) Builds a JSON string from an AutoHotkey object Parameters: obj - An AutoHotkey array or object, which can include nested objects. Remarks: Originally Obj2Str() by Coco, http://www.autohotkey.com/board/topic/93300-what-format-to-store-settings-in/page-2#entry588373 Modified to use double quotes instead of single quotes and to leave numeric values unquoted. Returns: The JSON string */ BuildJson(obj) { str := "" , array := true for k in obj { if (k == A_Index) continue array := false break } for a, b in obj str .= (array ? "" : """" a """: ") . (IsObject(b) ? this.BuildJson(b) : this.IsNumber(b) ? b : """" b """") . ", " str := RTrim(str, " ,") return (array ? "[" str "]" : "{" str "}") } /**************************************************************************************** Function: ParseJson(jsonStr) Converts a JSON string into an AutoHotkey object Parameters: jsonstr - the JSON string to convert Remarks: Originally by Getfree, http://www.autohotkey.com/board/topic/93300-what-format-to-store-settings-in/#entry588268 Returns: The AutoHotkey object. */ ParseJson(jsonStr) { SC := ComObjCreate("ScriptControl") SC.Language := "JScript" ComObjError(false) jsCode = ( function arrangeForAhkTraversing(obj){ if(obj instanceof Array){ for(var i=0 ; i<obj.length ; ++i) obj[i] = arrangeForAhkTraversing(obj[i]) ; return ['array',obj] ; }else if(obj instanceof Object){ var keys = [], values = [] ; for(var key in obj){ keys.push(key) ; values.push(arrangeForAhkTraversing(obj[key])) ; } return ['object',[keys,values]] ; }else return [typeof obj,obj] ; } ) SC.ExecuteStatement(jsCode "; obj=" jsonStr) return this.convertJScriptObjToAhks( SC.Eval("arrangeForAhkTraversing(obj)") ) } /*! Function: convertJScriptObjToAhks(jsObj) Used by ParseJson() */ convertJScriptObjToAhks(jsObj) { if(jsObj[0]="object"){ obj := {}, keys := jsObj[1][0], values := jsObj[1][1] loop % keys.length obj[keys[A_INDEX-1]] := this.convertJScriptObjToAhks( values[A_INDEX-1] ) return obj }else if(jsObj[0]="array"){ array := [] loop % jsObj[1].length array.insert(this.convertJScriptObjToAhks( jsObj[1][A_INDEX-1] )) return array }else return jsObj[1] } /*! Function: IsNumber(Num) Checks if Num is a number. Returns: True if Num is a number, false if not */ IsNumber(Num) { if Num is number return true else return false } ; ============= more functions ====================== Array_Gui(Array, Parent="") { if !Parent { Gui, +HwndDefault Gui, New, +HwndGuiArray +LabelGuiArray +Resize Gui, Margin, 5, 5 Gui, Add, TreeView, w300 h200 Item := TV_Add("Array", 0, "+Expand") this.Array_Gui(Array, Item) Gui, Show,, GuiArray Gui, %Default%:Default WinWait, ahk_id%GuiArray% WinWaitClose, ahk_id%GuiArray% return } For Key, Value in Array { Item := TV_Add(Key, Parent) if (IsObject(Value)) this.Array_Gui(Value, Item) else TV_Add(Value, Item) } return GuiArrayClose: Gui, Destroy return GuiArraySize: GuiControl, Move, SysTreeView321, % "w" A_GuiWidth - 10 " h" A_GuiHeight - 10 return } ; by GeekDude }
Looks like the code block lines aren't being numbered.
Extremely usefull code! I use it a lot.
I made one small modification, store WinHTTP as a static variable to speed up multiple requests:
class HTTP {
sendPOSTHTTPReq(creoSONUrl, reqBody) {
HTTPLabel_Counter := 0
static WinHTTP
HTTPLabel:
if (!IsObject(WinHTTP)){
WinHTTP := ComObjCreate("WinHTTP.WinHttpRequest.5.1")
}
WinHTTP.Open("POST", creoSONUrl, 0)
WinHTTP.SetRequestHeader("Content-Type", "application/json")
try {
WinHTTP.Send(reqBody)
;status := WinHTTP.Status
response := WinHTTP.ResponseText
} catch e {
HTTPLabel_Counter++
if (HTTPLabel_Counter < 5){
goto HTTPLabel
}
if (InStr(e.message, "A connection with the server could not be established")){
TrayTip, HttpRequest, % e.message
}
else{
MsgBox, % e.message
}
Exit
}
return response
}
}
Hi Mauro,
Glad to hear CREOSON was working perfectly! 🙂
We created the JSON interface as a "generic" solution for any language to use. We are not experts in every language, VB is a good example of something we have used - but only when necessary.
The best advice I can give is to look up how to execute a HTTP request to send/receive JSON data using Visual Basic and start experimenting. The toughest part is going to be figuring out the request/response communications, once you have that figured out... you can focus on CREOSON and automating CREO Parametric with it.
The examples are included in the documentation for how to use CREOSON - look at the Functions section in the Help Documentation, you will find the specification and often more than a few examples of how the requests/responses look.
Once you figure out how to execute JSON requests with VB, I am sure many others would appreciate any solution you come up with. So please share what works.
The YouTube was meant to be a "taste" of what could be done with the interface... not actual instruction - more motivation. 🙂
Thanks again for your positive feedback.
Dave
How'd a smiley get into a code block? Don't forget to replace the 'Smiley Very Happy' with ':' and 'D'
James,
WOW - you are the MAN!
Oh regarding Windchill... I think we are not going to be adding many more functions specific to Windchill for a while... we are using JLINK ya know... (limited functionality) 🙂
Dave
@DavidBigelow Even Creo Toolkit has limited functionality dealing with Windchill operations at Creo.
That's seems to be a deadend.
My I ask, in a real world scenario how would you be using CREOSON?
@JoaoGoncalves ... Well...we use the Windchill interface all the time for automated back end processes ... specifically to take a Bill Of Materials (BOM) as an input, connect to Windchill, create a local workspace, then retrieve components and assemblies ... building the final assembly on the fly. OR, again Windchill specifically, just retrieving components from windchill for batch modification/updates.
The CORE of CREOSON is used in commercial products like Nitro-CELL, Nitro-BOM and Nitro-PROGRAM which are used by our customers to automate a variety of things using Excel.
CREOSON specifically can be as a local application service to integrate CREO Parametric with your existing application(s) (e.g. CREO Parametric becomes another thing to talk to much like a database, excel, text file, or web service vs embedding everything inside CREO Parametric and reaching out to those other data targets).
CREOSON an also be used for local task-specific applications (e.g. I can't put logic in a mapkey to run the right commands, but with CREOSON I could evaluate model state/condition/information quickly and then make the right calls to get to a desired result faster). <-- we see this frustration a lot!
As a bonus, CREOSON enables remote manipulation of CREO Parametric (over your network or over the Internet). No one has really talked about this capability yet and it is not perfect today; however, there was someone early on in the discussions that caught on to the potentials through. This is a bit of a mind-bender for most users who see CREO Parametric as "in front of them" always. We all know cloud services are coming like a Freight Train... I personally see CREOSON easily enabling customer-internal, cloud-based, micro-services using CREO Parametric at some point very soon. The services could easily expensive replace commercial configurators, quoting systems, etc... and reduce the need for outsourcing. This could be easily done by choosing a more modular and direct approach to delivering highly accurate results very quickly via CREO Parametric - and do it remotely, and headless... (ex. web page to collect requirements, submit, requirements validated, new part/assembly generated with documentation, results available for download within 30-seconds....) <--- Note: We have done this in the past for a few customers.
There are MANY use cases for CREOSON... the beauty of it - generic, simple, very powerful and can be easily integrated/leveraged by ANY scripting/programming language that can execute JSON requests over HTTP (locally or over the internet)
CREOSON is a bit of clay... it is up to you to figure out what you want to build with it.
I hope you dig in and give it a try -- I am already blown away by what people have done so far.
Dave
Hi,
I've tried to retrieve a model from a workspace using the following J-Link class and it didn't work.
public class RetrvFile extends DefaultUICommandActionListener { /** * Declaration of an empty field of a Session object type. */ Session session; /** * The following method works to override the OnCommand() method of the * UICommandActionListener class. The OnCommand() method triggers when * the user clicks the icon. * @throws com.ptc.cipjava.jxthrowable */ @Override public void OnCommand() throws jxthrowable { /** * Required: The reference to the session object. The method * GetProESession() returns a handle to the current session object. */ session = pfcGlobal.GetProESession(); if (session != null) { // Workspace full path example // wtws://<server_alias>/<workspace_name>/<object_name>.<object_extension> String fileFullPath = "wtws://Windchill/ZKL-VaV_Poptavky/test_prt_2.prt"; ModelDescriptor modelDescr = pfcModel.ModelDescriptor_CreateFromFileName(fileFullPath); session.OpenFile(modelDescr); Window currentWindow = session.GetCurrentWindow(); currentWindow.Activate(); MessageDialogOptions options = pfcUI.MessageDialogOptions_Create(); options.SetDialogLabel("Test"); session.UIShowMessageDialog("Device: " + modelDescr.GetDevice() + "\n" + "Extension: " + modelDescr.GetExtension() + "\n" + "FileName: " + modelDescr.GetFileName() + "\n" + "FullName: " + modelDescr.GetFullName() + "\n" + "GenericName: " + modelDescr.GetGenericName() + "\n" + "InstanceName: " + modelDescr.GetInstanceName() + "\n" + "Host: " + modelDescr.GetHost() + "\n" + "Path: " + modelDescr.GetPath() + "\n" + "String: " + modelDescr.toString(), options); } else { sessionObj.UIShowMessageDialog(session, "Synchronous connection has failed.", null); } } }
@James62 I think you posted this code in the wrong thread.
CREOSON does it completely differently.
Dave
Dave,
Can CREOSON open a model from workspace? I tried with CREOSON and it failed, could post that code too if you want.
~J
@jfojtik mmm -- this should be a really simple thing.
You should just have to do a windchill set_workspace - then a normal file open...
Can you post the CREOSON code transactions you are trying to execute?
Dave
hi Dave,
I ran the following AHK code that has a CreoSON class with a few methods.
obj := new CreoSON() obj.creoSONUrl := "http://localhost:9056/creoson" fileFullPath := "wtws://Windchill/ZKL-VaV_Poptavky/test_prt_2.prt" res1 := obj.connect(obj.creoSONUrl) arr1 := Utils.ParseJson(res1) sessionId := arr1["sessionId"] res2 := obj.getWorkDirPath(obj.creoSONUrl, sessionId) /* MsgBox, % "response 1:`n" . res1 . "`n`n" . "response 1 converted:`n" . Utils.BuildJson(arr1) . "`n`n" . "sessionId: " . sessionId . "`n`n" . "response 2:`n" . res2 */ res5 := obj.openFileByFullPath(obj.creoSONUrl, sessionId, fileFullPath) MsgBox, % res5 ExitApp ;=================== classes ========================= class CreoSON { creoSONUrl := "N/A" connect(creoSONUrl) { reqBody = (LTrim Join { "command": "connection", "function": "connect" } ) return this.HTTP.sendPOSTHTTPReq(creoSONUrl, reqBody) } getWorkDirPath(creoSONUrl, sessionId) { reqBody = (LTrim Join { "sessionId": "%sessionId%", "command": "creo", "function": "pwd" } ) return this.HTTP.sendPOSTHTTPReq(creoSONUrl, reqBody) } getBOMPathsFromAsm(creoSONUrl, sessionId, asmFileName := "plate_assy.asm") { reqBody = (LTrim Join { "sessionId": "%sessionId%", "command": "bom", "function": "get_paths", "data": { "file": "%asmFileName%" } } ) return this.HTTP.sendPOSTHTTPReq(creoSONUrl, reqBody) } openFileByName(creoSONUrl, sessionId, fileName := "plate_assy.asm") { reqBody = (LTrim Join { "sessionId": "%sessionId%", "command": "file", "function": "open", "data": { "file": "%fileName%", "display": true, "activate": true } } ) return this.HTTP.sendPOSTHTTPReq(creoSONUrl, reqBody) } openFileByFullPath(creoSONUrl, sessionId, fileFullPath) { fileDir := subStr(fileFullPath, 1, inStr(fileFullPath, "/", , 0) - 1) fileName := subStr(fileFullPath, inStr(fileFullPath, "/", , 0) + 1, strLen(fileFullPath)) reqBody = (LTrim Join { "sessionId": "%sessionId%", "command": "file", "function": "open", "data": { "file": "%fileName%", "dirname": "%fileDir%", "display": true, "activate": true } } ) return this.HTTP.sendPOSTHTTPReq(creoSONUrl, reqBody) } class HTTP { sendPOSTHTTPReq(creoSONUrl, reqBody) { WinHTTP := ComObjCreate("WinHTTP.WinHttpRequest.5.1") WinHTTP.Open("POST", creoSONUrl, 0) WinHTTP.SetRequestHeader("Content-Type", "application/json") try { WinHTTP.Send(reqBody) ;status := WinHTTP.Status response := WinHTTP.ResponseText } catch e { MsgBox, % e.message ExitApp } return response } } } ; ============== libs and functions from ahk community ================== class Utils { /**************************************************************************************** Function: BuildJson(obj) Builds a JSON string from an AutoHotkey object Parameters: obj - An AutoHotkey array or object, which can include nested objects. Remarks: Originally Obj2Str() by Coco, http://www.autohotkey.com/board/topic/93300-what-format-to-store-settings-in/page-2#entry588373 Modified to use double quotes instead of single quotes and to leave numeric values unquoted. Returns: The JSON string */ BuildJson(obj) { str := "" , array := true for k in obj { if (k == A_Index) continue array := false break } for a, b in obj str .= (array ? "" : """" a """: ") . (IsObject(b) ? this.BuildJson(b) : this.IsNumber(b) ? b : """" b """") . ", " str := RTrim(str, " ,") return (array ? "[" str "]" : "{" str "}") } /**************************************************************************************** Function: ParseJson(jsonStr) Converts a JSON string into an AutoHotkey object Parameters: jsonstr - the JSON string to convert Remarks: Originally by Getfree, http://www.autohotkey.com/board/topic/93300-what-format-to-store-settings-in/#entry588268 Returns: The AutoHotkey object. */ ParseJson(jsonStr) { SC := ComObjCreate("ScriptControl") SC.Language := "JScript" ComObjError(false) jsCode = ( function arrangeForAhkTraversing(obj){ if(obj instanceof Array){ for(var i=0 ; i<obj.length ; ++i) obj[i] = arrangeForAhkTraversing(obj[i]) ; return ['array',obj] ; }else if(obj instanceof Object){ var keys = [], values = [] ; for(var key in obj){ keys.push(key) ; values.push(arrangeForAhkTraversing(obj[key])) ; } return ['object',[keys,values]] ; }else return [typeof obj,obj] ; } ) SC.ExecuteStatement(jsCode "; obj=" jsonStr) return this.convertJScriptObjToAhks( SC.Eval("arrangeForAhkTraversing(obj)") ) } /*! Function: convertJScriptObjToAhks(jsObj) Used by ParseJson() */ convertJScriptObjToAhks(jsObj) { if(jsObj[0]="object"){ obj := {}, keys := jsObj[1][0], values := jsObj[1][1] loop % keys.length obj[keys[A_INDEX-1]] := this.convertJScriptObjToAhks( values[A_INDEX-1] ) return obj }else if(jsObj[0]="array"){ array := [] loop % jsObj[1].length array.insert(this.convertJScriptObjToAhks( jsObj[1][A_INDEX-1] )) return array }else return jsObj[1] } /*! Function: IsNumber(Num) Checks if Num is a number. Returns: True if Num is a number, false if not */ IsNumber(Num) { if Num is number return true else return false } ; ============= more functions ====================== Array_Gui(Array, Parent="") { if !Parent { Gui, +HwndDefault Gui, New, +HwndGuiArray +LabelGuiArray +Resize Gui, Margin, 5, 5 Gui, Add, TreeView, w300 h200 Item := TV_Add("Array", 0, "+Expand") this.Array_Gui(Array, Item) Gui, Show,, GuiArray Gui, %Default%:Default WinWait, ahk_id%GuiArray% WinWaitClose, ahk_id%GuiArray% return } For Key, Value in Array { Item := TV_Add(Key, Parent) if (IsObject(Value)) this.Array_Gui(Value, Item) else TV_Add(Value, Item) } return GuiArrayClose: Gui, Destroy return GuiArraySize: GuiControl, Move, SysTreeView321, % "w" A_GuiWidth - 10 " h" A_GuiHeight - 10 return } ; by GeekDude }
Notice the response shown from the MsgBox on line 24 on the picture bellow. In the code that is the line that says 'MsgBox, % res5',
Thanks.
~J
I think you need a CREOSON to do the following:
"windchill" "set_server"
"windchill" "authorize"
"windchill" "set_workspace"
THEN
"file" "open"
I think you are missing a few commands before trying to perform the operation.
Dave
hi Dave,
Thank you for the reply. Finally had a chance to try what you proposed and it worked!
Solution using CreoSON and AHK follows. I added a little gui to get user credentials.
;Ask for user login credentials Gui, Add, Edit, vUser x10 w180, Username Gui, Add, Edit, vPass x10 w180 Password, Password Gui, Add, Button, Default gSubmit x10 w180, OK Gui, Show, , Log in Return GuiClose: ;User closed the window. ExitApp Submit: Gui, Submit, NoHide Gui, Destroy obj := new CreoSON() obj.creoSONUrl := "http://localhost:9056/creoson" fileFullPath := "wtws://Windchill/Workspace on ZKL-VaV_Poptavky/test_prt_2.prt" res1 := obj.connect(obj.creoSONUrl) arr1 := Utils.ParseJson(res1) sessionId := arr1["sessionId"] res5 := obj.wchSetServer(obj.creoSONUrl, sessionId, "Windchill") res6 := obj.wchAuthorize(obj.creoSONUrl, sessionId, User, Pass) res7 := obj.wchSetWorkspace(obj.creoSONUrl, sessionId, "Workspace on ZKL-VaV_Poptavky") res8 := obj.openFileByFullPath(obj.creoSONUrl, sessionId, fileFullPath) MsgBox, (LTrim response1: %res1% response5: %res5% response6: %res6% response7: %res7% response8: %res8% ) ExitApp ;=================== classes ========================= class CreoSON { creoSONUrl := "N/A" /** * connection : connect */ connect(creoSONUrl) { reqBody = (LTrim Join { "command": "connection", "function": "connect" } ) return this.HTTP.sendPOSTHTTPReq(creoSONUrl, reqBody) } /** * creo : pwd */ getWorkDirPath(creoSONUrl, sessionId) { reqBody = (LTrim Join { "sessionId": "%sessionId%", "command": "creo", "function": "pwd" } ) return this.HTTP.sendPOSTHTTPReq(creoSONUrl, reqBody) } /** * bom : get_paths */ getBOMPathsFromAsm(creoSONUrl, sessionId, asmFileName := "plate_assy.asm") { reqBody = (LTrim Join { "sessionId": "%sessionId%", "command": "bom", "function": "get_paths", "data": { "file": "%asmFileName%" } } ) return this.HTTP.sendPOSTHTTPReq(creoSONUrl, reqBody) } /** * file : open */ openFileByName(creoSONUrl, sessionId, fileName := "plate_assy.asm") { reqBody = (LTrim Join { "sessionId": "%sessionId%", "command": "file", "function": "open", "data": { "file": "%fileName%", "display": true, "activate": true } } ) return this.HTTP.sendPOSTHTTPReq(creoSONUrl, reqBody) } /** * file : open */ openFileByFullPath(creoSONUrl, sessionId, fileFullPath) { fileDir := subStr(fileFullPath, 1, inStr(fileFullPath, "/", , 0) - 1) fileName := subStr(fileFullPath, inStr(fileFullPath, "/", , 0) + 1, strLen(fileFullPath)) reqBody = (LTrim Join { "sessionId": "%sessionId%", "command": "file", "function": "open", "data": { "file": "%fileName%", "dirname": "%fileDir%", "display": true, "activate": true } } ) return this.HTTP.sendPOSTHTTPReq(creoSONUrl, reqBody) } /** * windchill : set_server */ wchSetServer(creoSONUrl, sessionId, urlOrAlias) { reqBody = (LTrim Join { "sessionId": "%sessionId%", "command": "windchill", "function": "set_server", "data": { "server_url": "%urlOrAlias%" } } ) return this.HTTP.sendPOSTHTTPReq(creoSONUrl, reqBody) } /** * windchill : authorize */ wchAuthorize(creoSONUrl, sessionId, user, pass) { reqBody = (LTrim Join { "sessionId": "%sessionId%", "command": "windchill", "function": "authorize", "data": { "user": "%user%", "password": "%pass%" } } ) return this.HTTP.sendPOSTHTTPReq(creoSONUrl, reqBody) } /** * windchill : set_workspace */ wchSetWorkspace(creoSONUrl, sessionId, workspaceName) { reqBody = (LTrim Join { "sessionId": "%sessionId%", "command": "windchill", "function": "set_workspace", "data": { "workspace": "%workspaceName%" } } ) return this.HTTP.sendPOSTHTTPReq(creoSONUrl, reqBody) } /** * Subclass */ class HTTP { sendPOSTHTTPReq(creoSONUrl, reqBody) { WinHTTP := ComObjCreate("WinHTTP.WinHttpRequest.5.1") WinHTTP.Open("POST", creoSONUrl, 0) WinHTTP.SetRequestHeader("Content-Type", "application/json") try { WinHTTP.Send(reqBody) ;status := WinHTTP.Status response := WinHTTP.ResponseText } catch e { MsgBox, % e.message ExitApp } return response } } } ; ============== libs and functions from ahk community ================== class Utils { /**************************************************************************************** Function: BuildJson(obj) Builds a JSON string from an AutoHotkey object Parameters: obj - An AutoHotkey array or object, which can include nested objects. Remarks: Originally Obj2Str() by Coco, http://www.autohotkey.com/board/topic/93300-what-format-to-store-settings-in/page-2#entry588373 Modified to use double quotes instead of single quotes and to leave numeric values unquoted. Returns: The JSON string */ BuildJson(obj) { str := "" , array := true for k in obj { if (k == A_Index) continue array := false break } for a, b in obj str .= (array ? "" : """" a """: ") . (IsObject(b) ? this.BuildJson(b) : this.IsNumber(b) ? b : """" b """") . ", " str := RTrim(str, " ,") return (array ? "[" str "]" : "{" str "}") } /**************************************************************************************** Function: ParseJson(jsonStr) Converts a JSON string into an AutoHotkey object Parameters: jsonstr - the JSON string to convert Remarks: Originally by Getfree, http://www.autohotkey.com/board/topic/93300-what-format-to-store-settings-in/#entry588268 Returns: The AutoHotkey object. */ ParseJson(jsonStr) { SC := ComObjCreate("ScriptControl") SC.Language := "JScript" ComObjError(false) jsCode = ( function arrangeForAhkTraversing(obj){ if(obj instanceof Array){ for(var i=0 ; i<obj.length ; ++i) obj[i] = arrangeForAhkTraversing(obj[i]) ; return ['array',obj] ; }else if(obj instanceof Object){ var keys = [], values = [] ; for(var key in obj){ keys.push(key) ; values.push(arrangeForAhkTraversing(obj[key])) ; } return ['object',[keys,values]] ; }else return [typeof obj,obj] ; } ) SC.ExecuteStatement(jsCode "; obj=" jsonStr) return this.convertJScriptObjToAhks( SC.Eval("arrangeForAhkTraversing(obj)") ) } /*! Function: convertJScriptObjToAhks(jsObj) Used by ParseJson() */ convertJScriptObjToAhks(jsObj) { if(jsObj[0]="object"){ obj := {}, keys := jsObj[1][0], values := jsObj[1][1] loop % keys.length obj[keys[A_INDEX-1]] := this.convertJScriptObjToAhks( values[A_INDEX-1] ) return obj }else if(jsObj[0]="array"){ array := [] loop % jsObj[1].length array.insert(this.convertJScriptObjToAhks( jsObj[1][A_INDEX-1] )) return array }else return jsObj[1] } /*! Function: IsNumber(Num) Checks if Num is a number. Returns: True if Num is a number, false if not */ IsNumber(Num) { if Num is number return true else return false } ; ============= more functions ====================== Array_Gui(Array, Parent="") { if !Parent { Gui, +HwndDefault Gui, New, +HwndGuiArray +LabelGuiArray +Resize Gui, Margin, 5, 5 Gui, Add, TreeView, w300 h200 Item := TV_Add("Array", 0, "+Expand") this.Array_Gui(Array, Item) Gui, Show,, GuiArray Gui, %Default%:Default WinWait, ahk_id%GuiArray% WinWaitClose, ahk_id%GuiArray% return } For Key, Value in Array { Item := TV_Add(Key, Parent) if (IsObject(Value)) this.Array_Gui(Value, Item) else TV_Add(Value, Item) } return GuiArrayClose: Gui, Destroy return GuiArraySize: GuiControl, Move, SysTreeView321, % "w" A_GuiWidth - 10 " h" A_GuiHeight - 10 return } ; by GeekDude }
Responses:
Thanks
~J
Sweet! Congrats on getting that to work!
Dave
Thanks, Now I wish I knew how to do the Upload of all modified objects in local workspace to the server-side workspace. Seems like CreoSON can't do Upload. The rest of Windchill operations I'd be able to do using Windchill Java API.
~J
Yea - CREOSON uses JLINK for the Windchill interface - so it is quite limited in this respect.
Good luck!
Dave