#include "gsProgman.h" #include // include shell for explorer-based OS'es #include // include dde for old (win 3.1/winNT 3.5) OS'es #include #include "FilePath.h" extern HINSTANCE app_instance; /** * A private function for Dde callbacks; in practice it needs to be here, * but does nothing whatsoever */ HDDEDATA CALLBACK DdeCallBack(UINT uType, // transaction type UINT uFmt, // clipboard data format HCONV hconv, // handle to the conversation HSZ hsz1, // handle to a string HSZ hsz2, // handle to a string HDDEDATA hdata, // handle to a global memory object DWORD dwData1, // transaction-specific data DWORD dwData2 // transaction-specific data ) { return NULL; } /** * A private little function to do DDE activity */ bool DDEShellCommand(DWORD instance, char *command) { HSZ serviceName; HCONV conversation; int commandLength; HDDEDATA ddeData; DWORD result; bool reply = false; // create DDE string from service request serviceName = DdeCreateStringHandle(instance, "PROGMAN", CP_WINANSI); if (serviceName == NULL) { /*char buffer[20]; sprintf(buffer, "%d %d", DdeGetLastError(instance), instance); MessageBox(0, buffer, "GSInstall", MB_OK);*/ return FALSE; } // strike up a conversation with the DDE service if ((conversation = DdeConnect(instance, serviceName, serviceName, NULL)) != NULL) { commandLength = lstrlen(command); // send the message via DDE // MessageBox(0, command, "Executing", MB_OK); ddeData = DdeClientTransaction((LPBYTE) command, commandLength + 1, conversation, NULL, CF_TEXT, XTYP_EXECUTE, 1000, &result); // if our reply isn't NULL, it succeeded reply = (ddeData != NULL); if (reply == false) { /* char buffer[20]; sprintf(buffer, "%d", DdeGetLastError(instance)); MessageBox(0, buffer, "DDE Error", MB_OK);*/ } // disconnect the conversation DdeDisconnect(conversation); } else { MessageBox(0, "DDE Connect failed", "GSInstall", MB_OK); } // free DDE string DdeFreeStringHandle(instance, serviceName); return reply; } gsProgramManager::gsProgramManager(installManager &manager) : installAgent(manager) { this->platform = new gsPlatform(); this->connected = false; } void gsProgramManager::logAction(string actionName, string group) { unInstallCommand command(actionName); command.addParameter(group); manager->storeCommand(command); } void gsProgramManager::logAction(string actionName, string group, string item, string parameter) { unInstallCommand command(actionName); command.addParameter(group); command.addParameter(item); command.addParameter(parameter); manager->storeCommand(command); } bool gsProgramManager::undoAction(string actionName, stringArray ¶ms) { if (actionName == "ProgManCreateGroup") { this->removeProgramGroup(params[0]); return true; } else if (actionName == "ProgManAddItem") { this->removeIcon(params[0], params[1]); return true; } return false; } bool gsProgramManager::connect() { HRESULT response; if (this->platform->isExplorerShell()) { // Initialise the shell connection response = CoInitialize(NULL); if (response < 0) { return false; } } else { FARPROC procPtr; procPtr = MakeProcInstance((FARPROC) DdeCallBack, app_instance); instance = 0L; if (DdeInitialize(&instance, (PFNCALLBACK) procPtr, APPCMD_CLIENTONLY, 0L) != DMLERR_NO_ERROR) { MessageBox(0, "DDE failed to initialise", "GSInstall", MB_OK); return false; } } this->connected = true; return true; } bool gsProgramManager::disconnect() { if (this->connected) { if (this->platform->isExplorerShell()) { CoUninitialize(); } else { DdeUninitialize(instance); } } this->connected = false; return true; } bool gsProgramManager::addProgramGroup(string groupName) { //CreateGroup(groupName); char buffer[256]; if (this->platform->isExplorerShell()) { // add using shell controls LPITEMIDLIST pidl; if (this->platform->isWindowsNT() && this->platform->isUserAdministrator()) { #if defined (__GNUC__) // this is a hack as windows port of gcc doesn't have CSIDL_COMMON_PROGRAMS defined if (SHGetSpecialFolderLocation(0, CSIDL_PROGRAMS, &pidl) != NOERROR) #else if (SHGetSpecialFolderLocation(0, CSIDL_COMMON_PROGRAMS, &pidl) != NOERROR) #endif { return false; } } else { if (SHGetSpecialFolderLocation(0, CSIDL_PROGRAMS, &pidl) != NOERROR) { return false; } } SHGetPathFromIDList(pidl, buffer); // Create the folder as required FilePath *path = new FilePath(buffer, groupName); if (!CreateDirectory((char *) path->cString(), NULL)) { // it probably existed already - if so skip it! DWORD reason = GetLastError(); if (reason == ERROR_ALREADY_EXISTS) { return true; } else { return false; } } delete path; } else { // add using program manager DDE sprintf(buffer, "[CreateGroup (%s)]", groupName.c_str()); if (!DDEShellCommand(this->instance, buffer)) { // flag error by returning false MessageBox(0, "Couldn't create group", "Greenstone Installer", MB_OK); return false; } } this->logAction("ProgManCreateGroup", groupName); return true; } bool gsProgramManager::addIcon(string groupName, // group of the icon string iconName, // name of the icon string iconDestination, // destination file of the icon string arguments, // any arguments to go along with iconDestination string description) // the textual description // of the icon (not usually displayed) { bool reply = false; char buffer[MAX_PATH]; if (this->platform->isExplorerShell()) { // create item using the shell LPITEMIDLIST pidl; HRESULT hres; IShellLink* psl; FilePath *fullPath; if (this->platform->isWindowsNT() && this->platform->isUserAdministrator()) { #if defined (__GNUC__) // this is a hack as windows port of gcc doesn't have CSIDL_COMMON_PROGRAMS defined if (SHGetSpecialFolderLocation(0, CSIDL_PROGRAMS, &pidl) != NOERROR) #else if (SHGetSpecialFolderLocation(0, CSIDL_COMMON_PROGRAMS, &pidl) != NOERROR) #endif { return false; } } else { if (SHGetSpecialFolderLocation(0, CSIDL_PROGRAMS, &pidl) != NOERROR) { return false; } } SHGetPathFromIDList(pidl, buffer); fullPath = new FilePath(4, buffer, groupName.c_str(), iconName.c_str(), "!.lnk"); // check if the shortcut already exists then don't create this again if (fullPath->exists()) { delete fullPath; return true; } // Get a pointer to the IShellLink interface. hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **) &psl); if (SUCCEEDED(hres)) { IPersistFile* ppf; // Set the path to the shortcut target, and add the // description. psl->SetPath(iconDestination.c_str()); psl->SetArguments(arguments.c_str()); psl->SetDescription(description.c_str()); // Query IShellLink for the IPersistFile interface for saving the // shortcut in persistent storage. hres = psl->QueryInterface(IID_IPersistFile, (void **) &ppf); if (SUCCEEDED(hres)) { WCHAR wsz[MAX_PATH]; // Ensure that the string is ANSI. MultiByteToWideChar(CP_ACP, 0, fullPath->cString(), -1, wsz, MAX_PATH); // store the link in the "persistent" file reply = (ppf->Save(wsz, TRUE) != E_FAIL); // release the persistent file handle ppf->Release(); } psl->Release(); } delete fullPath; } else { // Back to the dark ages with win 3.1! // ensure that the requisite group is active; the add icon command will // use the active group. sprintf(buffer, "[ShowGroup(%s,5)]", groupName.c_str()); if (!DDEShellCommand(this->instance, buffer)) { // TODO: articulate/determine possible errors; expand error handling return false; } // if the item is there already, mark it for replacement; this may fail, // so we don't test for success sprintf(buffer, "[ReplaceItem(%s)]", iconName.c_str()); DDEShellCommand(this->instance, buffer); // and now add the item itself to the active (given) group sprintf(buffer, "[AddItem(%s,%s)]", iconDestination.c_str(), iconName.c_str()); if (!DDEShellCommand(this->instance, buffer)) { // TODO: again work out what the problems could be MessageBox(0, "Can't create item", "Greenstone Installer", MB_OK); return false; } reply = true; } if (reply) { this->logAction("ProgManAddItem", groupName, iconName, iconDestination); } return reply; } bool gsProgramManager::removeProgramGroup(string groupName) { //CreateGroup(groupName); char buffer[256]; if (this->platform->isExplorerShell()) { // add using shell controls LPITEMIDLIST pidl; if (this->platform->isWindowsNT() && this->platform->isUserAdministrator()) { #if defined (__GNUC__) // this is a hack as windows port of gcc doesn't have CSIDL_COMMON_PROGRAMS defined if (SHGetSpecialFolderLocation(0, CSIDL_PROGRAMS, &pidl) != NOERROR) #else if (SHGetSpecialFolderLocation(0, CSIDL_COMMON_PROGRAMS, &pidl) != NOERROR) #endif { return false; } } else { if (SHGetSpecialFolderLocation(0, CSIDL_PROGRAMS, &pidl) != NOERROR) { return false; } } SHGetPathFromIDList(pidl, buffer); // Create the folder as required FilePath *path = new FilePath(buffer, groupName); if (!RemoveDirectory((char *) path->cString())) { // TODO: find cause of failure to remove DWORD reason = GetLastError(); if (reason != 0) { return false; } } } else { // add using program manager DDE sprintf(buffer, "[DeleteGroup (%s)]", groupName.c_str()); if (!DDEShellCommand(this->instance, buffer)) { // flag error by returning false return false; } } return true; } bool gsProgramManager::removeIcon(string groupName, // group of the icon string iconName) // name of the icon { bool reply = false; char buffer[MAX_PATH]; if (this->platform->isExplorerShell()) { // create item using the shell LPITEMIDLIST pidl; // HRESULT hres; // IShellLink * psl; FilePath * fullPath; // if the user is adminstrator, take the folder from the common programs folder // (in the "All Users" profile) if (this->platform->isWindowsNT() && this->platform->isUserAdministrator()) { #if defined (__GNUC__) // this is a hack as windows port of gcc doesn't have CSIDL_COMMON_PROGRAMS defined if (SHGetSpecialFolderLocation(0, CSIDL_PROGRAMS, &pidl) != NOERROR) #else if (SHGetSpecialFolderLocation(0, CSIDL_COMMON_PROGRAMS, &pidl) != NOERROR) #endif { return false; } } // otherwise get it from the user's own programs folder in their profile else { if (SHGetSpecialFolderLocation(0, CSIDL_PROGRAMS, &pidl) != NOERROR) { return false; } } // get path of folder from shell SHGetPathFromIDList(pidl, buffer); // delete file fullPath = new FilePath(4, buffer, groupName.c_str(), iconName.c_str(), "!.lnk"); if (!DeleteFile(fullPath->cString())) { reply = false; } delete fullPath; } else { // Back to the dark ages with win 3.1! // ensure that the requisite group is active; the add icon command will // use the active group. sprintf(buffer, "[ShowGroup(%s,5)]", groupName.c_str()); if (!DDEShellCommand(this->instance, buffer)) { // TODO: articulate/determine possible errors; expand error handling return false; } // and now add the item itself to the active (given) group sprintf(buffer, "[DeleteItem(%s)]", iconName.c_str()); if (!DDEShellCommand(this->instance, buffer)) { // TODO: again work out what the problems could be return false; } } return reply; }