|
|
/*++
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; }
|