BWAPI
trunk/bwapi/BWAPI_MPQDraftInjector/source/MPQDraftPlugin.h
Go to the documentation of this file.
00001 /*
00002   QDPlugin.h
00003   The central hive of the MPQDraft plugin system.
00004 
00005   In addition to the standard MPQ "adding" functionality of MPQDraft,
00006   MPQDraft also supports a powerful plugin system to acommodate addition
00007   methods of patching. These plugins are specially constructed DLLs which
00008   1) Export the GetMPQDraftPlugin function, and 2) Impliment the
00009   IMPQDraftPlugin interface. Up to 8 plugins may be loaded in one patching
00010   session (although 8 is a rather arbitrary number, and may be changed in
00011   later versions, if there is reason to do so).
00012 
00013   - PLUGIN MODULES -
00014   MPQDraft supports the creation of completely self-contained SEMPQs. But,
00015   this ability creates a palette of problems all its own. All of a plugin's
00016   data files have to be packed into the SEMPQ. This means that a special
00017   mechanism is needed, to marshall the data files from the plugin to the
00018   SEMPQ, and back to the plugin; this is the plugin module system. Each data
00019   file of the plugin is referred to as a "module", and identified by
00020   a pair of DWORDs: a plugin ID, and a module ID. The plugin ID is the
00021   globally unique ID of the plugin; the module ID is the plugin-specific ID
00022   of the module.
00023 
00024   [FURTHER TEXT TO BE ADDED HERE]
00025 
00026   - SETUP SIDE -
00027   There are two halves to each plugin: a setup side and a patching side. The
00028   setup side is when the plugin gets loaded in MPQDraft, and displayed in
00029   the plugin list, in either the patching wizard or SEMPQ wizard.
00030   Specifically, MPQDraft loads all plugins when the plugins page in the
00031   wizard first gets activated. The plugins will remain loaded until the
00032   wizard is closed. If a patch is performed, the plugins will remain loaded
00033   until the patch is completed. This allows plugins to get the opportunity
00034   to delete any temporary files that were created for the patch.
00035 
00036   Order and timing of calls to setup-side plugin functions:
00037 
00038   When the plugins wizard page is first activated, and MPQDraft is building
00039   its plugin database:
00040   1. The plugin gets loaded with LoadLibrary.
00041   2. The plugin's GetMPQDraftPlugin function gets called to obtain the
00042   plugin's IMPQDraftPlugin interface.
00043   3. IMPQDraftPlugin::Identify gets called.
00044   4. IMPQDraftPlugin::GetPluginName gets called.
00045 
00046   Each time the plugins page is switched to, MPQDraft determines which
00047   plugins to display in the plugin list:
00048   - IMPQDraftPlugin::CanPatchExecutable gets called for the currently
00049   selected executable. If the plugin can patch the executable, it will
00050   appear in the plugin list if it can't, then it won't appear. NOTE: this
00051   step does not occur when selecting plugins for use in an SEMPQ. In this
00052   case, ALL plugins will be available to select.
00053 
00054   If the "Configure" button is clicked while a plugin is selected:
00055   - IMPQDraftPlugin::Configure is called, with the HWND to the wizard in
00056   use. This allows the plugin to create a modal dialog with various plugin
00057   settings.
00058 
00059   If the "Finish" button is clicked to initiate a patch:
00060   1. IMPQDraftPlugin::ReadyForPatch is called to discern whether the plugin
00061   is properly configured, and ready to perform the patch.
00062   2. IMPQDraftPlugin::GetModules is called to obtain the number of plugin
00063   modules the plugin will require.
00064   3. IMPQDraftPlugin::GetModule is called again to get the plugin's modules.
00065 
00066   Either after the patch is completed or the wizard is cancelled:
00067   - FreeLibrary is called to unload the plugin. The plugin is responsible
00068   for cleaning up any data files it created temporarily.
00069 
00070   NOTE: Plugins will not be loaded in setup-side when an SEMPQ is executed.
00071 
00072   - PATCHING SIDE -
00073   The patching side is when a plugin gets loaded by the MPQDraft patching
00074   kernel. The plugin will be loaded inside the patchee (the process being
00075   patched) BEFORE any patchee code gets executed, but after any DLLs the
00076   patchee uses are loaded and initialized (DllMain is called). This means
00077   that plugins will be able to modify initialized data in the patchee, but
00078   not uninitialized data. If the latter is necessary, a thread can be
00079   spawned by the plugin to wait until the data has been initialized.
00080 
00081   Order and timing of calls to patching-side plugin functions:
00082 
00083   After MPQDraft performs its own initializations, it will load each
00084   selected plugin (this is done before any MPQs are loaded):
00085   1. LoadLibrary gets called to load the plugin inside the patch target.
00086   2. GetMPQDraftPlugin gets called to obtain an IMPQDraftPlugin interface.
00087   3. IMPQDraftPlugin::InitializePlugin gets called with a pointer to the
00088   MPQDraft server interface, to allow the plugin to locate its data files.
00089 
00090   When the patchee is closing down, and MPQDraft is terminating:
00091   1. IMPQDraftPlugin::TerminatePlugin gets called to remove any patches the
00092   plugin performed.
00093   2. The plugin is unloaded with FreeLibrary.
00094 */
00095 
00096 #ifndef QDPLUGIN_H
00097 #define QDPLUGIN_H
00098 
00099 #include <windows.h>
00100 
00101 // The maximum length of a plugin module's filename. INCLUDES final NULL.
00102 #define MPQDRAFT_MAX_PATH 264
00103 
00104 // The maximum length of a plugin's name. INCLUDES final NULL.
00105 #define MPQDRAFT_MAX_PLUGIN_NAME 64
00106 
00107 /*
00108   MPQDRAFTPLUGINMODULE
00109 
00110   Structure used by IMPQDraftPlugin::GetModules to notify MPQDraft of any
00111   files (called plugin modules) that are to be loaded. Read description of
00112   that function for more information.
00113 */
00114 #include <pshpack1.h>
00115 struct MPQDRAFTPLUGINMODULE
00116 {
00117   /* dwComponentID: The ID of the plugin. Should be the same value as is
00118   returned by IMPQDraftPlugin::Identify. Must be globally unique. */
00119   DWORD dwComponentID;
00120   /* dwModuleID: The unique ID of the plugin module. This will be used
00121   instead of the actual filename for identifying plugin modules. */
00122   DWORD dwModuleID;
00123   // bExecute: Used internally by MPQDraft. Must be set to FALSE.
00124   BOOL bExecute;
00125   // szModuleFileName: The absolute path of the plugin module file.
00126   char szModuleFileName[MPQDRAFT_MAX_PATH];
00127 };
00128 #include <poppack.h>
00129 
00130 /*
00131   IMPQDraftServer
00132 
00133   Serves as a portal back to MPQDraft, allowing the plugin to
00134   not only be executed by MPQDraft, but also it communicate with MPQDraft.
00135   A plugin will be given an IMPQDraftServer pointer when MPQDraft calls
00136   IMPQDraftPlugin::InitializePlugin.
00137 */
00138 struct IMPQDraftServer
00139 {
00140   /*
00141     IMPQDraftServer::GetPluginModule
00142 
00143     Allows a plugin to locate its modules when it is loaded in patch-side.
00144 
00145     Return TRUE on success, and FALSE on failure.
00146 
00147     Parameters:
00148       dwPluginID [in] - The ID of the plugin who is attempting to locate
00149       its modules.
00150       dwModuleID [in] - The ID of the module to be located.
00151       lpszFileName [out] - Pointer to a buffer where MPQDraft will copy
00152       the file name of the module to. This buffer should be
00153       MPQDRAFT_MAX_PATH characters long.
00154 
00155     Behavior:
00156       - If lpszFileName is NULL, GetPluginModules will fail.
00157 
00158       - If the buffer pointer to by lpszFileName is shorter than the
00159       length of the module's filename (which will never be more than
00160       MPQDRAFT_MAX_PATH), a crash will result.
00161       - If no module identified by dwPluginID and dwModuleID can be
00162       found, GetPluginModule will fail.
00163       - If more than one module with identical dwPluginID and
00164       dwModuleID exist, MPQDraft will arbitrarily choose one to return.
00165 
00166       - If the desired module exists, GetPluginModule will copy the
00167       filename of the module to lpszFileName.
00168   */
00169   virtual BOOL WINAPI GetPluginModule(DWORD dwPluginID, DWORD dwModuleID, LPSTR lpszFileName) = 0;
00170 };
00171 
00172 /*
00173   IMPQDraftPlugin
00174 
00175   The primary gateway between the MPQDraft patching kernel and the plugin.
00176   This interface must be fully implimented by every MPQDraft plugin (or at
00177   least until it is superseded by IMPQDraftPlugin2, in a much later version
00178   of MPQDraft). MPQDraft will obtain this interface when it calls
00179   GetMPQDraftPlugin. It will then store the interface in its plugin
00180   database, and use it in all subsequent calls to the plugin.
00181 
00182   NOTE: The specifications for this interface are based on the recommended
00183   responses. In some places it may be legal to slightly depart from the
00184   recommended specs (i.e. functions may fail instead of asserting).
00185 */
00186 struct IMPQDraftPlugin
00187 {
00188   /*
00189     IMPQDraftPlugin::Identify
00190 
00191     Identifies the plugin to MPQDraft with a globally unique ID code.
00192 
00193     Returns TRUE on success, and FALSE on failure (which should never
00194     happen).
00195 
00196     Parameters:
00197       lpdwPluginID [out] - A pointer to a DWORD that will receive the
00198       plugin's ID. MPQDraft will supply this DWORD.
00199 
00200     Behavior:
00201       - If lpdwPluginID is NULL, Identify will assert.
00202 
00203       - On success, Identify will copy its ID to lpdwPluginID.
00204   */
00205   virtual BOOL WINAPI Identify(LPDWORD lpdwPluginID) = 0;
00206 
00207   /*
00208     GetPluginName
00209 
00210     Retrieves the name of the plugin which will be displayed in the
00211     plugin list in either of the MPQDraft wizards. This name should also
00212     include the version of the plugin, i.e. "StarGraft v1.08 QD".
00213 
00214     Returns TRUE on success, and FALSE on failure.
00215 
00216     Parameters:
00217       lpszPluginName [out] - A pointer to a buffer which will receive
00218       the name of the plugin. This buffer will by provided by MPQDraft,
00219       and will usually be MPQDRAFT_MAX_PLUGIN_NAME chars long.
00220       nNameBufferLength [in] - The length of the buffer pointed to by
00221       lpszPluginName, including space for the final NULL.
00222 
00223     Behavior:
00224       - If lpszPluginName is null, GetPluginName will assert.
00225 
00226       - If nNameBufferLength is shorter than the name of the plugin,
00227       GetPluginName will fail.
00228 
00229       - On success, GetPluginName will copy the plugin name to the
00230       buffer pointed to by lpszPluginName.
00231   */
00232   virtual BOOL WINAPI GetPluginName(LPSTR lpszPluginName, DWORD nNameBufferLength) = 0;
00233   /*
00234     IMPQDraftPlugin::CanPatchExecutable
00235 
00236     Called by MPQDraft in the plugins page of the patch wizard (but not on
00237     the SEMPQ wizard). Its return value determines whether or not the
00238     plugin will appear in the list of available plugins, as MPQDraft will
00239     only list plugins which are compatible with the currently selected
00240     patch target.
00241 
00242     Returns TRUE if the plugin can patch the selected executable, and
00243     FALSE if it cannot.
00244 
00245     Parameters:
00246       lpszEXEFileName [in] - The absolute path of the currently selected
00247       executable.
00248 
00249     Behavior:
00250       - If lpszEXEFileName is NULL, CanPatchExecutable will assert.
00251 
00252       - If an error occurs (i.e. the executable cannot be opened or read
00253       from, CanPatchExecutable will fail.
00254   */
00255   virtual BOOL WINAPI CanPatchExecutable(LPCSTR lpszEXEFileName) = 0;
00256   /*
00257     IMPQDraftPlugin::Configure
00258 
00259     Called by MPQDraft from the plugin page in either of the wizards.
00260     Configure should present the user with settings which can be
00261     adjusted to change the way the plugin will function (i.e. selecting
00262     the PAT to use in StarGraft). If necessary, the plugin can create a
00263     settings dialog. It is recommended that the plugin stores the settings
00264     from the last time it was configured in the registry, but this is not
00265     mandatory. Some plugins may even not require any configuration at all,
00266     in which case this function would be a simple "return TRUE".
00267 
00268     Returns TRUE on success and FALSE on failure.
00269 
00270     Parameters:
00271       hParentWnd [in] - A handle to the wizard from which Configure was
00272       called. This handle is to be used exclusively to pass to
00273       DialogBox, to create a modal dialog. It is NOT to be used to
00274       attempt to modify the wizard. Such an attempt will probably crash.
00275 
00276     Behavior:
00277       - If hParentWnd is NULL, Configure will assert.
00278 
00279       - If an error occurs while configuring the plugin, Configure will
00280       fail.
00281 
00282       - If the configuration completed sucessfully (even if the user
00283       pressed the "Cancel" button on a dialog), Configure will succeed.
00284   */
00285   virtual BOOL WINAPI Configure(HWND hParentWnd) = 0;
00286 
00287   /*
00288     IMPQDraftPlugin::ReadyForPatch
00289 
00290     Called by MPQDraft right before a patch, to determine whether all
00291     plugins are properly configured, and ready to patch.
00292 
00293     Returns TRUE if the plugin is configured properly, FALSE if it isn't.
00294   */
00295   virtual BOOL WINAPI ReadyForPatch() = 0;
00296 
00297   /*
00298     IMPQDraftPlugin::GetModules
00299 
00300     Called twice by MPQDraft right before it is about to perform a patch.
00301     The first time, MPQDraft collects the number of modules from all
00302     plugins, so that it can allocate the proper amount of memory to hold
00303     the list of modules. The second it will be to actually retrieve the
00304     list of modules. These modules will be packed into an SEMPQ. Or, if
00305     if a straight patch is being performed, MPQDraft will just pass on the
00306     module list to the patching kernel.
00307 
00308     Returns TRUE on success, and FALSE on failure.
00309 
00310     Parameters:
00311       lpPluginModules [out] - A pointer to the memory MPQDraft has
00312       allocated to hold the list of modules. The plugin must  list each
00313       module it will require in the patching process. When MPQDraft
00314       first calls GetModules, lpPluginModules will be NULL.
00315       lpnNumModules [out] - A pointer to the number of plugin modules
00316       the plugin will need. This number ought not to exceed 4.
00317 
00318     Behavior:
00319       - If lpnNumModules is NULL, GetModules will assert.
00320 
00321       - If an error occurs, and GetModules is unable to supply the
00322       required information, GetModules will fail. In this case, MPQDraft
00323       will abort the patch.
00324 
00325       - If lpPluginModules is non-NULL, GetModules will copy the
00326       list of modules to lpPluginModules, and give the number of modules
00327       in lpnNumModules.
00328       - If lpPluginModules is NULL, GetModules will give the exact
00329       number of modules it will require in lpnNumModules, and succeed.
00330   */
00331   virtual BOOL WINAPI GetModules(MPQDRAFTPLUGINMODULE* lpPluginModules, LPDWORD lpnNumModules) = 0;
00332 
00333   /*
00334     IMPQDraftPlugin::InitializePlugin
00335 
00336     Called by MPQDraft from inside the patch target, to allow the plugin
00337     to perform its patch. Any patches the plugin makes should be stored,
00338     and undone upon TerminatePlugin.
00339 
00340     A return value of TRUE indicates that MPQDraft should continue with
00341     the patch. FALSE indicates that MPQDraft should abort the patch. The
00342     plugin should report any errors BEFORE it returns FALSE, as MPQDraft
00343     will terminate the patch silently.
00344 
00345     Parameters:
00346       lpMPQDraftServer [in] - A pointer to an IMPQDraftServer interface,
00347       provided by MPQDraft. This interface can be used to locate the
00348       plugin's modules. This pointer should be saved in case it is
00349       needed in future use.
00350 
00351     Behavior:
00352       - If lpMPQDraftServer is NULL, InitializePlugin will assert.
00353 
00354       - If the plugin was unable to perform the patch, and the the patch
00355       target should be terminated, InitializePlugin will display an
00356       error message box and return FALSE. MPQDraft will abort the patch.
00357       - If the plugin was unable to perform the patch, and MPQDraft
00358       should ignore the error and continue, InitializePlugin will
00359       return TRUE. MPQDraft will continue the patch.
00360 
00361       - If the patch was performed successfully, InitializePlugin will
00362       return TRUE.
00363   */
00364   virtual BOOL WINAPI InitializePlugin(IMPQDraftServer* lpMPQDraftServer) = 0;
00365 
00366   /*
00367     IMPQDraftPlugin::TerminatePlugin
00368 
00369     Called by MPQDraft inside the patch target during the shutdown
00370     process, to allow the plugin to unload any patches it made.
00371 
00372     Returns TRUE on success, and FALSE on failure.
00373 
00374     Behavior:
00375       - If InitializePlugin was not called previously, TerminatePlugin
00376       asserts.
00377 
00378       - If the patches performed in InitializePlugin were not
00379       successfully removed, TerminatePlugin fails.
00380       - If the patches performed in InitializePlugin were successfully
00381       removed, TerminatePlugin succeeds.
00382 
00383       - It is possible that on rare occasions InitializePlugin will be
00384       called, then the plugin will be unloaded before TerminatePlugin
00385       gets called. The plugin should check for this on
00386       DLL_PROCESS_DETACH, and call TerminatePlugin itself.
00387   */
00388   virtual BOOL WINAPI TerminatePlugin() = 0;
00389 };
00390 
00391 /*
00392   GetMPQDraftPlugin
00393 
00394   Exported by name from the plugin DLL. Called by MPQDraft to obtain the
00395   IMPQDraftPlugin interface of the plugin.
00396 
00397   Returns TRUE on success, and FALSE on failure.
00398 
00399   Parameters:
00400     lppMPQDraftPlugin [out] - A pointer to a pointer that will hold the
00401     IMPQDraftPlugin. The plugin must set this to point to the plugin's
00402     IMPQDraftPlugin interface.
00403 
00404   Behavior:
00405     - GetMPQDraftPlugin will only be called once, so it isn't necessary
00406     to instantiate an IMPQDraftPlugin for each call. A single global
00407     IMPQDraftPlugin is sufficient.
00408 */
00409 BOOL WINAPI GetMPQDraftPlugin(IMPQDraftPlugin** lppMPQDraftPlugin);
00410 
00411 #endif // #ifndef QDPLUGIN_H
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines