windows-nt/Source/XPSP1/NT/termsrv/clcreator/putingrp/putingrp.c

834 lines
23 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1994 Microsoft Corporation
Module Name:
PutInGrp.C
Abstract:
Reads the command line to find a file spec (or wildcard spec) and a
program manager group name and then for each file in the current dir
that matches the file spec, creates a program item in the specified
group. If an error occurs and a program item cannot be created, then
the app returns non-zero (DOS ERRORLEVEL 1) otherwise 0 is returned if
all matching files are put into the group. The icon name used for the
program item is the filename (minus extension) of the file found.
Author:
Bob Watson (a-robw)
Revision History:
12 Jun 1994 Created
--*/
//
// System include files
//
#include <windows.h> // windows definitions
#include <tchar.h> // unicode data and function definitions
#include <stdio.h> // printf's etc.
#include <stdlib.h>
#include <ddeml.h> // DDEML interface definitions
#include "putingrp.h" // application definitions
//
// DDEML constants that depend on UNICODE/ANSI data format
//
#if _UNICODE
#define STRING_CODEPAGE CP_WINUNICODE
#define APP_TEXT_FORMAT CF_UNICODETEXT
#else
#define STRING_CODEPAGE CP_WINANSI
#define APP_TEXT_FORMAT CF_TEXT
#endif
//
// other application constants
//
// time to wait for a dde command to complete (10 sec.)
//
#define APP_DDE_TIMEOUT 10000
//
// Small buffer size used for general purpose temporary buffers
//
#define SMALL_BUFFER_SIZE 1024
//
// Large buffer size used for general purpose temporary buffers
//
#define BIG_BUFFER_SIZE (16 * SMALL_BUFFER_SIZE)
//
// number of times to retry a DDE command before giving up
//
#define APP_RETRY_COUNT 5
//
// number of buffers in GetStringResource function. These buffers
// are used sequentially to allow up to this many calls before a
// buffer is overwritten.
//
#define RES_STRING_BUFFER_COUNT 4
//
// time delay between DDE EXECUTE calls
// 500 = .5 sec
//
#define PAUSE_TIME 500
LPCTSTR
GetFileName (
IN LPCTSTR szFileName
)
/*++
Routine Description:
returns a buffer that contains the filename without the
period or extension. The filename returned has the
first character upper-cased and all other characters are
kept the same.
Arguments:
IN LPCTSTR szFileName
pointer to a filename string. This is assumed to be just
a filename with no path information.
Return Value:
pointer to a buffer containing the filename.
--*/
{
static TCHAR szReturnBuffer[MAX_PATH]; // buffer for result
LPCTSTR szSrc; // pointer into source string
LPTSTR szDest; // pointer into destination string
BOOL bFirst = TRUE; // used to tell when 1st char has been UC'd
szSrc = szFileName;
szDest = &szReturnBuffer[0];
*szDest = 0; // clear old contents
// go through source until end or "." whichever comes first.
while ((*szSrc != TEXT('.')) && (*szSrc != 0)) {
*szDest++ = *szSrc++;
// uppercase first letter
if (bFirst) {
*szDest = 0;
_tcsupr (&szReturnBuffer[0]);
bFirst = FALSE;
}
}
*szDest = 0;
return (LPCTSTR)szReturnBuffer;
}
LPCTSTR
GetStringResource (
IN UINT nId
)
/*++
Routine Description:
Used to load a string resource for this app so it can be used as a
string constant. NOTE the resulting string should be copied into
a local buffer since the contents of the buffer returned by this
routine may change in subsequent calls.
Arguments:
IN UINT nId
Resource ID to return.
Return Value:
pointer to string referenced by Resource ID value.
--*/
{
static TCHAR szStringBuffer[RES_STRING_BUFFER_COUNT][SMALL_BUFFER_SIZE];
static DWORD dwBufferNdx; // current buffer in use
LPTSTR szBuffer; // pointer to current buffer
int nLength; // length of string found
// select new buffer
dwBufferNdx++; // go to next index
dwBufferNdx %= RES_STRING_BUFFER_COUNT; // keep within bounds
szBuffer = &szStringBuffer[dwBufferNdx][0]; // set pointer
// get buffer
nLength = LoadString (
(HINSTANCE)GetModuleHandle(NULL),
nId,
szBuffer,
SMALL_BUFFER_SIZE);
// return pointer to buffer in use
return (LPCTSTR)szBuffer;
}
VOID
DisplayUsage (
VOID
)
{
UINT nString;
for (nString = APP_USAGE_START; nString <= APP_USAGE_END; nString++){
_tprintf (GetStringResource(nString));
}
}
BOOL
IsProgmanWindow (
IN HWND hWnd,
IN LPARAM lParam
)
/*++
Routine Description:
Function called by EnumWindows function to tell if the
Program Manger window has been found. A match is determined
by comparing the window caption (so it's not fool proof).
Arguments:
IN HWND hWnd
handle of window to test
IN LPARAM lParam
address of window handle variable to be loaded when program
manager window is found. set to NULL if this window is NOT
the Program Manager
Return Value:
TRUE if this is NOT the Program Manager window
FALSE if this IS the Program Manager window
(this is to accomodate the EnumWindows logic)
--*/
{
static TCHAR szWindowName[MAX_PATH]; // buffer to write this window's title
DWORD dwProgmanTitleLen; // length of "Program Manager"
LPTSTR szProgmanTitle; // pointer to title string
HWND *hwndReturn; // return window handle pointer
hwndReturn = (HWND *)lParam; // cast LPARAM to HWND *
if (hwndReturn != NULL) {
*hwndReturn = NULL; // initialize to NULL handle
}
if (IsWindow (hWnd)) {
// only check windows
//
// get title string to match against
szProgmanTitle = (LPTSTR)GetStringResource (APP_PROGMAN_TITLE);
dwProgmanTitleLen = lstrlen(szProgmanTitle);
//
// get title of this window
GetWindowText (hWnd, &szWindowName[0], MAX_PATH);
// check the length
if ((DWORD)lstrlen(&szWindowName[0]) < dwProgmanTitleLen) {
// this is too short to match
return TRUE; // not Program Manager, get next window
} else {
// make window name same length as program manager string
szWindowName[dwProgmanTitleLen] = 0;
// compare window name to match title string
if (lstrcmpi(&szWindowName[0], szProgmanTitle) == 0) {
// it's a match
if (hwndReturn != NULL) {
*hwndReturn = hWnd;
}
return FALSE; // found it so leave
} else {
return TRUE; // not this one, so keep going
}
}
} else {
return TRUE; // not this one, so keep going
}
}
BOOL
RestoreProgmanWindow (
VOID
)
/*++
Routine Description:
Activates and Restores the Program Manager window and makes it the
foreground app.
Arguments:
None
Return Value:
TRUE if window restored
FALSE if window not found
--*/
{
HWND hwndProgman;
// find progman and restore it
EnumWindows (IsProgmanWindow, (LPARAM)&hwndProgman);
if (IsWindow (hwndProgman)) {
// if iconic, then restore
if (IsIconic(hwndProgman)) {
ShowWindow (hwndProgman, SW_RESTORE);
}
// make the foreground app.
SetForegroundWindow (hwndProgman);
return TRUE;
} else {
return FALSE;
}
}
HDDEDATA CALLBACK
DdeCallback (
IN UINT wType,
IN UINT wFmt,
IN HCONV hConv,
IN HSZ hsz1,
IN HSZ hsz2,
IN HDDEDATA hData,
IN DWORD lData1,
IN DWORD lData2
)
/*++
Routine Description:
Generic Callback function required by DDEML calls
Arguments:
See WinHelp
Return Value:
See WinHelp
--*/
{
switch (wType) {
case XTYP_REGISTER:
case XTYP_UNREGISTER:
return (HDDEDATA)NULL;
case XTYP_ADVDATA:
// received when new data is available
return (HDDEDATA)DDE_FACK;
case XTYP_XACT_COMPLETE:
// received when an async transaction is complete
return (HDDEDATA)NULL;
case XTYP_DISCONNECT:
// connection termination has been requested
return (HDDEDATA)NULL;
default:
return (HDDEDATA)NULL;
}
}
HCONV
ConnectToProgman (
IN DWORD dwInst
)
/*++
Routine Description:
Establishes a DDE connection to the program manager's DDE
server.
Arguments:
IN DWORD dwInst
DDEML Instance as returned by DdeInitialize call
Return Value:
Handle to conversation if successful,
0 if not
--*/
{
HSZ hszProgman1;
HSZ hszProgman2;
HCONV hConversation;
CONVCONTEXT ccConversation;
// init conversation context buffer
ccConversation.cb = sizeof(CONVCONTEXT);
ccConversation.wFlags = 0;
ccConversation.wCountryID = 0;
ccConversation.iCodePage = 0;
ccConversation.dwLangID = 0L;
ccConversation.dwSecurity = 0L;
ccConversation.qos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
ccConversation.qos.ImpersonationLevel = SecurityImpersonation;
ccConversation.qos.ContextTrackingMode = SECURITY_STATIC_TRACKING;
ccConversation.qos.EffectiveOnly = TRUE;
// get server name
hszProgman1 = DdeCreateStringHandle (dwInst,
(LPTSTR)GetStringResource (APP_SERVER),
STRING_CODEPAGE);
if (hszProgman1 != 0) {
// get topic name
hszProgman2 = DdeCreateStringHandle (dwInst,
(LPTSTR)GetStringResource (APP_TOPIC),
STRING_CODEPAGE);
if (hszProgman2 != 0) {
// connect to server
hConversation = DdeConnect (
dwInst,
hszProgman1,
hszProgman2,
&ccConversation);
// free string handle
DdeFreeStringHandle (dwInst, hszProgman2);
}
// free string handle
DdeFreeStringHandle (dwInst, hszProgman1);
}
return hConversation; // return handle
}
BOOL
CreateAndShowGroup (
IN DWORD dwInst,
IN HCONV hConversation,
IN LPCTSTR szGroupName
)
/*++
Routine Description:
creates and activates the program manager group specified
in the argument list
Arguments:
IN DWORD dwInst
Instance ID returned from DdeInitialize
IN HCONV hConversation
Handle to the current DDE conversation
IN LPCTSTR szGroupName
Pointer to string containing name of program manager group to
create and/or activate
Return Value:
TRUE if operation succeeded
FALSE if not
--*/
{
LPTSTR szCmdBuffer; // DDE command string to send
LPTSTR szCmdFmt; // DDE command format for sprintf
DWORD dwCmdLength; // size of command string
BOOL bResult; // result of function calls
DWORD dwTransactionResult; // result of Command
// allocate temporary memory buffers
szCmdFmt = GlobalAlloc (GPTR, (SMALL_BUFFER_SIZE * sizeof(TCHAR)));
szCmdBuffer = GlobalAlloc (GPTR, (SMALL_BUFFER_SIZE * sizeof(TCHAR)));
if ((szCmdBuffer != NULL) &&
(szCmdFmt != NULL)) {
// get command format string
lstrcpy (szCmdFmt, GetStringResource(APP_CREATE_AND_SHOW_FMT));
// format command to include desired group name
dwCmdLength = _stprintf (szCmdBuffer, szCmdFmt, szGroupName) + 1;
dwCmdLength *= sizeof(TCHAR) ;
// create group or activate group if it already exists
// send command to server
Sleep (PAUSE_TIME);
bResult = DdeClientTransaction (
(LPBYTE)szCmdBuffer,
dwCmdLength,
hConversation,
0L,
APP_TEXT_FORMAT,
XTYP_EXECUTE,
APP_DDE_TIMEOUT,
&dwTransactionResult);
#if DEBUG_OUT
if (!bResult) {
_tprintf (GetStringResource (APP_DDE_EXECUTE_ERROR_FMT),
DdeGetLastError(dwInst),
szCmdBuffer);
}
#endif
// now activate the group
// get the command format string
lstrcpy (szCmdFmt, GetStringResource(APP_RESTORE_GROUP_FMT));
// create the command that includes the group name
dwCmdLength = _stprintf (szCmdBuffer, szCmdFmt, szGroupName) + 1;
dwCmdLength *= sizeof(TCHAR);
// send command to server
Sleep (PAUSE_TIME);
bResult = DdeClientTransaction (
(LPBYTE)szCmdBuffer,
dwCmdLength,
hConversation,
0L,
APP_TEXT_FORMAT,
XTYP_EXECUTE,
APP_DDE_TIMEOUT,
&dwTransactionResult);
#if DEBUG_OUT
if (!bResult) {
_tprintf (GetStringResource (APP_DDE_EXECUTE_ERROR_FMT),
DdeGetLastError(dwInst),
szCmdBuffer);
}
#endif
// free global memory buffers
GlobalFree (szCmdBuffer);
GlobalFree (szCmdFmt);
return bResult;
} else {
// unable to allocate memory buffers so return error
SetLastError (ERROR_OUTOFMEMORY);
return FALSE;
}
}
BOOL
LoadFilesToGroup (
IN DWORD dwInst,
IN HCONV hConversation,
IN LPCTSTR szFileSpec,
IN LPCTSTR szGroupName
)
/*++
Routine Description:
Searches the current directory for the file(s) that match the
fileSpec argument and creates program items the program
manager group specified by szGroupName.
Arguments:
IN DWORD dwInst
DDEML instance handle returned by DdeInitialize
IN HCONV hConversation
Handle to current conversation with DDE Server
IN LPCTSTR szFileSpec
file spec to look up for program items
IN LPCTSTR szGroupName
program manager group to add items to
Return Value:
TRUE if all items loaded successfully
FALSE of one or more items did not get installed in Program Manager
--*/
{
WIN32_FIND_DATA fdSearchData; // search data struct for file search
HANDLE hFileSearch; // file search handle
BOOL bSearchResult; // results of current file lookup
BOOL bResult; // function return
BOOL bReturn = TRUE; // value returned to calling fn.
LPTSTR szCmdBuffer; // buffer for one command
LPTSTR szCmdFmt; // command format buffer for sprintf
DWORD dwCmdLength; // length of command buffer
DWORD dwBufferUsed; // chars in DdeCmd that have been used
DWORD dwTransaction; // returned by DdeClientTransaction
DWORD dwTransactionResult; // result code
// Allocate global memory
szCmdBuffer = GlobalAlloc (GPTR, (SMALL_BUFFER_SIZE * sizeof(TCHAR)));
szCmdFmt = GlobalAlloc (GPTR, (SMALL_BUFFER_SIZE * sizeof(TCHAR)));
if ((szCmdBuffer != NULL) &&
(szCmdFmt != NULL)) {
// get single entry command format for sprintf
lstrcpy (szCmdFmt, GetStringResource(APP_ADD_PROGRAM_FMT));
// start file search
hFileSearch = FindFirstFile (szFileSpec, &fdSearchData);
if (hFileSearch != INVALID_HANDLE_VALUE) {
// file search initialized OK so start processing files
dwBufferUsed = 0;
bSearchResult = TRUE;
while (bSearchResult) {
// make sure it's a real file and not a dir or a
// temporary file
if (!((fdSearchData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
(fdSearchData.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY))) {
// make a command for this file
dwCmdLength = _stprintf (szCmdBuffer, szCmdFmt,
fdSearchData.cFileName,
GetFileName(fdSearchData.cFileName)) + 1;
dwCmdLength *= sizeof(TCHAR);
dwTransactionResult = 0;
Sleep (PAUSE_TIME);
dwTransaction = DdeClientTransaction (
(LPBYTE)szCmdBuffer,
dwCmdLength,
hConversation,
0L,
APP_TEXT_FORMAT,
XTYP_EXECUTE,
APP_DDE_TIMEOUT,
&dwTransactionResult);
if (dwTransaction > 0) {
_tprintf (GetStringResource (APP_ADD_SUCCESS_FMT),
fdSearchData.cFileName, szGroupName);
bResult = TRUE;
} else {
_tprintf (GetStringResource (APP_ADD_ERROR_FMT),
fdSearchData.cFileName, szGroupName);
bResult = FALSE;
}
if (!bResult) {
#if DEBUG_OUT
_tprintf (GetStringResource (APP_DDE_EXECUTE_ERROR_FMT),
DdeGetLastError(dwInst),
szDdeCmd);
#endif
// at least one entry didn't work so set return value
bReturn = FALSE;
}
}
// get next matching file
bSearchResult = FindNextFile (hFileSearch, &fdSearchData);
}
}
// free global memory
GlobalFree (szCmdBuffer);
GlobalFree (szCmdFmt);
return bReturn;
} else {
SetLastError (ERROR_OUTOFMEMORY);
return FALSE;
}
}
BOOL
SaveNewGroup (
IN DWORD dwInst,
IN HCONV hConversation,
IN LPCTSTR szGroupName
)
/*++
Routine Description:
Sends the Reload command to save and reload the new group. This will
save the information.
Arguments:
IN DWORD dwInst
DDEML instance handle returned by DdeInitialize
IN HCONV hConversation
Handle to current conversation with DDE Server
IN LPCTSTR szGroupName
program manager group to add items to
Return Value:
TRUE if successful
FALSE if not
--*/
{
LPTSTR szCmdBuffer; // DDE command string to send
LPTSTR szCmdFmt; // DDE command format for sprintf
DWORD dwCmdLength; // size of command string
BOOL bResult; // result of function calls
DWORD dwTransactionResult; // result of Command
// allocate temporary memory buffers
szCmdFmt = GlobalAlloc (GPTR, (SMALL_BUFFER_SIZE * sizeof(TCHAR)));
szCmdBuffer = GlobalAlloc (GPTR, (SMALL_BUFFER_SIZE * sizeof(TCHAR)));
if ((szCmdBuffer != NULL) &&
(szCmdFmt != NULL)) {
// get command format string
lstrcpy (szCmdFmt, GetStringResource(APP_RELOAD_GROUP_FMT));
// format command to include desired group name
dwCmdLength = _stprintf (szCmdBuffer, szCmdFmt, szGroupName) + 1;
dwCmdLength *= sizeof(TCHAR);
// create group or activate group if it already exists
// send command to server
Sleep (PAUSE_TIME);
bResult = DdeClientTransaction (
(LPBYTE)szCmdBuffer,
dwCmdLength,
hConversation,
0L,
APP_TEXT_FORMAT,
XTYP_EXECUTE,
APP_DDE_TIMEOUT,
&dwTransactionResult);
return bResult;
} else {
SetLastError (ERROR_OUTOFMEMORY);
return FALSE;
}
}
int
__cdecl main (
int argc,
char **argv
)
/*++
Routine Description:
Main entry point for command line
Arguments:
IN int argc
count of arguments passed in from command line
IN char *argv[]
array of pointers to each command line argument
argv[0] = this program'e .exe path
argv[1] = file(s) to put in group
argv[2] = group to create/load
Return Value:
0 if all files matching the path are successfully loaded into progman
non-zero if one or more files did not have a progman item created
--*/
{
DWORD dwInstId = 0; // DDEML Instance
UINT nReturn; // return value
BOOL bResult; // function return value
HCONV hConversation; // handle to DDE conversation
LPTSTR szFiles; // file path read from command line
LPTSTR szGroup; // group name read from command line
if (argc < 3) {
// check for correct command line arg count
DisplayUsage();
return ERROR_BAD_COMMAND;
}
// allocate buffers for command line arguments
szFiles = GlobalAlloc (GPTR, (strlen(argv[1]) + 1) * sizeof(TCHAR));
szGroup = GlobalAlloc (GPTR, (strlen(argv[2]) + 1) * sizeof(TCHAR));
if ((szFiles == NULL) || (szGroup == NULL)) {
return ERROR_OUTOFMEMORY;
}
// read in command line arguments using appropriate function
#if _UNICODE
mbstowcs (szFiles, argv[1], lstrlenA(argv[1]));
mbstowcs (szGroup, argv[2], lstrlenA(argv[2]));
#else
lstrcpyA (szFiles, argv[1]);
lstrcpyA (szGroup, argv[2]);
#endif
// make Program Manager window the foreground app and restore it's size
RestoreProgmanWindow ();
// begin DDEML session
nReturn = DdeInitialize (&dwInstId,
(PFNCALLBACK)DdeCallback,
APPCMD_CLIENTONLY,
0L);
if (nReturn == DMLERR_NO_ERROR) {
// connect to Program Manager DDE server
hConversation = ConnectToProgman (dwInstId);
if (hConversation != 0) {
bResult = DdeEnableCallback (dwInstId, hConversation,
EC_ENABLEALL);
// create program group
if (CreateAndShowGroup (dwInstId, hConversation, szGroup)) {
// load selected files into group
if (!LoadFilesToGroup (dwInstId, hConversation, szFiles, szGroup)) {
// 1 or more files did not get a program item
nReturn = ERROR_CAN_NOT_COMPLETE;
} else {
SaveNewGroup (dwInstId, hConversation, szGroup);
// all files were loaded into program manager successfully
nReturn = ERROR_SUCCESS;
}
// that's it so close conversation handle
DdeDisconnect (hConversation);
} else {
// unable to create program group
nReturn = ERROR_CAN_NOT_COMPLETE;
}
} else {
// unablet to establish conversation
nReturn = ERROR_CAN_NOT_COMPLETE;
}
// terminate DDEML session
if (!DdeUninitialize (dwInstId)) {
nReturn = ERROR_CAN_NOT_COMPLETE;
}
}
// free global buffers
GlobalFree (szFiles);
GlobalFree (szGroup);
// return value to command shell
return nReturn;
}