Launching Non-SDK Programs From the Desktop
Introduction
When SDK applications are launched from the Desktop, they are passed an object handle that they can use to create a session that exactly matches the session of the desktop that launched them. Further the desktop can manage these programs and for instance put up an error message if you try to close the Desktop while they are still running.
Quite a few people create programs that aren’t written using our SDK, but still are tightly integrated to Sage 300 ERP via one of our APIs such as the COM API, .Net API or Java API. You can add arbitrary EXE programs to the Desktop as icons and launch them just like any other screen.
When we designed the current UI framework, we had the intention that our UIs could be run from many places, such as VBA macros or hosted inside Internet Explorer. We also envisioned them being strung together in workflow type applications. Towards this we created the Session Manager and the Signon Manager to help tie together programs running inside the desktop with programs running outside the desktop. For information on using the Session Manager, check out this blog posting.
Generally this has worked quite well. Especially if you only signon to one company, then all the various things running will share the same session and you won’t have to signon to everything separately. However there are a few limitations to our current approach. If there are two desktops running (usually signed on to different companies) then when the external program is run, it has to present a dialog to choose which company’s session to use. This makes sense if you say start an EXE program from the start menu, since how would it know which desktop session to use? But when you run from the desktop you would expect it to just use that desktop’s session, rather than being treated like it wasn’t run from the desktop. Similarly if you started an EXE program from the desktop you would expect the Desktop to prevent closing until this program is closed, right now this check is only for SDK programs run from the desktop and doesn’t apply to anything else.
A lot of people are creating standalone EXE’s that use our APIs and they are using the Session Manager, which generally works well, but would like to get the other cases handled as nicely. So for the upcoming Sage 300 ERP 2014 release we have added some support to the Desktop to help with this. To basically allow non-SDK programs to start with the same protocol as the SDK programs so they can behave in the same manner. The alpha (developer) early release of Sage 300 ERP 2014 is available to ISVs so you can try this out now.
New Macro Substitution
If you add a program to a groupfile or if you add a program via file new in the desktop, if you specify $objecthandle$ as an argument, then this will be translated into an object handle when you are run that you can use in other API calls to get a session that matches your desktop. For instance in a group file:
[ PROGRAM ] ID = "XX0500" PARENT = "XX0000" DESCRIPTION = "test ojbect key" CMDLINE = "c:\\accpac6\\sm\\testobj\\testobj.exe $objecthandle$" RSC = "XXSDK"
This is then the token you can use to create your session exactly from the Desktop that ran you.
If you aren’t an SDK program, you probably don’t have your own group file. However you can use a couple of SDK tools to add your item to an existing group file. The program unccgrp.exe (usually installed in c:\pluswdev\bin) will de-compile a group file (these are usually grp.dat files in a programs language folder, like ar62a\eng\grp.dat). Then you can add your own entries to this and then use ccgrp.exe to re-compile the group file. This is a bit of a kludge because it may overwritten by Product Updates and two people trying to do this at once may collide and interfere with each other. But it can be an effective and useful technique.
How to Use the Object Handle
You can then pass the object handle into a session init call and your session will be configured to match the desktop you are run from. Additionally if you want to register your windows handle, you can use the roto api to do so given the object handle. You should also clear this when you terminate.
Below is a VB program which does these things. It uses the session it gets to display the company name in a label. This way it will be connected to the right Desktop and the Desktop knows when it’s running.
Private Declare Sub rotoSetObjectWindow Lib "a4wroto.dll" (ByVal objectHandle As Long, ByVal hWnd As Long) Dim strObjectHandle As String Private Sub Command1_Click() Unload Me ' ' clear our window handle when closing so we don't block the desktop closing ' rotoSetObjectWindow Val(strObjectHandle), 0 End Sub Private Sub Form_Load() Dim mSession As New AccpacCOMAPI.AccpacSession ' ' Get the object handle from the command line ' strObjectHandle = Command$ MsgBox "Object Handle = " + strObjectHandle ' ' Use the object handle to intialize the session. With this you will inherit ' an open session matching the desktop that launched you. ' mSession.Init strObjectHandle, "XY", "XY1000", "62A" ' ' Set the window handle so the desktop can track whether you have closed ' effectively doing a roto openok. ' rotoSetObjectWindow Val(strObjectHandle), Me.hWnd Dim mDBLinkCmpRW As AccpacCOMAPI.AccpacDBLink Set mDBLinkCmpRW = mSession.OpenDBLink(DBLINK_COMPANY, DBLINK_FLG_READWRITE) Dim CSCOM As AccpacCOMAPI.AccpacView Dim CSCOMFields As AccpacCOMAPI.AccpacViewFields mDBLinkCmpRW.OpenView "CS0001", CSCOM Set CSCOMFields = CSCOM.Fields CSCOM.Fetch Label1.Caption = CSCOMFields("CONAME").Value End Sub
[…] Introduction When SDK applications are launched from the Desktop, they are passed an object handle that they can use to create a session that exactly matches the session of the desktop that launche… […]
Launching Non-SDK Programs From the Desktop | S...
July 6, 2013 at 8:53 pm
Should Desktop pass ObjectHandle to EXE program automatically when launching EXE as Program Short-cut on Desktop?
This is not really an improvement, as it require access to ccgrp.exe and unccgrp.exe (SDK). However, if already using SDK (or as it said, SDK tools) you can simply add exe entry into ROTO instead of GROUP file and it already pass ObjectHandle to the program.
Khanh Trinh
July 7, 2013 at 4:44 am
Perhaps I shouldn’t have included the paragraph on unccgrp/ccgrp since the intent here is to do it without the SDK. Ie use File New to add and EXE file to the desktop.
smist08
July 7, 2013 at 3:04 pm
Yes. The Macro substitution section make me understand I need to alter grp.dat to make it work. I hope desktop will add ObjectHandle to the last end of command line arguments, since almost current program that has arguments won’t need to be changed if they don’t want to take this advantage.
Khanh Trinh
July 8, 2013 at 2:13 pm
[…] Launching Non-SDK Programs From the Desktop […]
Looking Back on 2013 and Forward to 2014 | Stephen Smith's Blog
December 28, 2013 at 6:33 pm
Hi Stephen, I used unccgrp for grp.dat under CP70A\ENG and without changing anything. I used ccgrp and produced the grp.dat file. Copied the new grp.dat file to the CP70A\ENG folder. After doing this, the ‘Generate EFT File’ icon is giving an error: ‘Program file problem. Object is not defined in the Roto event file.’. Is this a known issue ? Is there a work-around? Thanks
Emy
March 5, 2014 at 8:04 pm
All I can think is that you inadvertently edited the entry for CP2700 somehow. Perhaps repair CP70A and try again?
smist08
March 5, 2014 at 8:10 pm
Thanks! That’s it. For some reasons, unccgrp changed CP2700 to CP8332. But, when I changed it to CP2700, it worked.
Emy
March 5, 2014 at 10:07 pm
Hi Stephen, I tried to use the $objecthandle$ following your instructions above, but, it’s not working for me. What is supposed to be the value expected for $objecthandle$ ? I get the value “Object Handle = $ObjectHandle$” from the message box, which seemed to be just the string value “$ObjectHandle$”. After that, I can’t inititate the Accpac session with “Runtime error ‘-217467259 (80004005)’: 1.2071.18”. Any ideas?
Thanks
Emy
April 17, 2014 at 4:18 pm
Try all lower case for objecthandle, also you need to be running Sage 300 ERP 2014 and the program in the group file must be an EXE.
smist08
April 21, 2014 at 7:15 pm
Hi Stephen,
I’m facing the same problem, tried all lower case for objecthandle but it still not worked. Do u have any ideas?
Thanks
LukeLe
October 21, 2014 at 11:22 am
Hi Stephen. Great article. I’m writing a .net app that integrates with Sage 300 ERP so this was very helpful in getting a session that I could use. One question. Is there any way to load a form (if sage 300 is open) from a non-sdk application? In other words, my application is creating a payment batch and I want the user to be able to click on a link or button inside of my app that will open up the payment batch that was created so they can save a few steps. Is that possible? I couldn’t find anything while searching but I may not be searching for the right keywords 🙂 Thanks Stephen.
Brad Edwards
May 22, 2014 at 2:20 pm
There is a hidden property ObjectHandle for each OCX that if you set the object handle talked about in the article, will hopefully do the job for you.
smist08
July 24, 2014 at 3:58 am
So sorry to post to an old thread, but can’t find any answers after hours of searching. When two or more companies have open desktops, rotoSetObjectWindow seems to always present a signon manager dialog to select which company, even though the I’ve verified that the $objecthandle$ value is unique to the desktop launching the custom non-SDK program. Any ideas what I’m doing wrong or leaving out? Sage300-2014 calling a VB6 program.
Tim Brodie
June 10, 2015 at 12:45 am
It sounds like you are using the session manager or signon manager. Perhaps try opening the session directly using this object handle.
smist08
June 10, 2015 at 3:58 am
Thanks for answering so quickly! I have the AccpacAP2100Ctrl control inside a VB6 form, as I am trying to add some additional field validation logic on the Vendor PO number that is specific to the business. On the form initialize event, I’ve coded the following:
Private Sub Form_Initialize()
Dim mSession As New AccpacCOMAPI.AccpacSession
‘ Get the object handle from the command line
strObjectHandle = Command$
MsgBox “Object Handle = ” + strObjectHandle
‘ Set the control object handle to use this handle
JLAP2100frm.AccpacAP2100UICtrl1.objectHandle = strObjectHandle
End Sub
I think this is what you’ve suggested to do, but I still get a Signon Manager dialog listing the two open companies. Or have I misunderstood you?
Thanks… Tim
Tim Brodie
June 10, 2015 at 9:04 pm
Hey Tim I believe I have a solution to your issue. Did you find a solution already?
Jason
July 31, 2015 at 5:29 pm
Jason, no we took another approach given time constraints — yet I really would like to see what the solution would have been! Thanks
Tim Brodie
July 31, 2015 at 5:50 pm
Here’s generally what I did….
————————-
‘declare control to fire events
Dim WithEvents oeRet As AccpacOE1600UICtrl
Private Sub Form_Load()
Dim myObjectHandle As String
‘add to the forms controls collection
Me.Controls.Add “AccpacOE1600.AccpacOE1600UICtrl”, “mycontrol”
‘assign a reference to it so we can manipulate it
Set oeRet = Me.Controls.Item(“mycontrol”)
‘get an object handle from the current session and set to the control
myObjectHandle = session.CreateObjectHandle2(“OE1600”, “”)
oeRet.objectHandle = myObjectHandle
‘Position the control on the screen
With oeRet
.Top = 0
.Left = 0
.Width = Me.Width
.Height = Me.Height
End With
oeRet.Visible = True
End Sub
Jason
August 5, 2015 at 6:41 pm
Hi Jason,
I was trying your suggestion however, I get runtime error when oeRet.objectHandle line is executed. I get the below error message
“The object doesn’t support this property or method”
Sage 300 ERP 2014
MS SQL Server 2008
Desktop version
Sample Company
Let me know if you need further info.
Thanks,
spkrish
October 20, 2017 at 3:18 am
Hi Steve,
Greetings for you
I am not getting this fixed when multiple companies are open and I run this code I still get a window asking user to choose the company database and not the signon window though. how to overcome this issue?
please give me a sample code as i am using VBControlExtender to add the AR Invoice UI
Looking forward to your suggestion.
Thanks,
Krish
here is my code…
‘ Code Starts ============================================
Option Explicit
Private WithEvents mAR2100 As VBControlExtender
Private mSession As AccpacSession
Private mDBLink As AccpacDBLink
Private Declare Sub rotoSetObjectWindow Lib “a4wroto.dll” (ByVal objectHandle As Long, ByVal hWnd As Long)
Private mstrObjectHandle As String
Private Sub Form_Load()
Debug.Print “Private Sub Form_Load()”
mstrObjectHandle = Command$
Set mSession = New AccpacSession
mSession.Init mstrObjectHandle, “RT”, “RT1000”, “62A”
rotoSetObjectWindow Val(mstrObjectHandle), Me.hWnd
Set mAR2100 = Me.Controls.Add(“ACCPACAR2100.ACCPACAR2100UICtrl”, “mAR2100”)
Me.Caption = “Customized A/R Invoice Entry” ‘mAR2100.object.uiname
mAR2100.Visible = True
End Sub
Private Sub Form_Unload(Cancel As Integer)
‘ clear our window handle when closing so we don’t block the desktop closing
‘
rotoSetObjectWindow Val(mstrObjectHandle), 0
End Sub
Private Sub mAR2100_ObjectEvent(Info As EventInfo)
Debug.Print “Private Sub mAR2100_ObjectEvent(Info As EventInfo)”
Select Case Info.Name
Case “OnUIAppClosed”
Case “OnUIAppOpened”
Me.Caption = mAR2100.object.CompanyID & ” – ” & “Customized A/R Invoice Entry” ‘mAR2100.object.uiname
Me.Icon = mAR2100.object.uiicon
Me.WindowState = vbNormal
Me.Move (Screen.Width – Me.Width) / 2, (Screen.Height – Me.Height) / 2, mAR2100.Width + 120, mAR2100.Height + 820
Me.Move (Screen.Width – Me.Width) / 2, (Screen.Height – Me.Height) / 2
With mAR2100.object
Set mSession = .UISession
Set mDBLink = .UIDBLinks(1)
End With ‘mAR2100.object
Case “OnPopupOpened”
End Select
End Sub
‘ Code Ends ============================================
spkrish
October 20, 2017 at 3:14 am
Hi,
I have created seperate .net C# app and pass $ObjectHandle$ as argument.It is working but when i close the Sage external app is not logging out.Kindly help me on this
Karthika
February 22, 2020 at 8:19 am
It should logout when the session object is destroyed. You might try setting the variable to null or calling logout explicitly to force it to happen. Also check your process is really fully terminated (and doesn’t show up in the task list).
smist08
February 22, 2020 at 4:41 pm