{ PluginUninstaller 1.1.2.1 for Miranda IM 0.3.3a and + ------------------------------------------------------------------------ Developers - C/C++ Header File Plugin Info: ---------------------------- | Version: 1.1.2.1 | Filename: uninstaller.dll | Author: H. Herkenrath (hrathh@users.sourceforge.net) | Description: Extends the plugin options and offers the possibility | to directly remove plugins and delete all associated | settings and files. Contents: ------------------------------- | > General Info: | - Uninstall Example/Template | - Changing displayed icon | - Changing displayed docs | - Message boxes on uninstall | - Service Accesibility | - Including this file | | > Structs: | - Uninstall Params (PLUGINUNINSTALLPARAMS) | | > Helpers: | - Macro: Run service while uninstalling (PUICallService) | - Function: Remove some files in directory (PUIRemoveFilesInDirectory) | | > Events: | - Allow to uninstall a plugin (ME_PLUGINUNINSTALLER_OKTOUNINSTALL) | - Plugin gets uninstalled (ME_PLUGINUNINSTALLER_UNINSTALL) | | > Services: | - Remove database module (MS_PLUGINUNINSTALLER_REMOVEDBMODULE) | - Remove a setting globally (MS_PLUGINUNINSTALLER_REMOVEDBSETTINGGLOBALLY) | - Remove skinned sound (MS_PLUGINUNINSTALLER_REMOVESKINSOUND) | - Uninstall a plugin (MS_PLUGINUNISTALLER_UNISTALLPLUGIN) | - Getting handles (MS_PLUGINUNINSTALLER_GETHANDLE) | This file is only thought for plugin developers. If you only want to use "PluginUninstaller" and don't want to develop a plugin or something with it you don't need this file. If there are any problems or bugs with or in this file or something else please mail me. My e-mail address is: hrathh@users.sourceforge.net For more documentation you can use this address, too. :-) If you have any whishes on some plugin uninstalling for your plugin you can mail me, too. :-) } {$IFNDEF M_UNINSTALLER} {$DEFINE M_UNINSTALLER} (* | General Info ----------------------------- Uninstall Example/Template --------------------------- Making your plugin uninstallable is very easy. Just add the following "Uninstall" function near the "Unload" function in your plugin. A template plugin is available in the source code package. Old: int __declspec(dllexport) Uninstall(BOOL bIsMirandaRunning, BOOL bDoDeleteSettings, AnsiChar* pszPluginPath); New: int __declspec(dllexport) UninstallEx(PLUGINUNINSTALLPARAMS* ppup) { Available Variables: ----------------------------- ppup->bIsMirandaRunning: Contains if Miranda is running (Currently this is always TRUE). ppup->bDoDeleteSettings: Contains if the users selected that he wants all settings be deleted. ppup->pszPluginsPath: Contains the plugins directory name. Notes: ----------------------------- Run before "Unload" function: -> IMPORTANT: Be careful not to write to the database or to files in "Unload" again!!! -> Perhaps create a global BOOL variable which is set to TRUE when your plugin gets uninstalled or check of a database setting "IsInstalled" in Unload() or sth. like that All Miranda is still loaded Here you can do: - Delete settings group in database - Delete registry items - Delete ini-files and other settings files - Delete other files Your plugin dll gets automatically deleted Services to remove are offered: MS_PLUGINUNINSTALLER_REMOVEDBMODULE MS_PLUGINUNINSTALLER_REMOVEDBSETTINGGLOBALLY MS_PLUGINUNINSTALLER_REMOVESKINSOUND Getting other useful paths: ----------------------------- System directory: AnsiChar szSysPath[MAX_PATH]; GetSystemDirectory(szSysPath, MAX_PATH); Windows directory: AnsiChar szWinPath[MAX_PATH]; GetWindowsDirectory(szWinPath, MAX_PATH); Other directories: AnsiChar szPath[MAX_PATH]; SHGetSpecialFolderPath(NULL, szPath, CSIDL_* , FALSE); Some available dirs: CSIDL_APPDATA CSIDL_SENDTO CSIDL_FAVORITES CSIDL_STARTUP CSIDL_PROFILE CSIDL_DESKTOPDIRECTORY Delete Files const AnsiChar* apszFiles[] = {"MyPlugin_Readme.txt", "MyPlugin_License.txt", "MyPlugin_Developer.txt", "MyPlugin_Translation.txt"}; PUIRemoveFilesInPath(ppup->pszPluginsPath, apszFiles); Delete Settings if(ppup->bDoDeleteSettings == TRUE) { if (ppup->bIsMirandaRunning == TRUE) // Check if it is possible to access services { Remove plugin's module PUIRemoveDbModule("MyPlugin"); Remove plugin's sounds PUIRemoveSkinSound("MySoundSetting1"); PUIRemoveSkinSound("MySoundSetting2"); } } Remember: Do not forget to remove your (eventually) created registry items here, too. The plugin's dll file gets deleted after returning. Remember: If your DLL file is additionally in use by another application (eg. Windows) you need to free the DLL *here* completely. Otherwise it can't be deleted. return 0; } *) { Changing displayed icon --------------------------- The icon that gets displayed on the options page is always the "first" icon in your DLL file. An icon in your DLL file is the first icon when it has the lowest recource ID. If you would like to have an other icon shown in the options please change your icon resource IDs so that the icon you would like to have has the lowest one. For example if you use MS Visual C++, open "resource.h" and change the resource define of your prefered icon to the lowest icon number. Changing displayed docs --------------------------- The items "License" and "More Information" on the plugin details page are created when the a license and/or a readme file for the plugin exists. The files get detected automatically and need a special name so that they get detected. The text files need to be either placed in the "Plugins" directory or in the "Docs" directory. Whereof the last one is the better one :-) For the license file the following file name formatings are possible: PluginName-License.txt (I personally think that this is the best naming solution... :-) ) PluginName_License.txt, For the readme file the following ones are possible: PluginName-Readme.txt (Again...I like this one :-D ), PluginName_Readme.txt, Message boxes on uninstall --------------------------- If you would like to ask the user for something to remove/uninstall please hook the event ME_PLUGINUNINSTALLER_UNINSTALL and show your message box there. Save the action the user chose in a global BOOL variable and do the chosen action in "UninstallEx". You can get the plugins options window handle with MS_PLUGINUNINSTALLER_GETHANDLE. Service Accessibility --------------------------- Remember that you only can use these functions after the event ME_SYSTEM_MODULESLOADED or later because "PluginUninstaller" needs to be loaded first. Normally you only use them in your "UninstallEx" function. IMPORTANT!: Please make sure that you always use the macro PUICallService in the "UninstallEx" function instead of the CallService function. Including this file --------------------------- To use some of the uninstalling functionality you have to include this file into your project. IMPORTANT!: Please make sure that you include the file "newpluginapi.h" before this one. If this isn't the case there may some compile errors come up. -> Example: If your plugin is in the directory "Plugins/MyPlugin/" and this include file is in the directory "Plugins/PluginUninstaller" you can use the following: #include "../PluginUninstaller/m_uninstaller.h" If your plugin is in an directory that is different to that one just change the include path to the one you want. } // | Structs // ----------------------------- // --------------------------------------------- // -- Struct: Uninstall Params ----------------- // --------------------------------------------- // Struct: PLUGINUNINSTALLPARAMS // (Gets passed to "UninstallEx" function) type THELPERPROC = function(proc:PAnsiChar;wParam:WPARAM;lParam:LPARAM) :int;cdecl; type PLUGINUNINSTALLPARAMS = record bIsMirandaRunning :bool; // Is TRUE when Miranda is loaded and services are available (Please use PUICallService instead of CallService) bDoDeleteSettings :bool; // Is TRUE when user wants to delete settings (If this is FALSE, please only delete your files) pszPluginsPath :PAnsiChar; // Contains the plugin directory path pszDocsPath :PAnsiChar; // Contains the document directory for plugins documentation (Added in version 1.1.1.0) pszIconsPath :PAnsiChar; // Contains the icon directory for icon dlls (Added in version 1.1.2.0) pHelperProcAddress:THELPERPROC; // Used internally (Contains proc address for PUICallService) end; (* Description: ------------- This service provides the possibility to call a Miranda service in the "UninstallEx" function. Important!: Use this macro always instead of "CallService", because else a crash occurs when the plugin was decativated and gets uninstalled Parameters: ------------- Same parameters as CallService of Miranda Core. Return Values: -------------- Return values are the same as the CallService function of Miranda Core. Additionaly returns CALLSERVICE_NOTFOUND if Miranda is not loaded which means the services are not accessable. Example: ---------------------------------- if ( (bIsMirandaRunning == TRUE) && (bDoDeleteSettings == TRUE) ) { // Remove plugin's module //PUICallService(MS_PLUGINUNINSTALLER_REMOVEDBMODULE, (WPARAM)"MyPlugin", 0); } *) { --------------------------------------------- -- Function: Remove some files in directory - --------------------------------------------- Function: PUIRemoveFilesInDirectory } //static BOOL __inline PUIRemoveFilesInDirectory(AnsiChar* pszPath, const AnsiChar* apszFiles[]); { Description: ------------- This helper provides the possibility to easily remove specified files in a specified directory. Note: The last version of this helper (PUIRemoveFilesInPath) did not work correctly. Please do now always append a NULL slot to the end of your array. Parameters: ------------- AnsiChar* pszPath = Path to the files in array const LPCSTR apszFiles[] = NULL-terminated array of files to be deleted. Return Values: -------------- Returns TRUE if the files could be deleted. FALSE if the files could not be deleted or did not exist. } (* static BOOL __inline PUIRemoveFilesInDirectory(AnsiChar* pszPath, const AnsiChar* apszFiles[]) { AnsiChar szFile[MAX_PATH]; BOOL bReturn = FALSE; int iFile = 0; while (apszFiles[iFile] != NULL) { strncpy(szFile, pszPath, sizeof(szFile)); strncat(szFile, apszFiles[iFile], sizeof(szFile)-strlen(szFile)); if ((BOOL)DeleteFile(szFile) == TRUE) bReturn = TRUE; iFile++; } return bReturn; } Example: ---------------------------------- const AnsiChar* apszFiles[] = {"File1.txt", "File2.txt", "File3.txt", NULL}; PUIRemoveFilesInDirectory(ppup->pszPluginsPath, apszFiles); *) const // | Events // ----------------------------- // --------------------------------------------- // -- Event: Allow to uninstall a plugin ------- // --------------------------------------------- // Event: ME_PLUGINUNINSTALLER_OKTOUNINSTALL ME_PLUGINUNINSTALLER_OKTOUNINSTALL = 'PluginUninstaller/OkToUninstall'; // Submitted Values: // ----------------- // wParam = pszPluginName (String containing the translated plugin name) // lParam = pszPluginFile (String containing the plugin dll file name in lower case) // Return Values: // ----------------- // Returning 1 on this event causes the "Remove Plugin" button to be disabled. // --------------------------------------------- // -- Event: Plugin gets uninstalled ----------- // --------------------------------------------- // Event: ME_PLUGINUNINSTALLER_UNINSTALL ME_PLUGINUNINSTALLER_UNINSTALL = 'PluginUninstaller/Uninstall'; // Submitted Values: // ----------------- // wParam = pszPluginName (String containing the translated plugin name) // lParam = pszPluginFile (String containing the plugin dll file name in lower case) // Return Values: // ----------------- // Returning 1 on this event causes the uninstall process to be canceled. // Notice: // Hook this event if you would like to ask the user for something to remove/uninstall // and show your message box on this event. Save the action the user chose in a // global BOOL variable and do the chosen action in "UninstallEx". // You can get the plugins options window handle with MS_PLUGINUNINSTALLER_GETHANDLE. // Other plugins can use this event to be noticed that another plugin isn't installed anylonger. // | Services // ----------------------------- // --------------------------------------------- // -- Service: Remove database module ---------- // --------------------------------------------- // Service: MS_PLUGINUNINSTALLER_REMOVEDBMODULE MS_PLUGINUNINSTALLER_REMOVEDBMODULE = 'PluginUninstaller/RemoveDbModule'; { Description: ------------- This service provides the possibility to delete all database modules associated to your plugin. The specified database module will be removed in all contacts including the NULL contact. Remember to call it always with PUICallService in "UninstallEx" function. Parameters: ------------- wParam = (AnsiChar*)pszModule // Pointer to a string containd module name. Can't be NULL lParam = (const AnsiChar*)apszIgnoreSettings // NULL terminated array of strings. Can be 0 if no settings should be ignored. // See example 3 for more details Return Values: -------------- Returns 0 on success. Nonzero if the module was not present in database. } (* Example 1: ---------------------------------- PUIRemoveDbModule("MyPlugin"); Example 2: ---------------------------------- AnsiChar szModule[] = "MyModule"; PUICallService(MS_PLUGINUNINSTALLER_REMOVEDBMODULE, (WPARAM)szModule, 0); Example 3: ---------------------------------- This deletes all settings in the specified module exept the specified settings: "Setting1",..."Setting4" AnsiChar szModule[] = "MyModule"; const AnsiChar* apszIgnoreSettings[] = {"Setting1", "Setting2", "Setting3", "Setting4", NULL}; PUICallService(MS_PLUGINUNINSTALLER_REMOVEDBMODULE, (WPARAM)szModule, (LPARAM)&apszIgnoreSettings); *) // --------------------------------------------- // -- Service: Remove a setting globally ------- // --------------------------------------------- // Service: MS_PLUGINUNINSTALLER_REMOVEDBSETTINGGLOBALLY MS_PLUGINUNINSTALLER_REMOVEDBSETTINGGLOBALLY = 'PluginUninstaller/RemoveDbSettingGlobally'; { Description: ------------- This service provides the possibility to delete a specific setting in database in all contacts including the NULL contact. Remember to call it always with PUICallService in "UninstallEx" function. Parameters: ------------- wParam = (AnsiChar*)pszModule lParam = (AnsiChar*)pszSetting Return Values: -------------- Returns 0 on success. Nonzero if the setting was not present in database. } (* Example 1: ---------------------------------- PUIRemoveDbSettingGlobally("MyPlugin", "MySetting"); Example 2: ---------------------------------- szModule[] = "MyPlugin"; szSetting[] = "MySetting"; PUICallService(MS_PLUGINUNINSTALLER_REMOVEDBSETTINGGLOBALLY, (WPARAM)szModule, (LPARAM)szSetting); *) // --------------------------------------------- // -- Service: Remove skinned sound ------------ // --------------------------------------------- // Service: MS_PLUGINUNINSTALLER_REMOVESKINSOUND MS_PLUGINUNINSTALLER_REMOVESKINSOUND = 'PluginUninstaller/RemoveSkinSound'; { Description: ------------- This service provides the possibility to delete all your sound settings associated to your plugin. The specified sound will be be removed. Remember to call it always with PUICallService in "UninstallEx" function. Parameters: ------------- wParam = (AnsiChar*)pszSoundSetting lParam = 0 Return Values: -------------- Returns 0 on success. Nonzero if the sound was not present in database. } (* Example 1: ---------------------------------- PUIRemoveSkinSound("MySoundSetting"); Example 2: ---------------------------------- szSoundModule[] = "MySoundSetting"; PUICallService(MS_PLUGINUNINSTALLER_REMOVEDBMODULE, (WPARAM)szSoundSetting, 0); *) // --------------------------------------------- // -- Service: Uninstall a plugin -------------- // --------------------------------------------- // Service: MS_PLUGINUNINSTALLER_UNINSTALLPLUGIN MS_PLUGINUNINSTALLER_UNINSTALLPLUGIN = 'PluginUninstaller/UninstallPlugin'; { Description: ------------- This service marks a plugin to be uninstalled at next restart of Miranda IM. It uses the default value for "Delete all settings". You can use this service for example when you want that your sub-plugin gets also removed when your main-plugin is uninstalled. Note: This service is not needed for the normal uninstalling functionality. Parameters: ------------- wParam = (AnsiChar*)pszPluginName // do not translate this! lParam = (AnsiChar*)pszPluginFile // without path, only file name! Return Values: -------------- Returns always 0. } (* Example 1: ---------------------------------- PUIUninstallPlugin("PluginName", "plugin.dll"); Example 2: ---------------------------------- hInst => Handle of a specific (your?) plugin AnsiChar szPluginName[] = "YourPluginName"; AnsiChar* pFileName; AnsiChar szPath[MAX_PATH]; GetModuleFileName(hInst, szPath, sizeof(szPath)); pFileName = strrchr(szPath, '\\'); pFileName = pFileName+1; // Pointer arithmetic CallService(MS_PLUGINUNINSTALLER_UNINSTALLPLUGIN, (WPARAM)szPluginName, (LPARAM)pFileName); *) // --------------------------------------------- // -- Service: Getting handles ----------------- // --------------------------------------------- // Service: MS_PLUGINUNINSTALLER_GETHANDLE MS_PLUGINUNINSTALLER_GETHANDLE = 'PluginUninstaller/GetHandle'; { Description: ------------- This service gets a specified window/instance handle. Note: This service must not be used in "UninstallEx" function. It is mainly thought for being used in ME_PLUGINUNINSTALLER_UNINSTALL event to give out a MessageBox or something like that. Parameters: ------------- wParam = UINT uHandleType; lParam = 0 } // Possible values for wParam: PUIHT_HINST_PLUGIN_INSTANCE = 0; // HINSTANCE of the PluginUninstaller plugin PUIHT_HWND_PLUGIN_OPTIONS = 1; // HWND of the plugin options dialog (if it is loaded; else NULL) (* Return Values: -------------- Returns the specified handle value. If no handle type is specified it returns NULL. The handle doesn't need to be destroyed. Example ---------------------------------- HWND hwndDlg; hwndDlg = (HWND)PUIGetHandle(PUIHT_HWND_PLUGIN_OPTIONS); *) {$ENDIF}