How to open windows desktop applications from Acumatica

Imagine you are working on Acumatica customization that needs to integrate with an existing desktop application. How can you launch the desktop application from the web-based app? It might seem impossible at first, but on Windows, it's actually quite simple. The key is to use Custom Protocol Handlers. All you need to do is install a new custom protocol and tell Windows which application should handle it. For example, let's say you have a desktop application that performs sales analysis based on the stock item when it is launched. You can create a new custom protocol called " ItemAnalyzer://" and whenever a URL with this protocol is entered into the browser, the desktop application will be launched and the text after the protocol will be treated as a parameter.

 

It's important to note that when using protocol handlers, the protocol name itself will be included as part of the argument passed to the desktop application. This may require some additional processing to remove the protocol name (such as the "GetStringBetweenDelimiters" function on line 17). For example, if you run the desktop application with an argument, you might get something like the following:

class Program
{
    static void Main(string[] args)
    {
        string inventoryCD = GetStringBetweenDelimiters(args[0]);
 
        Console.WriteLine($"Processing...: {inventoryCD}");
        // ...
        // do something with inventoryCD
        // ...
 
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
 
    static string GetStringBetweenDelimiters(string input)
    {
        int firstIndex = input.IndexOf("://") + 3;
        int lastIndex = input.IndexOf('/', firstIndex);
        return input.Substring(firstIndex, lastIndex - firstIndex);
    }
 
    static void RegProtocol()
    {
        var key = Registry.ClassesRoot.CreateSubKey("ItemAnalyzer");
        
        key.SetValue("", "URL:ItemAnalyzer Protocol");
        key.SetValue("URL Protocol", "");
        
        var subKey = key.CreateSubKey(@"shell\open\command");
        var execPath = Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location),
                                    System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
 
        subKey.SetValue("", $"{execPath} %1");
        subKey.Close();
        key.Close();
    }
}

To make the magic happen, we need to register the custom protocol handler in the Windows registry. This can be done manually or automatically. First, let's do it manually. To do this, open the Windows registry as a system administrator (type "Regedit" in the start menu or run it as a command). Then, follow these steps:

 

  1. Under HKEY_CLASSES_ROOT, create a new key with the same name as the protocol (in this case, " ItemAnalyzer ").
  2. Inside the new key, add a default new string value with no name (just "Default") and set its content to "URL:protocol_name Protocol" (in this case, "URL: ItemAnalyzer Protocol").

3. Add a new string with the name "URL Protocol" and no content.

4. Under the " ItemAnalyzer" key, add the following keys hierarchically: shell\open\command

5. Inside the "command" key, add a new string with an empty name (just "Default") and set its value to the location of the executable followed by %1, which represents the argument to pass to the executable.

After completing these steps, if you open the run window and type "ItemAnalyzer:// " and press enter, the application will be launched. You can also do this from the browser, and the browser will prompt you for confirmation before launching the application.

Now, let's proceed to the implementation of an action within Acumatica that will initiate the opening of a desktop application when activated. Specifically, we want to create an action on the Sales Order screen that, will execute a specified program to run our desktop application and pass the InventoryCD as an argument.

namespace AcuStockItemAnalizer
{
    public class SOOrderEntryExt : PXGraphExtension<SOOrderEntry>
    {
        public static bool IsActive() => true;
 
        #region Action
        public PXAction<SOOrder> RunStockItemAnalyzer;
        
        [PXUIField(DisplayName = "Run Item Analyzer")]
        [PXButton(CommitChanges = true)]
        protected virtual IEnumerable runStockItemAnalyzer(PXAdapter adapter)
        {
            var tranRow = Base.Transactions.Current;
            if (tranRow != null)
            {
                var inventoryItem = PXSelectorAttribute.Select<SOLine.inventoryID>(Base.Caches[typeof(SOLine)], tranRow, tranRow?.InventoryID) as InventoryItem;
                if (inventoryItem != null)
                {
                    string urlProtocol = string.Format($"ItemAnalyzer://{inventoryItem.InventoryCD}");
                    throw new PXRedirectToUrlException(urlProtocol, null);
                }
            }
            
            return adapter.Get();
        }
        #endregion
    }
}
As demonstrated in the example, activating the action initiates the opening of a desktop application, with the InventoryCD being passed as a parameter.


To automate the process of registering a custom protocol handler, you can change the registry during the application installation or have the application do it automatically. One way to do this in C# is to use the code provided.

Another option is to create a .REG file. This is a plain text file with a .REG extension that contains registry entries, and it can be used to add or modify registry entries automatically when opened. When you double-click a .REG file, it will be imported into the registry, and the registry entries it contains will be added or modified. This can be a convenient way to automatically register custom protocol handlers without manually editing the registry.

 

Windows Registry Editor Version 5.00

 

[HKEY_CLASSES_ROOT\ItemAnalyzer]

@="URL: ItemAnalyzer Protocol"

"URL Protocol"=""

 

[HKEY_CLASSES_ROOT\ItemAnalyzer\shell]

 

[HKEY_CLASSES_ROOT\ItemAnalyzer\shell\open]

 

[HKEY_CLASSES_ROOT\ItemAnalyzer\shell\open\command]

@="\"C:\\TestApplication\\StockItemAnalizer.exe\" \"%1\""