2 static char *RCSid() { return RCSid("$Id: wmenu.c,v 1.8 2006/08/09 07:39:34 mikulik Exp $"); }
5 /* GNUPLOT - win/wmenu.c */
7 * Copyright 1992, 1993, 1998, 2004 Maurice Castro, Russell Lang
9 * Permission to use, copy, and distribute this software and its
10 * documentation for any purpose with or without fee is hereby granted,
11 * provided that the above copyright notice appear in all copies and
12 * that both that copyright notice and this permission notice appear
13 * in supporting documentation.
15 * Permission to modify the software is granted, but not the right to
16 * distribute the complete modified source code. Modifications are to
17 * be distributed as patches to the released version. Permission to
18 * distribute binaries produced by compiling modified sources is granted,
20 * 1. distribute the corresponding source modifications from the
21 * released version in the form of a patch file along with the binaries,
22 * 2. add special version identification to distinguish your version
23 * in addition to the base release version number,
24 * 3. provide your name and address as the primary contact for the
25 * support of your modified version, and
26 * 4. retain our contact information in regard to use of the base
28 * Permission to distribute the released version of the source code along
29 * with corresponding source modifications in the form of a patch file is
30 * granted with same provisions 2 through 4 for binary distributions.
32 * This software is provided "as is" without express or implied warranty
33 * to the extent permitted by applicable law.
46 #define _WIN32_IE 0x0501
52 #include <string.h> /* only use far items */
53 #include <sys/types.h>
60 /* WITH_ADV_DIR_DIALOG is defined in wcommon.h */
61 #ifdef WITH_ADV_DIR_DIALOG
67 BOOL CALLBACK WINEXPORT InputBoxDlgProc(HWND, UINT, WPARAM, LPARAM);
68 LRESULT CALLBACK WINEXPORT MenuButtonProc(HWND, UINT, WPARAM, LPARAM);
72 #define MACROLEN 10000
73 /* #define NUMMENU 256 defined in wresourc.h */
85 "[INPUT]", "[EOS]", "[OPEN]", "[SAVE]", "[DIRECTORY]",
86 "{ENTER}", "{ESC}", "{TAB}",
87 "{^A}", "{^B}", "{^C}", "{^D}", "{^E}", "{^F}", "{^G}", "{^H}",
88 "{^I}", "{^J}", "{^K}", "{^L}", "{^M}", "{^N}", "{^O}", "{^P}",
89 "{^Q}", "{^R}", "{^S}", "{^T}", "{^U}", "{^V}", "{^W}", "{^X}",
90 "{^Y}", "{^Z}", "{^[}", "{^\\}", "{^]}", "{^^}", "{^_}",
93 INPUT, EOS, OPEN, SAVE, DIRECTORY,
95 1, 2, 3, 4, 5, 6, 7, 8,
96 9, 10, 11, 12, 13, 14, 15, 16,
97 17, 18, 19, 20, 21, 22, 23, 24,
98 25, 26, 28, 29, 30, 31,
102 #ifdef WITH_ADV_DIR_DIALOG
104 #ifdef SHELL_DIR_DIALOG
106 /* This is missing in MingW 2.95 */
108 # define BIF_EDITBOX 0x0010
111 /* Note: this code has been bluntly copied from MSDN article KB179378
112 "How To Browse for Folders from the Current Directory"
114 INT CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData)
116 TCHAR szDir[MAX_PATH];
119 case BFFM_INITIALIZED:
120 if (GetCurrentDirectory(sizeof(szDir)/sizeof(TCHAR), szDir)) {
121 /* WParam is TRUE since you are passing a path.
122 It would be FALSE if you were passing a pidl. */
123 SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)szDir);
127 case BFFM_SELCHANGED:
128 /* Set the status window to the currently selected path. */
129 if (SHGetPathFromIDList((LPITEMIDLIST) lp, szDir)) {
130 SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)szDir);
137 #else /* SHELL_DIR_DIALOG */
139 /* Yes, you can use Windows shell functions even without C++ !
140 These functions are not defined in shlobj.h, so we do it ourselves:
142 #define IShellFolder_BindToObject(This,pidl,pbcReserved,riid,ppvOut) \
143 (This)->lpVtbl -> BindToObject(This,pidl,pbcReserved,riid,ppvOut)
144 #define IShellFolder_GetDisplayNameOf(This,pidl,uFlags,lpName) \
145 (This)->lpVtbl -> GetDisplayNameOf(This,pidl,uFlags,lpName)
147 /* My windows header files do not define these: */
148 #ifndef WC_NO_BEST_FIT_CHARS
149 #define WC_NO_BEST_FIT_CHARS 0x00000400 /* do not use best fit chars */
152 /* We really need this struct which is used by newer Windows versions */
153 typedef struct tagOFN {
158 LPTSTR lpstrCustomFilter;
159 DWORD nMaxCustFilter;
163 LPTSTR lpstrFileTitle;
165 LPCTSTR lpstrInitialDir;
172 LPOFNHOOKPROC lpfnHook;
173 LPCTSTR lpTemplateName;
174 /* #if (_WIN32_WINNT >= 0x0500) */
178 /* #endif // (_WIN32_WINNT >= 0x0500) */
179 } NEW_OPENFILENAME, *NEW_LPOPENFILENAME;
182 UINT_PTR CALLBACK OFNHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
185 case WM_INITDIALOG: {
187 parent = GetParent(hdlg);
188 /* Hint: The control codes for this can be found on MSDN */
189 /* Hide "file type" display */
190 CommDlg_OpenSave_HideControl(parent, stc2);
191 CommDlg_OpenSave_HideControl(parent, cmb1);
192 /* Hide "current file" display */
193 CommDlg_OpenSave_HideControl(parent, stc3);
194 CommDlg_OpenSave_HideControl(parent, cmb13);
199 LPOFNOTIFY lpOfNotify = (LPOFNOTIFY) lParam;
200 switch(lpOfNotify->hdr.code) {
202 /* Well, this event is not called for ordinary files (sigh) */
203 case CDN_INCLUDEITEM:
207 /* But there's a solution which can be found here:
208 http://msdn.microsoft.com/msdnmag/issues/03/10/CQA/default.aspx
209 http://msdn.microsoft.com/msdnmag/issues/03/09/CQA/
210 It's C++ though (sigh again), so here is its analogue in plain C:
212 /* case CDN_SELCHANGE: */
213 case CDN_FOLDERCHANGE: {
214 HWND parent, hlst2, list;
215 LPCITEMIDLIST pidlFolder;
220 /* find listbox control */
221 parent = GetParent(hdlg);
222 hlst2 = GetDlgItem(parent, lst2);
223 list = GetDlgItem(hlst2, 1);
225 SHGetMalloc(&pMalloc);
227 /* First, get PIDL of current folder by sending CDM_GETFOLDERIDLIST
228 get length first, then allocate. */
229 len = CommDlg_OpenSave_GetFolderIDList(parent, 0, 0);
231 LPSHELLFOLDER ishDesk;
232 LPSHELLFOLDER ishFolder;
236 pidlFolder = IMalloc_Alloc(pMalloc, len+1);
237 CommDlg_OpenSave_GetFolderIDList(parent, (WPARAM)(void*)pidlFolder, len);
239 /* Now get IShellFolder for pidlFolder */
240 SHGetDesktopFolder(&ishDesk);
241 hr = IShellFolder_BindToObject(ishDesk, pidlFolder, NULL, &IID_IShellFolder, &ishFolder);
242 if (!SUCCEEDED(hr)) {
246 /* Enumerate listview items */
247 count = ListView_GetItemCount(list);
248 for (i = count-1; i >= 0; i--)
250 const ULONG flags = SHGDN_NORMAL | SHGDN_FORPARSING;
254 /* The normal code to retrieve the item's text is
255 not very useful since user may select "hide common
257 path = (char *)malloc(MAX_PATH+1);
258 ListView_GetItemText(list, i, 0, path, MAX_PATH );
260 /* The following code retrieves the real path of every
262 /* Retrieve PIDL of current item */
263 ZeroMemory(&lvitem,sizeof(lvitem));
265 lvitem.mask = LVIF_PARAM;
266 ListView_GetItem(list, &lvitem);
267 pidl = (LPCITEMIDLIST)lvitem.lParam;
269 /* Finally, get the path name from pidlFolder */
270 str.uType = STRRET_WSTR;
271 hr = IShellFolder_GetDisplayNameOf(ishFolder, pidl, flags, &str);
273 struct _stat itemStat;
274 char path[MAX_PATH+1];
276 /* (sigh) conversion would have been so easy...
277 hr = StrRetToBuf( str, pidl, path, MAX_PATH); */
278 if (str.uType == STRRET_WSTR) {
279 unsigned wlen = wcslen(str.pOleStr);
280 wlen = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
281 str.pOleStr, wlen+1, path, MAX_PATH,
283 _wstat(str.pOleStr, &itemStat);
284 /* Must free memory allocated by shell using shell's IMalloc */
285 IMalloc_Free(pMalloc, (LPVOID)str.pOleStr);
286 } else if (str.uType == STRRET_CSTR) {
287 strncpy(path, str.cStr, MAX_PATH);
288 _stat(str.cStr, &itemStat);
290 /* this shouldn't happen */
294 /* discard all non-directories from list */
295 if ((itemStat.st_mode & _S_IFDIR) == 0) {
296 ListView_DeleteItem(list, i);
299 } /* Enumerate listview items */
300 IMalloc_Free(pMalloc, (void*)pidlFolder);
302 IMalloc_Release(pMalloc);
304 } /* CDN_FOLDERCHANGE */
305 } /* switch(hdr.code) */
308 }; /* switch(uiMsg) */
312 #endif /* !SHELL_DIR_DIALOG */
313 #endif /* WITH_ADV_DIR_DIALOG */
316 /* Send a macro to the text window */
318 SendMacro(LPTW lptw, UINT m)
325 LPMW lpmw = lptw->lpmw;
333 if ( (buf = LocalAllocPtr(LHND, MAXSTR+1)) == (char *)NULL )
336 if (m>=lpmw->nCountMenu)
341 while (s && *s && (d-buf < MAXSTR)) {
342 if (*s>=CMDMIN && *s<=CMDMAX) {
344 case SAVE: /* [SAVE] - get a save filename from a file list box */
345 case OPEN: /* [OPEN] - get a filename from a file list box */
347 /* This uses COMMDLG.DLL from Windows 3.1
348 COMMDLG.DLL is redistributable */
353 if ( (szTitle = LocalAllocPtr(LHND, MAXSTR+1)) == (char *)NULL )
355 if ( (szFile = LocalAllocPtr(LHND, MAXSTR+1)) == (char *)NULL )
357 if ( (szFilter = LocalAllocPtr(LHND, MAXSTR+1)) == (char *)NULL )
362 for(i=0; (*s >= 32 && *s <= 126); i++)
363 szTitle[i] = *s++; /* get dialog box title */
366 for(i=0; (*s >= 32 && *s <= 126); i++)
367 szFile[i] = *s++; /* temporary copy of filter */
369 lstrcpy(szFilter,"Default (");
370 lstrcat(szFilter,szFile);
371 lstrcat(szFilter,")");
373 i++; /* move past NULL */
374 lstrcpy(szFilter+i,szFile);
375 i+=lstrlen(szFilter+i);
376 i++; /* move past NULL */
377 lstrcpy(szFilter+i,"All Files (*.*)");
378 i+=lstrlen(szFilter+i);
379 i++; /* move past NULL */
380 lstrcpy(szFilter+i,"*.*");
381 i+=lstrlen(szFilter+i);
382 i++; /* move past NULL */
383 szFilter[i++]='\0'; /* add a second NULL */
386 /* the Windows 3.1 implentation - MC */
388 /* clear the structrure */
389 _fmemset(&ofn, 0, sizeof(OPENFILENAME));
390 ofn.lStructSize = sizeof(OPENFILENAME);
391 ofn.hwndOwner = lptw->hWndParent;
392 ofn.lpstrFilter = szFilter;
393 ofn.nFilterIndex = 1;
394 ofn.lpstrFile = szFile;
395 ofn.nMaxFile = MAXSTR;
396 ofn.lpstrFileTitle = szFile;
397 ofn.nMaxFileTitle = MAXSTR;
398 ofn.lpstrTitle = szTitle;
399 /* Windows XP has it's very special meaning of 'default directory' */
400 /* (search for OPENFILENAME on MSDN). So we set it here explicitly: */
401 /* ofn.lpstrInitialDir = (LPSTR)NULL; */
402 _getcwd(&cwd, sizeof(cwd));
403 ofn.lpstrInitialDir = cwd;
404 ofn.Flags = OFN_SHOWHELP | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
405 flag = (save ? GetSaveFileName(&ofn) : GetOpenFileName(&ofn));
407 lpmw->nChar = lstrlen(ofn.lpstrFile);
408 for (i=0; i<lpmw->nChar; i++)
409 *d++=ofn.lpstrFile[i];
412 LocalFreePtr((void NEAR *)OFFSETOF(szTitle));
413 LocalFreePtr((void NEAR *)OFFSETOF(szFilter));
414 LocalFreePtr((void NEAR *)OFFSETOF(szFile));
419 /* Use InputBox if you don't have COMMDLG.DLL */
420 s++; /* skip list box title */
421 for(i=0; (*s >= 32 && *s <= 126); i++)
425 #ifndef WITH_ADV_DIR_DIALOG
426 case DIRECTORY: /* [DIRECTORY] fall back to INPUT dialog */
428 case INPUT: /* [INPUT] - input a string of characters */
430 for(i=0; (*s >= 32 && *s <= 126); i++)
431 lpmw->szPrompt[i] = *s++;
432 lpmw->szPrompt[i]='\0';
434 flag = DialogBox( hdllInstance, "InputDlgBox", lptw->hWndParent, InputBoxDlgProc);
437 lpmw->lpProcInput = (DLGPROC)GetProcAddress(hdllInstance, "InputBoxDlgProc");
439 lpmw->lpProcInput = (DLGPROC)MakeProcInstance((FARPROC)InputBoxDlgProc, hdllInstance);
441 flag = DialogBox( hdllInstance, "InputDlgBox", lptw->hWndParent, lpmw->lpProcInput);
444 for (i=0; i<lpmw->nChar; i++)
445 *d++ = lpmw->szAnswer[i];
449 FreeProcInstance((FARPROC)lpmw->lpProcInput);
454 #ifdef WITH_ADV_DIR_DIALOG
455 case DIRECTORY: /* [DIRECTORY] - show standard directory dialog */
457 #ifdef SHELL_DIR_DIALOG
461 NEW_OPENFILENAME ofn;
463 /* allocate some space */
464 if ( (szTitle = LocalAllocPtr(LHND, MAXSTR+1)) == (char *)NULL )
467 /* get dialog box title */
469 for(i=0; (*s >= 32 && *s <= 126); i++)
475 #ifdef SHELL_DIR_DIALOG
477 use the Shell's internal directory chooser
479 /* Note: This code does not work NT 3.51 and Win32s
480 Windows 95 has shell32.dll version 4.0, but does not
481 have a version number, so this will return FALSE.
483 /* Make sure that the installed shell version supports this approach */
484 if (GetDllVersion(TEXT("shell32.dll")) >= PACKVERSION(4,0)) {
485 ZeroMemory(&bi,sizeof(bi));
486 bi.hwndOwner = lptw->hWndParent;
488 bi.pszDisplayName = NULL;
489 bi.lpszTitle = szTitle;
490 bi.ulFlags = BIF_EDITBOX |
492 BIF_RETURNONLYFSDIRS | BIF_RETURNFSANCESTORS;
493 bi.lpfn = BrowseCallbackProc;
496 pidl = SHBrowseForFolder( &bi );
501 char szPath[MAX_PATH];
504 /* Convert the item ID list's binary
505 representation into a file system path */
506 BOOL f = SHGetPathFromIDList(pidl, szPath);
508 len = strlen( szPath );
511 for (i=0; i<len; i++)
514 /* Allocate a pointer to an IMalloc interface
515 Get the address of our task allocator's IMalloc interface */
516 hr = SHGetMalloc(&pMalloc) ;
518 /* Free the item ID list allocated by SHGetSpecialFolderLocation */
519 IMalloc_Free( pMalloc, pidl );
521 /* Free our task allocator */
522 IMalloc_Release( pMalloc );
525 #else /* SHELL_DIR_DIALOG */
527 use (abuse ?) standard "file open" dialog and discard the filename
528 from result, have all non-directory items removed.
530 /* Note: This code does not work NT 3.51 and Win32s
531 Windows 95 has shell32.dll version 4.0, but does not
532 have a version number, so this will return FALSE.
534 /* Make sure that the installed shell version supports this approach */
535 if (GetDllVersion(TEXT("shell32.dll")) >= PACKVERSION(4,0)) {
536 /* copy current working directory to szFile */
537 if ( (szFile = LocalAllocPtr(LHND, MAX_PATH+1)) == (char *)NULL )
539 GP_GETCWD( szFile, MAX_PATH );
540 strcat( szFile, "\\*.*" );
542 ZeroMemory(&ofn,sizeof(ofn));
543 ofn.lStructSize = sizeof(ofn);
544 ofn.hwndOwner = lptw->hWndParent;
545 ofn.lpstrFilter = (LPSTR)NULL;
546 ofn.nFilterIndex = 0;
547 ofn.lpstrFile = szFile;
548 ofn.nMaxFile = MAX_PATH;
549 ofn.lpstrFileTitle = szFile;
550 ofn.nMaxFileTitle = MAXSTR;
551 ofn.lpstrTitle = szTitle;
552 ofn.lpstrInitialDir = (LPSTR)NULL;
553 ofn.Flags = OFN_PATHMUSTEXIST | OFN_NOVALIDATE |
554 OFN_HIDEREADONLY | OFN_ENABLESIZING |
555 OFN_EXPLORER | OFN_ENABLEHOOK;
556 ofn.lpfnHook = OFNHookProc;
557 flag = GetOpenFileName((LPOPENFILENAME)&ofn);
559 if ((flag) && (ofn.nFileOffset >0)) {
562 /* strip filename from result */
563 len = ofn.nFileOffset - 1;
564 ofn.lpstrFile[len] = '\0';
565 for (i=0; i<len; i++)
566 *d++ = ofn.lpstrFile[i];
568 LocalFreePtr((void NEAR *)OFFSETOF(szFile));
570 #endif /* !SHELL_DIR_DIALOG */
572 strcpy(lpmw->szPrompt, szTitle);
573 flag = DialogBox( hdllInstance, "InputDlgBox", lptw->hWndParent, InputBoxDlgProc);
575 for (i=0; i<lpmw->nChar; i++)
576 *d++ = lpmw->szAnswer[i];
579 LocalFreePtr((void NEAR *)OFFSETOF(szTitle));
582 #endif /* WITH_ADV_DIR_DIALOG */
584 case EOS: /* [EOS] - End Of String - do nothing */
589 if (!flag) { /* abort */
602 SendMessage(lptw->hWndText,WM_CHAR,*d,1L);
610 typedef struct tagGFILE {
612 char getbuf[GBUFSIZE];
617 GFILE * Gfopen(LPSTR lpszFileName, int fnOpenMode)
621 gfile = (GFILE *)LocalAllocPtr(LHND, sizeof(GFILE));
625 gfile->hfile = _lopen(lpszFileName, fnOpenMode);
626 if (gfile->hfile == HFILE_ERROR) {
627 LocalFreePtr((void NEAR *)OFFSETOF(gfile));
635 void Gfclose(GFILE * gfile)
638 _lclose(gfile->hfile);
639 LocalFreePtr((void NEAR *)OFFSETOF(gfile));
643 /* returns number of characters read */
645 Gfgets(LPSTR lp, int size, GFILE *gfile)
649 for (i=0; i<size; i++) {
650 if (gfile->getleft <= 0) {
651 if ( (gfile->getleft = _lread(gfile->hfile, gfile->getbuf, GBUFSIZE)) == 0)
655 ch = *lp++ = gfile->getbuf[gfile->getnext++];
671 /* Get a line from the menu file */
672 /* Return number of lines read from file including comment lines */
673 int GetLine(char * buffer, int len, GFILE *gfile)
678 status = (Gfgets(buffer,len,gfile) != 0);
680 while( status && ( buffer[0] == 0 || buffer[0] == '\n' || buffer[0] == ';' ) ) {
681 /* blank line or comment - ignore */
682 status = (Gfgets(buffer,len,gfile) != 0);
685 if (lstrlen(buffer)>0)
686 buffer[lstrlen(buffer)-1] = '\0'; /* remove trailing \n */
689 nLine = 0; /* zero lines if file error */
694 /* Left justify string */
695 void LeftJustify(char *d, char *s)
697 while ( *s && (*s==' ' || *s=='\t') )
698 s++; /* skip over space */
704 /* Translate string to tokenized macro */
705 void TranslateMacro(char *string)
710 for( i=0; keyword[i]!=(char *)NULL; i++ ) {
711 if( (ptr = _fstrstr( string, keyword[i] )) != NULL ) {
712 len = lstrlen( keyword[i] );
714 lstrcpy( ptr+1, ptr+len );
715 i--; /* allows for more than one occurrence of keyword */
720 /* Load Macros, and create Menu from Menu file */
722 LoadMacros(LPTW lptw)
728 HMENU hMenu[MENUDEPTH+1];
732 HGLOBAL hmacro, hmacrobuf;
738 int ButtonX, ButtonY;
739 char FAR *ButtonText[BUTTONMAX];
743 /* mark all buffers and menu file as unused */
747 lpmw->macro = (BYTE FAR * FAR *)NULL;
748 lpmw->macrobuf = (BYTE FAR *)NULL;
749 lpmw->szPrompt = (char *)NULL;
750 lpmw->szAnswer = (char *)NULL;
751 menufile = (GFILE *)NULL;
754 if ((menufile=Gfopen(lpmw->szMenuName,OF_READ)) == (GFILE *)NULL)
757 /* allocate buffers */
758 if ((buf = LocalAllocPtr(LHND, MAXSTR)) == (char *)NULL)
760 hmacro = GlobalAlloc(GHND,(NUMMENU) * sizeof(BYTE FAR *));
761 if ((lpmw->macro = (BYTE FAR * FAR *)GlobalLock(hmacro)) == (BYTE FAR * FAR *)NULL)
763 hmacrobuf = GlobalAlloc(GHND, MACROLEN);
764 if ((lpmw->macrobuf = (BYTE FAR*)GlobalLock(hmacrobuf)) == (BYTE FAR *)NULL)
766 if ((lpmw->szPrompt = LocalAllocPtr(LHND, MAXSTR)) == (char *)NULL)
768 if ((lpmw->szAnswer = LocalAllocPtr(LHND, MAXSTR)) == (char *)NULL)
771 macroptr = lpmw->macrobuf;
773 lpmw->nCountMenu = 0;
774 lpmw->hMenu = hMenu[0] = CreateMenu();
777 while ((nInc = GetLine(buf,MAXSTR,menufile)) != 0) {
779 LeftJustify(buf,buf);
781 /* ignore blank lines */
783 else if (!lstrcmpi(buf,"[Menu]")) {
785 if (!(nInc = GetLine(buf,MAXSTR,menufile))) {
787 wsprintf(buf,"Problem on line %d of %s\n",nLine,lpmw->szMenuName);
788 MessageBox(lptw->hWndParent,(LPSTR) buf,lptw->Title, MB_ICONEXCLAMATION);
791 LeftJustify(buf,buf);
792 if (nMenuLevel<MENUDEPTH)
795 wsprintf(buf,"Menu is too deep at line %d of %s\n",nLine,lpmw->szMenuName);
796 MessageBox(lptw->hWndParent,(LPSTR) buf,lptw->Title, MB_ICONEXCLAMATION);
799 hMenu[nMenuLevel] = CreateMenu();
800 AppendMenu(hMenu[nMenuLevel > 0 ? nMenuLevel-1 : 0],
801 MF_STRING | MF_POPUP, (UINT)hMenu[nMenuLevel], (LPCSTR)buf);
803 else if (!lstrcmpi(buf,"[EndMenu]")) {
805 nMenuLevel--; /* back up one menu */
807 else if (!lstrcmpi(buf,"[Button]")) {
809 if (lpmw->nButton >= BUTTONMAX) {
810 wsprintf(buf,"Too many buttons at line %d of %s\n",nLine,lpmw->szMenuName);
811 MessageBox(lptw->hWndParent,(LPSTR) buf,lptw->Title, MB_ICONEXCLAMATION);
814 if (!(nInc = GetLine(buf,MAXSTR,menufile))) {
816 wsprintf(buf,"Problem on line %d of %s\n",nLine,lpmw->szMenuName);
817 MessageBox(lptw->hWndParent,(LPSTR) buf,lptw->Title, MB_ICONEXCLAMATION);
820 LeftJustify(buf,buf);
821 if (lstrlen(buf)+1 < MACROLEN - (macroptr-lpmw->macrobuf))
822 lstrcpy((char FAR *)macroptr,buf);
824 wsprintf(buf,"Out of space for storing menu macros\n at line %d of \n",nLine,lpmw->szMenuName);
825 MessageBox(lptw->hWndParent,(LPSTR) buf,lptw->Title, MB_ICONEXCLAMATION);
828 ButtonText[lpmw->nButton] = (char FAR *)macroptr;
829 macroptr += lstrlen((char FAR *)macroptr)+1;
831 if (!(nInc = GetLine(buf,MAXSTR,menufile))) {
833 wsprintf(buf,"Problem on line %d of %s\n",nLine,lpmw->szMenuName);
834 MessageBox(lptw->hWndParent,(LPSTR) buf,lptw->Title, MB_ICONEXCLAMATION);
837 LeftJustify(buf,buf);
839 if (lstrlen(buf)+1 < MACROLEN - (macroptr - lpmw->macrobuf))
840 lstrcpy((char FAR *)macroptr,buf);
842 wsprintf(buf,"Out of space for storing menu macros\n at line %d of \n",nLine,lpmw->szMenuName);
843 MessageBox(lptw->hWndParent,(LPSTR) buf,lptw->Title, MB_ICONEXCLAMATION);
846 lpmw->hButtonID[lpmw->nButton] = lpmw->nCountMenu;
847 lpmw->macro[lpmw->nCountMenu] = macroptr;
848 macroptr += lstrlen((char FAR *)macroptr)+1;
855 if (lpmw->nCountMenu>=NUMMENU) {
856 wsprintf(buf,"Too many menu items at line %d of %s\n",nLine,lpmw->szMenuName);
857 MessageBox(lptw->hWndParent,(LPSTR) buf,lptw->Title, MB_ICONEXCLAMATION);
860 LeftJustify(buf,buf);
861 /* HBB 981202: added MF_SEPARATOR to the MF_MENU*BREAK items. This is meant
862 * to maybe avoid a CodeGuard warning about passing last argument zero
863 * when item style is not SEPARATOR... Actually, a better solution would
864 * have been to combine the '|' divider with the next menu item. */
867 AppendMenu(hMenu[0], MF_SEPARATOR | MF_MENUBREAK, 0, (LPSTR)NULL);
869 AppendMenu(hMenu[nMenuLevel], MF_SEPARATOR, 0, (LPSTR)NULL);
871 else if (buf[0]=='|') {
872 AppendMenu(hMenu[nMenuLevel], MF_SEPARATOR | MF_MENUBARBREAK, 0, (LPSTR)NULL);
875 AppendMenu(hMenu[nMenuLevel],MF_STRING, lpmw->nCountMenu, (LPSTR)buf);
876 if (!(nInc = GetLine(buf,MAXSTR,menufile))) {
878 wsprintf(buf,"Problem on line %d of %s\n",nLine,lpmw->szMenuName);
879 MessageBox(lptw->hWndParent,(LPSTR) buf,lptw->Title, MB_ICONEXCLAMATION);
882 LeftJustify(buf,buf);
884 if (lstrlen(buf)+1 < MACROLEN - (macroptr - lpmw->macrobuf))
885 lstrcpy((char FAR *)macroptr,buf);
887 wsprintf(buf,"Out of space for storing menu macros\n at line %d of %s\n",nLine,lpmw->szMenuName);
888 MessageBox(lptw->hWndParent,(LPSTR) buf,lptw->Title, MB_ICONEXCLAMATION);
891 lpmw->macro[lpmw->nCountMenu] = macroptr;
892 macroptr += lstrlen((char FAR *)macroptr)+1;
899 if ( (lpmw->nCountMenu - lpmw->nButton) > 0 ) {
900 /* we have a menu bar so put it on the window */
901 SetMenu(lptw->hWndParent,lpmw->hMenu);
902 DrawMenuBar(lptw->hWndParent);
906 goto cleanup; /* no buttons */
908 /* calculate size of buttons */
909 hdc = GetDC(lptw->hWndParent);
910 SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));
911 GetTextMetrics(hdc, &tm);
912 ButtonX = 8 * tm.tmAveCharWidth;
913 ButtonY = 6 * (tm.tmHeight + tm.tmExternalLeading) / 4;
914 ReleaseDC(lptw->hWndParent,hdc);
916 /* move top of client text window down to allow space for buttons */
917 lptw->ButtonHeight = ButtonY+1;
918 GetClientRect(lptw->hWndParent, &rect);
919 SetWindowPos(lptw->hWndText, (HWND)NULL, 0, lptw->ButtonHeight,
920 rect.right, rect.bottom-lptw->ButtonHeight,
921 SWP_NOZORDER | SWP_NOACTIVATE);
923 /* create the buttons */
925 lpmw->lpfnMenuButtonProc = (WNDPROC)GetProcAddress(hdllInstance, "MenuButtonProc");
927 lpmw->lpfnMenuButtonProc = (WNDPROC)MakeProcInstance((FARPROC)MenuButtonProc, hdllInstance);
929 for (i=0; i<lpmw->nButton; i++) {
930 lpmw->hButton[i] = CreateWindow("button", ButtonText[i],
931 WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
934 lptw->hWndParent, (HMENU)i,
935 lptw->hInstance, lptw);
936 lpmw->lpfnButtonProc[i] = (WNDPROC) GetWindowLong(lpmw->hButton[i], GWL_WNDPROC);
937 SetWindowLong(lpmw->hButton[i], GWL_WNDPROC, (LONG)lpmw->lpfnMenuButtonProc);
944 MessageBox(lptw->hWndParent,"Out of memory",lptw->Title, MB_ICONEXCLAMATION);
947 GlobalUnlock(hmacro);
951 GlobalUnlock(hmacrobuf);
952 GlobalFree(hmacrobuf);
954 if (lpmw->szPrompt != (char *)NULL)
955 LocalFreePtr((void NEAR *)OFFSETOF(lpmw->szPrompt));
956 if (lpmw->szAnswer != (char *)NULL)
957 LocalFreePtr((void NEAR *)OFFSETOF(lpmw->szAnswer));
960 if (buf != (char *)NULL)
961 LocalFreePtr((void NEAR *)OFFSETOF(buf));
962 if (menufile != (GFILE *)NULL)
969 CloseMacros(LPTW lptw)
977 if (lpmw->lpfnMenuButtonProc)
978 FreeProcInstance((FARPROC)lpmw->lpfnMenuButtonProc);
981 hglobal = (HGLOBAL)GlobalHandle( SELECTOROF(lpmw->macro) );
983 GlobalUnlock(hglobal);
986 hglobal = (HGLOBAL)GlobalHandle( SELECTOROF(lpmw->macrobuf) );
988 GlobalUnlock(hglobal);
991 if (lpmw->szPrompt != (char *)NULL)
992 LocalFreePtr((void NEAR *)OFFSETOF(lpmw->szPrompt));
993 if (lpmw->szAnswer != (char *)NULL)
994 LocalFreePtr((void NEAR *)OFFSETOF(lpmw->szAnswer));
998 /***********************************************************************/
999 /* InputBoxDlgProc() - Message handling routine for Input dialog box */
1000 /***********************************************************************/
1002 BOOL CALLBACK WINEXPORT
1003 InputBoxDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
1007 lptw = (LPTW)GetWindowLong(GetParent(hDlg), 0);
1012 SetDlgItemText( hDlg, ID_PROMPT, lpmw->szPrompt);
1016 switch(LOWORD(wParam)) {
1021 lpmw->nChar = GetDlgItemText( hDlg, ID_ANSWER, lpmw->szAnswer, MAXSTR);
1022 EndDialog( hDlg, TRUE);
1026 lpmw->szAnswer[0] = 0;
1027 EndDialog( hDlg, FALSE);
1039 LRESULT CALLBACK WINEXPORT
1040 MenuButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1045 LONG n = GetWindowLong(hwnd, GWL_ID);
1047 WORD n = GetWindowWord(hwnd, GWW_ID);
1049 lptw = (LPTW)GetWindowLong(GetParent(hwnd), 0);
1057 GetWindowRect(hwnd, &rect);
1059 if (PtInRect(&rect, pt))
1060 SendMessage(lptw->hWndText, WM_COMMAND, lpmw->hButtonID[n], 0L);
1061 SetFocus(lptw->hWndText);
1065 return CallWindowProc((lpmw->lpfnButtonProc[n]), hwnd, message, wParam, lParam);