Program screen ID

SUGGESTED

hi all,

I am following example on this link https://www.sagecity.com/us/sage300/b/sage_300_erp_r_and_d/posts/launching-non-sdk-programs-from-the-desktop to create a screen using C#. I am able to create and working fine. However, the details is not looking pretty because it does not have screen ID, so it is showing full path instead. Can we add screen ID to this exe and to show the screen ID as the details? If cannot, can we hide the path?

My grp.txt content for this program is below:

Thank you

  • 0

    So, you're saying that everything is working properly and the $objecthandle$ is being passed to your application, and your application is picking up the $objecthandle$ and using the current session, but the problem you're having is that when you look at the details of the new application in Sage 300, instead of a screen ID, it shows the path to the application?

    I'm afraid that this is how it works. If you write an application outside of the SDK using standard forms, this is what you will get. The application you have created has no screen ID built in. You might be able to do something with the grp.dat file but I am not sure it will work because the screen isn't a proper Sage screen and isn't registered in the app in the same way. It's been a long time since I did this myself.

    When I have done this, the only complication I found was allowing the app to run once for the user, but allowing for multiple users to run it simultaneously, and also preventing Sage from closing while the app was open. I managed to sort this though.

  • 0 in reply to Vega

    Hi Vega, thank you for the clarification. I am only starting to learn development with Sage 300 SDK, so this is my first problem. Now you have mentioned the complication, and I am having the same as well. How did you sort it out?

  • 0 in reply to murni
    SUGGESTED

    It took me a while to work this out. Obviously you have references to your ACCPAC.Advantage and ACCPAC.Advantage.Types. First things first. Make sure there is a GUID set for your application in Project -> Properties -> Application -> Assembly Information -> GUID. There should be and this should never change. Then you need to make your Main() method like this:

        static class Program
        {
            /// <summary>
            /// The main entry point for the application.
            /// </summary>
            [STAThread]
            static void Main()
            {
                // This prevents the program from being executed more than once but allows when more than one users runs it from a Sage session
                using (Mutex mutex = new Mutex(false, ((GuidAttribute)Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), typeof(GuidAttribute), false)).Value.ToUpper()))
                {
                    if (!mutex.WaitOne(0, false))
                    {
                        return;
                    }
    
                    GC.Collect();
    
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
                    Application.Run(new FrmMain());
                }
            }
        }
    

    Assuming your main form is called FrmMain you then need to tell the application to load the form as a child window of Sage. To do that, you do the following:

        public partial class FrmMain : Form
        {
            // This DLL import allows the loading of the specified DLL which registers the loading application with Sage so that it is a child window of the Sage desktop. It means you can't close Sage and leave this window open. There is more code in the form open and the close and cleanup function
            [DllImport(@"a4wroto.dll")]
            static extern void rotoSetObjectWindow(int objectHandle, int hWnd);
    
            string msWindowTitle = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false).OfType<AssemblyDescriptionAttribute>().FirstOrDefault().Description + ":- v" + Assembly.GetExecutingAssembly().GetName().Version.ToString();
            string msWindowHandle = "0";
            Session accpacSession;
            DBLink mDBLinkCmpRW;
    
            #region Form functions and event handlers
            public FrmMain()
            {
                InitializeComponent();
            }
    
            private void FrmMain_Load(object sender, EventArgs e)
            {
    #if DEBUG
                tbDebug.Visible = true;
    #endif
                Cursor.Current = Cursors.AppStarting;
                Icon = Resources.logo_consulting;
                Text = msWindowTitle;
    
    #if DEBUG
                Debugger.Launch();
    #endif
    
                try
                {
                    msWindowHandle = Environment.GetCommandLineArgs()[1];
                    rotoSetObjectWindow(Convert.ToInt32(msWindowHandle), Handle.ToInt32());
                    accpacSession = new Session();
                    accpacSession.Init(msWindowHandle, "XY", "XY1000", "65A");
                    Text = accpacSession.CompanyID + " - " + msWindowTitle;
    
                    try
                    {
                        mDBLinkCmpRW = accpacSession.OpenDBLink(DBLinkType.Company, DBLinkFlags.ReadWrite);
    
                        // Rest of your code
                        

    The DLL Import loads the a4wroto.dll registered on your machine. I set a couple of variables for the window title and window handle. The window title is reading from Project -> Properties -> Application -> Assembly Information and the window handle defaults to 0.

    Then, in the FrmLoad_Load() method you pick up the window handle set by your $objecthandle$ variable when you added it to Sage. You then pass this value to rotoSetObjectWindow. I set the window title, and from there I set up the session. In the Init() method, the first parameter is the window handle value. After that, the rest is the same. I use the #if DEBUG directives so that during debugging, I can launch the debugger, because once you set this up in this way you will not be able to run the application properly. What you do is add your icon to Sage, but when you set the path, set it to the exe file generated in the Debug folder of your project. When Sage runs that, in debug mode it will load the debugger. For this to work correctly, you will also need to run Visual Studio as an the administrator. So, open your project but load VS as an administrator and when you compile the code, and then from within Sage launch the application, the debugger will kick in and you choose which VS window will run your debugger session. Use the one that has your project loaded.

  • 0 in reply to Vega
    SUGGESTED

    Oh yes, I forgot this. You need to set this in the form closing event.

            private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
            {
                rotoSetObjectWindow(Convert.ToInt32(msWindowHandle), 0);
    
                // Dispose all the other views that you opened here as well
                
                if (mDBLinkCmpRW != null) mDBLinkCmpRW.Dispose();
                if (accpacSession != null) accpacSession.Dispose();
            }

  • 0 in reply to murni

    Did my suggestions help?

  • 0 in reply to Vega

    Hi Vega, sorry, takes too long to try it out. I have tried it today and it works! thank you for the help.