source: trunk/gsinstaller/gsProgman.cpp@ 1580

Last change on this file since 1580 was 1580, checked in by cs025, 24 years ago

Fixed fault in detection of success in adding items.
This resulted in the failure to log such actions.

  • Property svn:keywords set to Author Date Id Revision
File size: 11.6 KB
Line 
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
12extern 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 */
18HDDEDATA 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 */
34bool 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
86gsProgramManager::gsProgramManager(installManager &manager)
87 : installAgent(manager)
88{
89 this->platform = new gsPlatform();
90 this->connected = false;
91}
92
93void gsProgramManager::logAction(string actionName, string group)
94{
95 unInstallCommand command(actionName);
96 command.addParameter(group);
97 manager->storeCommand(command);
98}
99
100void 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
109bool gsProgramManager::undoAction(string actionName, stringArray &params)
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
124bool 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
154bool 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
171bool 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->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 {
195 if (SHGetSpecialFolderLocation(0, CSIDL_PROGRAMS, &pidl) != NOERROR)
196 {
197 return false;
198 }
199 }
200 SHGetPathFromIDList(pidl, buffer);
201
202 // Create the folder as required
203 FilePath *path = new FilePath(buffer, groupName);
204 if (!CreateDirectory((char *) path->cString(), NULL))
205 {
206 // it probably existed already - if so skip it!
207 DWORD reason = GetLastError();
208 if (reason == ERROR_ALREADY_EXISTS)
209 { return true;
210 }
211 else
212 { return false;
213 }
214 }
215 delete path;
216 }
217 else
218 {
219 // add using program manager DDE
220 sprintf(buffer, "[CreateGroup (%s)]", groupName.c_str());
221 if (!DDEShellCommand(this->instance, buffer))
222 {
223 // flag error by returning false
224 return false;
225 }
226 }
227
228 this->logAction("ProgManCreateGroup", groupName);
229 return true;
230}
231
232bool 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 description) // the textual description
236 // of the icon (not usually displayed)
237{
238 bool reply = false;
239 char buffer[MAX_PATH];
240
241 if (this->platform->isExplorerShell())
242 {
243 // create item using the shell
244 LPITEMIDLIST pidl;
245 HRESULT hres;
246 IShellLink* psl;
247 FilePath *fullPath;
248
249 if (this->platform->isUserAdministrator())
250 {
251#if defined (__GNUC__)
252 // this is a hack as windows port of gcc doesn't have CSIDL_COMMON_PROGRAMS defined
253 if (SHGetSpecialFolderLocation(0, CSIDL_PROGRAMS, &pidl) != NOERROR)
254#else
255 if (SHGetSpecialFolderLocation(0, CSIDL_COMMON_PROGRAMS, &pidl) != NOERROR)
256#endif
257
258 {
259 return false;
260 }
261 }
262 else
263 {
264 if (SHGetSpecialFolderLocation(0, CSIDL_PROGRAMS, &pidl) != NOERROR)
265 {
266 return false;
267 }
268 }
269
270 SHGetPathFromIDList(pidl, buffer);
271 fullPath = new FilePath(4, buffer, groupName.c_str(), iconName.c_str(), "!.lnk");
272
273 // check if the shortcut already exists then don't create this again
274 if (fullPath->exists())
275 {
276 delete fullPath;
277 return true;
278 }
279
280 // Get a pointer to the IShellLink interface.
281 hres = CoCreateInstance(CLSID_ShellLink, NULL,
282 CLSCTX_INPROC_SERVER, IID_IShellLink, (void **) &psl);
283 if (SUCCEEDED(hres))
284 {
285 IPersistFile* ppf;
286
287 // Set the path to the shortcut target, and add the
288 // description.
289 psl->SetPath(iconDestination.c_str());
290
291 psl->SetDescription(description.c_str());
292
293 // Query IShellLink for the IPersistFile interface for saving the
294 // shortcut in persistent storage.
295 hres = psl->QueryInterface(IID_IPersistFile, (void **) &ppf);
296
297 if (SUCCEEDED(hres))
298 {
299 WCHAR wsz[MAX_PATH];
300
301 // Ensure that the string is ANSI.
302 MultiByteToWideChar(CP_ACP, 0, fullPath->cString(), -1, wsz, MAX_PATH);
303
304 // store the link in the "persistent" file
305 reply = (ppf->Save(wsz, TRUE) != E_FAIL);
306
307 // release the persistent file handle
308 ppf->Release();
309 }
310 psl->Release();
311 }
312 delete fullPath;
313 }
314 else
315 {
316 // Back to the dark ages with win 3.1!
317
318 // ensure that the requisite group is active; the add icon command will
319 // use the active group.
320 sprintf(buffer, "[ShowGroup(%s,5)]", groupName.c_str());
321 if (!DDEShellCommand(this->instance, buffer))
322 {
323 // TODO: articulate/determine possible errors; expand error handling
324 return false;
325 }
326
327 // and now add the item itself to the active (given) group
328 sprintf(buffer, "[AddItem(%s,%s)]", iconDestination.c_str(), iconName.c_str());
329 if (!DDEShellCommand(this->instance, buffer))
330 {
331 // TODO: again work out what the problems could be
332 return false;
333 }
334 reply = true;
335 }
336
337 if (reply)
338 {
339 this->logAction("ProgManAddItem", groupName, iconName, iconDestination);
340 }
341 return reply;
342}
343
344bool gsProgramManager::removeProgramGroup(string groupName)
345{
346 //CreateGroup(groupName);
347 char buffer[256];
348
349 if (this->platform->isExplorerShell())
350 {
351 // add using shell controls
352 LPITEMIDLIST pidl;
353
354 if (this->platform->isUserAdministrator())
355 {
356#if defined (__GNUC__)
357 // this is a hack as windows port of gcc doesn't have CSIDL_COMMON_PROGRAMS defined
358 if (SHGetSpecialFolderLocation(0, CSIDL_PROGRAMS, &pidl) != NOERROR)
359#else
360 if (SHGetSpecialFolderLocation(0, CSIDL_COMMON_PROGRAMS, &pidl) != NOERROR)
361#endif
362 {
363 return false;
364 }
365 }
366 else
367 {
368 if (SHGetSpecialFolderLocation(0, CSIDL_PROGRAMS, &pidl) != NOERROR)
369 {
370 return false;
371 }
372 }
373 SHGetPathFromIDList(pidl, buffer);
374
375 // Create the folder as required
376 FilePath *path = new FilePath(buffer, groupName);
377 if (!RemoveDirectory((char *) path->cString()))
378 {
379 // TODO: find cause of failure to remove
380 DWORD reason = GetLastError();
381 if (reason != 0)
382 {
383 return false;
384 }
385 }
386 }
387 else
388 {
389 // add using program manager DDE
390 sprintf(buffer, "[DeleteGroup (%s)]", groupName.c_str());
391 if (!DDEShellCommand(this->instance, buffer))
392 {
393 // flag error by returning false
394 return false;
395 }
396 }
397 return true;
398}
399
400bool gsProgramManager::removeIcon(string groupName, // group of the icon
401 string iconName) // name of the icon
402{
403 bool reply = false;
404 char buffer[MAX_PATH];
405
406 if (this->platform->isExplorerShell())
407 {
408 // create item using the shell
409 LPITEMIDLIST pidl;
410 // HRESULT hres;
411 // IShellLink * psl;
412 FilePath * fullPath;
413
414 // if the user is adminstrator, take the folder from the common programs folder
415 // (in the "All Users" profile)
416 if (this->platform->isUserAdministrator())
417 {
418#if defined (__GNUC__)
419 // this is a hack as windows port of gcc doesn't have CSIDL_COMMON_PROGRAMS defined
420 if (SHGetSpecialFolderLocation(0, CSIDL_PROGRAMS, &pidl) != NOERROR)
421#else
422 if (SHGetSpecialFolderLocation(0, CSIDL_COMMON_PROGRAMS, &pidl) != NOERROR)
423#endif
424 {
425 return false;
426 }
427 }
428 // otherwise get it from the user's own programs folder in their profile
429 else
430 {
431 if (SHGetSpecialFolderLocation(0, CSIDL_PROGRAMS, &pidl) != NOERROR)
432 {
433 return false;
434 }
435 }
436
437 // get path of folder from shell
438 SHGetPathFromIDList(pidl, buffer);
439
440 // delete file
441 fullPath = new FilePath(4, buffer, groupName.c_str(), iconName.c_str(), "!.lnk");
442 if (!DeleteFile(fullPath->cString()))
443 { reply = false;
444 }
445 delete fullPath;
446 }
447 else
448 {
449 // Back to the dark ages with win 3.1!
450
451 // ensure that the requisite group is active; the add icon command will
452 // use the active group.
453 sprintf(buffer, "[ShowGroup(%s,5)]", groupName.c_str());
454 if (!DDEShellCommand(this->instance, buffer))
455 {
456 // TODO: articulate/determine possible errors; expand error handling
457 return false;
458 }
459
460 // and now add the item itself to the active (given) group
461 sprintf(buffer, "[DeleteItem(%s)]", iconName.c_str());
462 if (!DDEShellCommand(this->instance, buffer))
463 {
464 // TODO: again work out what the problems could be
465 return false;
466 }
467 }
468 return reply;
469}
Note: See TracBrowser for help on using the repository browser.