1: /*
2: ============================================================================
3: xoblite™ -> an advanced "extended shell" for Microsoft® Windows® 11
4: Copyright © 2002-2026 Karl Henrik Henriksson [qwilk/@xoblite]
5: Copyright © 2001-2004 The Blackbox for Windows Development Team
6: http://xoblite.net/ + https://github.com/xoblite/
7: ============================================================================
8:
9: Blackbox for Windows is free software, released under the
10: GNU General Public License (GPL version 2 or later), with an extension
11: that allows linking of proprietary modules under a controlled interface.
12: What this means is that plugins etc. are allowed to be released
13: under any license the author wishes. Please note, however, that the
14: original Blackbox gradient math code used in Blackbox for Windows
15: is available under the BSD license.
16:
17: http://www.fsf.org/licenses/gpl.html
18: http://www.fsf.org/licenses/gpl-faq.html#LinkingOverControlledInterface
19: http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5
20:
21: This program is distributed in the hope that it will be useful,
22: but WITHOUT ANY WARRANTY; without even the implied warranty of
23: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24: GNU General Public License for more details.
25:
26: For additional license information, please read the included license.html.
27:
28: ============================================================================
29: */
30:
31: #include "..\API\BBApi.h"
32: #include "PluginManager.h"
33: #include "..\Dock\Dock.h"
34: #include "..\Toolbar\Toolbar.h"
35: #include "..\Desktop\Desktop.h"
36: #include <windows.h>
37: #include <vector>
38: #include <string>
39: #include <process.h>
40:
41: extern PluginManager *pPluginManager;
42: extern Settings *pSettings;
43: extern Dock *pDock;
44: extern Toolbar *pToolbar;
45: extern Desktop *pDesktop;
46:
47: //===========================================================================
48:
49: PluginManager::PluginManager(HINSTANCE hMainInstance)
50: {
51: char szBuffer[MAX_LINE_LENGTH]="";
52:
53: startupLock = true;
54:
55: // SAFE MODE: Hold down control to disable loading of plugins at startup
56: // ### Beware! -> Do not load any plugins when running in safe mode or you
57: // will overwrite the contents of your plugins.rc! ###
58: if (!(GetAsyncKeyState(VK_CONTROL) & 0x8000))
59: {
60: FILE *f = FileOpen(plugrcPath());
61: while (ReadNextCommand(f, szBuffer, sizeof(szBuffer))) LoadPlugin(szBuffer);
62: FileClose(f);
63: }
64: else SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_WARNING_MESSAGE, (LPARAM)"Safe mode: Holding down the Ctrl key disables loading of plugins at startup.");
65:
66: //====================
67:
68: if (!pluginList.empty())
69: {
70: char szCurrentPlugin[MAX_LINE_LENGTH] = "", szPreviousPlugin[MAX_LINE_LENGTH] = "";
71: char szMultiplier[10];
72: int numberOfInstances = 1;
73:
74: // Display the names of all loaded plugins in the console...
75: // (nb. grouped together if more than one plugin of the same name is loaded in succession)
76: strcpy_s(szBuffer, sizeofArray(szBuffer), "Loading plugins -> ");
77: for (int i=0; i < (int)pluginList.size(); i++)
78: {
79: pluginInfo = (pluginInfoFunc)GetProcAddress(pluginList[i].hModule, "pluginInfo");
80: if (pluginInfo)
81: {
82: strcpy_s(szCurrentPlugin, sizeofArray(szCurrentPlugin), pluginInfo(PLUGIN_NAME));
83:
84: if (!_stricmp(szCurrentPlugin, szPreviousPlugin))
85: {
86: numberOfInstances++;
87: continue;
88: }
89: else
90: {
91: if (numberOfInstances > 1)
92: {
93: sprintf_s(szMultiplier, sizeofArray(szMultiplier), " x %d", numberOfInstances);
94: strcat_s(szBuffer, sizeofArray(szBuffer), szMultiplier);
95: numberOfInstances = 1;
96: }
97:
98: if (i > 0) strcat_s(szBuffer, sizeofArray(szBuffer), " | ");
99: strcat_s(szBuffer, sizeofArray(szBuffer), szCurrentPlugin);
100:
101: strcpy_s(szPreviousPlugin, sizeofArray(szPreviousPlugin), szCurrentPlugin);
102: }
103: }
104: else // Extract name from file name...
105: {
106: char pluginName[MAX_PATH];
107: strcpy_s(pluginName, sizeofArray(pluginName), pluginList[i].path);
108: int n = GetParentFolder(pluginName);
109: strcpy_s(pluginName, sizeofArray(pluginName), &pluginList[i].path[n]);
110: PathRemoveExtension(pluginName);
111: if (i > 0) strcat_s(szBuffer, sizeofArray(szBuffer), " | ");
112: strcat_s(szBuffer, sizeofArray(szBuffer), pluginName);
113: }
114: }
115:
116: if (numberOfInstances > 1)
117: {
118: sprintf_s(szMultiplier, sizeofArray(szMultiplier), " x %d", numberOfInstances);
119: strcat_s(szBuffer, sizeofArray(szBuffer), szMultiplier);
120: }
121:
122: SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_REGULAR_MESSAGE, (LPARAM)szBuffer);
123: }
124:
125: //====================
126:
127: startupLock = false;
128: pSettings->checkingForUpdates = false;
129:
130: // Automatic checking for updates at startup? (note: call later moved to Blackbox.cpp, kept here only for reference)
131: // if (_stricmp(pSettings->checkedForUpdates, "*Disabled*")) _beginthread(periodicCheckForUpdates, 0, NULL);
132: }
133:
134: //====================
135:
136: PluginManager::~PluginManager()
137: {
138: for (int i=0; i < (int)pluginList.size(); i++)
139: {
140: endPlugin = (endPluginFunc)GetProcAddress(pluginList[i].hModule, "endPlugin");
141: endPlugin(pluginList[i].hModule);
142: FreeLibrary(pluginList[i].hModule);
143: }
144:
145: pluginList.clear();
146: }
147:
148: //===========================================================================
149:
150: bool PluginManager::LoadPlugin(LPSTR pluginPath)
151: {
152: char msg[MAX_LINE_LENGTH];
153:
154: //====================
155:
156: if (strchr(pluginPath, '\"')) StrRemoveEncap(pluginPath);
157: if (strchr(pluginPath, '$')) ReplaceShellFolders(pluginPath);
158: if (strchr(pluginPath, '%')) ReplaceEnvVars(pluginPath);
159:
160: if (IsInString(pluginPath, "BBSystemBar.dll") || // Do not load the BBSystemBar plugin (integrated functionality in xoblite)
161: IsInString(pluginPath, "BBSystemBarEx.dll") || // Do not load the BBSystemBarEx plugin (similar to integrated functionality in xoblite)
162: IsInString(pluginPath, "SystemBarEx.dll") || // Do not load the SystemBarEx plugin (similar to integrated functionality in xoblite)
163: IsInString(pluginPath, "BBSlit.dll") || // Do not load the BBSlit plugin (integrated functionality in xoblite)
164: IsInString(pluginPath, "BBKeys.dll") || // Do not load the BBKeys plugin (integrated functionality in xoblite)
165: IsInString(pluginPath, "RandomStyle.dll") || // Do not load the RandomStyle plugin (integrated functionality in xoblite)
166: IsInString(pluginPath, "BBDDE.dll")) // Do not load the BBDDE plugin (integrated functionality in xoblite)
167: {
168: strcpy_s(msg, sizeofArray(msg), "The following plugins are automatically excluded \n"
169: "because the functionality they provide (or similar \n"
170: "functionality) is already part of xoblite itself: \n\n"
171: "BBSystemBar\nBBSystemBarEx/SystemBarEx\nBBSlit\nBBKeys\nRandomStyle\nBBDDE \n");
172: MessageBox(GetBBWnd(), msg, "xoblite", MB_OK | MB_ICONINFORMATION | MB_TOPMOST);
173: return false;
174: }
175:
176: //====================
177:
178: // Check if this particular plugin has already been loaded...
179:
180: char dllName[MAX_LINE_LENGTH], dllTempName[MAX_LINE_LENGTH];
181: strcpy_s(dllName, sizeofArray(dllName), pluginPath);
182: int nLen = strnlen_s(dllName, sizeofArray(dllName)) - 1;
183: if (IsInString(dllName, "/")) while (nLen >0 && dllName[nLen] != '/') nLen--;
184: else while (nLen >0 && dllName[nLen] != '\\') nLen--;
185: strcpy_s(dllName, sizeofArray(dllName), &pluginPath[nLen+1]);
186:
187: for (int i=0; i < (int)pluginList.size(); i++)
188: {
189: strcpy_s(dllTempName, sizeofArray(dllTempName), pluginList[i].path);
190: nLen = strnlen_s(dllTempName, sizeofArray(dllTempName)) - 1;
191: if (IsInString(dllTempName, "/")) while ((nLen > 0) && (dllTempName[nLen] != '/')) nLen--;
192: else while ((nLen > 0) && (dllTempName[nLen] != '\\')) nLen--;
193: strcpy_s(dllTempName, sizeofArray(dllTempName), &pluginList[i].path[nLen+1]);
194:
195: if (!_stricmp(dllName, dllTempName))
196: {
197: strcpy_s(msg, sizeofArray(msg), pluginPath);
198: strcat_s(msg, sizeofArray(msg), " \n\nThis plugin is already loaded. ");
199: MessageBox(GetBBWnd(), msg, "xoblite", MB_OK | MB_ICONINFORMATION | MB_TOPMOST);
200: return false;
201: }
202: }
203:
204: //====================
205:
206: bool dockingEnabled;
207:
208: if (pluginPath[0] == '&') // Dock plugin?
209: {
210: dockingEnabled = true;
211: hModule = LoadLibrary(&pluginPath[1]);
212: }
213: else // Normal plugin
214: {
215: dockingEnabled = false;
216: hModule = LoadLibrary(pluginPath);
217: }
218:
219: if (hModule)
220: {
221: if (StartPlugin(hModule, pluginPath, dockingEnabled))
222: {
223: pluginItem plg;
224: plg.hModule = hModule;
225: plg.DockingEnabled = dockingEnabled;
226: strcpy_s(plg.path, sizeofArray(plg.path), pluginPath);
227: plg.UpdateAvailable = false;
228: pluginList.push_back(plg);
229:
230: if (IsInString(pluginPath, "xDesignerGUI.dll")) pSettings->designerModeEnabled = true; // Safeguard ;)
231:
232: // if (!startupLock) // ...writing to plugins.rc during startup is not a good idea... <g>
233: else if (!startupLock) // ...writing to plugins.rc during startup is not a good idea... <g>
234: {
235: if (!WritePluginsRC()) MessageBox(GetBBWnd(), "Could not write to plugins.rc!", "xoblite", MB_OK | MB_ICONERROR | MB_TOPMOST);
236: }
237:
238: return true;
239: }
240: }
241: else
242: {
243: strcpy_s(msg, sizeofArray(msg), pluginPath);
244: strcat_s(msg, sizeofArray(msg), " (LoadLibrary failed)");
245: Log("Plugin error", msg);
246: strcpy_s(msg, sizeofArray(msg), pluginPath);
247: strcat_s(msg, sizeofArray(msg), " \n\nThe plugin you are trying to load does not exist, \nor is not compatible with your operating system. \n\nPlease check your plugin configuration file. ");
248: MessageBox(GetBBWnd(), msg, "xoblite", MB_OK | MB_ICONERROR | MB_TOPMOST);
249: }
250:
251: return false;
252: }
253:
254: //===========================================================================
255:
256: bool PluginManager::StartPlugin(HMODULE hModule, LPSTR pluginPath, bool dockingEnabled)
257: {
258: beginPluginEx = (beginPluginExFunc)GetProcAddress(hModule, "beginPluginEx");
259: beginPlugin = (beginPluginFunc)GetProcAddress(hModule, "beginPlugin");
260: beginSlitPlugin = (beginSlitPluginFunc)GetProcAddress(hModule, "beginSlitPlugin");
261: endPlugin = (endPluginFunc)GetProcAddress(hModule, "endPlugin");
262:
263: if (!beginPluginEx && !beginPlugin && !beginSlitPlugin)
264: {
265: FreeLibrary(hModule);
266: char msg[MAX_LINE_LENGTH];
267: strcpy_s(msg, sizeofArray(msg), pluginPath);
268: strcat_s(msg, sizeofArray(msg), " (entry point missing)");
269: Log("Plugin failed", msg);
270: strcpy_s(msg, sizeofArray(msg), pluginPath);
271: strcat_s(msg, sizeofArray(msg), " \n\nThe plugin you are trying to load is \nmissing the necessary entry point. \n\nPlease contact the plugin author. ");
272: MessageBox(GetBBWnd(), msg, "xoblite", MB_OK | MB_ICONERROR | MB_TOPMOST);
273: return false;
274: }
275:
276: if (!endPlugin)
277: {
278: FreeLibrary(hModule);
279: char msg[MAX_LINE_LENGTH];
280: strcpy_s(msg, sizeofArray(msg), pluginPath);
281: strcat_s(msg, sizeofArray(msg), " (exit point missing)");
282: Log("Plugin failed", msg);
283: strcpy_s(msg, sizeofArray(msg), pluginPath);
284: strcat_s(msg, sizeofArray(msg), " \n\nThe plugin you are trying to load is \nmissing the necessary exit point. \n\nPlease contact the plugin author. ");
285: MessageBox(GetBBWnd(), msg, "xoblite", MB_OK | MB_ICONERROR | MB_TOPMOST);
286: return false;
287: }
288:
289: // Show plugins if they are hidden and we're not starting up...
290: // (needed for visibility consistency when loading a new plugin)
291: if (pSettings->pluginsHidden && !startupLock && !IsInString(pluginPath, "xDesignerGUI.dll")) PostMessage(GetBBWnd(), BB_TOGGLEPLUGINS, 0, 0);
292:
293: //====================
294:
295: try
296: {
297: if (pDock)
298: {
299: if (beginPluginEx) beginPluginEx(hModule, pDock->hDockWnd);
300: else if (beginSlitPlugin && dockingEnabled) beginSlitPlugin(hModule, pDock->hDockWnd);
301: else if (beginPlugin) beginPlugin(hModule);
302: else if (beginSlitPlugin) beginSlitPlugin(hModule, pDock->hDockWnd);
303: }
304: else if (beginPlugin) beginPlugin(hModule);
305: }
306: catch (...)
307: {
308: FreeLibrary(hModule);
309: char msg[MAX_LINE_LENGTH];
310: strcpy_s(msg, sizeofArray(msg), pluginPath);
311: strcat_s(msg, sizeofArray(msg), " (try/catch exception)");
312: Log("Plugin failed", msg);
313: strcpy_s(msg, sizeofArray(msg), pluginPath);
314: strcat_s(msg, sizeofArray(msg), " \n\nThe plugin you are trying to load has failed. \n\nPlease contact the plugin author. ");
315: MessageBox(GetBBWnd(), msg, "xoblite", MB_OK | MB_ICONERROR | MB_TOPMOST);
316: return false;
317: }
318:
319: //====================
320:
321: return true;
322: }
323:
324: //===========================================================================
325:
326: void PluginManager::UnloadPlugin(LPSTR pluginPath, int pluginNumber)
327: {
328: if (pluginNumber != -1)
329: {
330: endPlugin = (endPluginFunc)GetProcAddress(pluginList[pluginNumber].hModule, "endPlugin");
331: endPlugin(pluginList[pluginNumber].hModule);
332: FreeLibrary(pluginList[pluginNumber].hModule);
333:
334: if (IsInString(pluginList[pluginNumber].path, "xDesignerGUI.dll")) pSettings->designerModeEnabled = false; // Safeguard ;)
335:
336: pluginList.erase(pluginList.begin() + pluginNumber);
337:
338: if (!WritePluginsRC()) MessageBox(GetBBWnd(), "Could not write to plugins.rc!", "xoblite", MB_OK | MB_ICONERROR | MB_TOPMOST);
339:
340: return;
341: }
342:
343: //====================
344:
345: if (strchr(pluginPath, '\"')) StrRemoveEncap(pluginPath);
346: if (strchr(pluginPath, '$')) ReplaceShellFolders(pluginPath);
347: if (strchr(pluginPath, '%')) ReplaceEnvVars(pluginPath);
348:
349: char dllName[MAX_LINE_LENGTH], dllTempName[MAX_LINE_LENGTH];
350: int nLen;
351:
352: // Extract the name of the .dll to unload (disregard the full path)...
353: strcpy_s(dllName, sizeofArray(dllName), pluginPath);
354: nLen = strnlen_s(dllName, sizeofArray(dllName)) - 1;
355: if (strchr(dllName, '/')) while (nLen >0 && dllName[nLen] != '/') nLen--;
356: else while (nLen >0 && dllName[nLen] != '\\') nLen--;
357: strcpy_s(dllName, sizeofArray(dllName), &pluginPath[nLen+1]);
358:
359: //====================
360:
361: for (int i=0; i < (int)pluginList.size(); i++)
362: {
363: // Extract the name of the current .dll (disregard the full path)...
364: strcpy_s(dllTempName, sizeofArray(dllTempName), pluginList[i].path);
365: nLen = strnlen_s(dllTempName, sizeofArray(dllTempName)) - 1;
366: if (strchr(dllName, '/')) while (nLen >0 && dllTempName[nLen] != '/') nLen--;
367: else while (nLen >0 && dllTempName[nLen] != '\\') nLen--;
368: strcpy_s(dllTempName, sizeofArray(dllTempName), &pluginList[i].path[nLen+1]);
369:
370: // Is the current plugin the plugin we wish to unload?
371: if (!_stricmp(dllName, dllTempName))
372: {
373: endPlugin = (endPluginFunc)GetProcAddress(pluginList[i].hModule, "endPlugin");
374: endPlugin(pluginList[i].hModule);
375: FreeLibrary(pluginList[i].hModule);
376:
377: if (IsInString(pluginPath, "xDesignerGUI.dll")) pSettings->designerModeEnabled = false; // Safeguard ;)
378:
379: pluginList.erase(pluginList.begin() + i);
380:
381: if (!WritePluginsRC()) MessageBox(GetBBWnd(), "Could not write to plugins.rc!", "xoblite", MB_OK | MB_ICONERROR | MB_TOPMOST);
382:
383: return;
384: }
385: }
386: /*
387: char msg[MAX_LINE_LENGTH];
388: strcpy_s(msg, sizeofArray(msg), pluginPath);
389: strcat_s(msg, sizeofArray(msg), " \n\nThe plugin you were trying to unload was not found running. ");
390: MessageBox(GetBBWnd(), msg, "xoblite", MB_OK | MB_ICONERROR | MB_TOPMOST);
391: */
392: }
393:
394: //===========================================================================
395:
396: void PluginManager::UpdatePlugin(LPSTR pluginPath, int pluginNumber, bool forceUpdate)
397: {
398: if (pSettings->checkingForUpdates) return;
399:
400: char msg[MAX_LINE_LENGTH], temp[MAX_LINE_LENGTH], path[MAX_LINE_LENGTH];
401:
402: // Make sure the updates metafile exists...
403: GetBlackboxPath(path, sizeof(path));
404: strcat_s(path, sizeofArray(path), "update.log");
405: if (!FileExists(path) || forceUpdate)
406: {
407: bool silent = true;
408: _beginthread(checkForUpdates, 0, &silent);
409: }
410:
411: //====================
412:
413: // Display "<->" icon in toolbar.windowLabel -> update in progress!
414: pSettings->checkingForUpdates = true;
415: // if ((pSettings->toolbarMode == TOOLBAR_MODE_WINDOWLABEL) && pToolbar) pToolbar->UpdateToolbarWindow();
416:
417: //====================
418:
419: if (pluginNumber != -1)
420: {
421: pluginInfo = (pluginInfoFunc)GetProcAddress(pluginList[pluginNumber].hModule, "pluginInfo");
422: if (pluginInfo)
423: {
424: if (FileExists(path))
425: {
426: char plugin[MAX_LINE_LENGTH], parameter[MAX_LINE_LENGTH];
427: char onlineVersion[MAX_LINE_LENGTH], currentVersion[MAX_LINE_LENGTH];
428: char onlineDate[MAX_LINE_LENGTH], currentDate[MAX_LINE_LENGTH];
429:
430: strcpy_s(plugin, sizeofArray(plugin), pluginInfo(PLUGIN_NAME));
431: strcpy_s(currentVersion, sizeofArray(currentVersion), pluginInfo(PLUGIN_VERSION));
432: strcpy_s(currentDate, sizeofArray(currentDate), pluginInfo(PLUGIN_RELEASEDATE));
433:
434: sprintf_s(parameter, sizeofArray(parameter), "%s.version:", plugin);
435: strcpy_s(onlineVersion, sizeofArray(onlineVersion), ReadString(path, parameter, ""));
436: if (!strnlen_s(onlineVersion, sizeofArray(onlineVersion)))
437: {
438: pluginList[pluginNumber].UpdateAvailable = false;
439: strcpy_s(temp, sizeofArray(temp), pluginInfo(PLUGIN_UPDATE_URL));
440: if (!IsInString(temp, "http://")) strcpy_s(temp, sizeofArray(temp), pSettings->pluginsRepository);
441: sprintf_s(msg, sizeofArray(msg), "%s \n\n%s is not supported by the specified repository! ", temp, plugin);
442: MessageBox(GetBBWnd(), msg, "xoblite", MB_OK | MB_SETFOREGROUND | MB_ICONERROR);
443: return;
444: }
445: sprintf_s(parameter, sizeofArray(parameter), "%s.date:", plugin);
446: strcpy_s(onlineDate, sizeofArray(onlineDate), ReadString(path, parameter, "xxxx-xx-xx"));
447:
448: //====================
449:
450: // Check if online version/date differs from the current version/date...
451: if (!_stricmp(currentDate, onlineDate))
452: {
453: if (!_stricmp(currentVersion, onlineVersion))
454: {
455: pluginList[pluginNumber].UpdateAvailable = false;
456: sprintf_s(msg, sizeofArray(msg), "You are already using the latest version of %s. ", plugin);
457: MessageBox(GetBBWnd(), msg, "xoblite", MB_OK | MB_SETFOREGROUND | MB_ICONINFORMATION);
458: return;
459: }
460: }
461:
462: //====================
463:
464: sprintf_s(msg, sizeofArray(msg), "%s update found!\n\nCurrent version:\t %s \t%s \nOnline version:\t %s \t%s ", plugin, currentVersion, currentDate, onlineVersion, onlineDate);
465:
466: sprintf_s(parameter, sizeofArray(parameter), "%s.changes:", plugin);
467: strcpy_s(temp, sizeofArray(temp), ReadString(path, parameter, ""));
468: if (strnlen_s(temp, sizeofArray(temp)))
469: {
470: strcat_s(msg, sizeofArray(msg), "\n\nUpdate information:\n");
471: strcat_s(msg, sizeofArray(msg), temp);
472: }
473:
474: strcat_s(msg, sizeofArray(msg), "\n\nDo you want to download this update? ");
475:
476: //====================
477:
478: if (MessageBox(GetBBWnd(), msg, "xoblite", MB_YESNO | MB_ICONQUESTION | MB_SETFOREGROUND | MB_TOPMOST) == IDYES)
479: {
480: int nLen;
481: char token[MAX_LINE_LENGTH], extra[MAX_LINE_LENGTH], filename[MAX_LINE_LENGTH], pluginPath[MAX_LINE_LENGTH];
482: char savedfiles[MAX_LINE_LENGTH] = "";
483: LPSTR tokens[1];
484: tokens[0] = token;
485:
486: // Copy the path to the plugin + the URL...
487: bool dllFound = false, zipFound = false;
488:
489: if (!strstr(pluginList[pluginNumber].path, ":\\"))
490: {
491: // Make sure we use the full path of the plugin and
492: // not just a path relative to the Blackbox folder...
493: GetBlackboxPath(filename, MAX_LINE_LENGTH);
494: strcat_s(filename, sizeofArray(filename), pluginList[pluginNumber].path);
495: }
496: else strcpy_s(filename, sizeofArray(filename), pluginList[pluginNumber].path);
497:
498: sprintf_s(parameter, sizeofArray(parameter), "%s.files:", plugin);
499: strcpy_s(temp, sizeofArray(temp), ReadString(path, parameter, ""));
500: if (!strnlen_s(temp, sizeofArray(temp)))
501: {
502: // Download the plugin .zip archive if no
503: // list of updated files was specified...
504: sprintf_s(parameter, sizeofArray(parameter), "%s.archive:", plugin);
505: strcpy_s(temp, sizeofArray(temp), ReadString(path, parameter, ""));
506: }
507:
508: if (IsInString(temp, ".dll")) dllFound = true;
509: else if (IsInString(temp, ".zip")) zipFound = true;
510:
511: if (!dllFound && !zipFound)
512: {
513: // Neither an archive (.zip) nor individual files (including at least one .dll)
514: // was directly linked to -> Open the link in the user's default browser...
515: if (IsInString(temp, "http")) BBSmartExecute(temp);
516: else
517: {
518: sprintf_s(msg, sizeofArray(msg), "Invalid update link detected for %s: \n\n%s ", plugin, temp);
519: if (strnlen_s(temp, sizeofArray(temp)) == 0) strcat_s(msg, sizeofArray(msg), "<empty> ");
520: strcat_s(msg, sizeofArray(msg), "\n\nUpdate request aborted. Click OK to continue.");
521: MessageBox(GetBBWnd(), msg, "Error updating plugin!", MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);
522: }
523: return;
524: }
525:
526: if (dllFound)
527: {
528: // Unload the plugin...
529: strcpy_s(pluginPath, sizeofArray(pluginPath), pluginList[pluginNumber].path);
530: endPlugin = (endPluginFunc)GetProcAddress(pluginList[pluginNumber].hModule, "endPlugin");
531: endPlugin(pluginList[pluginNumber].hModule);
532: FreeLibrary(pluginList[pluginNumber].hModule);
533: pluginList.erase(pluginList.begin() + pluginNumber);
534: }
535:
536: // Download the updated files...
537: while(strnlen_s(temp, sizeofArray(temp)))
538: {
539: token[0] = extra[0] = '\0';
540: BBTokenize (temp, tokens, 1, extra);
541: strcpy_s(temp, sizeofArray(temp), extra);
542:
543: // Extract the plugin folder from the plugin path...
544: nLen = strnlen_s(filename, sizeofArray(filename)) - 1;
545: if (IsInString(filename, "/")) while (nLen >0 && filename[nLen] != '/') nLen--;
546: else while (nLen >0 && filename[nLen] != '\\') nLen--;
547: filename[nLen + 1] = 0;
548:
549: // Extract the name of the file from the URL...
550: nLen = strnlen_s(token, sizeofArray(token)) - 1;
551: while (nLen >0 && token[nLen] != '/') nLen--;
552: strcat_s(filename, sizeofArray(filename), &token[nLen+1]);
553:
554: // Download the file and save it in the plugin folder...
555: DownloadFile(token, filename);
556:
557: // Copy the path of the saved file to the list of updated files...
558: strcat_s(savedfiles, sizeofArray(savedfiles), "\n");
559: strcat_s(savedfiles, sizeofArray(savedfiles), filename);
560: strcat_s(savedfiles, sizeofArray(savedfiles), " ");
561: }
562:
563: if (dllFound)
564: {
565: // Reload the plugin...
566: bool dockingEnabled;
567:
568: if (pluginPath[0] == '&') // dock plugin?
569: {
570: dockingEnabled = true;
571: hModule = LoadLibrary(&pluginPath[1]);
572: }
573: else // normal plugin
574: {
575: dockingEnabled = false;
576: hModule = LoadLibrary(pluginPath);
577: }
578:
579: if (hModule)
580: {
581: if (StartPlugin(hModule, pluginPath, dockingEnabled))
582: {
583: pluginItem plg;
584: plg.hModule = hModule;
585: plg.DockingEnabled = dockingEnabled;
586: strcpy_s(plg.path, sizeofArray(plg.path), pluginPath);
587: plg.UpdateAvailable = false;
588: pluginList.insert(pluginList.begin() + pluginNumber, plg);
589: }
590: }
591: else return;
592:
593: sprintf_s(msg, sizeofArray(msg), "%s update downloaded and installed. \n%s", plugin, savedfiles);
594: MessageBox(GetBBWnd(), msg, "xoblite", MB_OK | MB_SETFOREGROUND | MB_TOPMOST | MB_ICONINFORMATION);
595: }
596: else if (zipFound)
597: {
598: sprintf_s(msg, sizeofArray(msg), "%s update in .zip format downloaded, \nsee archive for further instructions. \n%s", plugin, savedfiles);
599: if (MessageBox(GetBBWnd(), msg, "xoblite", MB_OK | MB_SETFOREGROUND | MB_TOPMOST | MB_ICONINFORMATION))
600: {
601: char arg[MAX_LINE_LENGTH];
602: strcpy_s(arg, sizeofArray(arg), "/e,/select,");
603: strcat_s(arg, sizeofArray(arg), savedfiles);
604: BBExecute(GetDesktopWindow(), NULL, "explorer.exe", arg, NULL, SW_SHOWNORMAL, false);
605: return;
606: }
607: }
608: else
609: {
610: sprintf_s(msg, sizeofArray(msg), "%s update downloaded. \n%s", plugin, savedfiles);
611: MessageBox(GetBBWnd(), msg, "xoblite", MB_OK | MB_SETFOREGROUND | MB_TOPMOST | MB_ICONINFORMATION);
612: }
613: }
614:
615: // Turn off the "update available" indicator...
616: pluginList[pluginNumber].UpdateAvailable = false;
617: }
618: else MessageBox(GetBBWnd(), "Could not find the updates metafile! [update.log] ", "xoblite", MB_OK | MB_SETFOREGROUND | MB_TOPMOST | MB_ICONERROR);
619: }
620: else MessageBox(GetBBWnd(), "This plugin does not support automatic updating. ", "xoblite", MB_OK | MB_SETFOREGROUND | MB_TOPMOST | MB_ICONERROR);
621: }
622:
623: // Remove "<->" icon from toolbar.windowLabel -> update no longer in progress
624: pSettings->checkingForUpdates = false;
625: // if ((pSettings->toolbarMode == TOOLBAR_MODE_WINDOWLABEL) && pToolbar) pToolbar->UpdateToolbarWindow();
626: }
627:
628: //===========================================================================
629:
630: void checkForUpdates(void *param)
631: {
632: if (pSettings->checkingForUpdates) _endthread();
633: else
634: {
635: // Display "<->" icon in toolbar.windowLabel -> update in progress!
636: pSettings->checkingForUpdates = true;
637: // if ((pSettings->toolbarMode == TOOLBAR_MODE_WINDOWLABEL) && pToolbar) pToolbar->UpdateToolbarWindow();
638: // SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_REGULAR_MESSAGE, (LPARAM)"xoblite -> Checking for updates...");
639: }
640:
641: bool silent = *((bool*)param);
642: int updates = 0;
643: char listOfURLs[MAX_LINE_LENGTH] = "", path[MAX_LINE_LENGTH], msg[MAX_LINE_LENGTH], listOfUpdates[MAX_LINE_LENGTH] = "";
644:
645: //====================
646: /*
647: // Extract distributed repository URLs from all
648: // plugins that support automatic updating...
649: for (int i=0; i < (int)pPluginManager->pluginList.size(); i++)
650: {
651: pPluginManager->pluginInfo = (pluginInfoFunc)GetProcAddress(pPluginManager->pluginList[i].hModule, "pluginInfo");
652: if (pPluginManager->pluginInfo)
653: {
654: strcpy_s(msg, sizeofArray(msg), pPluginManager->pluginInfo(PLUGIN_UPDATE_URL));
655:
656: // Make sure the string supplied by the plugin is a valid URL
657: // and that it isn't the same URL as for the central repository...
658: if (IsInString(msg, "http://") && !IsInString(msg, pSettings->pluginsRepository))
659: {
660: if (!IsInString(listOfURLs, msg))
661: {
662: strcat_s(listOfURLs, sizeofArray(listOfURLs), msg);
663: strcat_s(listOfURLs, sizeofArray(listOfURLs), " ");
664: }
665: }
666: }
667: }
668: */
669: // Finally, we add the central repository URL at the end of the list
670: // (i.e. if a plugin does not return a URL for automatic updating we fall
671: // back to the central plugin repository defined in xoblite.rc, which means
672: // that the information provided by the distributed repositories
673: // will have precedence in case of duplicate plugin update information! :D )
674: strcat_s(listOfURLs, sizeofArray(listOfURLs), pSettings->pluginsRepository);
675:
676: //====================
677:
678: if (IsInString(listOfURLs, "http://"))
679: {
680: GetBlackboxPath(path, sizeof(path));
681: strcat_s(path, sizeofArray(path), "update.log");
682:
683: if (FileExists(path)) remove(path); // Delete existing update.log file...
684:
685: //====================
686:
687: if (DownloadFile(listOfURLs, path))
688: {
689: char plugin[MAX_LINE_LENGTH], parameter[MAX_LINE_LENGTH];
690: char onlineVersion[MAX_LINE_LENGTH], currentVersion[MAX_LINE_LENGTH];
691: char onlineDate[MAX_LINE_LENGTH], currentDate[MAX_LINE_LENGTH];
692: char onlineAuthor[MAX_LINE_LENGTH];
693:
694: for (int i=0; i < (int)pPluginManager->pluginList.size(); i++)
695: {
696: pPluginManager->pluginInfo = (pluginInfoFunc)GetProcAddress(pPluginManager->pluginList[i].hModule, "pluginInfo");
697: if (pPluginManager->pluginInfo)
698: {
699: strcpy_s(plugin, sizeofArray(plugin), pPluginManager->pluginInfo(PLUGIN_NAME));
700: strcpy_s(currentVersion, sizeofArray(currentVersion), pPluginManager->pluginInfo(PLUGIN_VERSION));
701: strcpy_s(currentDate, sizeofArray(currentDate), pPluginManager->pluginInfo(PLUGIN_RELEASEDATE));
702:
703: sprintf_s(parameter, sizeofArray(parameter), "%s.version:", plugin);
704: strcpy_s(onlineVersion, sizeofArray(onlineVersion), ReadString(path, parameter, ""));
705: if (!strnlen_s(onlineVersion, sizeofArray(onlineVersion)))
706: {
707: // The plugin was not not supported by the specified repository (or invalid syntax)...
708: pPluginManager->pluginList[i].UpdateAvailable = false;
709: continue;
710: }
711: sprintf_s(parameter, sizeofArray(parameter), "%s.date:", plugin);
712: strcpy_s(onlineDate, sizeofArray(onlineDate), ReadString(path, parameter, "xxxx-xx-xx"));
713:
714: //====================
715:
716: // Check if online version/date differs from the current version/date...
717: if (!_stricmp(currentDate, onlineDate))
718: {
719: if (!_stricmp(currentVersion, onlineVersion))
720: {
721: // If not, continue looking...
722: pPluginManager->pluginList[i].UpdateAvailable = false;
723: continue;
724: }
725: }
726:
727: // ...but if it differs we have found an updated plugin!
728: pPluginManager->pluginList[i].UpdateAvailable = true;
729:
730: sprintf_s(parameter, sizeofArray(parameter), "%s.author:", plugin);
731: strcpy_s(onlineAuthor, sizeofArray(onlineAuthor), ReadString(path, parameter, (LPSTR)pPluginManager->pluginInfo(PLUGIN_AUTHOR)));
732:
733: sprintf_s(msg, sizeofArray(msg), "\n%s %s by %s (%s) ", plugin, onlineVersion, onlineAuthor, onlineDate);
734: strcat_s(listOfUpdates, sizeofArray(listOfUpdates), msg);
735: updates++;
736: }
737: else pPluginManager->pluginList[i].UpdateAvailable = false;
738: }
739: }
740: else
741: {
742: strcpy_s(msg, sizeofArray(msg), "Note: Some repositories were not currently available, \nwhich may affect the result of this check for updates. ");
743: MessageBox(GetBBWnd(), msg, "xoblite", MB_OK | MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TOPMOST);
744: }
745: }
746:
747: //====================
748:
749: if (!silent)
750: {
751: char xobVersion[MAX_LINE_LENGTH], xobOnlineVersion[MAX_LINE_LENGTH];
752: ULONG *size = 0;
753: void *versionPtr;
754: UINT bytes;
755:
756: // Extract currently running xoblite version...
757: // (make sure the correct version encoding is used, currently "000004b0" = language neutral)
758: DWORD number = GetFileVersionInfoSize("Blackbox.exe", size);
759: char temp[MAX_LINE_LENGTH];
760: GetFileVersionInfo("Blackbox.exe", NULL, number, (LPVOID)temp);
761: VerQueryValue(temp, TEXT("\\StringFileInfo\\000004b0\\FileVersion"), &versionPtr, &bytes);
762: strcpy_s(xobVersion, sizeofArray(xobVersion), (LPCSTR)versionPtr);
763: if ((xobVersion[strnlen_s(xobVersion, sizeofArray(xobVersion))-1] == '\n') || (xobVersion[strnlen_s(xobVersion, sizeofArray(xobVersion))-1] == '\r')) xobVersion[strnlen_s(xobVersion, sizeofArray(xobVersion))-1] = '\0'; // Failsafe
764:
765: // ...and compare that with the xoblite version available online...
766: strcpy_s(xobOnlineVersion, sizeofArray(xobOnlineVersion), ReadString(path, "xoblite.version:", ""));
767: if ((xobOnlineVersion[strnlen_s(xobOnlineVersion, sizeofArray(xobOnlineVersion))-1] == '\n') || (xobOnlineVersion[strnlen_s(xobOnlineVersion, sizeofArray(xobOnlineVersion))-1] == '\r')) xobOnlineVersion[strnlen_s(xobOnlineVersion, sizeofArray(xobOnlineVersion))-1] = '\0'; // Failsafe
768:
769: bool xobliteUpdateFound = false;
770: if (strnlen_s(xobOnlineVersion, sizeofArray(xobOnlineVersion)) && _stricmp(xobVersion, xobOnlineVersion)) xobliteUpdateFound = true;
771:
772: //====================
773:
774: // Display result of the check for updates in the console...
775: if (updates > 0)
776: {
777: if (xobliteUpdateFound) sprintf_s(msg, sizeofArray(msg), "Checking for updates -> xoblite %s and %d updated plugin", xobOnlineVersion, updates);
778: else sprintf_s(msg, sizeofArray(msg), "Checking for updates -> %d updated plugin", updates);
779: if (updates > 1) strcat_s(msg, sizeofArray(msg), "s");
780: strcat_s(msg, sizeofArray(msg), " available.");
781: }
782: else if (xobliteUpdateFound) sprintf_s(msg, sizeofArray(msg), "Checking for updates -> xoblite %s available.", xobOnlineVersion);
783: else strcpy_s(msg, sizeofArray(msg), "Checking for updates -> No updates were found.");
784:
785: SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)msg);
786:
787: //====================
788:
789: if (xobliteUpdateFound)
790: {
791: sprintf_s(msg, sizeofArray(msg), "Shell update found! \n\nCurrent version: \nxoblite %s \n\nOnline version: \nxoblite %s \n\nDo you want to download this update? \n(clicking \"Yes\" will take you to the xoblite website) ", xobVersion, xobOnlineVersion);
792:
793: if (MessageBox(GetBBWnd(), msg, "xoblite", MB_YESNO | MB_ICONQUESTION | MB_SETFOREGROUND | MB_TOPMOST) == IDYES)
794: {
795: // Choosing to download an update will (for now) take the user to the xoblite
796: // website to manually download the latest build (mostly to reduce maintenance
797: // overhead, however this could possibly change in a future release...)
798: BBExecute(GetDesktopWindow(), NULL, "http://xoblite.net/", NULL, NULL, SW_SHOWNORMAL, true);
799: }
800:
801: // Choosing to download an update will (for now) take the user to the xoblite
802: // website to manually download the latest build (mostly to reduce maintenance
803: // overhead, however this could possibly change in a future release...)
804: // SendMessage(GetBBWnd(), BB_POPUPMESSAGE, (WPARAM)msg, (LPARAM)"@GoToURL http://xoblite.net/");
805: }
806:
807: //====================
808:
809: if (updates > 0)
810: {
811: sprintf_s(msg, sizeofArray(msg), "Found %d updated plugins: \n", updates);
812: strcat_s(msg, sizeofArray(msg), listOfUpdates);
813: if (updates == 1) strcat_s(msg, sizeofArray(msg), "\n\nDo you want to download this update? ");
814: else strcat_s(msg, sizeofArray(msg), "\n\nDo you want to download any of these updates? ");
815:
816: if (MessageBox(GetBBWnd(), msg, "xoblite", MB_YESNO | MB_ICONQUESTION | MB_SETFOREGROUND | MB_TOPMOST) == IDYES)
817: {
818: for (int i=0; i < (int)pPluginManager->pluginList.size(); i++)
819: {
820: if (pPluginManager->pluginList[i].UpdateAvailable)
821: {
822: pSettings->checkingForUpdates = false; // Disable update lock to access updatePlugin() ...
823: pPluginManager->UpdatePlugin(NULL, i, false);
824: pSettings->checkingForUpdates = true; // Re-enable update lock...
825: }
826: }
827: }
828: }
829: else
830: {
831: strcpy_s(msg, sizeofArray(msg), "No updated plugins were found. ");
832: MessageBox(GetBBWnd(), msg, "xoblite", MB_OK | MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TOPMOST);
833: }
834: }
835:
836: //====================
837:
838: // Finally, we update xoblite.checked.for.updates in xoblite.rc... (temporarily disable write protection if necessary!)
839: time_t systemTime;
840: struct tm localTime;
841: time(&systemTime);
842: localtime_s(&localTime, &systemTime);
843:
844: _locale_t timestampLocale = _create_locale(LC_TIME, "en-US"); // -> Always use en-US format for the "checked for updates" timestamp...
845: _strftime_l(pSettings->checkedForUpdates, 20, "#%j / %Y-%m-%d", &localTime, timestampLocale);
846: _free_locale(timestampLocale);
847:
848: bool tempBool = pSettings->writeProtection;
849: pSettings->writeProtection = false;
850: WriteString(pSettings->xobrcDefaultFile, "xoblite.checked.for.updates:", pSettings->checkedForUpdates);
851: pSettings->writeProtection = tempBool;
852:
853: //====================
854:
855: // Remove "<->" icon from toolbar.windowLabel -> update no longer in progress
856: pSettings->checkingForUpdates = false;
857: // if ((pSettings->toolbarMode == TOOLBAR_MODE_WINDOWLABEL) && pToolbar) pToolbar->UpdateToolbarWindow();
858:
859: _endthread();
860: }
861:
862: //===========================================================================
863:
864: void periodicCheckForUpdates(void *)
865: {
866: if (pSettings->checkingForUpdates) _endthread();
867:
868: char temp[MAX_LINE_LENGTH];// , windowLabel[25];
869:
870: // Get current day of the year...
871: time_t systemTime;
872: struct tm localTime;
873: time(&systemTime);
874: localtime_s(&localTime, &systemTime);
875: int currentDay = localTime.tm_yday + 1;
876:
877: // Extract day of the year for the last check...
878: // strncpy(temp, &pSettings->checkedForUpdates[1], 3);
879: strncpy_s(temp, sizeofArray(temp), &pSettings->checkedForUpdates[1], 3);
880: temp[3] = 0;
881: int checkedDay = atoi(temp);
882:
883: // Calculate the number of days since the last check for updates...
884: int interval;
885: if (currentDay >= checkedDay) interval = currentDay - checkedDay;
886: else interval = 366 - checkedDay + currentDay;
887:
888: //====================
889: /*
890: // Is the last checked date in xoblite.rc == the default?
891: // If so, xoblite is running for the first time -> display a nice welcome screen! =]
892: if (!_stricmp(pSettings->checkedForUpdates, "#001 / 2006-01-01"))
893: {
894: interval = 365; // ...just to trigger the update messagebox below! <g>
895: strcpy_s(windowLabel, sizeofArray(windowLabel), "Welcome to xoblite!");
896: strcpy_s(temp, sizeofArray(temp),
897: "You seem to be running xoblite for the first time. \n\n"
898: "xoblite features a mechanism to notify you of available updates to the core (Blackbox.exe) and your loaded plugins. \n\n"
899: "A check for updates can be triggered using: \n"
900: "- The \"Check for updates...\" item in the Configuration/Global menu \n"
901: "- The core broadcast message: @xoblite CheckForUpdates \n"
902: "- Monthly periodic checking (user is notified if/when more than 30 days have passed since the last check) \n\n"
903: "Do you want to check for updates now? ");
904: }
905: else
906: {
907: strcpy_s(windowLabel, sizeofArray(windowLabel), "xoblite");
908: sprintf_s(temp, sizeofArray(temp), "%d days have passed since you last checked for updates. \n\nDo you want to check for updates now? ", interval);
909: }
910: */
911: //====================
912:
913: if (interval > 30) // Has more than 30 days passed since the last check for updates?
914: {
915: /*
916: // Ask the user if he/she wants to check for updates...
917: if (MessageBox(NULL, temp, windowLabel, MB_YESNO | MB_ICONQUESTION | MB_SETFOREGROUND | MB_TOPMOST) == IDYES)
918: {
919: bool silent = false;
920: checkForUpdates(&silent); // We're already running in a separate thread! (NOTE: checkForUpdates will terminate the thread)
921: }
922: else
923: {
924: // Update xoblite.checked.for.updates in xoblite.rc... (temporarily disable write protection if necessary!)
925: _locale_t timestampLocale = _create_locale(LC_TIME, "en-US"); // -> Always use en-US format for the checked for updates timestamp...
926: _strftime_l(pSettings->checkedForUpdates, 20, "#%j / %Y-%m-%d", localTime, timestampLocale);
927: _free_locale(timestampLocale);
928:
929: bool tempBool = pSettings->writeProtection;
930: pSettings->writeProtection = false;
931: WriteString(pSettings->xobrcDefaultFile, "xoblite.checked.for.updates:", pSettings->checkedForUpdates);
932: pSettings->writeProtection = tempBool;
933: }
934: */
935: bool silent = false;
936: checkForUpdates(&silent); // We're already running in a separate thread! (NOTE: checkForUpdates will terminate the thread)
937: }
938:
939: //====================
940:
941: _endthread();
942: }
943:
944: //===========================================================================
945:
946: void PluginManager::AboutPlugins()
947: {
948: char msg[MAX_LINE_LENGTH] = "", temp[MAX_LINE_LENGTH];
949:
950: for (int i=0; i < (int)pluginList.size(); i++)
951: {
952: pluginInfo = (pluginInfoFunc)GetProcAddress(pluginList[i].hModule, "pluginInfo");
953: if (pluginInfo)
954: {
955: sprintf_s(temp, sizeofArray(temp), "%s %s by %s (%s)", pluginInfo(PLUGIN_NAME), pluginInfo(PLUGIN_VERSION), pluginInfo(PLUGIN_AUTHOR), pluginInfo(PLUGIN_RELEASEDATE));
956: strcat_s(msg, sizeofArray(msg), temp);
957: if (pluginList[i].path[0] == '&') strcat_s(msg, sizeofArray(msg), " *\n"); // &-loaded plugin (beginSlitPlugin)
958: else strcat_s(msg, sizeofArray(msg), "\n"); // Normal plugin (beginPlugin, beginPluginEx)
959: }
960: else
961: {
962: strcat_s(msg, sizeofArray(msg), pluginList[i].path);
963: if (pluginList[i].path[0] == '&') strcat_s(msg, sizeofArray(msg), " *\n"); // &-loaded plugin (beginSlitPlugin)
964: else strcat_s(msg, sizeofArray(msg), "\n"); // Normal plugin (beginPlugin, beginPluginEx)
965: }
966: }
967:
968: if (strnlen_s(msg, sizeofArray(msg)))
969: {
970: msg[strnlen_s(msg, sizeofArray(msg))-1] = '\0'; // Remove the last line feed auto-generated above...
971: SendMessage(GetBBWnd(), BB_POPUPMESSAGE, (WPARAM)"About the loaded plugins...", (LPARAM)msg);
972: }
973: else SendMessage(GetBBWnd(), BB_POPUPMESSAGE, (WPARAM)"About the loaded plugins...", (LPARAM)"--- No plugins loaded --- ");
974: }
975:
976: //===========================================================================
977:
978: LPCSTR PluginManager::GetPluginInfo(int pluginNumber, int infoParam)
979: {
980: pluginInfo = (pluginInfoFunc)GetProcAddress(pluginList[pluginNumber].hModule, "pluginInfo");
981: if (pluginInfo)
982: {
983: LPCSTR result = pluginInfo(infoParam); // e.g. PLUGIN_VERSION (see BBApi.h)
984: if (result) return result;
985: // Fetch default fallback string in case the result was NULL
986: // (i.e. if the requested field was not supported/defined)
987: // else return pluginInfo(-1);
988: else return pluginInfo(PLUGIN_NAME);
989: }
990: else
991: {
992: // Extract the name of the plugin...
993: strcpy_s(pluginName, sizeofArray(pluginName), pluginList[pluginNumber].path);
994: int nLen = strnlen_s(pluginName, sizeofArray(pluginName)) - 1;
995: if (IsInString(pluginName, "/")) while (nLen >0 && pluginName[nLen] != '/') nLen--;
996: else while (nLen >0 && pluginName[nLen] != '\\') nLen--;
997: strcpy_s(pluginName, sizeofArray(pluginName), &pluginList[pluginNumber].path[nLen+1]);
998: pluginName[strnlen_s(pluginName, sizeofArray(pluginName))-4] = 0; // Remove .dll at the end...
999: return pluginName;
1000: }
1001: }
1002:
1003: //===========================================================================
1004:
1005: bool PluginManager::WritePluginsRC()
1006: {
1007: if (pSettings->writeProtection) return true;
1008:
1009: HANDLE f = CreateFile(plugrcPath(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1010: if (f)
1011: {
1012: char szTemp[MAX_LINE_LENGTH];
1013: DWORD retLength = 0;
1014:
1015: for (int i=0; i < (int)pluginList.size(); i++)
1016: {
1017: // If the full path to the plugin is specified (e.g. from drag'n'drop) and it is in
1018: // a subfolder to the Blackbox folder, extract the relative path to the plugin
1019: // -> full path minus Blackbox folder path.
1020: // Example: "C:\Blackbox\plugins\BBbin\BBbin.dll" becomes "plugins\BBbin\BBbin.dll"
1021: // This way the Blackbox folder can be moved, and the plugin path will still work! :D
1022:
1023: if (!pSettings->usingDefaultTheme && IsInString(pluginList[i].path, pSettings->SF_currentThemePath))
1024: {
1025: strcpy_s(szTemp, sizeofArray(szTemp), "$CurrentTheme$");
1026: strcat_s(szTemp, sizeofArray(szTemp), &pluginList[i].path[(strnlen_s(pSettings->SF_currentThemePath, sizeofArray(pSettings->SF_blackboxPath)))]);
1027: }
1028: else if (IsInString(pluginList[i].path, pSettings->SF_blackboxPath))
1029: {
1030: strcpy_s(szTemp, sizeofArray(szTemp), &pluginList[i].path[(strnlen_s(pSettings->SF_blackboxPath, sizeofArray(pSettings->SF_blackboxPath))+1)]);
1031: }
1032: else strcpy_s(szTemp, sizeofArray(szTemp), pluginList[i].path);
1033:
1034: strcat_s(szTemp, sizeofArray(szTemp), "\r\n");
1035: WriteFile(f, szTemp, strnlen_s(szTemp, sizeofArray(szTemp)), &retLength, NULL);
1036: }
1037:
1038: CloseHandle(f);
1039: return true;
1040: }
1041: else
1042: {
1043: CloseHandle(f);
1044: return false;
1045: }
1046: }
1047:
1048: //===========================================================================
1049:
1050: void PluginManager::LoadPluginDialog()
1051: {
1052: char msg[MAX_LINE_LENGTH];
1053: strcpy_s(msg, sizeofArray(msg), "Always be careful when loading plugins and \nrunning scripts downloaded from the internet. \n\nEnsure they are from a trusted source. \n\nDo you want to continue? ");
1054:
1055: if (MessageBox(GetBBWnd(), msg, "xoblite", MB_YESNO | MB_ICONQUESTION | MB_SETFOREGROUND | MB_TOPMOST) == IDYES)
1056: {
1057: char file[MAX_PATH] = "", path[MAX_PATH];
1058:
1059: if (pSettings->usingDefaultTheme)
1060: {
1061: strcpy_s(path, sizeofArray(path), pSettings->SF_blackboxPath);
1062: strcat_s(path, sizeofArray(path), "\\plugins");
1063: }
1064: else
1065: {
1066: strcpy_s(path, sizeofArray(path), pSettings->SF_currentThemePath);
1067: strcat_s(path, sizeofArray(path), "\\plugins");
1068: if (!FolderExists(path))
1069: {
1070: strcpy_s(path, sizeofArray(path), pSettings->SF_blackboxPath);
1071: strcat_s(path, sizeofArray(path), "\\plugins");
1072: }
1073: }
1074:
1075: // Set the required formats for the file dialog...
1076: OPENFILENAME ofn;
1077: ZeroMemory(&ofn, sizeof(ofn));
1078: ofn.lStructSize = sizeof(ofn);
1079: ofn.hwndOwner = NULL;
1080: ofn.lpstrFilter = "Plugins (*.dll)\0*.dll", NULL, NULL;
1081: ofn.lpstrFile = file;
1082: ofn.nMaxFile = MAX_PATH;
1083: ofn.lpstrInitialDir = path;
1084: ofn.lpstrTitle = "Load plugin...";
1085: ofn.lpstrDefExt = NULL;
1086: ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_EXPLORER;
1087:
1088: if (GetOpenFileName(&ofn)) LoadPlugin(ofn.lpstrFile);
1089: }
1090: }
1091:
1092: //===========================================================================
1093:
1094: bool PluginManager::IsPluginLoaded(LPSTR pluginPath)
1095: {
1096: bool fileNameOnly = false;
1097: if (!strchr(pluginPath, '\\')) fileNameOnly = true;
1098:
1099: for (int i=0; i < (int)pluginList.size(); i++)
1100: {
1101: if (fileNameOnly)
1102: {
1103: if (IsInString(pluginList[i].path, pluginPath)) return true;
1104: }
1105: else
1106: {
1107: if (!_stricmp(pluginList[i].path, pluginPath)) return true;
1108: }
1109: }
1110:
1111: return false;
1112: }
1113:
1114: //===========================================================================
1115: