home *** CD-ROM | disk | FTP | other *** search
- /* AddMenu, v0.4.1
- *
- * This program is notably inefficient insofar as every change that is save is written to
- * the profile file. Granted, now that we all use disk caches that's not really a problem,
- * but I admit that it isn't great programming technique. I'm lazy.
- *
- * The program, AddMenu, is designed to let you add options to your system menus. When
- * running, it hooks into the system menus to add the specified options to all menus. It
- * also hooks into the keyboard and mouse to intercept requests for those options in order
- * to execute those commands.
- *
- * Please appreciate that this is version 0. This means that it is a pre-release release.
- * In other words, I appreciate that there are problems with the code, but I don't have
- * time to worry about it right now. If you find bugs, please let me know, but don't
- * expect a timely response. But by all means, let me know what you think.
- *
- * There are many notable limitations/problems with the program as it currently exists:
- *
- * 1. No control of the order of items on the menu.
- * 2. Program currently uses both WH_CALLWNDPROC and WH_GETMESSAGE hooks. The first
- * adversely affects system performance.
- * 3. This program rather arbitrarily uses menu id's starting at 0xE120. This is intended
- * to minimized conflicts with existing system menus (0xF000 and higher) and likely
- * ids used by other programs. It is possible that these could conflict with other
- * programs. By adding a line "First Id=n" to the profile, where "n" is some number,
- * can control what id should be used. I didn't know how else to get around possible
- * conflicts.
- * 4. No help file yet.
- * 5. And more, as of yet undiscovered, problems ...
- *
- * Program requires COMMDLG.DLL, which comes with Windows 3.1 (but can be distributed with
- * the program). Program also requires AMFILTER.DLL which installs the two filters and handles
- * the menu events and posts the appropriate private messages to this program.
- *
- * This program is copywrite of Robert M. Ryan, 1992. It is provided without warrantee
- * of any sort. This program is FreeWare, and can be used and distributed for
- * non-commercial use without fee providing that:
- *
- * a) it is not to be altered without my permission;
- * b) my name remains on the package at all times;
- * c) any programs which employ code taken from this program must credit me for
- * the appropriate routines; and
- * d) no fee is ever charged for the distribution of the program short of the cost
- * of disk media and shipping cost (if any).
- *
- * If you want to use it for commercial purposes or have any questions about these policies,
- * do not hesitate to contact me.
- *
- * v0.3.0, Robert M. Ryan, 28 April 1992, first public release
- * v0.3.1
- * - fix exit bug
- * - modify so combo box works like it's supposed to
- * v0.3.2
- * - remove extraneous check of WM_MOVE (fixed by 0.3.1)
- * - extend "executables" to include "*.exe;*.com;*.pif;*.bat"
- * v0.3.3, 9 May 1992
- * - Change filter to {"Programs","*.exe;*.com;*.pif;*.bat","All Files","*.*"}
- * v0.3.4, 12 May 1992
- * - Change "All Files" to "All Files *.*"
- * v0.3.5, 7 June 1992
- * - Fix bug in Browse. Initialize lpFilename to "\0".
- * v0.3.6, 6 July 1992
- * - Extend WinExec() processing to change drive and directory first.
- * - Add error messages to WinExec() (see Run())
- * - Fix bug about change of current entry
- * v0.4.1, 7 July 1992
- * - Simplified and debugged PM_UPDATE code to simply account for subtle
- * differences between CBN_SELCHANGE and CBN_EDITUPDATE. Both don't
- * change visible contents of IDD_MENUNAME, but the first actually
- * doesn't update GetDlgItemText() while the second does.
- * - Second public release
- *
- * Rob Ryan
- * internet: Robert_Ryan@brown.edu
- * bitnet: ST802200@BROWNVM.BITNET
- * Compu$erve: 70324,227
- */
-
-
- /* global defines */
-
- #define PROGNAME "AddMenu"
- #define VERSION PROGNAME " v0.4.1"
- #define VERDATE __DATE__
- #define PROGRAMMER "Robert M. Ryan"
- #define STRING_MAX 256 /* COMMDLG requires at least 256*/
- #define IDM_FIRST 0xE120 /* default first id for additions to system menu */
- #define IDM_INCREMENT 0x10 /* increment between successive ids */
- #define HANDLE_MAX 200 /* how many parent handles can we enumerate? */
- #define BUF_SIZE 8000 /* size of buffer to hold ini stuff */
- #define WILDCARD "*.exe;*.com;*.pif;*.bat" /* what wildcards for browse command, 0.3.2 */
- #define TICKTHRESH 1000 /* minimium GetTickCount() interval */
- enum SeparatorTypes {SEP_NONE = 0, SEP_LINE, SEP_BREAK};
-
-
- /****************************************************************************
- * include files
- ****************************************************************************/
-
- #include <windows.h>
- #include <stdarg.h>
- #include <dos.h>
- #include <direct.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <commdlg.h>
- #include <ctype.h>
-
- #include "addmenu.h"
- #include "amfilter.h"
-
-
- /****************************************************************************
- * type definitions
- ****************************************************************************/
-
- typedef struct tagMenuLst { /* used for linked list of menu commands */
- PSTR szText;
- PSTR szCommand;
- struct tagMenuLst *pNext;
- } MENULST;
-
- typedef HWND FAR *LPHWND;
-
-
- /****************************************************************************
- * global variables
- ****************************************************************************/
-
- LPSTR lpClass = PROGNAME;
- HANDLE hInst;
- HWND hwndMain; /* window handle of main program */
- HWND hwndDialog; /* window handle of main dialog */
- HWND hwndCombo; /* window handle of combobox */
- FARPROC lpitMain; /* instance thunk of main dialog */
-
- /* misc .ini variables */
-
- LPSTR lpHidden = "Hidden";
- LPSTR lpSeparator = "Separator";
- LPSTR lpFirst = "First Id";
- LPSTR lpOptions = "Options";
- LPSTR lpProfile = "addmenu.ini";
-
- /* misc program status variables */
-
- BOOL bHidden; /* is icon hidden? */
- WORD nSeparator; /* either SEP_NONE, SEP_LINE, or SEP_BREAK */
- WORD wFirst; /* what is the first id to be used */
- BOOL bChanges; /* are there any changes to save? */
- BOOL bChangesMade; /* have any changes been saved? */
-
- /* Keep track of time that command was last executed. This is here
- * because Write (in Windows 3.1) apparently sends two commands. It
- * is the only application that I've seen that does it, but to prevent
- * problems, I check these variables and make sure that TICKTHRES msec
- * have taken place before issuing the same command.
- */
- DWORD dwLastCmdTicks; /* when was the last PM_MENUOPTION (in msec) */
- WORD wLastCmd; /* and what was it */
-
- /* the base for the linked list of menu options */
-
- MENULST mlFirst = { NULL, NULL, NULL };
-
- /* variables used while editing dialog box contents */
-
- char szMenuName[STRING_MAX];
- LPSTR lpMenuName = szMenuName;
- char szPrevName[STRING_MAX];
- LPSTR lpPrevName = szMenuName;
- char szFilename[STRING_MAX];
- LPSTR lpFilename = szFilename;
-
- /* variables used in GetOpenFileName() from COMMDLG.H */
-
- LPSTR lpFilter = "Programs\0" WILDCARD "\0All Files (*.*)\0*.*\0\0";
- LPSTR lpPick = "Browse";
- LPSTR lpExe = "exe";
-
- /* variables use in the enumeration of windows */
-
- LPHWND hwndArray;
- int nCountArray;
- int nCountWindow;
-
-
- /****************************************************************************
- * function prototypes
- ****************************************************************************/
-
- void ReadIni(void);
- LONG FAR PASCAL WndProc(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam);
- int FAR PASCAL AboutDlg(HWND hDlg, WORD wMsg, WORD wParam, LONG lParam);
- int FAR PASCAL MainDlg(HWND hDlg, WORD wMsg, WORD wParam, LONG lParam);
- LPSTR SpaceLess(LPSTR lpStr);
- BOOL Run(HWND hWnd, PSTR szFile, int nCmdShow);
- void ErrorBox(HWND hWnd, PSTR szFormat, ...);
- void Modal(HWND hWnd, LPSTR lpName, FARPROC lpFunc);
- void WritePrivateProfileInt(LPSTR lpAppName, LPSTR lpKeyName, int nInt, LPSTR lpFileName);
- int FindExactInCB(HWND hDlg, int nIdd, LPSTR lpName);
- void EnableMenus(HWND hWnd);
- void PickFile(HWND hWnd);
- void ProcessWindows(void);
- BOOL FAR PASCAL EnumWindowsFunc(HWND hWnd, DWORD lParam);
- BOOL FAR PASCAL EnumChildrenFunc(HWND hWnd, DWORD lParam);
- void FixWindow(HWND hWnd);
-
-
- /****************************************************************************
- * the code
- ****************************************************************************/
-
- int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
- {
- WNDCLASS wndclass;
- MSG msg;
- LONG lDlgBaseUnits = GetDialogBaseUnits();
- int nWidth, nHeight;
- HWND hWnd;
-
- /* if already running, make it visible if its not already, and give focus */
-
- if (hPrevInstance != NULL) {
- hWnd = FindWindow(lpClass, lpClass);
- ShowWindow(hWnd, SW_RESTORE);
- SetFocus(hWnd);
- return 0;
- }
-
- /* read profile string parameters */
- ReadIni();
-
- hInst = hInstance;
-
- wndclass.style = 0;
- wndclass.lpfnWndProc = WndProc;
- wndclass.cbClsExtra = 0;
- wndclass.cbWndExtra = 0;
- wndclass.hInstance = hInstance;
- wndclass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(1));
- wndclass.hCursor = NULL;
- wndclass.hbrBackground = COLOR_WINDOW + 1;
- wndclass.lpszMenuName = NULL;
- wndclass.lpszClassName = lpClass;
-
- RegisterClass(&wndclass);
-
- /* Make Window big enough for child dialog (exactly) */
-
- nWidth = (WINDOW_WIDTH * LOWORD(lDlgBaseUnits)) / 4 +
- GetSystemMetrics(SM_CXBORDER) * 2;
- nHeight = (WINDOW_HEIGHT * HIWORD(lDlgBaseUnits)) / 8 +
- GetSystemMetrics(SM_CYBORDER) * 2 +
- GetSystemMetrics(SM_CYMENU) +
- GetSystemMetrics(SM_CYCAPTION);
-
- hwndMain = CreateWindow(lpClass,
- lpClass,
- WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU, /* WS_OVERLAPPEDWINDOW, */
- CW_USEDEFAULT, 0,
- nWidth, nHeight,
- NULL, LoadMenu(hInstance, MAKEINTRESOURCE(1)),
- hInstance, NULL);
-
- /* show it as appropriate */
-
- ShowWindow(hwndMain, nCmdShow);
- SetFocus(hwndMain);
-
- while(GetMessage(&msg, NULL, 0, 0)) {
- if (IsDialogMessage(hwndDialog, &msg))
- continue;
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
-
- FreeProcInstance(lpitMain);
-
- return msg.wParam;
- } /* WinMain */
-
-
- /* ReadIni
- *
- * Read the contents from the private profile file.
- */
- void ReadIni(void)
- {
- HANDLE hData;
- LPSTR pData;
- LPSTR pPtr;
- char szTemp[STRING_MAX];
- MENULST *pList = &mlFirst;
-
- bHidden = GetPrivateProfileInt(lpClass, lpHidden, 0, lpProfile);
- nSeparator = GetPrivateProfileInt(lpClass, lpSeparator, SEP_LINE, lpProfile);
- wFirst = GetPrivateProfileInt(lpClass, lpFirst, IDM_FIRST, lpProfile);
-
- hData = GlobalAlloc(GMEM_DISCARDABLE | GMEM_MOVEABLE, BUF_SIZE);
- if (!hData) {
- ErrorBox(NULL, "ReadIni: Unable to allocate memory");
- return;
- }
-
- pData = GlobalLock(hData);
- if (!pData) {
- ErrorBox(NULL, "ReadIni: Unable to access memory");
- return;
- }
-
- if (!GetPrivateProfileString(lpOptions, NULL, NULL, pData, BUF_SIZE, lpProfile)) {
- GlobalUnlock(hData);
- GlobalFree(hData);
- return;
- }
-
- pPtr = pData;
- while (*pPtr) {
- pList->pNext = malloc(sizeof(MENULST));
- pList = pList->pNext;
- if (!pList)
- return;
- pList->szText = malloc(lstrlen(pPtr) + 1);
- lstrcpy(pList->szText, pPtr);
- if (GetPrivateProfileString(lpOptions, pPtr, "", szTemp, STRING_MAX, lpProfile)) {
- pList->szCommand = malloc(lstrlen(szTemp) + 1);
- lstrcpy(pList->szCommand, szTemp);
- } else
- pList->szCommand = NULL;
- pList->pNext = NULL;
- pPtr += lstrlen(pPtr) + 1;
- }
- GlobalUnlock(hData);
- GlobalFree(hData);
- } /* ReadIni */
-
-
- /* WndProc
- *
- * The main window's callback function.
- */
-
- LONG FAR PASCAL WndProc(HWND hWnd, WORD wMsg, WORD wParam, LONG lParam)
- {
- MENULST *pList;
- WORD wIdd;
- HMENU hMenu;
-
- switch (wMsg) {
- case WM_CREATE: /* create child (modeless) dialog */
- lpitMain = MakeProcInstance((FARPROC) MainDlg, hInst);
- hwndDialog = CreateDialog(hInst, MAKEINTRESOURCE(2), hWnd, lpitMain);
- SetHook(hWnd);
- break;
-
- case WM_SETFOCUS: /* If get focus, give it to dialog */
- SetFocus(hwndDialog);
- break;
-
- case WM_CLOSE: /* send close message to child */
- PostMessage(hwndDialog, wMsg, wParam, lParam);
- break;
-
- case WM_INITMENU: /* enable menu options as appropriate based upon the */
- EnableMenus(hWnd); /* contents of the child dialog */
- break;
-
- case WM_SIZE: /* if iconic, hide window if supposed to */
- if (wParam == SIZEICONIC) {
- SendMessage(hwndDialog, PM_QUERYSAVE, 0, 0L);
- SendMessage(hwndDialog, PM_UPDATE, 0, 0L);
- }
- if ((wParam == SIZEICONIC) && bHidden) {
- PostMessage(hwndMain, PM_HIDE, 0, 0L);
- }
- break;
-
- case PM_HIDE: /* hide: called by WM_SIZE: need to use PostMessage() */
- ShowWindow(hwndMain, SW_HIDE);
- break;
-
- case PM_ADDTOMENU: /* this is called by amfilter.dll for new menus */
- hMenu = GetSystemMenu(wParam, 0);
- if (GetMenuState(hMenu, wFirst, MF_BYCOMMAND) == (WORD) -1) {
- pList = mlFirst.pNext;
- wIdd = wFirst;
- if (pList && (nSeparator == SEP_LINE))
- AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
- while (pList) { /* search linked list */
- if (pList->szText)
- if ((wIdd == wFirst) && (nSeparator == SEP_BREAK))
- AppendMenu(hMenu, MF_STRING | MF_ENABLED | MF_MENUBARBREAK, wIdd, pList->szText);
- else
- AppendMenu(hMenu, MF_STRING | MF_ENABLED, wIdd, pList->szText);
- wIdd += IDM_INCREMENT;
- pList = pList->pNext;
- }
- }
- break;
-
- case PM_MENUOPTION: /* msg from dll saying that option selected from menu */
- if ((wParam >= wFirst) && (wParam < SC_SIZE)) {
- if (wParam == wLastCmd) /* all because of Write in Windows 3.1! */
- if ((GetTickCount() - dwLastCmdTicks) < TICKTHRESH)
- break;
- dwLastCmdTicks = GetTickCount();
- wLastCmd = wParam;
- pList = mlFirst.pNext;
- wIdd = wFirst;
- while(pList) { /* search linked list for appropriate ID number */
- if (wParam == wIdd) {
- if (pList->szCommand) {
- Run(NULL, pList->szCommand, SW_SHOWNORMAL);
- } else
- MessageBox(NULL, "This option has no command associated with it.",
- "System Menu Error", MB_ICONINFORMATION | MB_OK);
- break;
- }
- wIdd += IDM_INCREMENT; /* note: increment by 0x10 because system */
- pList = pList->pNext; /* menus apparently use lower 4 bits */
- }
- }
- break;
-
- case WM_COMMAND: /* Pass any menu commands to dialog */
- switch (wParam) {
- case IDM_NEW:
- case IDM_SAVE:
- case IDM_DELETE:
- case IDM_PICK:
- case IDM_EXIT:
- case IDM_ABOUT:
- SendMessage(hwndDialog, wMsg, wParam, lParam);
- break;
- default:
- return(DefWindowProc(hWnd, wMsg, wParam, lParam));
- } /* switch wParam */
- break;
-
- case WM_DESTROY: /* 0.3.1: somehow this got omitted */
- PostQuitMessage(0);
- break;
-
- /* 0.3.1: Since the combo box is in the child, but we're processing mouse input
- * here, we have to perform the same sort of processing that DefDlgProc would.
- */
- case WM_LBUTTONDOWN:
- case WM_NCLBUTTONDOWN:
- if ((GetFocus() == hwndCombo) || (GetParent(GetFocus()) == hwndCombo))
- SendMessage(hwndCombo, CB_SHOWDROPDOWN, FALSE, 0L);
- return(DefWindowProc(hWnd, wMsg, wParam, lParam));
-
- default:
- return(DefWindowProc(hWnd, wMsg, wParam, lParam));
- }
-
- return FALSE;
- }
-
-
- /* AboutDlg
- *
- * This routine displays the about dialog box.
- */
-
- int FAR PASCAL AboutDlg(HWND hDlg, WORD wMsg, WORD wParam, LONG lParam)
- {
- switch (wMsg) {
- case WM_INITDIALOG:
- SetDlgItemText(hDlg, IDD_TITLE, VERSION);
- SetDlgItemText(hDlg, IDD_DATE, VERDATE);
- break;
-
- case WM_CLOSE: /* did we manually close dlg? */
- EndDialog(hDlg, FALSE);
- break;
-
- case WM_COMMAND:
- switch (wParam) {
- case IDD_OK: /* did we push ok? */
- EndDialog(hDlg, FALSE);
- break;
- default:
- return FALSE;
- } /* switch wParam */
- break;
-
- default:
- return FALSE;
- } /* switch wMsg */
- return TRUE;
- } /* AboutDlg */
-
-
- /* MainDlg
- *
- * This modeless dialog box provides the lion's share of the processing in
- * this program. This is really the main callback function.
- */
- BOOL FAR PASCAL MainDlg(HWND hDlg, WORD wMsg, WORD wParam, LONG lParam)
- {
- int i;
- int nIndex;
- MENULST *pList, *pPrev;
-
- switch (wMsg) {
-
- /* initialize the dialog */
-
- case WM_INITDIALOG:
- /* Fill the combobox */
-
- pList = mlFirst.pNext;
- while(pList) {
- SendDlgItemMessage(hDlg, IDD_MENUNAME, CB_ADDSTRING, 0,
- (DWORD) (LPSTR) pList->szText);
- pList = pList->pNext;
- }
-
- CheckDlgButton(hDlg, IDD_HIDDEN, bHidden);
- switch (nSeparator) {
- case SEP_NONE:
- CheckDlgButton(hDlg, IDD_SEPARATOR, 0);
- CheckDlgButton(hDlg, IDD_NEWCOL, 0);
- break;
- case SEP_LINE:
- CheckRadioButton(hDlg, IDD_SEPARATOR, IDD_NEWCOL, IDD_SEPARATOR);
- break;
- case SEP_BREAK:
- CheckRadioButton(hDlg, IDD_SEPARATOR, IDD_NEWCOL, IDD_NEWCOL);
- break;
- }
-
- /* Set text limits */
-
- SendDlgItemMessage(hDlg, IDD_MENUNAME, CB_LIMITTEXT, STRING_MAX, 0L);
- SendDlgItemMessage(hDlg, IDD_FILENAME, EM_LIMITTEXT, STRING_MAX, 0L);
-
- /* initialize routine's variables */
-
- bChanges = FALSE;
- bChangesMade = FALSE;
- nIndex = CB_ERR-1;
- hwndCombo = GetDlgItem(hDlg, IDD_MENUNAME);
-
- /* and prepare to draw screen */
-
- PostMessage(hDlg, PM_UPDATE, 0, 0L);
-
- break;
-
- /* if this gets focus, pass it to menu name field */
-
- case WM_SETFOCUS:
- SetFocus(GetDlgItem(hDlg, IDD_MENUNAME));
- break;
-
- case WM_CLOSE: /* close: save changes? warn user */
- SendMessage(hDlg, PM_QUERYSAVE, 0, 0L);
-
- if (IDYES != MessageBox(hDlg, "If you quit this program, you will not be "
- "able to take advantage of the System Menu additions. If you "
- "wish to make use of the additions, please simply minimize "
- "the program. Do you REALLY want to quit?", "Quit?",
- MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2))
- break;
- FreeHook();
- ProcessWindows();
-
- DestroyWindow(hwndMain);
- break;
-
- case PM_QUERYSAVE: /* do you want to save? */
- if (bChanges) {
- if (MessageBox(hDlg, "Changes have been made."
- " Do you want to save the changes?",
- "Save?",
- MB_YESNO | MB_ICONQUESTION) == IDYES)
- SendMessage(hDlg, WM_COMMAND, IDM_SAVE, 0L);
- bChanges = FALSE;
- }
- break;
-
- /* fill the dialog contents and enable controls based upon the
- * currently selected menuname. One of three conditions can
- * hold:
- * 1. The user typed something in the edit control;
- * 2. The user selected some action (New, Delete, etc.)
- * which changed the contents of the edit control; or
- * 3. The user selected something from the list box.
- * If the 3rd is the case, the text of IDD_MENUNAME hasn't changed
- * yet because of a peculiarity with CBN_SELCHANGE, so we have to
- * use CB_GETLBTEXT in this case. Otherwise, we can just use
- * GetDlgItemText().
- */
- case PM_UPDATE: /* fill in the contents of dialog */
- if (wParam == CBN_SELCHANGE) {
- i = SendDlgItemMessage(hDlg, IDD_MENUNAME, CB_GETCURSEL, 0, 0L);
- SendDlgItemMessage(hDlg, IDD_MENUNAME, CB_GETLBTEXT, (WORD) i, (DWORD) lpMenuName);
- } else if (!GetDlgItemText(hDlg, IDD_MENUNAME, lpMenuName, STRING_MAX))
- i = CB_ERR;
- else
- i = FindExactInCB(hDlg, IDD_MENUNAME, lpMenuName);
-
- if (!lstrlen(lpPrevName))
- nIndex = CB_ERR-1;
-
- lstrcpy(lpPrevName, lpMenuName);
-
- if (nIndex == i)
- break;
-
- nIndex = i;
-
- if (nIndex == CB_ERR) {
- SetDlgItemText(hDlg, IDD_FILENAME, "");
- EnableWindow(GetDlgItem(hDlg, IDD_FILENAME),
- GetWindowTextLength(GetDlgItem(hDlg, IDD_MENUNAME)));
- EnableWindow(GetDlgItem(hDlg, IDD_FILEPROMPT),
- GetWindowTextLength(GetDlgItem(hDlg, IDD_MENUNAME)));
- } else {
- EnableWindow(GetDlgItem(hDlg, IDD_FILENAME), TRUE);
- EnableWindow(GetDlgItem(hDlg, IDD_FILEPROMPT), TRUE);
-
- if (GetPrivateProfileString(lpOptions, lpMenuName, "", lpFilename, STRING_MAX, lpProfile))
- SetDlgItemText(hDlg, IDD_FILENAME, lpFilename);
- else
- SetDlgItemText(hDlg, IDD_FILENAME, "");
- }
-
- bChanges = FALSE;
- break;
-
- case WM_COMMAND:
- switch (wParam) {
-
- /* Group name (folder) combo box message */
-
- case IDD_MENUNAME:
- switch (HIWORD(lParam)) {
- case CBN_SELCHANGE:
- case CBN_EDITUPDATE:
- SendMessage(hDlg, PM_QUERYSAVE, 0, 0L);
- SendMessage(hDlg, PM_UPDATE, HIWORD(lParam), 0L);
- break;
-
- case CBN_ERRSPACE:
- ErrorBox(hDlg, "MainDlg: CBN_ERRSPACE");
- break;
-
- default:
- return FALSE;
- }
- break;
-
- /* Any edit parameters change? */
-
- case IDD_FILENAME:
- switch (HIWORD(lParam)) {
- case EN_CHANGE:
- bChanges = TRUE;
- break;
-
- case EN_ERRSPACE:
- ErrorBox(hDlg, "ParamDlg: EN_ERRSPACE");
- break;
-
- default:
- return FALSE;
- }
- break;
-
- /* Have check boxes been clicked? */
-
- case IDD_HIDDEN: /* hidden check box used */
- if (HIWORD(lParam) == BN_CLICKED) {
- bHidden = !IsDlgButtonChecked(hDlg, wParam);
- CheckDlgButton(hDlg, wParam, bHidden);
- WritePrivateProfileInt(lpClass, lpHidden, bHidden, lpProfile);
- } else
- return FALSE;
- break;
-
- case IDD_SEPARATOR:
- case IDD_NEWCOL:
- if (HIWORD(lParam) != BN_CLICKED)
- return FALSE;
- ProcessWindows(); /* before farting with nSeparator, */
- /* get rid of existing separators if any */
- if (IsDlgButtonChecked(hDlg, wParam)) {
- CheckDlgButton(hDlg, wParam, 0);
- nSeparator = SEP_NONE;
- } else {
- CheckRadioButton(hDlg, IDD_SEPARATOR, IDD_NEWCOL, wParam);
- nSeparator = (wParam == IDD_SEPARATOR ? SEP_LINE : SEP_BREAK);
- }
- WritePrivateProfileInt(lpClass, lpSeparator, nSeparator, lpProfile);
- break;
-
- case IDM_DELETE: /* select delete from menu */
- if (GetDlgItemText(hDlg, IDD_MENUNAME, lpMenuName, STRING_MAX)) {
- if (MessageBox(hDlg, "Are you sure?", "Delete",
- MB_YESNO | MB_DEFBUTTON2 | MB_ICONQUESTION) == IDNO) {
- break;
- }
- } else
- break;
-
- i = FindExactInCB(hDlg, IDD_MENUNAME, lpMenuName);
- if (i != CB_ERR) {
- SendDlgItemMessage(hDlg, IDD_MENUNAME, CB_SETCURSEL, (WORD) -1, 0L);
- if (CB_ERR == SendDlgItemMessage(hDlg, IDD_MENUNAME,
- CB_DELETESTRING, i, 0L))
- ErrorBox(hDlg, "Delete: invalid index");
- }
-
- SetDlgItemText(hDlg, IDD_MENUNAME, "");
-
- /* delete from profile file */
-
- WritePrivateProfileString(lpOptions, lpMenuName, NULL, lpProfile);
- bChangesMade = TRUE;
-
- /* remove from all system menus */
-
- ProcessWindows();
-
- /* delete from linked list (keep node, remove szText) */
-
- pList = mlFirst.pNext;
- pPrev = &mlFirst;
- while (pList) {
- if (!lstrcmp(lpMenuName, pList->szText)) {
- free(pList->szText);
- free(pList->szCommand);
- pPrev->pNext = pList->pNext;
- free(pList);
- pList = pPrev->pNext;
- } else {
- pPrev = pList;
- pList = pList->pNext;
- }
- }
-
- /* and let's go back to what we were doing */
-
- SetFocus(hDlg);
- PostMessage(hDlg, PM_UPDATE, 0, 0L);
- break;
-
- case IDM_SAVE: /* select save from menu */
- if (!lpPrevName[0])
- break;
-
- GetDlgItemText(hDlg, IDD_FILENAME, lpFilename, STRING_MAX);
-
- /* if the name isn't in listbox, add it and add it to the linked list */
-
- if (FindExactInCB(hDlg, IDD_MENUNAME, lpPrevName) == CB_ERR) {
- SendDlgItemMessage(hDlg, IDD_MENUNAME, CB_ADDSTRING, 0, (DWORD) lpPrevName);
-
- /* add item to end of linked list */
-
- pList = &mlFirst;
- while (pList->pNext)
- pList = pList->pNext;
- pList->pNext = malloc(sizeof(MENULST));
- pList = pList->pNext;
- pList->pNext = NULL;
- pList->szText = malloc(lstrlen(lpPrevName)+1);
- pList->szCommand = malloc(lstrlen(lpFilename)+1);
- lstrcpy(pList->szText, lpPrevName);
- lstrcpy(pList->szCommand, lpFilename);
-
- ProcessWindows(); /* add to system menus */
- } else { /* just update linked list entry */
- pList = mlFirst.pNext;
- while (pList) {
- if (!lstrcmp(lpPrevName, pList->szText)) {
- free(pList->szCommand);
- pList->szCommand = malloc(lstrlen(lpFilename)+1);
- lstrcpy(pList->szCommand, lpFilename); /* 0.3.6 */
- }
- pList = pList->pNext;
- }
- }
-
- WritePrivateProfileString(lpOptions, lpPrevName, lpFilename, lpProfile);
- bChanges = FALSE;
- bChangesMade = TRUE;
-
- /* let's go back to what we were doing */
-
- PostMessage(hDlg, PM_UPDATE, 0, 0L);
- SetFocus(hDlg);
- break;
-
- /* Close button pressed */
-
- case IDM_EXIT:
- PostMessage(hDlg, WM_CLOSE, 0, 0L);
- break;
-
- /* Pick button pressed */
-
- case IDM_PICK:
- PickFile(hDlg);
- break;
-
- /* New option selected */
-
- case IDM_NEW:
- SendMessage(hDlg, WM_COMMAND, IDD_MENUNAME,
- MAKELONG(GetDlgItem(hDlg, IDD_MENUNAME), CBN_EDITUPDATE));
- SetDlgItemText(hDlg, IDD_MENUNAME, "");
- break;
-
- case IDM_ABOUT:
- Modal(hDlg, (LPSTR) MAKEINTRESOURCE(1), (FARPROC) AboutDlg);
- break;
-
- default:
- return FALSE;
- } /* switch wParam */
- break;
-
- default:
- return FALSE;
- } /* switch wMsg */
- return TRUE;
- } /* MainDlg */
-
-
- /* SpaceLess
- *
- * Remove leading spaces and delete everything after first subsequent space
- */
- LPSTR SpaceLess(LPSTR lpStr)
- {
- LPSTR lpPtr = lpStr;
- int i;
-
- while(lpPtr[0] == ' ') /* Remove leading spaces */
- lpPtr++;
-
- for (i = 0; i < lstrlen(lpPtr); i++) /* Remove anything after */
- if (lpPtr[i] == ' ') /* any spaces */
- lpPtr[i] = '\0';
-
- return lpPtr;
- } /* SpaceLess */
-
-
- /* Run
- *
- * The WinExec() function has several notable limitations. Notably, unlike
- * the program manager's "Run" command, it does not change disk or drive.
- * This addresses these limitations, simulating the "Run" command.
- *
- * v0.3.6
- */
- BOOL Run(HWND hWnd, PSTR szFile, int nCmdShow)
- {
- WORD wRc;
- OFSTRUCT of;
- char szFileName[STRING_MAX+1];
- int i;
- int nDrives;
- BOOL bExtension = FALSE;
-
- /* change to windows disk and directory (0.3.6) */
-
- GetWindowsDirectory(szFileName, STRING_MAX);
- if (szFileName[1] == ':')
- _dos_setdrive(toupper(szFileName[0]) - 'A' + 1, &nDrives);
- chdir(szFileName);
-
- strcpy(szFileName, szFile); /* get file name */
-
- /* add extension .exe if none */
-
- SpaceLess(szFileName); /* remove options */
- for (i = strlen(szFileName)-1; i >= 0; i--) {
- if (szFileName[i] == '.') {
- bExtension = TRUE;
- break;
- }
- if (szFileName[i] == '\\')
- break;
- }
- if (!bExtension)
- strcat(szFileName, ".exe");
-
- /* see if file exists and get full path in process */
-
- if (OpenFile(SpaceLess(szFileName), &of, OF_EXIST) == -1) {
- ErrorBox(NULL, "The file \"%s\" was not found.", of.szPathName);
- return FALSE;
- }
-
- /* copy the filename into lpFileName and set of.szPathName to be just path */
-
- lstrcpy(szFileName, of.szPathName);
- for (i = lstrlen(of.szPathName)-1; i >= 0; i--)
- if (of.szPathName[i] == '\\') {
- of.szPathName[i] = '\0';
- break;
- }
-
- /* change to that directory 0.3.6 */
-
- if (of.szPathName[1] == ':')
- _dos_setdrive(toupper(of.szPathName[0]) - 'A' + 1, &nDrives);
- chdir(of.szPathName);
-
- /* add any parameters to our new file name */
-
- for (i = 0; i < lstrlen(szFile); i++) /* copy parameters */
- if ((szFile[i] == ' ') || (szFile[i] == '/')) {
- strcat(szFileName, szFile + i);
- break;
- }
-
- wRc = WinExec(szFileName, nCmdShow);
-
- if (wRc > 32)
- return TRUE;
-
- switch (wRc) {
- case 0:
- ErrorBox(hWnd, "System was out of memory, executable file was corrupt, or relocations were invalid.");
- break;
- case 2: /* this should be caught by above processing */
- ErrorBox(hWnd, "File was not found. (%s)", szFile);
- break;
- case 3: /* this should be caught by above processing */
- ErrorBox(hWnd, "Path was not found. (%s)", szFile);
- break;
- case 5:
- ErrorBox(hWnd, "Attempt was made to dynamically link to a task, or there was a sharing or network-protection error.");
- break;
- case 6:
- ErrorBox(hWnd, "Library required separate data segments for each task.");
- break;
- case 8:
- ErrorBox(hWnd, "There was insufficient memory to start the application. (%s)", szFile);
- break;
- case 10:
- ErrorBox(hWnd, "Windows version was incorrect.");
- break;
- case 11:
- ErrorBox(hWnd, "Executable file was invalid. Either it was not a Windows application or there was an error in the .EXE image. (%s)", szFile);
- break;
- case 12:
- ErrorBox(hWnd, "Application was designed for a different operating system.");
- break;
- case 13:
- ErrorBox(hWnd, "Application was designed for MS-DOS 4.0. (%s)", szFile);
- break;
- case 14:
- ErrorBox(hWnd, "Type of executable file was unknown. (%s)", szFile);
- break;
- case 15:
- ErrorBox(hWnd, "Attempt was made to load a real-mode application (developed for an earlier version of Windows).");
- break;
- case 16:
- ErrorBox(hWnd, "Attempt was made to load a second instance of an executable file containing multiple data segments that were not marked read-only.");
- break;
- case 19:
- ErrorBox(hWnd, "Attempt was made to load a compressed executable file. The file must be decompressed before it can be loaded.");
- break;
- case 20:
- ErrorBox(hWnd, "Dynamic-link library (DLL) file was invalid. One of the DLLs required to run this application was corrupt.");
- break;
- case 21:
- ErrorBox(hWnd, "Application requires Microsoft Windows 32-bit extensions.");
- break;
- default:
- ErrorBox(hWnd, "Unknown error (%d)", wRc);
- break;
- }
-
- return FALSE;
- } /* Run */
-
-
- /* ErrorBox
- *
- * Print an error box message. Accepts a variable number of arguments
- * according to the ANSI standard. The szFormat string is a simple format
- * string like used with printf, permitting the use of "%d" (int), "%ld"
- * (long int), "%f" (double), "%s" (char *), and "%Fs" (LPSTR).
- */
- void ErrorBox(HWND hWnd, PSTR szFormat, ...)
- {
- va_list args;
- char szString[STRING_MAX];
-
- va_start(args, szFormat);
-
- vsprintf(szString, szFormat, args);
-
- MessageBox(hWnd, szString, "Error", MB_ICONEXCLAMATION | MB_OK);
-
- return;
- } /* ErrorBox */
-
-
- /* Modal
- * This routine is the constructor for a modal dialog box. Note that
- * with this definition, merely creating a item of type "ModalDialog"
- * will create a thunk instance and create the box. The thunk is freed
- * in when done and the focus is returned to what is was on entry.
- * Note that there is no destructor because the instance is freed in
- * this routine (this is so the focus window could be recorded and
- * restored upon termination).
- */
- void Modal(HWND hWnd, LPSTR lpName, FARPROC lpFunc)
- {
- FARPROC lpitDialog;
- HWND hWndFocus = GetFocus();
-
- if (!(lpitDialog = MakeProcInstance(lpFunc, hInst)))
- ErrorBox(hWnd, "Modal constructor: MakeProcInstance failure");
- if (DialogBox(hInst, lpName, hWnd, lpitDialog) == -1)
- ErrorBox(hWnd, "Modal constructor: Unable to create dialog");
- FreeProcInstance(lpitDialog);
-
- SetFocus(hWndFocus);
- } /* Modal */
-
-
- /* WritePrivateProfileInt
- *
- * While the system provides both GetProfileString and GetProfileInt,
- * it only provide WriteProfileString. This is the logical partner.
- */
- void WritePrivateProfileInt(LPSTR lpAppName, LPSTR lpKeyName, int nInt, LPSTR lpFileName)
- {
- static char szNumber[80];
-
- itoa(nInt, szNumber, 10);
- WritePrivateProfileString(lpAppName, lpKeyName, szNumber, lpFileName);
-
- } /* WritePrivateProfileInt */
-
-
- /* FindExactinCB
- *
- * The command to look up string in Combobox isn't too picky. Let's find
- * the one which precisely matches the string we're looking for.
- */
- int FindExactInCB(HWND hDlg, int nIdd, LPSTR lpName)
- {
- int i;
- char szString[STRING_MAX];
- LPSTR lpString = szString;
-
- i = SendDlgItemMessage(hDlg, nIdd, CB_FINDSTRING, (WORD) -1, (DWORD) lpName);
- if (i != CB_ERR)
- SendDlgItemMessage(hDlg, nIdd, CB_GETLBTEXT, i, (DWORD) lpString);
-
- if (lstrcmp(lpString, lpName))
- return CB_ERR;
-
- return i;
- } /* FindStringInCB */
-
-
- void EnableMenus(HWND hWnd)
- {
- HMENU hMenu;
- int i;
-
- hMenu = GetMenu(hWnd);
-
- i = GetWindowTextLength(GetDlgItem(hwndDialog, IDD_MENUNAME));
-
- if (i) {
- EnableMenuItem(hMenu, IDM_SAVE, MF_BYCOMMAND | MF_ENABLED);
- EnableMenuItem(hMenu, IDM_DELETE, MF_BYCOMMAND | MF_ENABLED);
- EnableMenuItem(hMenu, IDM_PICK, MF_BYCOMMAND | MF_ENABLED);
- EnableMenuItem(hMenu, IDM_NEW, MF_BYCOMMAND | MF_ENABLED);
- } else {
- EnableMenuItem(hMenu, IDM_SAVE, MF_BYCOMMAND | MF_GRAYED);
- EnableMenuItem(hMenu, IDM_DELETE, MF_BYCOMMAND | MF_GRAYED);
- EnableMenuItem(hMenu, IDM_PICK, MF_BYCOMMAND | MF_GRAYED);
- EnableMenuItem(hMenu, IDM_NEW, MF_BYCOMMAND | MF_GRAYED);
- }
-
- /* this program can be neither maximized nor resized */
-
- hMenu = GetSystemMenu(hWnd, 0);
- EnableMenuItem(hMenu, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
- EnableMenuItem(hMenu, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
-
- return;
- } /* EnableMenus */
-
-
- void PickFile(HWND hWnd)
- {
- OPENFILENAME ofn;
-
- lpFilename[0] = '\0';
-
- ofn.lStructSize = sizeof(OPENFILENAME);
- ofn.hwndOwner = hWnd;
- ofn.hInstance = hInst;
- ofn.lpstrFilter = lpFilter;
- ofn.lpstrCustomFilter = NULL;
- ofn.nMaxCustFilter = 0;
- ofn.nFilterIndex = 1;
- ofn.lpstrFile = lpFilename;
- ofn.nMaxFile = STRING_MAX;
- ofn.lpstrFileTitle = NULL;
- ofn.nMaxFileTitle = 0;
- ofn.lpstrInitialDir = NULL;
- ofn.lpstrTitle = lpPick;
- ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
- ofn.nFileOffset = 0;
- ofn.nFileExtension = 0;
- ofn.lpstrDefExt = lpExe;
- ofn.lCustData = 0;
- ofn.lpfnHook = NULL;
- ofn.lpTemplateName = NULL;
-
- if (GetOpenFileName(&ofn))
- SetDlgItemText(hWnd, IDD_FILENAME, lpFilename);
- } /* PickFile */
-
-
- void ProcessWindows(void)
- {
- FARPROC lpit = MakeProcInstance(EnumWindowsFunc, hInst);
- HANDLE hData;
- int i;
-
- if (!lpit) {
- ErrorBox(hwndMain, "ProcessWindows: Error making instance thunk (1).");
- return;
- }
- hData = GlobalAlloc(GMEM_MOVEABLE, sizeof(HWND) * HANDLE_MAX);
- if (!hData) {
- ErrorBox(hwndMain, "ProcessWindows: Error creating data buffer.");
- return;
- }
- hwndArray = (LPHWND) GlobalLock(hData);
- if (!hwndArray) {
- ErrorBox(hwndMain, "ProcessWindows: Error accessing data buffer.");
- return;
- }
-
- nCountArray = 0;
- EnumWindows(lpit, 0L);
- FreeProcInstance(lpit);
-
- lpit = MakeProcInstance(EnumChildrenFunc, hInst);
- if (!lpit) {
- ErrorBox(hwndMain, "ProcessWindows: Error making instance thunk (2).");
- return;
- }
-
- nCountWindow = 0;
-
- for (i = 0; i < nCountArray; i++)
- EnumChildWindows(hwndArray[i], lpit, 0L);
-
- FreeProcInstance(lpit);
-
- #if defined(DEBUG)
- ErrorBox(hwndMain, "There were %d parents and %d children.", nCountArray, nCountWindow);
- #endif
-
- GlobalUnlock(hData);
- GlobalFree(hData);
-
- return;
- } /* ProcessWindows */
-
-
- BOOL FAR PASCAL EnumWindowsFunc(HWND hWnd, DWORD lParam)
- {
- if (nCountArray >= HANDLE_MAX) {
- MessageBox(hwndMain, "Too many parents!", "Error", MB_ICONSTOP | MB_OK);
- return 0;
- }
-
- if (hWnd) {
- hwndArray[nCountArray] = hWnd;
- nCountArray++;
- }
-
- FixWindow(hWnd);
-
- return TRUE;
- } /* EnumWindowsFunc */
-
-
- BOOL FAR PASCAL EnumChildrenFunc(HWND hWnd, DWORD lParam)
- {
- nCountWindow++;
- FixWindow(hWnd);
-
- return TRUE;
- } /* EnumTaskWindows */
-
-
- void FixWindow(HWND hWnd)
- {
- HMENU hMenu;
- MENULST *pList;
- WORD wIdd;
- int i;
-
- if (!hWnd) {
- return; /* if no window, quit */
- }
- if (!(GetWindowLong(hWnd, GWL_STYLE) & WS_SYSMENU)) {
- return; /* if no system menu in window, quit */
- }
-
- hMenu = GetSystemMenu(hWnd, 0);
- pList = mlFirst.pNext;
- wIdd = wFirst;
-
- /* We're deleting all of them, so then do it. Note that we also want to remove the
- * separator too, so this also removes the menu item before the first one found.
- * While this logic sound confusing, it is necessary to make sure that we haven't
- * deleted the first menu item.
- */
- if ((GetMenuState(hMenu, wIdd, MF_BYCOMMAND) != (WORD) -1) && (nSeparator == SEP_LINE)) {
- for (i = 1; i < GetMenuItemCount(hMenu); i++)
- if (GetMenuItemID(hMenu, i) == wIdd)
- DeleteMenu(hMenu, i-1, MF_BYPOSITION);
- }
- while (pList) {
- if (GetMenuState(hMenu, wIdd, MF_BYCOMMAND) != (WORD) -1)
- DeleteMenu(hMenu, wIdd, MF_BYCOMMAND);
- pList = pList->pNext;
- wIdd += IDM_INCREMENT;
- }
- return;
- } /* FixWindow */
-