From 4c30821aa5875ea330c5ae9a2ae535935a20a32e Mon Sep 17 00:00:00 2001 From: kichik Date: Sat, 29 Nov 2008 22:03:33 +0000 Subject: [PATCH] applied patch #1912699 - "Pinned" / always loaded plugins support this patch also adds plugin_api_version to exec_flags so your plug-in can now tell if features it needs are available more plug-ins that need this will be converted once the patch to make both the stubs and the plug-ins use the same header file is in place git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@5809 212acab6-be3b-0410-9dea-997c60f758d6 --- Contrib/ExDLL/exdll.h | 15 ++++++- Contrib/System/Source/Plugin.c | 5 +++ Contrib/System/Source/Plugin.h | 21 +++++++-- Source/exehead/Main.c | 3 ++ Source/exehead/SConscript | 1 + Source/exehead/Ui.c | 9 ++++ Source/exehead/exec.c | 7 ++- Source/exehead/fileform.h | 2 +- Source/exehead/plugin.c | 81 ++++++++++++++++++++++++++++++++++ Source/exehead/plugin.h | 36 +++++++++++++++ 10 files changed, 173 insertions(+), 7 deletions(-) create mode 100644 Source/exehead/plugin.c create mode 100644 Source/exehead/plugin.h diff --git a/Contrib/ExDLL/exdll.h b/Contrib/ExDLL/exdll.h index a891aadd..f4d14317 100644 --- a/Contrib/ExDLL/exdll.h +++ b/Contrib/ExDLL/exdll.h @@ -75,7 +75,7 @@ typedef struct { int exec_reboot; int reboot_called; int XXX_cur_insttype; // deprecated - int XXX_insttype_changed; // deprecated + int plugin_api_version; // used to be XXX_insttype_changed, but that was deprecated int silent; int instdir_error; int rtl; @@ -84,10 +84,23 @@ typedef struct { int status_update; } exec_flags_type; +// NSIS Plug-In Callback Messages +enum NSPIM +{ + NSPIM_UNLOAD, // This is the last message a plugin gets, do final cleanup + NSPIM_GUIUNLOAD, // Called after .onGUIEnd +}; + +// Prototype for callbacks registered with extra_parameters->RegisterPluginCallback() +// Return NULL for unknown messages +// Should always be __cdecl for future expansion possibilities +typedef UINT_PTR (*NSISPLUGINCALLBACK)(NSPIM); + typedef struct { exec_flags_type *exec_flags; int (__stdcall *ExecuteCodeSegment)(int, HWND); void (__stdcall *validate_filename)(char *); + BOOL (__stdcall *RegisterPluginCallback)(HMODULE, NSISPLUGINCALLBACK); } extra_parameters; // utility functions (not required but often useful) diff --git a/Contrib/System/Source/Plugin.c b/Contrib/System/Source/Plugin.c index 45e1e17c..104d4007 100644 --- a/Contrib/System/Source/Plugin.c +++ b/Contrib/System/Source/Plugin.c @@ -166,6 +166,11 @@ HANDLE GlobalCopy(HANDLE Old) return copymem(GlobalAlloc(GPTR, size), Old, (int) size); } +UINT_PTR NSISCallback(UINT msg) +{ + return (UINT_PTR) NULL; +} + #ifdef _DEBUG void main() { diff --git a/Contrib/System/Source/Plugin.h b/Contrib/System/Source/Plugin.h index b6ffb3de..fe222da7 100644 --- a/Contrib/System/Source/Plugin.h +++ b/Contrib/System/Source/Plugin.h @@ -36,11 +36,23 @@ INST_LANG, // $LANGUAGE __INST_LAST }; -#define PLUGINFUNCTION(name) void __declspec(dllexport) name(HWND hwndParent, int string_size, char *variables, stack_t **stacktop) { \ -/* g_hwndParent=hwndParent; */\ +typedef UINT_PTR (*NSISPLUGINCALLBACK)(UINT); + +typedef struct { + void *exec_flags; + int (__stdcall *ExecuteCodeSegment)(int, HWND); + void (__stdcall *validate_filename)(char *); + BOOL (__stdcall *RegisterPluginCallback)(HMODULE, NSISPLUGINCALLBACK); +} extra_parameters; + +#define PLUGINFUNCTION(name) \ + void __declspec(dllexport) name( \ + HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra) { \ + /*g_hwndParent=hwndParent;*/ \ g_stringsize=string_size; \ g_stacktop=stacktop; \ - g_variables=variables; + g_variables=variables; \ + extra->RegisterPluginCallback(g_hInstance, NSISCallback); #define PLUGINFUNCTIONEND } #define PLUGINFUNCTIONSHORT(name) void __declspec(dllexport) name(HWND hwndParent, int string_size, char *variables, stack_t **stacktop) { \ @@ -61,9 +73,12 @@ extern void pushint(int value); extern HANDLE GlobalCopy(HANDLE Old); extern char *copymem(char *output, char *input, int size); +extern UINT_PTR NSISCallback(UINT); + extern HWND g_hwndParent; extern int g_stringsize; extern stack_t **g_stacktop; extern char *g_variables; +extern HINSTANCE g_hInstance; #endif diff --git a/Source/exehead/Main.c b/Source/exehead/Main.c index 44cb4a26..05d913fd 100644 --- a/Source/exehead/Main.c +++ b/Source/exehead/Main.c @@ -25,6 +25,7 @@ #include "lang.h" #include "state.h" #include "exec.h" +#include "plugin.h" #if !defined(NSIS_CONFIG_VISIBLE_SUPPORT) && !defined(NSIS_CONFIG_SILENT_SUPPORT) #error One of NSIS_CONFIG_SILENT_SUPPORT or NSIS_CONFIG_VISIBLE_SUPPORT must be defined. @@ -341,6 +342,8 @@ void NSISCALL CleanUp() dbd_hFile = INVALID_HANDLE_VALUE; } #endif + // Notify plugins that we are about to unload + Plugins_UnloadAll(); #ifdef NSIS_CONFIG_PLUGIN_SUPPORT // Clean up after plug-ins myDelete(state_plugins_dir, DEL_DIR | DEL_RECURSE | DEL_REBOOT); diff --git a/Source/exehead/SConscript b/Source/exehead/SConscript index b004c790..bebdd54f 100644 --- a/Source/exehead/SConscript +++ b/Source/exehead/SConscript @@ -4,6 +4,7 @@ files = Split(""" exec.c fileform.c Main.c + plugin.c Ui.c util.c #Source/crc32.c diff --git a/Source/exehead/Ui.c b/Source/exehead/Ui.c index 5b26e554..117ac9ad 100644 --- a/Source/exehead/Ui.c +++ b/Source/exehead/Ui.c @@ -28,6 +28,7 @@ #include "util.h" #include "ui.h" #include "exec.h" +#include "plugin.h" #include "lang.h" #include "components.h" @@ -268,6 +269,11 @@ FORCE_INLINE int NSISCALL ui_doinstall(void) // initialize auto close flag g_exec_flags.autoclose=g_flags&CH_FLAGS_AUTO_CLOSE; +#ifdef NSIS_CONFIG_PLUGIN_SUPPORT + // initialize plugin api + g_exec_flags.plugin_api_version=NSISPIAPIVER_CURR; +#endif + // read install directory from registry if (!is_valid_instpath(state_install_directory)) { @@ -396,6 +402,9 @@ FORCE_INLINE int NSISCALL ui_doinstall(void) int ret=DialogBox(g_hInstance,MAKEINTRESOURCE(IDD_INST+dlg_offset),0,DialogProc); #if defined(NSIS_SUPPORT_CODECALLBACKS) && defined(NSIS_CONFIG_ENHANCEDUI_SUPPORT) ExecuteCallbackFunction(CB_ONGUIEND); +#endif +#ifdef NSIS_CONFIG_PLUGIN_SUPPORT + Plugins_SendMsgToAllPlugins(NSPIM_GUIUNLOAD); #endif return ret; } diff --git a/Source/exehead/exec.c b/Source/exehead/exec.c index 4e62c4b8..60814828 100644 --- a/Source/exehead/exec.c +++ b/Source/exehead/exec.c @@ -23,6 +23,7 @@ #include "ui.h" #include "components.h" #include "exec.h" +#include "plugin.h" #include "lang.h" #include "resource.h" @@ -48,10 +49,12 @@ struct { exec_flags *flags; void *ExecuteCodeSegment; void *validate_filename; + void *RegisterPluginCallback; } plugin_extra_parameters = { &g_exec_flags, &ExecuteCodeSegment, - &validate_filename + &validate_filename, + &RegisterPluginCallback }; #if defined(NSIS_SUPPORT_ACTIVEXREG) || defined(NSIS_SUPPORT_CREATESHORTCUT) @@ -996,7 +999,7 @@ static int NSISCALL ExecuteEntry(entry *entry_) update_status_text(LANG_CANNOTFINDSYMBOL,buf0); log_printf3("Error registering DLL: %s not found in %s",buf0,buf1); } - if (!parm3) FreeLibrary(h); + if (!parm3 && Plugins_CanUnload(h)) FreeLibrary(h); } else { diff --git a/Source/exehead/fileform.h b/Source/exehead/fileform.h index 5ee4cbf2..3fc55874 100644 --- a/Source/exehead/fileform.h +++ b/Source/exehead/fileform.h @@ -498,7 +498,7 @@ typedef struct int __; #endif int XXX_cur_insttype; // depreacted - int XXX_insttype_changed; // deprecated + int plugin_api_version; // used to be XXX_insttype_changed, but that was deprecated #ifdef NSIS_CONFIG_SILENT_SUPPORT int silent; #else diff --git a/Source/exehead/plugin.c b/Source/exehead/plugin.c new file mode 100644 index 00000000..066516a2 --- /dev/null +++ b/Source/exehead/plugin.c @@ -0,0 +1,81 @@ +#include "plugin.h" + +#ifdef NSIS_CONFIG_PLUGIN_SUPPORT + +typedef struct _loaded_plugin +{ + struct _loaded_plugin* next; + NSISPLUGINCALLBACK proc; + HMODULE dll; +} +loaded_plugin; + +static loaded_plugin* g_plugins = 0; // not thread safe! + +void NSISCALL Plugins_SendMsgToAllPlugins(int msg) +{ + loaded_plugin* p; + + for (p = g_plugins; p; p = p->next) + { + p->proc(msg); + } +} + +void NSISCALL Plugins_UnloadAll() +{ + loaded_plugin* p = g_plugins; + + Plugins_SendMsgToAllPlugins(NSPIM_UNLOAD); + + while (p) + { + loaded_plugin* oldp = p; + p = oldp->next; + FreeLibrary(oldp->dll); + GlobalFree(oldp); + } + + g_plugins = NULL; +} + +BOOL NSISCALL Plugins_CanUnload(HANDLE pluginHandle) +{ + loaded_plugin* p; + + for (p = g_plugins; p; p = p->next) + { + if (p->dll == pluginHandle) + { + return FALSE; + } + } + return TRUE; +} + +BOOL NSISCALL RegisterPluginCallback(HMODULE pluginHandle, NSISPLUGINCALLBACK proc) +{ + loaded_plugin* p; + + if (!Plugins_CanUnload(pluginHandle)) + { + // already registered + return FALSE; + } + + p = (loaded_plugin*) GlobalAlloc(LPTR, sizeof(loaded_plugin)); + if (p) + { + p->proc = proc; + p->dll = pluginHandle; + p->next = g_plugins; + + g_plugins = p; + + return TRUE; + } + + return FALSE; +} + +#endif /* #ifdef NSIS_CONFIG_PLUGIN_SUPPORT */ diff --git a/Source/exehead/plugin.h b/Source/exehead/plugin.h new file mode 100644 index 00000000..c6fd54b9 --- /dev/null +++ b/Source/exehead/plugin.h @@ -0,0 +1,36 @@ +#ifndef _PLUGINCALLBACKS_H_ +#define _PLUGINCALLBACKS_H_ + +#include "../Platform.h" +#include "fileform.h" + +#ifdef NSIS_CONFIG_PLUGIN_SUPPORT + +// Starting with NSIS 2.42, you can check the version of the plugin API in exec_flags->plugin_api_version +// The format is 0xXXXXYYYY where X is the major version and Y is the minor version (MAKELONG(y,x)) +// When doing version checks, always remember to use >=, ex: if (pX->exec_flags->plugin_api_version >= NSISPIAPIVER_1_0) {} + +#define NSISPIAPIVER_1_0 0x00010000 +#define NSISPIAPIVER_CURR NSISPIAPIVER_1_0 + +// NSIS Plug-In Callback Messages +enum NSPIM +{ + NSPIM_UNLOAD, // This is the last message a plugin gets, do final cleanup + NSPIM_GUIUNLOAD, // Called after .onGUIEnd +}; + +// Prototype for callbacks registered with extra_parameters->RegisterPluginCallback() +// Return NULL for unknown messages +// Should always be __cdecl for future expansion possibilities +typedef UINT_PTR (*NSISPLUGINCALLBACK)(NSPIM); + +extern BOOL NSISCALL RegisterPluginCallback(HMODULE pluginHandle, NSISPLUGINCALLBACK proc); + +extern void NSISCALL Plugins_SendMsgToAllPlugins(int msg); +extern void NSISCALL Plugins_UnloadAll(); +extern BOOL NSISCALL Plugins_CanUnload(HANDLE pluginHandle); + +#endif /* #ifdef NSIS_CONFIG_PLUGIN_SUPPORT */ + +#endif /* _PLUGINCALLBACKS_H_ */