1 | #include "gsProgman.h"
|
---|
2 |
|
---|
3 | #include <stdio.h>
|
---|
4 |
|
---|
5 | // include shell for explorer-based OS'es
|
---|
6 | #include <shlobj.h>
|
---|
7 | // include dde for old (win 3.1/winNT 3.5) OS'es
|
---|
8 | #include <ddeml.h>
|
---|
9 |
|
---|
10 | #include "FilePath.h"
|
---|
11 |
|
---|
12 | extern HINSTANCE app_instance;
|
---|
13 |
|
---|
14 | /**
|
---|
15 | * A private function for Dde callbacks; in practice it needs to be here,
|
---|
16 | * but does nothing whatsoever
|
---|
17 | */
|
---|
18 | HDDEDATA CALLBACK DdeCallBack(UINT uType, // transaction type
|
---|
19 | UINT uFmt, // clipboard data format
|
---|
20 | HCONV hconv, // handle to the conversation
|
---|
21 | HSZ hsz1, // handle to a string
|
---|
22 | HSZ hsz2, // handle to a string
|
---|
23 | HDDEDATA hdata, // handle to a global memory object
|
---|
24 | DWORD dwData1, // transaction-specific data
|
---|
25 | DWORD dwData2 // transaction-specific data
|
---|
26 | )
|
---|
27 | {
|
---|
28 | return NULL;
|
---|
29 | }
|
---|
30 |
|
---|
31 | /**
|
---|
32 | * A private little function to do DDE activity
|
---|
33 | */
|
---|
34 | bool DDEShellCommand(DWORD instance, char *command)
|
---|
35 | {
|
---|
36 | HSZ serviceName;
|
---|
37 | HCONV conversation;
|
---|
38 | int commandLength;
|
---|
39 | HDDEDATA ddeData;
|
---|
40 | DWORD result;
|
---|
41 | bool reply = false;
|
---|
42 |
|
---|
43 | // create DDE string from service request
|
---|
44 | serviceName = DdeCreateStringHandle(instance, "PROGMAN", CP_WINANSI);
|
---|
45 | if (serviceName == NULL)
|
---|
46 | {
|
---|
47 | /*char buffer[20];
|
---|
48 | sprintf(buffer, "%d %d", DdeGetLastError(instance), instance);
|
---|
49 | MessageBox(0, buffer, "GSInstall", MB_OK);*/
|
---|
50 | return FALSE;
|
---|
51 | }
|
---|
52 |
|
---|
53 | // strike up a conversation with the DDE service
|
---|
54 | if ((conversation = DdeConnect(instance, serviceName, serviceName, NULL)) != NULL)
|
---|
55 | {
|
---|
56 | commandLength = lstrlen(command);
|
---|
57 |
|
---|
58 | // send the message via DDE
|
---|
59 | // MessageBox(0, command, "Executing", MB_OK);
|
---|
60 | ddeData = DdeClientTransaction((LPBYTE) command, commandLength + 1,
|
---|
61 | conversation, NULL, CF_TEXT, XTYP_EXECUTE,
|
---|
62 | 1000, &result);
|
---|
63 | // if our reply isn't NULL, it succeeded
|
---|
64 | reply = (ddeData != NULL);
|
---|
65 | if (reply == false)
|
---|
66 | { /*
|
---|
67 | char buffer[20];
|
---|
68 |
|
---|
69 | sprintf(buffer, "%d", DdeGetLastError(instance));
|
---|
70 | MessageBox(0, buffer, "DDE Error", MB_OK);*/
|
---|
71 | }
|
---|
72 |
|
---|
73 | // disconnect the conversation
|
---|
74 | DdeDisconnect(conversation);
|
---|
75 | }
|
---|
76 | else
|
---|
77 | {
|
---|
78 | MessageBox(0, "DDE Connect failed", "GSInstall", MB_OK);
|
---|
79 | }
|
---|
80 |
|
---|
81 | // free DDE string
|
---|
82 | DdeFreeStringHandle(instance, serviceName);
|
---|
83 | return reply;
|
---|
84 | }
|
---|
85 |
|
---|
86 | gsProgramManager::gsProgramManager(installManager &manager)
|
---|
87 | : installAgent(manager)
|
---|
88 | {
|
---|
89 | this->platform = new gsPlatform();
|
---|
90 | this->connected = false;
|
---|
91 | }
|
---|
92 |
|
---|
93 | void gsProgramManager::logAction(string actionName, string group)
|
---|
94 | {
|
---|
95 | unInstallCommand command(actionName);
|
---|
96 | command.addParameter(group);
|
---|
97 | manager->storeCommand(command);
|
---|
98 | }
|
---|
99 |
|
---|
100 | void gsProgramManager::logAction(string actionName, string group, string item, string parameter)
|
---|
101 | {
|
---|
102 | unInstallCommand command(actionName);
|
---|
103 | command.addParameter(group);
|
---|
104 | command.addParameter(item);
|
---|
105 | command.addParameter(parameter);
|
---|
106 | manager->storeCommand(command);
|
---|
107 | }
|
---|
108 |
|
---|
109 | bool gsProgramManager::undoAction(string actionName, stringArray ¶ms)
|
---|
110 | {
|
---|
111 | if (actionName == "ProgManCreateGroup")
|
---|
112 | {
|
---|
113 | this->removeProgramGroup(params[0]);
|
---|
114 | return true;
|
---|
115 | }
|
---|
116 | else if (actionName == "ProgManAddItem")
|
---|
117 | {
|
---|
118 | this->removeIcon(params[0], params[1]);
|
---|
119 | return true;
|
---|
120 | }
|
---|
121 | return false;
|
---|
122 | }
|
---|
123 |
|
---|
124 | bool gsProgramManager::connect()
|
---|
125 | {
|
---|
126 | HRESULT response;
|
---|
127 |
|
---|
128 | if (this->platform->isExplorerShell())
|
---|
129 | {
|
---|
130 | // Initialise the shell connection
|
---|
131 | response = CoInitialize(NULL);
|
---|
132 | if (response < 0)
|
---|
133 | {
|
---|
134 | return false;
|
---|
135 | }
|
---|
136 | }
|
---|
137 | else
|
---|
138 | {
|
---|
139 | FARPROC procPtr;
|
---|
140 |
|
---|
141 | procPtr = MakeProcInstance((FARPROC) DdeCallBack, app_instance);
|
---|
142 |
|
---|
143 | instance = 0L;
|
---|
144 | if (DdeInitialize(&instance, (PFNCALLBACK) procPtr, APPCMD_CLIENTONLY, 0L) != DMLERR_NO_ERROR)
|
---|
145 | {
|
---|
146 | MessageBox(0, "DDE failed to initialise", "GSInstall", MB_OK);
|
---|
147 | return false;
|
---|
148 | }
|
---|
149 | }
|
---|
150 | this->connected = true;
|
---|
151 | return true;
|
---|
152 | }
|
---|
153 |
|
---|
154 | bool gsProgramManager::disconnect()
|
---|
155 | {
|
---|
156 | if (this->connected)
|
---|
157 | {
|
---|
158 | if (this->platform->isExplorerShell())
|
---|
159 | {
|
---|
160 | CoUninitialize();
|
---|
161 | }
|
---|
162 | else
|
---|
163 | {
|
---|
164 | DdeUninitialize(instance);
|
---|
165 | }
|
---|
166 | }
|
---|
167 | this->connected = false;
|
---|
168 | return true;
|
---|
169 | }
|
---|
170 |
|
---|
171 | bool gsProgramManager::addProgramGroup(string groupName)
|
---|
172 | {
|
---|
173 | //CreateGroup(groupName);
|
---|
174 | char buffer[256];
|
---|
175 |
|
---|
176 | if (this->platform->isExplorerShell())
|
---|
177 | {
|
---|
178 | // add using shell controls
|
---|
179 | LPITEMIDLIST pidl;
|
---|
180 |
|
---|
181 | if (this->platform->isWindowsNT() && this->platform->isUserAdministrator())
|
---|
182 | {
|
---|
183 | #if defined (__GNUC__)
|
---|
184 | // this is a hack as windows port of gcc doesn't have CSIDL_COMMON_PROGRAMS defined
|
---|
185 | if (SHGetSpecialFolderLocation(0, CSIDL_PROGRAMS, &pidl) != NOERROR)
|
---|
186 | #else
|
---|
187 | if (SHGetSpecialFolderLocation(0, CSIDL_COMMON_PROGRAMS, &pidl) != NOERROR)
|
---|
188 | #endif
|
---|
189 | {
|
---|
190 | return false;
|
---|
191 | }
|
---|
192 | }
|
---|
193 | else
|
---|
194 | { if (SHGetSpecialFolderLocation(0, CSIDL_PROGRAMS, &pidl) != NOERROR)
|
---|
195 | {
|
---|
196 | return false;
|
---|
197 | }
|
---|
198 | }
|
---|
199 | SHGetPathFromIDList(pidl, buffer);
|
---|
200 |
|
---|
201 | // Create the folder as required
|
---|
202 | FilePath *path = new FilePath(buffer, groupName);
|
---|
203 | if (!CreateDirectory((char *) path->cString(), NULL))
|
---|
204 | {
|
---|
205 | // it probably existed already - if so skip it!
|
---|
206 | DWORD reason = GetLastError();
|
---|
207 | if (reason == ERROR_ALREADY_EXISTS)
|
---|
208 | { return true;
|
---|
209 | }
|
---|
210 | else
|
---|
211 | { return false;
|
---|
212 | }
|
---|
213 | }
|
---|
214 | delete path;
|
---|
215 | }
|
---|
216 | else
|
---|
217 | {
|
---|
218 | // add using program manager DDE
|
---|
219 | sprintf(buffer, "[CreateGroup (%s)]", groupName.c_str());
|
---|
220 | if (!DDEShellCommand(this->instance, buffer))
|
---|
221 | {
|
---|
222 | // flag error by returning false
|
---|
223 | MessageBox(0, "Couldn't create group", "Greenstone Installer", MB_OK);
|
---|
224 | return false;
|
---|
225 | }
|
---|
226 | }
|
---|
227 |
|
---|
228 | this->logAction("ProgManCreateGroup", groupName);
|
---|
229 | return true;
|
---|
230 | }
|
---|
231 |
|
---|
232 | bool gsProgramManager::addIcon(string groupName, // group of the icon
|
---|
233 | string iconName, // name of the icon
|
---|
234 | string iconDestination, // destination file of the icon
|
---|
235 | string arguments, // any arguments to go along with iconDestination
|
---|
236 | string description) // the textual description
|
---|
237 | // of the icon (not usually displayed)
|
---|
238 | {
|
---|
239 | bool reply = false;
|
---|
240 | char buffer[MAX_PATH];
|
---|
241 |
|
---|
242 | if (this->platform->isExplorerShell())
|
---|
243 | {
|
---|
244 | // create item using the shell
|
---|
245 | LPITEMIDLIST pidl;
|
---|
246 | HRESULT hres;
|
---|
247 | IShellLink* psl;
|
---|
248 | FilePath *fullPath;
|
---|
249 |
|
---|
250 | if (this->platform->isWindowsNT() && this->platform->isUserAdministrator())
|
---|
251 | {
|
---|
252 | #if defined (__GNUC__)
|
---|
253 | // this is a hack as windows port of gcc doesn't have CSIDL_COMMON_PROGRAMS defined
|
---|
254 | if (SHGetSpecialFolderLocation(0, CSIDL_PROGRAMS, &pidl) != NOERROR)
|
---|
255 | #else
|
---|
256 | if (SHGetSpecialFolderLocation(0, CSIDL_COMMON_PROGRAMS, &pidl) != NOERROR)
|
---|
257 | #endif
|
---|
258 |
|
---|
259 | {
|
---|
260 | return false;
|
---|
261 | }
|
---|
262 | }
|
---|
263 | else
|
---|
264 | {
|
---|
265 | if (SHGetSpecialFolderLocation(0, CSIDL_PROGRAMS, &pidl) != NOERROR)
|
---|
266 | {
|
---|
267 | return false;
|
---|
268 | }
|
---|
269 | }
|
---|
270 |
|
---|
271 | SHGetPathFromIDList(pidl, buffer);
|
---|
272 | fullPath = new FilePath(4, buffer, groupName.c_str(), iconName.c_str(), "!.lnk");
|
---|
273 |
|
---|
274 | // check if the shortcut already exists then don't create this again
|
---|
275 | if (fullPath->exists())
|
---|
276 | {
|
---|
277 | delete fullPath;
|
---|
278 | return true;
|
---|
279 | }
|
---|
280 |
|
---|
281 | // Get a pointer to the IShellLink interface.
|
---|
282 | hres = CoCreateInstance(CLSID_ShellLink, NULL,
|
---|
283 | CLSCTX_INPROC_SERVER, IID_IShellLink, (void **) &psl);
|
---|
284 | if (SUCCEEDED(hres))
|
---|
285 | {
|
---|
286 | IPersistFile* ppf;
|
---|
287 |
|
---|
288 | // Set the path to the shortcut target, and add the
|
---|
289 | // description.
|
---|
290 | psl->SetPath(iconDestination.c_str());
|
---|
291 | psl->SetArguments(arguments.c_str());
|
---|
292 | psl->SetDescription(description.c_str());
|
---|
293 |
|
---|
294 | // Query IShellLink for the IPersistFile interface for saving the
|
---|
295 | // shortcut in persistent storage.
|
---|
296 | hres = psl->QueryInterface(IID_IPersistFile, (void **) &ppf);
|
---|
297 |
|
---|
298 | if (SUCCEEDED(hres))
|
---|
299 | {
|
---|
300 | WCHAR wsz[MAX_PATH];
|
---|
301 |
|
---|
302 | // Ensure that the string is ANSI.
|
---|
303 | MultiByteToWideChar(CP_ACP, 0, fullPath->cString(), -1, wsz, MAX_PATH);
|
---|
304 |
|
---|
305 | // store the link in the "persistent" file
|
---|
306 | reply = (ppf->Save(wsz, TRUE) != E_FAIL);
|
---|
307 |
|
---|
308 | // release the persistent file handle
|
---|
309 | ppf->Release();
|
---|
310 | }
|
---|
311 | psl->Release();
|
---|
312 | }
|
---|
313 | delete fullPath;
|
---|
314 | }
|
---|
315 | else
|
---|
316 | {
|
---|
317 | // Back to the dark ages with win 3.1!
|
---|
318 |
|
---|
319 | // ensure that the requisite group is active; the add icon command will
|
---|
320 | // use the active group.
|
---|
321 | sprintf(buffer, "[ShowGroup(%s,5)]", groupName.c_str());
|
---|
322 | if (!DDEShellCommand(this->instance, buffer))
|
---|
323 | {
|
---|
324 | // TODO: articulate/determine possible errors; expand error handling
|
---|
325 | return false;
|
---|
326 | }
|
---|
327 |
|
---|
328 | // if the item is there already, mark it for replacement; this may fail,
|
---|
329 | // so we don't test for success
|
---|
330 | sprintf(buffer, "[ReplaceItem(%s)]", iconName.c_str());
|
---|
331 | DDEShellCommand(this->instance, buffer);
|
---|
332 |
|
---|
333 | // and now add the item itself to the active (given) group
|
---|
334 | sprintf(buffer, "[AddItem(%s,%s)]", iconDestination.c_str(), iconName.c_str());
|
---|
335 | if (!DDEShellCommand(this->instance, buffer))
|
---|
336 | {
|
---|
337 | // TODO: again work out what the problems could be
|
---|
338 | MessageBox(0, "Can't create item", "Greenstone Installer", MB_OK);
|
---|
339 | return false;
|
---|
340 | }
|
---|
341 | reply = true;
|
---|
342 | }
|
---|
343 |
|
---|
344 | if (reply)
|
---|
345 | {
|
---|
346 | this->logAction("ProgManAddItem", groupName, iconName, iconDestination);
|
---|
347 | }
|
---|
348 | return reply;
|
---|
349 | }
|
---|
350 |
|
---|
351 | bool gsProgramManager::removeProgramGroup(string groupName)
|
---|
352 | {
|
---|
353 | //CreateGroup(groupName);
|
---|
354 | char buffer[256];
|
---|
355 |
|
---|
356 | if (this->platform->isExplorerShell())
|
---|
357 | {
|
---|
358 | // add using shell controls
|
---|
359 | LPITEMIDLIST pidl;
|
---|
360 |
|
---|
361 | if (this->platform->isWindowsNT() && this->platform->isUserAdministrator())
|
---|
362 | {
|
---|
363 | #if defined (__GNUC__)
|
---|
364 | // this is a hack as windows port of gcc doesn't have CSIDL_COMMON_PROGRAMS defined
|
---|
365 | if (SHGetSpecialFolderLocation(0, CSIDL_PROGRAMS, &pidl) != NOERROR)
|
---|
366 | #else
|
---|
367 | if (SHGetSpecialFolderLocation(0, CSIDL_COMMON_PROGRAMS, &pidl) != NOERROR)
|
---|
368 | #endif
|
---|
369 | {
|
---|
370 | return false;
|
---|
371 | }
|
---|
372 | }
|
---|
373 | else
|
---|
374 | {
|
---|
375 | if (SHGetSpecialFolderLocation(0, CSIDL_PROGRAMS, &pidl) != NOERROR)
|
---|
376 | {
|
---|
377 | return false;
|
---|
378 | }
|
---|
379 | }
|
---|
380 | SHGetPathFromIDList(pidl, buffer);
|
---|
381 |
|
---|
382 | // Create the folder as required
|
---|
383 | FilePath *path = new FilePath(buffer, groupName);
|
---|
384 | if (!RemoveDirectory((char *) path->cString()))
|
---|
385 | {
|
---|
386 | // TODO: find cause of failure to remove
|
---|
387 | DWORD reason = GetLastError();
|
---|
388 | if (reason != 0)
|
---|
389 | {
|
---|
390 | return false;
|
---|
391 | }
|
---|
392 | }
|
---|
393 | }
|
---|
394 | else
|
---|
395 | {
|
---|
396 | // add using program manager DDE
|
---|
397 | sprintf(buffer, "[DeleteGroup (%s)]", groupName.c_str());
|
---|
398 | if (!DDEShellCommand(this->instance, buffer))
|
---|
399 | {
|
---|
400 | // flag error by returning false
|
---|
401 | return false;
|
---|
402 | }
|
---|
403 | }
|
---|
404 | return true;
|
---|
405 | }
|
---|
406 |
|
---|
407 | bool gsProgramManager::removeIcon(string groupName, // group of the icon
|
---|
408 | string iconName) // name of the icon
|
---|
409 | {
|
---|
410 | bool reply = false;
|
---|
411 | char buffer[MAX_PATH];
|
---|
412 |
|
---|
413 | if (this->platform->isExplorerShell())
|
---|
414 | {
|
---|
415 | // create item using the shell
|
---|
416 | LPITEMIDLIST pidl;
|
---|
417 | // HRESULT hres;
|
---|
418 | // IShellLink * psl;
|
---|
419 | FilePath * fullPath;
|
---|
420 |
|
---|
421 | // if the user is adminstrator, take the folder from the common programs folder
|
---|
422 | // (in the "All Users" profile)
|
---|
423 | if (this->platform->isWindowsNT() && this->platform->isUserAdministrator())
|
---|
424 | {
|
---|
425 | #if defined (__GNUC__)
|
---|
426 | // this is a hack as windows port of gcc doesn't have CSIDL_COMMON_PROGRAMS defined
|
---|
427 | if (SHGetSpecialFolderLocation(0, CSIDL_PROGRAMS, &pidl) != NOERROR)
|
---|
428 | #else
|
---|
429 | if (SHGetSpecialFolderLocation(0, CSIDL_COMMON_PROGRAMS, &pidl) != NOERROR)
|
---|
430 | #endif
|
---|
431 | {
|
---|
432 | return false;
|
---|
433 | }
|
---|
434 | }
|
---|
435 | // otherwise get it from the user's own programs folder in their profile
|
---|
436 | else
|
---|
437 | {
|
---|
438 | if (SHGetSpecialFolderLocation(0, CSIDL_PROGRAMS, &pidl) != NOERROR)
|
---|
439 | {
|
---|
440 | return false;
|
---|
441 | }
|
---|
442 | }
|
---|
443 |
|
---|
444 | // get path of folder from shell
|
---|
445 | SHGetPathFromIDList(pidl, buffer);
|
---|
446 |
|
---|
447 | // delete file
|
---|
448 | fullPath = new FilePath(4, buffer, groupName.c_str(), iconName.c_str(), "!.lnk");
|
---|
449 | if (!DeleteFile(fullPath->cString()))
|
---|
450 | { reply = false;
|
---|
451 | }
|
---|
452 | delete fullPath;
|
---|
453 | }
|
---|
454 | else
|
---|
455 | {
|
---|
456 | // Back to the dark ages with win 3.1!
|
---|
457 |
|
---|
458 | // ensure that the requisite group is active; the add icon command will
|
---|
459 | // use the active group.
|
---|
460 | sprintf(buffer, "[ShowGroup(%s,5)]", groupName.c_str());
|
---|
461 | if (!DDEShellCommand(this->instance, buffer))
|
---|
462 | {
|
---|
463 | // TODO: articulate/determine possible errors; expand error handling
|
---|
464 | return false;
|
---|
465 | }
|
---|
466 |
|
---|
467 | // and now add the item itself to the active (given) group
|
---|
468 | sprintf(buffer, "[DeleteItem(%s)]", iconName.c_str());
|
---|
469 | if (!DDEShellCommand(this->instance, buffer))
|
---|
470 | {
|
---|
471 | // TODO: again work out what the problems could be
|
---|
472 | return false;
|
---|
473 | }
|
---|
474 | }
|
---|
475 | return reply;
|
---|
476 | }
|
---|