There are times when it may be desirable or necessary to change GoFiler’s software key or unregister it from your system. There’s no easy way to do this through the application’s GUI. One can always uninstall the software or reinstall it to apply a different key than the one attached to the current installation, but that’s time-consuming and can destroy GoFiler preferences and settings you’d like to keep. With Legato and some batch scripting, changing the software key for a GoFiler installation or unregistering the application is simple. Note: whatever software key you apply to your installation must be valid, and a valid key can only be purchased through Novaworks. Contact the support or sales departments to inquire about the status of your software key(s) or to purchase new or additional keys.
Friday, July 07. 2017
LDC #42: Unregistering and Changing Software Keys
// // // GoFiler Legato Script - Unregister and Exit // ------------------------------------------ // // Rev 07/05/2017 // // (c) 2017 Novaworks, LLC -- All rights reserved. // // Unregisters GoFiler with server, asks if user wants to change software key while unregistering. #define BAT_NAME "RegisterGF.bat" #define SOFTKEY_REGEX "^([A-Za-z0-9]{5}-){4}[A-Za-z0-9]{5}$" #define TIMEOUT "timeout /t 3 /nobreak > nul\r\n" #define CLOSE_OPEN_WINDOWS_WRN "Please close any open windows before unregistering the application." #define INVALID_KEY_ERR "Invalid software key. Enter a valid key." #include "ChangeKey.rc" int run (int f_id, string mode);/* Call from Hook Processor */ string new_key; /* new key to use */ /****************************************/ int setup() { /* Called from Application Startup */ /****************************************/ string fnScript; /* Us */ string item[10]; /* Menu Item */ int rc; /* Return Code */ /* */ /* ** Add Menu Item */ /* * Define Function */ item["Code"] = "UNREGISTER_EXIT"; /* Function Code */ item["MenuText"] = "&Unregister and Exit"; /* Menu Text */ item["Description"] = "<B>Unregister and Exit</B> "; /* Description (long) */ item["Description"]+= "\r\rCloses and Unregisters GoFiler."; /* * description */ /* * Check for Existing */ rc = MenuFindFunctionID(item["Code"]); /* Look for existing */ if (IsNotError(rc)) { /* Was already be added */ return ERROR_NONE; /* Exit */ } /* end error */ /* * Registration */ rc = MenuAddFunction(item); /* Add the item */ if (IsError(rc)) { /* Was already be added */ return ERROR_NONE; /* Exit */ } /* end error */ fnScript = GetScriptFilename(); /* Get the script filename */ MenuSetHook(item["Code"], fnScript, "run"); /* Set the Test Hook */ return ERROR_NONE; /* Return value (does not matter) */ } /* end setup */ /****************************************/ int main() { /* Initialize from Hook Processor */ /****************************************/ setup(); /* Add to the menu */ return ERROR_NONE; /* Return value (does not matter) */ } /* end setup */ /****************************************/ int run(int f_id, string mode) { /* Call from Hook Processor */ /****************************************/ string temp_folder; /* temp folder */ boolean change_key; /* true if changing key */ int rc; /* return code */ string edit_windows[][]; /* open edit windows */ string gofiler; /* path to GoFiler */ string bat_contents; /* contents of bat file */ string bat_file; /* location of bat file */ /* */ if (mode!="preprocess"){ /* if not preprocess */ return ERROR_NONE; /* return without error */ } /* */ edit_windows = EnumerateEditWindows(); /* get all open windows */ if (ArrayGetAxisDepth(edit_windows)>0){ /* if there are any open windows */ MessageBox('i',CLOSE_OPEN_WINDOWS_WRN); /* display warning */ return ERROR_NONE; /* return */ } /* */ gofiler = "\""+AddPaths(GetApplicationExecuteFolder(), /* path to GoFiler */ "GoFiler.exe\""); /* */ change_key = YesNoBox('q',"Change software key?"); /* ask if changing software key */ bat_contents = TIMEOUT; /* add a sleep to bat file */ bat_contents += gofiler+ " /unregister -silent\r\n"; /* */ if (change_key == IDYES){ /* if changing the software key */ rc = DialogBox("ChangeKey", "change_"); /* open dialog */ if (rc==ERROR_CANCEL || new_key == ""){ /* if no new key selected */ return ERROR_CANCEL; /* return cancelled. */ } /* */ bat_contents += TIMEOUT; /* add a sleep to bat file */ bat_contents += gofiler+ " /register:"+new_key+"\r\n"; /* add registration command to bat */ } /* */ temp_folder = GetTempFileFolder(); /* get temp folder */ bat_file = AddPaths(temp_folder, BAT_NAME); /* get full path to bat file */ StringToFile(bat_contents,bat_file); /* write out bat file */ RunProgram("cmd.exe", "/C \""+bat_file+"\""); /* run the bat file */ RunMenuFunction("FILE_EXIT"); /* quit GoFiler */ return ERROR_NONE; /* Return value (does not matter) */ } /* end setup */ /****************************************/ int change_validate(){ /* validate key */ /****************************************/ string key; /* key from dialog */ /* */ new_key = ""; /* reset variable */ key = EditGetText(SOFTKEY); /* get text */ if (IsRegexMatch(key,SOFTKEY_REGEX)==false){ /* if invalid key */ MessageBox('x',INVALID_KEY_ERR); /* display message */ return ERROR_EXIT; /* return an error */ } /* */ new_key = key; /* store key for later use */ return ERROR_NONE; /* Return value (does not matter) */ }
We begin this week with a bunch of defines that we’ll use to reference some constant data we’ll need. This includes the location and name of our batch script to register the application (which, in this case, is in the same folder as our Legato script), as well as a regex format for our software key and some warning/error messages. In addition, we’ll include a resource file, “ChangeKey.rc”. Let’s take a look inside that:
// // View and Edit Software Key // ------------------- // // (c) 2017 Novaworks // // DO NOT EDIT THIS FILE - SEE INSTRUCTIONS IN EXTENSIONS FOLDER // #define SOFTKEY 201 ChangeKey DIALOGEX 0, 0, 270, 50 EXSTYLE WS_EX_DLGMODALFRAME STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU CAPTION "Change Software Key" FONT 8, "MS Sans Serif" { CONTROL "&Software Key", -1, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 12, 8, 48, 8, 0 CONTROL "", SOFTKEY, "edit", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 70, 6, 190, 12, 0 CONTROL "OK", IDOK, "BUTTON", BS_DEFPUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 160, 26, 50, 14 CONTROL "Cancel", IDCANCEL, "BUTTON", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 216, 26, 50, 14 CONTROL "", -1, "static", SS_ETCHEDFRAME | WS_CHILD | WS_VISIBLE, 6, 48, 260, 1, 0 }
The above code defines our modal dialog “ChangeKey”, through which we can query the user for a new software key using an edit control. We also provide OK and Cancel buttons. For more information on using dialogs, controls, and resource files, see this previous blog post.
Now that we have our dialog defined, we can move onto the meat of our script. We have our three basic functions: setup, main, and run. We also have a fourth function, change_validate, that will look at the new software key supplied by the user and employ some regular expressions matching to determine if the new key is valid. This is called through our dialog box, so we’ll talk more about it later.
Our main function simply calls our setup function, so let’s dive into that.
/****************************************/ int setup() { /* Called from Application Startup */ /****************************************/ string fnScript; /* Us */ string item[10]; /* Menu Item */ int rc; /* Return Code */ /* */ /* ** Add Menu Item */ /* * Define Function */ item["Code"] = "UNREGISTER_EXIT"; /* Function Code */ item["MenuText"] = "&Unregister and Exit"; /* Menu Text */ item["Description"] = "<B>Unregister and Exit</B> "; /* Description (long) */ item["Description"]+= "\r\rCloses and Unregisters GoFiler."; /* * description */ /* * Check for Existing */ rc = MenuFindFunctionID(item["Code"]); /* Look for existing */ if (IsNotError(rc)) { /* Was already added */ return ERROR_NONE; /* Exit */ } /* end error */ /* * Registration */ rc = MenuAddFunction(item); /* Add the item */ if (IsError(rc)) { /* Was already be added */ return ERROR_NONE; /* Exit */ } /* end error */ fnScript = GetScriptFilename(); /* Get the script filename */ MenuSetHook(item["Code"], fnScript, "run"); /* Set the Test Hook */ return ERROR_NONE; /* Return value (does not matter) */ } /* end setup */
This function is going to hook our unregister function into the menu in GoFiler. We’ve covered menu hooks in previous blog posts more extensively. Briefly, we define an array of properties about our menu item (in the item string array) and check to see if the menu function ID is in use already with the MenuFindFunctionID function. If it is, we must exit (no error is necessary - our function’s already been added!). Otherwise, we call the MenuAddFunction function and pass it our array of menu item properties. After that, we set the hook. We need to get the script file name (using the GetScriptFilename function) and pass that, the new menu function ID, and the function we’ll be hooking into the menu item, which is our run function. We can return without an error.
Now we’ve added our “Unregister and Exit” menu item. Let’s see what will happen when the user executes it by looking at the run function:
/****************************************/ int run(int f_id, string mode) { /* Call from Hook Processor */ /****************************************/ string temp_folder; /* temp folder */ boolean change_key; /* true if changing key */ int rc; /* return code */ string edit_windows[][]; /* open edit windows */ string gofiler; /* path to GoFiler */ string bat_contents; /* contents of bat file */ string bat_file; /* location of bat file */ /* */ if (mode!="preprocess"){ /* if not preprocess */ return ERROR_NONE; /* return without error */ } /* */ edit_windows = EnumerateEditWindows(); /* get all open windows */ if (ArrayGetAxisDepth(edit_windows)>0){ /* if there are any open windows */ MessageBox('i',CLOSE_OPEN_WINDOWS_WRN); /* display warning */ return ERROR_NONE; /* return */ } /* */ gofiler = "\""+AddPaths(GetApplicationExecuteFolder(), /* path to GoFiler */ "GoFiler.exe\""); /* */ change_key = YesNoBox('q',"Change software key?"); /* ask if changing software key */ bat_contents = TIMEOUT; /* add a sleep to bat file */ bat_contents += gofiler+ " /unregister -silent\r\n"; /* */ if (change_key == IDYES){ /* if changing the software key */ rc = DialogBox("ChangeKey", "change_"); /* open dialog */ if (rc==ERROR_CANCEL || new_key == ""){ /* if no new key selected */ return ERROR_CANCEL; /* return cancelled. */ } /* */ bat_contents += TIMEOUT; /* add a sleep to bat file */ bat_contents += gofiler+ " /register:"+new_key+"\r\n"; /* add registration command to bat */ } /* */ temp_folder = GetTempFileFolder(); /* get temp folder */ bat_file = AddPaths(temp_folder, BAT_NAME); /* get full path to bat file */ StringToFile(bat_contents,bat_file); /* write out bat file */ RunProgram("cmd.exe", "/C \""+bat_file+"\""); /* run the bat file */ RunMenuFunction("FILE_EXIT"); /* quit GoFiler */ return ERROR_NONE; /* Return value (does not matter) */ } /* end setup */
Our run function first defines the local variables it needs, which include strings for a temporary folder location, an array of edit windows, strings for the location and contents of our batch script, and a boolean to signify if the software key is being changed. First, as many times before, we exit if the mode parameter isn’t preprocess. Now we enumerate our edit windows with the EnumerateEditWindows function. If the application is going to be closed, every edit window must be closed first, so we’ll alert the user by checking if there are any edit windows open and using the MessageBox function to display our warning string defined above. Then we exit the run function. Note that we could add further functionality by having the script attempt to close the edit windows itself, but this would involve querying the user about saving each window that’s been changed, and that’s beyond the scope of this article.
Once we know for sure all the edit windows are closed (meaning the size of the edit_windows array is 0), we build the location of the GoFiler application with the AddPaths and GetApplicationExecuteFolder functions. Now let’s build our batch commands. We’ll add our timeout and then concatenate the commands to unregister the application silently. For more information about how to construct batch commands and the command line interface for Windows, see MSDN.
Before we run these commands, though, let’s check to see if the user wants to change the software key. We’ll query first using the YesNoMessageBox function. We’ll store the result of that function in our boolean change_key flag. If the result is IDYES, we open our “ChangeKey” dialog using the DialogBox function and hook it into our change_ event handlers. Again, for more information on dialog events and defining functions to handle them, see our previous series concerning merging XBRL files. There’s only one dialog function that we have defined: change_validate.
int change_validate(){ /* validate key */ /****************************************/ string key; /* key from dialog */ /* */ new_key = ""; /* reset variable */ key = EditGetText(SOFTKEY); /* get text */ if (IsRegexMatch(key,SOFTKEY_REGEX)==false){ /* if invalid key */ MessageBox('x',INVALID_KEY_ERR); /* display message */ return ERROR_EXIT; /* return an error */ } /* */ new_key = key; /* store key for later use */ return ERROR_NONE; /* Return value (does not matter) */ }
This is called when the Ok button is pressed on the dialog. We’ll use the EditGetText function to retrieve whatever the user entered into the SOFTKEY edit field defined in our resource template. We can then validate that string against our regex pattern using the IsRegexMatch function. This will catch any invalid keys based on the key’s structure (appropriate type and number of digits/characters, etc). It does not validate the key against the application’s servers to determine if the key can be used to successfully register only that the key is the correct format. If the key is invalid, we again use the MessageBox function to alert the user and exit with an error. Otherwise, we save the key.
Back in our run function, we append the new_key variable, if it’s available, to our batch commands. This will register the new key after unregistering the old one. Now we get the location of the temporary folder using the GetTempFileFolder function. We define the file name and path of our batch script that we’re building using the AddPaths function, the temp folder location, and our predefined batch script name. The StringToFile function converts our string variable with our batch commands to the file we just created. Now we can use the RunProgram function, and we hand it the command console (“cmd.exe”) and our batch script with its location. Then we exit the application using the RunMenuFunction function and handing it the FILE_EXIT menu function ID.
You should note that if you are trying to register a new software key, GoFiler will allow you to adjust the key again through its installation dialog. The key fields will automatically populate with the new key. If that new key is not active, there will be an error. You can hit Cancel at this point. Because nothing has changed, GoFiler will attempt to re-register itself with its old key.
So this is a simple way to unregister and/or change your software key in GoFiler using Legato, which can be a useful tool in a multi-user environment if you need to adjust where and how GoFiler is installed.
Steven Horowitz has been working for Novaworks for over five years as a technical expert with a focus on EDGAR HTML and XBRL. Since the creation of the Legato language in 2015, Steven has been developing scripts to improve the GoFiler user experience. He is currently working toward a Bachelor of Sciences in Software Engineering at RIT and MCC. |
Additional Resources
Legato Script Developers LinkedIn Group
Primer: An Introduction to Legato