Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

908 lines
22 KiB

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
progman.c
Abstract:
Routines to manipulate program groups and items.
Entry points:
CreateInitialProgmanItems
Author:
Ted Miller (tedm) 5-Apr-1995
Revision History:
Based on various other code that has been rewritten/modified
many times by many people.
--*/
#include "setupp.h"
#pragma hdrstop
#define DDEEXECUTE_TIMEOUT 20000
#define WAITINPUTIDLE_TIMEOUT 120000
#define TERMINATE_TIMEOUT 10000
//
// DDE App and Topic name.
//
PCWSTR szProgman = L"PROGMAN";
HCONV ProgmanConversation = NULL;
HWND ProgmanWindow = NULL;
HANDLE ProgmanProcess = NULL;
BOOL DdeInitialized = FALSE;
DWORD idDDEMLInst = 0;
BOOL
ExecuteDdeCommand(
IN PCWSTR Command
);
#define DDEDBG
#ifdef DDEDBG
#define DBGOUT(x) DbgOut x
VOID
DbgOut(
IN PCSTR FormatString,
...
)
{
CHAR Str[256];
va_list arglist;
wsprintfA(Str,"SETUP (%u): ",GetTickCount());
OutputDebugStringA(Str);
va_start(arglist,FormatString);
wvsprintfA(Str,FormatString,arglist);
va_end(arglist);
OutputDebugStringA(Str);
OutputDebugStringA("\n");
}
#else
#define DBGOUT(x)
#endif
HDDEDATA
CALLBACK
DdeCallback(
IN UINT wType,
IN UINT wFmt,
IN HCONV hConv,
IN HSZ hsz1,
IN HSZ hsz2,
IN HDDEDATA hData,
IN DWORD dwData1,
IN DWORD dwData2
)
{
UNREFERENCED_PARAMETER(wType);
UNREFERENCED_PARAMETER(wFmt);
UNREFERENCED_PARAMETER(hConv);
UNREFERENCED_PARAMETER(hsz1);
UNREFERENCED_PARAMETER(hsz2);
UNREFERENCED_PARAMETER(hData);
UNREFERENCED_PARAMETER(dwData1);
UNREFERENCED_PARAMETER(dwData2);
return(0);
}
BOOL
EndProgmanDde(
VOID
)
{
DWORD d;
DBGOUT(("EndProgmanDde: enter"));
if(ProgmanConversation) {
//
// Only send exit command if we actually executed progman
// with CreateProcess() (as opposed to the case where
// it was already running when we came along).
//
if(ProgmanProcess) {
DBGOUT(("EndProgmanDde: terminating progman..."));
//
// The exit command we send specifies to save state on exit.
//
ExecuteDdeCommand(L"[exitprogman(1)]");
//
// Wait for progman to die. Want to let everything get cleaned up
// before we enter another install section and attempt additional
// program group/item operations.
//
// Note that if the timeout fails, there's nothing meaningful we can do
// about it. We don't want Setup to hang.
//
d = WaitForSingleObject(ProgmanProcess,TERMINATE_TIMEOUT);
if(d != WAIT_OBJECT_0) {
DBGOUT((
"EndProgmanDde: problem waiting for progman to die, wait returned %u, last err = %u",
d,
GetLastError()
));
}
if(IsWindow(ProgmanWindow)) {
DBGOUT(("SETUP: Warning: progman process is dead but its window lives on"));
}
//
// Progman process is gone as far as we are concerned.
//
CloseHandle(ProgmanProcess);
ProgmanProcess = NULL;
} else {
//
// Just do a disconnect.
//
if(DdeDisconnect(ProgmanConversation)) {
DBGOUT(("EndProgmanDde: DdeDisconnect success"));
} else {
DBGOUT(("EndProgmanDde: DdeDisconnect failure (%lx)",DdeGetLastError(idDDEMLInst)));
}
}
//
// Conversation is ended.
//
ProgmanConversation = NULL;
} else {
DBGOUT(("EndProgmanDde: No conversation to end"));
}
//
// Forget the progman window handle.
//
ProgmanWindow = NULL;
//
// Uninitialize DDE.
//
if(DdeInitialized) {
if(DdeUninitialize(idDDEMLInst)) {
DBGOUT(("EndProgmanDde: DdeUninitialize success"));
} else {
DBGOUT(("EndProgmanDde: DdeUninitialize failure"));
}
idDDEMLInst = 0;
DdeInitialized = FALSE;
} else {
DBGOUT(("EndProgmanDde: Dde not intitialized"));
}
DBGOUT(("EndProgmanDde: exit success"));
return(TRUE);
}
BOOL
ActivateProgmanWorker(
VOID
)
/*++
Routine Description:
Perform a single DDE transaction, sending a dde command to progman.
Assumes that a valid conversation with progman exists.
Arguments:
Command - supplies the command to be sent to progman.
Return Value:
TRUE if the transaction succeeeded and was acknowledged by progman.
FALSE if not or if there is no valid conversation with progman.
--*/
{
HSZ hszApp;
HSZ hszTopic;
DWORD dw;
MSG rMsg;
CONVINFO ci;
STARTUPINFO si;
PROCESS_INFORMATION pi;
BOOL b;
DBGOUT(("ActivateProgman: Enter"));
//
// If dde has not been started, start it.
//
if(!DdeInitialized) {
DBGOUT(("ActivateProgman: DDE not started yet..."));
//
// We shouln't have a dde instance yet!
//
MYASSERT(idDDEMLInst == 0);
if((dw = DdeInitialize(&idDDEMLInst,DdeCallback,APPCMD_CLIENTONLY,0)) == DMLERR_NO_ERROR) {
DBGOUT(("ActivateProgman: DDE started successfully; DDEML id = %lx",idDDEMLInst));
DdeInitialized = TRUE;
//
// Since we just initialized DDE, there shouldn't be a conversation
// going on yet and we shouldn't have progman's process or window handle.
//
MYASSERT(ProgmanConversation == NULL);
MYASSERT(ProgmanProcess == NULL);
MYASSERT(ProgmanWindow == NULL);
} else {
DBGOUT(("ActivateProgman: error %u from DdeInitialize!",dw));
return(FALSE);
}
}
//
// Find out if a connection has already been established with progman.
// If not try to connect.
//
if(!ProgmanConversation) {
DBGOUT(("ActivateProgman: no conversation yet..."));
//
// If progman is already running in the system, we should be able to
// connect with it -- no need to call CreateProcess().
//
hszApp = DdeCreateStringHandle(idDDEMLInst,szProgman,0);
hszTopic = DdeCreateStringHandle(idDDEMLInst,szProgman,0);
ProgmanConversation = DdeConnect(idDDEMLInst,hszApp,hszTopic,NULL);
if(ProgmanConversation) {
DBGOUT(("ActivateProgman: first DdeConnect succeded"));
} else {
WCHAR wszProgman[] = L"PROGMAN /NTSETUP";
DBGOUT(("ActivateProgman: first DdeConnect failed (%lx); attempting to invoke progman",DdeGetLastError(idDDEMLInst)));
//
// Connect failed -- try to run progman.
// Initialize startup info and call CreateProcess().
//
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 = SW_SHOWNORMAL;
si.lpReserved2 = NULL;
si.cbReserved2 = 0;
b = CreateProcess(
NULL, // lpApplicationName
wszProgman, // lpCommandLine
NULL, // lpProcessAttributes
NULL, // lpThreadAttributes
DETACHED_PROCESS, // dwCreationFlags
FALSE, // bInheritHandles
NULL, // lpEnvironment
NULL, // lpCurrentDirectory
&si, // lpStartupInfo
&pi // lpProcessInformation
);
if(b) {
DBGOUT(("ActivateProgman: CreateProcess succeded"));
//
// Exec was successful.
// Close thread handle immediately and save process handle.
//
CloseHandle(pi.hThread);
ProgmanProcess = pi.hProcess;
if(dw = WaitForInputIdle(ProgmanProcess,WAITINPUTIDLE_TIMEOUT)) {
//
// Timeout or error. Close the process handle and forget it,
// so we don't try to clean it up when dde is terminated.
// The user will see an error, and retry should eventually get
// things going.
//
CloseHandle(ProgmanProcess);
ProgmanProcess = NULL;
DBGOUT(("ActivateProgman: WaitForInputIdle() timed out!"));
} else {
//
// 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,NULL,0,0,PM_NOREMOVE) && GetMessage(&rMsg,NULL,0,0)) {
TranslateMessage(&rMsg);
DispatchMessage(&rMsg);
if(rMsg.message == WM_ACTIVATEAPP) {
break;
}
}
//
// Now try to connect.
//
if(ProgmanConversation = DdeConnect(idDDEMLInst,hszApp,hszTopic,NULL)) {
DBGOUT(("ActivateProgman: second DdeConnect succeded"));
} else {
DBGOUT(("ActivateProgman: second DdeConnect failed (%lx)",DdeGetLastError(idDDEMLInst)));
}
}
} else {
DBGOUT(("ActivateProgman: CreateProcess failed (%u)",GetLastError()));
}
}
DdeFreeStringHandle(idDDEMLInst,hszApp);
DdeFreeStringHandle(idDDEMLInst,hszTopic);
//
// If we've connected, restore progman window if iconic and
// bring progman window to foreground.
//
if(ProgmanConversation) {
ci.cb = sizeof(CONVINFO);
if(ProgmanWindow = (DdeQueryConvInfo(ProgmanConversation,QID_SYNC,&ci) ? ci.hwndPartner : NULL)) {
DBGOUT(("ActivateProgman: Progman Window = %lx",ProgmanWindow));
if(IsIconic(ProgmanWindow)) {
ShowWindow(ProgmanWindow,SW_RESTORE);
}
SetForegroundWindow(ProgmanWindow);
} else {
DBGOUT(("ActivateProgman: unable to determine progman Window (%lx)",DdeGetLastError(idDDEMLInst)));
}
}
}
DBGOUT(("ActivateProgman: exit %s",ProgmanConversation ? "success" : "failure"));
return(ProgmanConversation != NULL);
}
BOOL
ActivateProgman(
VOID
)
{
//
// Try twice.
//
if(ActivateProgmanWorker()) {
return(TRUE);
} else {
Sleep(1000);
return(ActivateProgmanWorker());
}
}
BOOL
ExecuteDdeCommandWorker(
IN PCSTR Command
)
/*++
Routine Description:
Perform a single DDE transaction, sending a dde command to progman.
Assumes that a valid conversation with progman exists.
Arguments:
Command - supplies the command to be sent to progman.
Return Value:
TRUE if the transaction succeeeded and was acknowledged by progman.
FALSE if not or if there is no valid conversation with progman.
--*/
{
DWORD dwResult;
HDDEDATA hResult;
DBGOUT(("ExecuteDdeCommand: enter: %s",Command));
//
// Ensure that we have a valid conversation with progman.
//
if(!ProgmanConversation) {
DBGOUT(("ExecuteDdeCommand: exit -- no conversation!"));
return(FALSE);
}
//
// Send the command and process the result.
//
hResult = DdeClientTransaction(
(PSTR)Command,
lstrlenA(Command) + 1,
ProgmanConversation,
0,
0,
XTYP_EXECUTE,
DDEEXECUTE_TIMEOUT,
&dwResult
);
if(hResult) {
DBGOUT(("ExecuteDdeCommand: DdeClientTransaction succeeded, result=%lx",dwResult));
} else {
DBGOUT(("ExecuteDdeCommand: DdeClientTransaction failed (%lx)",DdeGetLastError(idDDEMLInst)));
}
DBGOUT((
"ExecuteDdeCommand: exit %s",
(hResult ? ((dwResult & DDE_FACK) != 0) : FALSE) ? "success" : "failure"
));
return(hResult ? ((dwResult & DDE_FACK) != 0) : FALSE);
}
BOOL
ExecuteDdeCommand(
IN PCWSTR Command
)
{
PCSTR AnsiCommand;
BOOL b;
b = FALSE;
AnsiCommand = UnicodeToAnsi(Command);
if(AnsiCommand) {
//
// Try twice.
//
b = ExecuteDdeCommandWorker(AnsiCommand);
if(!b) {
Sleep(250);
b = ExecuteDdeCommandWorker(AnsiCommand);
}
MyFree(AnsiCommand);
}
if(!b) {
LogItem0(LogSevWarning,MSG_LOG_PROGMAN_DDEFAIL,Command);
}
return(b);
}
BOOL
CreateProgmanGroup(
IN PCWSTR Group,
IN PCWSTR Path, OPTIONAL
IN BOOL CommonGroup
)
{
PCWSTR CmdBase = L"[CreateGroup(%s%s%s,%s)]";
PWSTR Command;
BOOL b;
b = FALSE;
if(Path == NULL) {
Path = L"";
}
if(!ActivateProgman()) {
LogItem2(
LogSevError,
MSG_LOG_PROGMAN_CREATGRP_FAIL,
Group,
MSG_LOG_ACTIVATEPROGMAN
);
goto err0;
}
Command = MyMalloc((lstrlen(CmdBase)+lstrlen(Group)+lstrlen(Path))*sizeof(WCHAR));
if(!Command) {
LogItem2(
LogSevError,
MSG_LOG_PROGMAN_CREATGRP_FAIL,
Group,
MSG_LOG_OUTOFMEMORY
);
goto err0;
}
wsprintf(
Command,
CmdBase,
Group,
*Path ? L"," : Path,
Path,
CommonGroup ? L"1" : L"0"
);
b = ExecuteDdeCommand(Command);
MyFree(Command);
err0:
return(b);
}
BOOL
RemoveProgmanGroup(
IN PCWSTR Group,
IN BOOL CommonGroup
)
{
PCWSTR CmdBase = L"[DeleteGroup(%s,%s)]";
BOOL b;
PWSTR Command;
b = FALSE;
if(!ActivateProgman()) {
LogItem2(
LogSevError,
MSG_LOG_PROGMAN_REMGRP_FAIL,
Group,
MSG_LOG_ACTIVATEPROGMAN
);
goto err0;
}
Command = MyMalloc((lstrlen(CmdBase)+lstrlen(Group))*sizeof(WCHAR));
if(!Command) {
LogItem2(
LogSevError,
MSG_LOG_PROGMAN_REMGRP_FAIL,
Group,
MSG_LOG_OUTOFMEMORY
);
goto err0;
}
wsprintf(Command,CmdBase,Group,CommonGroup ? "1" : "0");
b = ExecuteDdeCommand(Command);
MyFree(Command);
err0:
return(b);
}
BOOL
ShowProgmanGroup(
IN PCWSTR Group,
IN UINT ShowCommand,
IN BOOL CommonGroup
)
{
PCWSTR CmdBase = L"[ShowGroup(%s, %s,%s)]";
PWSTR Command;
BOOL b;
WCHAR showCommand[24];
b = FALSE;
if(!ActivateProgman()) {
LogItem2(
LogSevError,
MSG_LOG_PROGMAN_SHOWGRP_FAIL,
Group,
MSG_LOG_ACTIVATEPROGMAN
);
goto err0;
}
wsprintf(showCommand,L"%u",ShowCommand);
Command = MyMalloc((lstrlen(CmdBase)+lstrlen(Group)+lstrlen(showCommand))*sizeof(WCHAR));
if(!Command) {
LogItem2(
LogSevError,
MSG_LOG_PROGMAN_SHOWGRP_FAIL,
Group,
MSG_LOG_OUTOFMEMORY
);
goto err0;
}
wsprintf(Command,CmdBase,Group,showCommand,CommonGroup ? L"1" : L"0");
b = ExecuteDdeCommand(Command);
MyFree(Command);
err0:
return(b);
}
BOOL
CreateProgmanItem(
IN PCWSTR Group,
IN PCWSTR Item,
IN PCWSTR Cmd,
IN PCWSTR IconFile,
IN INT IconNum,
IN BOOL CommonGroup,
IN BOOL CreateGroupFirst
)
{
PCWSTR CmdBase = L"[AddItem(%s, %s, %s, %d)]";
UINT Size;
PWSTR Command;
BOOL b;
//
// Create the group first if necessary.
//
if(CreateGroupFirst) {
if(!CreateProgmanGroup(Group,NULL,CommonGroup)) {
return(FALSE);
}
} else {
if(!ActivateProgman()) {
LogItem3(
LogSevError,
MSG_LOG_PROGMAN_CREATITEM_FAIL,
Group,
Item,
MSG_LOG_ACTIVATEPROGMAN
);
return(FALSE);
}
}
b = FALSE;
Size = (lstrlen(CmdBase) + lstrlen(Item) + lstrlen(Cmd) + lstrlen(IconFile) + 20) * sizeof(WCHAR);
Command = MyMalloc(Size);
if(!Command) {
LogItem3(
LogSevError,
MSG_LOG_PROGMAN_CREATITEM_FAIL,
Group,
Item,
MSG_LOG_OUTOFMEMORY
);
goto err0;
}
wsprintf(Command,CmdBase,Cmd,Item,IconFile,IconNum+666);
b = ExecuteDdeCommand(Command);
MyFree(Command);
err0:
return(b);
}
BOOL
RemoveProgmanItem(
IN PCWSTR Group,
IN PCWSTR Item,
IN BOOL CommonGroup
)
{
PCWSTR CmdBase = L"[DeleteItem(%s)]";
PWSTR Command;
BOOL b;
//
// Create the group first.
//
if(!CreateProgmanGroup(Group,NULL,CommonGroup)) {
return(FALSE);
}
b = FALSE;
Command = MyMalloc((lstrlen(CmdBase)+lstrlen(Item))*sizeof(WCHAR));
if(!Command) {
LogItem3(
LogSevError,
MSG_LOG_PROGMAN_REMITEM_FAIL,
Group,
Item,
MSG_LOG_OUTOFMEMORY
);
goto err0;
}
wsprintf(Command,CmdBase,Item);
b = ExecuteDdeCommand(Command);
MyFree(Command);
err0:
return(b);
}
BOOL
AddItemsToProgmanGroup(
IN HINF InfHandle,
IN PCWSTR GroupDescription,
IN PCWSTR SectionName,
IN BOOL Upgrade
)
{
INFCONTEXT InfContext;
UINT LineCount,LineNo;
PCWSTR Description;
PCWSTR Binary;
PCWSTR CommandLine;
PCWSTR IconFile;
PCWSTR IconNumberStr;
PCWSTR UpgradeStr;
INT IconNumber;
BOOL b;
BOOL DoItem;
WCHAR Dummy;
PWSTR FilePart;
//
// Get the number of lines in the section. The section may be empty
// or non-existant; this is not an error condition.
//
LineCount = (UINT)SetupGetLineCount(InfHandle,SectionName);
if((LONG)LineCount <= 0) {
return(TRUE);
}
b = TRUE;
for(LineNo=0; LineNo<LineCount; LineNo++) {
if(SetupGetLineByIndex(InfHandle,SectionName,LineNo,&InfContext)) {
Description = pSetupGetField(&InfContext,0);
Binary = pSetupGetField(&InfContext,1);
CommandLine = pSetupGetField(&InfContext,2);
IconFile = pSetupGetField(&InfContext,3);
IconNumberStr = pSetupGetField(&InfContext,4);
UpgradeStr = pSetupGetField(&InfContext,5);
if(Description && CommandLine && (!Upgrade || (UpgradeStr && _wtoi(UpgradeStr)))) {
if(!IconFile) {
IconFile = L"";
}
IconNumber = (IconNumberStr && *IconNumberStr) ? wcstoul(IconNumberStr,NULL,10) : 0;
//
// If there's a binary name, search for it. Otherwise do the
// item add unconditionally.
//
DoItem = (Binary && *Binary)
? (SearchPath(NULL,Binary,NULL,0,&Dummy,&FilePart) != 0)
: TRUE;
if(DoItem) {
//
// Remove the item first in upgrade case or else we get 2 copies.
//
if(Upgrade) {
b = b && RemoveProgmanItem(GroupDescription,Description,FALSE);
}
b = b && CreateProgmanItem(
GroupDescription,
Description,
CommandLine,
IconFile,
IconNumber,
FALSE,
FALSE
);
}
}
}
}
return(b);
}
BOOL
DoProgmanItems(
IN HINF InfHandle,
IN BOOL Upgrade
)
{
INFCONTEXT InfContext;
PCWSTR GroupId,GroupDescription;
PCWSTR MainGroupDescription;
BOOL b;
//
// Iterate the [ProgramGroups] section in the inf.
// Each line is the name of a group that needs to be created.
//
if(SetupFindFirstLine(InfHandle,L"ProgramGroups",NULL,&InfContext)) {
b = TRUE;
} else {
return(FALSE);
}
MainGroupDescription = NULL;
do {
//
// Fetch the identifier for the group and its name.
//
if((GroupId = pSetupGetField(&InfContext,0))
&& (GroupDescription = pSetupGetField(&InfContext,1))) {
//
// Track the description for the 'main' group.
//
if(!Upgrade && !MainGroupDescription && !lstrcmpi(GroupId,L"Main")) {
MainGroupDescription = GroupDescription;
}
//
// Create and show the group.
//
b = b && CreateProgmanGroup(GroupDescription,NULL,FALSE);
b = b && ShowProgmanGroup(GroupDescription,SW_NORMAL,FALSE);
//
// Now create items within the group. We do this by iterating
// through the section in the inf that relate to the current group.
//
b = b && AddItemsToProgmanGroup(InfHandle,GroupDescription,GroupId,Upgrade);
//
// Minimize the group.
//
if(!Upgrade) {
b = b && ShowProgmanGroup(GroupDescription,SW_MINIMIZE,FALSE);
}
}
} while(SetupFindNextLine(&InfContext,&InfContext));
//
// Restore the "Main" group's window.
//
if(!Upgrade && MainGroupDescription) {
b = b && ShowProgmanGroup(MainGroupDescription,SW_SHOWNOACTIVATE,FALSE);
}
//
// Done with progman for now.
//
EndProgmanDde();
PumpMessageQueue();
return(TRUE);
}
BOOL
CreateProgmanItems(
IN HINF InfHandle
)
{
return(DoProgmanItems(InfHandle,FALSE));
}
BOOL
UpgradeProgmanItems(
IN HINF InfHandle
)
{
return(DoProgmanItems(InfHandle,TRUE));
}