BWAPI
|
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