|
|
/* File: progcm.c */ /**************************************************************************/ /* Install: Program Manager commands.
/* Uses DDE to communicate with ProgMan
/* Can create groups, delete groups, add items to groups
/* Originally written 3/9/89 by toddla (the stuff that looks terrible)
/* Munged greatly for STUFF 4/15/91 by chrispi (the stuff that doesn't work)
/**************************************************************************/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <cmnds.h>
#include <dde.h>
#include "install.h"
#include "uilstf.h"
#define BIG_ENUF 1024
_dt_system(Install) _dt_subsystem(ProgMan Operations)
HANDLE ExecuteApplication( LPSTR lpApp, WORD nCmdShow );
HWND hwndFrame; HWND hwndProgressGizmo;
CHAR szProgMan[] = "PROGMAN"; HWND hwndDde = NULL; // dummy window to handle DDE messages
HWND hwndProgMan = NULL; // global handle of progman window
BOOL fInitiate = fFalse; // are we initializing?
BOOL fAck = fFalse; BOOL fProgManExeced = fFalse; HANDLE hInstCur = NULL;
/*
** Purpose: ** Arguments: ** Returns: ** **************************************************************************/ _dt_private BOOL APIENTRY FDdeTerminate(VOID) { PreCondition(hwndProgMan != NULL, fFalse); PreCondition(hwndDde != NULL, fFalse);
SetForegroundWindow(hwndFrame); UpdateWindow(hwndFrame); MPostWM_DDE_TERMINATE( hwndProgMan, hwndDde ); hwndProgMan = NULL;
return(fTrue); }
/*
** Purpose: ** Arguments: ** Returns: ** **************************************************************************/ _dt_private LONG_PTR APIENTRY WndProcDde( HWND hwnd, UINT uiMessage, WPARAM wParam, LPARAM lParam ) { AssertDataSeg();
switch (uiMessage) {
case WM_DDE_TERMINATE:
if(hwndProgMan == NULL) { DestroyWindow(hwnd); hwndDde = NULL; } else { EvalAssert(FDdeTerminate()); }
DDEFREE( uiMessage, lParam ); return(0L);
case WM_DDE_ACK:
if (fInitiate) {
ATOM aApp = LOWORD(lParam); ATOM aTopic = HIWORD(lParam);
hwndProgMan = (HWND)wParam; //conversation established 1632
GlobalDeleteAtom (aApp); GlobalDeleteAtom (aTopic); }
else {
WORD wStatus = GET_WM_DDE_EXECACK_STATUS(wParam, lParam); HANDLE hCommands = GET_WM_DDE_EXECACK_HDATA(wParam, lParam); if (hCommands) { fAck = ((DDEACK *)(&wStatus))->fAck; GlobalFree(hCommands); }
DDEFREE( uiMessage, lParam ); }
return(0L);
default:
break;
}
return(DefWindowProc(hwnd, uiMessage, wParam, lParam)); }
/*
** Purpose: ** Arguments: ** Returns: ** **************************************************************************/ _dt_private BOOL APIENTRY FDdeInit( HANDLE hInst ) {
if (hInst == NULL) {
/* try to re-init with hInst from last FDdeInit call */
if (hInstCur == NULL) { return(fFalse); }
hInst = hInstCur; } else {
hInstCur = hInst;
}
if (hwndDde == NULL) {
static CHP szClassName[] = "ddeClass"; WNDCLASS rClass;
Assert(hwndProgMan == NULL);
if (!GetClassInfo(hInst, szClassName, &rClass)) { rClass.hCursor = NULL; rClass.hIcon = NULL; rClass.lpszMenuName = NULL; rClass.lpszClassName = szClassName; rClass.hbrBackground = NULL; rClass.hInstance = hInst; rClass.style = 0; rClass.lpfnWndProc = WndProcDde; rClass.cbClsExtra = 0; rClass.cbWndExtra = 0;
if (!RegisterClass(&rClass)) { return(fFalse); }
}
hwndDde = CreateWindow( szClassName, NULL, 0L, 0, 0, 0, 0, (HWND)NULL, (HMENU)NULL, (HANDLE)hInst, (LPSTR)NULL ); }
return(hwndDde != NULL); }
/*
** Purpose: ** Arguments: ** Returns: ** **************************************************************************/ _dt_private VOID APIENTRY DdeSendConnect( ATOM aApp, ATOM aTopic ) { fInitiate = fTrue; SendMessage( (HWND)-1, WM_DDE_INITIATE, (WPARAM)hwndDde, MAKELONG(aApp, aTopic) ); fInitiate = fFalse; }
/*
** Purpose: ** Arguments: ** Returns: ** **************************************************************************/ _dt_private BOOL APIENTRY FDdeConnect( SZ szApp, SZ szTopic ) { BOOL fStatus = fTrue; MSG rMsg; HANDLE hProcess = NULL;
//
// Form the Global Atoms used to indicate the app and topic
//
ATOM aApp = GlobalAddAtom(szApp); ATOM aTopic = GlobalAddAtom(szTopic);
//
// Connect to the progman dde server
//
DdeSendConnect(aApp, aTopic);
if (hwndProgMan == NULL) {
//
// If the connect failed then try to run progman.
//
if ((hProcess = ExecuteApplication("PROGMAN /NTSETUP", SW_SHOWNORMAL)) == NULL ) { fStatus = fFalse; } else { INT i; DWORD dw; #define TIMEOUT_INTERVAL 120000
//
// Indicate that Progman has been execed
//
fProgManExeced = fTrue;
//
// exec was successful, first wait for input idle
//
if( (dw = WaitForInputIdle( hProcess, TIMEOUT_INTERVAL )) != 0 ) { CloseHandle( hProcess ); fStatus = fFalse; } else { CloseHandle( hProcess );
//
// Empty the message queue till no messages
// are left in the queue or till WM_ACTIVATEAPP is processed. Then
// try connecting to progman. I am using PeekMessage followed
// by GetMessage because PeekMessage doesn't remove some messages
// ( WM_PAINT for one ).
//
while ( PeekMessage( &rMsg, hwndFrame, 0, 0, PM_NOREMOVE ) && GetMessage(&rMsg, NULL, 0, 0) ) {
if (TRUE && (hwndProgressGizmo == NULL || !IsDialogMessage(hwndProgressGizmo, &rMsg))) { TranslateMessage(&rMsg); DispatchMessage(&rMsg); }
if ( rMsg.message == WM_ACTIVATEAPP ) { break; }
} DdeSendConnect(aApp, aTopic); } } }
//
// Delete the atom resources
//
GlobalDeleteAtom(aApp); GlobalDeleteAtom(aTopic);
return ( fStatus ); }
/*
** Purpose: ** Arguments: ** Returns: ** **************************************************************************/ _dt_private BOOL APIENTRY FDdeWait(VOID) { MSG rMsg; BOOL fResult = fTrue; DWORD dwTimeOut, dwTickDelta, dwLastTick, dwCurrentTick;
Assert(hwndProgMan != NULL); Assert(hwndDde != NULL);
//
// Set timeout for 30 seconds from now. This assumes that it will
// take less than 30 seconds for Progman to respond.
//
dwTimeOut = 30000L; dwLastTick = GetTickCount();
while (TRUE) {
//
// While there is a connection established to progman and there
// are DDE messages we can fetch, fetch the messages dispatch them
// and try to find out if they are terminators (data, ack or terminate)
//
while ( hwndProgMan != NULL && PeekMessage(&rMsg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE) ) {
TranslateMessage(&rMsg); DispatchMessage(&rMsg);
if (rMsg.wParam == (WPARAM)hwndProgMan) { switch (rMsg.message) {
case WM_DDE_ACK: return ( fAck );
case WM_DDE_DATA: return (fTrue);
default: break; } } }
//
// If connection to progman has been broken, this may be resulting
// from a terminate, so return true
//
if (hwndProgMan == NULL) { return (fTrue); }
//
// Check to see if timeout hasn't been reached. If the timeout is
// reached we will assume that our command succeeded (for want of
// a better verification scheme
//
dwTickDelta = ((dwCurrentTick = GetTickCount()) < dwLastTick) ? dwCurrentTick : (dwCurrentTick - dwLastTick);
if (dwTimeOut < dwTickDelta) { return (fTrue); }
dwTimeOut = dwTimeOut - dwTickDelta; dwLastTick = dwCurrentTick;
//
// Lastly, since user doesn't have idle detection, we will be
// sitting in a tight loop here. To prevent this just do a
// sleep for 250 milliseconds.
//
Sleep( 250 );
}
return(fTrue); }
/*
** Purpose: ** Arguments: ** Returns: ** **************************************************************************/ _dt_private BOOL APIENTRY FDdeExec( SZ szCmd ) { BOOL bResult = fFalse; HANDLE hCmd;
Assert(hwndProgMan != NULL); Assert(hwndDde != NULL);
hCmd = GlobalAlloc(GMEM_DDESHARE, (LONG)CchpStrLen(szCmd) + 1); if (hCmd != NULL) {
LPSTR lpCmd = GlobalLock(hCmd);
if (lpCmd != NULL) { lstrcpy(lpCmd, szCmd); GlobalUnlock(hCmd); MPostWM_DDE_EXECUTE(hwndProgMan, hwndDde, hCmd); bResult = FDdeWait(); }
else { GlobalFree(hCmd); } }
return(bResult); }
/*
** Purpose: ** Arguments: ** Returns: ** **************************************************************************/ _dt_private BOOL APIENTRY FActivateProgMan(VOID) { //
// Find out if the dde client window has been started, if not start it
//
if (hwndDde == NULL) { if (!FDdeInit(NULL)) { return(fFalse); } Assert(hwndDde != NULL); }
//
// Find out if the connection has been established with the progman
// server, if not try to connect
//
if (hwndProgMan == NULL) { //
// Try to conncect and then see if we were successful
//
if ( (!FDdeConnect(szProgMan, szProgMan)) || (hwndProgMan == NULL) ) { return(fFalse); } }
//
// Bring progman to the foreground
//
SetForegroundWindow(hwndProgMan);
//
// If progman is iconic restore it
//
if (GetWindowLong(hwndProgMan, GWL_STYLE) & WS_ICONIC) { ShowWindow(hwndProgMan, SW_RESTORE); }
return(fTrue); }
/*
** Purpose: ** Creates a new Program Manager group. ** Arguments: ** Valid command options: ** cmoVital ** Notes: ** Initializes and activates the DDE communication if it is not ** currently open. ** Returns: ** fTrue if group was created, or already existed ** fFalse otherwise. ** **************************************************************************/ _dt_private BOOL APIENTRY FCreateProgManGroup( SZ szGroup, SZ szPath, CMO cmo, BOOL CommonGroup ) { static CHP szCmdBase[] = "[CreateGroup(%s%s%s,%s)]"; CCHP cchp; char szBuf[BIG_ENUF]; BOOL fVital = cmo & cmoVital; EERC eerc;
if (szPath == NULL) { szPath = ""; }
FActivateProgMan();
wsprintf(szBuf, szCmdBase, szGroup, (*szPath ? "," : szPath), szPath, CommonGroup ? "1" : "0");
FDdeExec(szBuf);
return(fTrue); }
/*
** Purpose: ** Removes a Program Manager group. ** Arguments: ** Valid command options: ** cmoVital ** Notes: ** Initializes and activates the DDE communication if it is not ** currently open. ** Returns: ** fTrue if successful if removed, or didn't exist ** fFalse otherwise. ** **************************************************************************/ _dt_private BOOL APIENTRY FRemoveProgManGroup( SZ szGroup, CMO cmo, BOOL CommonGroup ) { static CHP szCmdBase[] = "[DeleteGroup(%s,%s)]"; CCHP cchp; char szBuf[BIG_ENUF]; BOOL fVital = cmo & cmoVital; EERC eerc;
FActivateProgMan();
wsprintf(szBuf, szCmdBase, szGroup, CommonGroup ? "1" : "0");
FDdeExec(szBuf);
return(fTrue); }
/*
** Purpose: ** Shows a program manager group in one of several different ways ** based upon the parameter szCommand. ** Arguments: ** szGroup: non-NULL, non-empty group to show. ** szCommand: non-NULL, non-empty command to exec. ** cmo: Valid command options - cmoVital and cmoNone. ** Notes: ** Initializes and activates the DDE communication if it is not ** currently open. ** Returns: ** Returns fTrue if successful, fFalse otherwise. ** **************************************************************************/ _dt_private BOOL APIENTRY FShowProgManGroup( SZ szGroup, SZ szCommand, CMO cmo, BOOL CommonGroup ) { static CHP szCmdBase[] = "[ShowGroup(%s, %s,%s)]"; CCHP cchp; CHP szBuf[BIG_ENUF]; BOOL fVital = cmo & cmoVital; EERC eerc;
ChkArg((szGroup != (SZ)NULL) && (*szGroup != '\0'), 1, fFalse); ChkArg((szCommand != (SZ)NULL) && (*szCommand != '\0'), 2, fFalse);
FActivateProgMan();
wsprintf(szBuf, szCmdBase, szGroup, szCommand, CommonGroup ? "1" : "0");
FDdeExec(szBuf);
return(fTrue); }
/*
** Purpose: ** Creates a new Program Manager item. ** Always attempts to create the group if it doesn't exist. ** Arguments: ** Valid command options: ** cmoVital ** cmoOverwrite ** Notes: ** Initializes and activates the DDE communication if it is not ** currently open. ** Returns: ** Returns fTrue if successful, fFalse otherwise. ** **************************************************************************/ _dt_private BOOL APIENTRY FCreateProgManItem( SZ szGroup, SZ szItem, SZ szCmd, SZ szIconFile, INT nIconNum, CMO cmo, BOOL CommonGroup ) { static CHP szCmdBase[] = "[AddItem(%s, %s, %s, %d)]";
CCHP cchp; char szBuf[BIG_ENUF]; BOOL fVital = cmo & cmoVital; EERC eerc; BOOL bStatus;
FActivateProgMan();
wsprintf(szBuf, szCmdBase, szCmd, szItem, szIconFile, nIconNum+666);
bStatus = FDdeExec(szBuf);
return(bStatus); }
/*
** Purpose: ** Removes a program manager item. ** Arguments: ** Valid command options: ** cmoVital ** Returns: ** Returns fTrue if successful, fFalse otherwise. ** **************************************************************************/ _dt_private BOOL APIENTRY FRemoveProgManItem( SZ szGroup, SZ szItem, CMO cmo, BOOL CommonGroup ) { static CHP szCmdBase[] = "[DeleteItem(%s)]";
CCHP cchp; char szBuf[BIG_ENUF]; BOOL fVital = cmo & cmoVital; EERC eerc; BOOL bStatus;
FActivateProgMan();
FCreateProgManGroup(szGroup, NULL, cmoVital, CommonGroup);
wsprintf(szBuf, szCmdBase, szItem);
bStatus = FDdeExec(szBuf);
return(bStatus);
}
/*
** Purpose: ** Initializes the DDE window for communication with ProgMan ** Does not actually initiate a conversation with ProgMan ** Arguments: ** hInst instance handle for the setup application ** Returns: ** Returns fTrue if successful, fFalse otherwise. ** **************************************************************************/ _dt_private BOOL APIENTRY FInitProgManDde( HANDLE hInst ) { if (hwndDde == NULL) { return(FDdeInit(hInst)); }
return(fTrue); }
/*
** Purpose: ** Closes conversation with ProgMan (if any) and destroys ** the DDE communication window (if any) ** Arguments: ** (none) ** Returns: ** Returns fTrue if successful, fFalse otherwise. ** **************************************************************************/ _dt_private BOOL APIENTRY FEndProgManDde(VOID) {
//
// if we execed progman then we should try to close it down. When we
// send a close message it will post us a WM_DDE_TERMINATE message
// eventaully. else we haven't started progman so we just need to
// terminate the connection.
//
if (fProgManExeced) {
fProgManExeced = fFalse;
//
// Clean up connection to progman
//
if (hwndProgMan) { SetForegroundWindow(hwndFrame); UpdateWindow(hwndFrame); FDdeExec("[exitprogman(1)]"); // close save state
hwndProgMan = NULL; }
//
// Destroy the DDE Window if need be
//
if (hwndDde) { DestroyWindow(hwndDde); hwndDde = NULL; }
}
else if (hwndProgMan != NULL) { EvalAssert( FDdeTerminate() ); }
else if (hwndDde != NULL) { DestroyWindow (hwndDde); hwndDde = NULL; }
return (fTrue);
}
/*
** Purpose: ** Arguments: ** Returns: ** **************************************************************************/ HANDLE ExecuteApplication( LPSTR lpApp, WORD nCmdShow ) { BOOL fStatus; STARTUPINFO si; PROCESS_INFORMATION pi;
#if DBG
DWORD dwLastError; #endif
//
// Initialise Startup info
//
si.cb = sizeof(STARTUPINFO); si.lpReserved = NULL; si.lpDesktop = NULL; si.lpTitle = NULL; si.dwX = si.dwY = si.dwXSize = si.dwYSize = 0L; si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = nCmdShow; si.lpReserved2 = NULL; si.cbReserved2 = 0;
//
// Execute using Create Process
//
fStatus = CreateProcess( (LPSTR)NULL, // lpApplicationName
lpApp, // lpCommandLine
(LPSECURITY_ATTRIBUTES)NULL, // lpProcessAttributes
(LPSECURITY_ATTRIBUTES)NULL, // lpThreadAttributes
DETACHED_PROCESS, // dwCreationFlags
FALSE, // bInheritHandles
(LPVOID)NULL, // lpEnvironment
(LPSTR)NULL, // lpCurrentDirectory
(LPSTARTUPINFO)&si, // lpStartupInfo
(LPPROCESS_INFORMATION)&pi // lpProcessInformation
);
//
// Since we are execing a detached process we don't care about when it
// exits. To do proper book keeping, we should close the handles to
// the process handle and thread handle
//
if (fStatus) { CloseHandle( pi.hThread ); return( pi.hProcess ); } #if DBG
else { dwLastError = GetLastError(); } #endif
//
// Return the status of this operation
return ( (HANDLE)NULL ); }
|