Rev 82769 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/** GraphApp - Cross-Platform Graphics Programming Library.** File: dialogs.c -- standard file dialogs and a few others.* Platform: Windows Version: 2.42 Date: 1998/07/07** Version: 1.00 Changes: Original version by Lachlan Patrick.* Version: 1.50 Changes: Uses new rectangles, callbacks.* Version: 2.20 Changes: Handle null strings correctly now.* Version: 2.40 Changes: Now uses YES, NO, CANCEL symbols.* Version: 2.42 Changes: Askstring fixed by Laurent Piguet.*//* Copyright (C) 1993-1998 Lachlan PatrickThis file is part of GraphApp, a cross-platform C graphics library.GraphApp is free software; you can redistribute it and/or modify itunder the terms of the GNU Library General Public License.GraphApp is distributed in the hope that it will be useful, butWITHOUT ANY WARRANTY.See the file COPYLIB.TXT for details.*//* Copyright (C) 2004--2008 The R FoundationCopyright (C) 2013--2022 The R Core TeamAdditions for R, Chris JacksonFind and replace dialog boxes and dialog handlers.Modify find and replace for RichEdit20W.*//* Mingw-w64 defines this to be 0x0502 */#ifndef _WIN32_WINNT# define _WIN32_WINNT 0x0500#endif#include "win-nls.h"#include "internal.h"#include "ga.h"#include <shlobj.h>typedef struct {char default_str[MAX_PATH];char question[40];} browserInfo;#define STATUSTEXT 14146static int CALLBACKInitBrowseCallbackProc( HWND hwnd, UINT uMsg, LPARAM lp, LPARAM lpData ){char szDir[MAX_PATH], status[MAX_PATH + 40 + 2];if (uMsg == BFFM_INITIALIZED) {SendMessage(hwnd, BFFM_SETSELECTION, 1,(LPARAM)&((browserInfo*)lpData)->default_str);} else if (uMsg == BFFM_SELCHANGED) {if (SHGetPathFromIDList((LPITEMIDLIST) lp, szDir)) {snprintf(status, MAX_PATH+40+2, "%s\n %s",((browserInfo*)lpData)->question, szDir);SetDlgItemText(hwnd, STATUSTEXT, status);SendMessage(hwnd, BFFM_ENABLEOK, 0, TRUE);} elseSendMessage(hwnd, BFFM_ENABLEOK, 0, FALSE);}return(0);}#define BUFSIZE _MAX_PATHstatic char strbuf[BUFSIZE];static wchar_t wcsbuf[65536];static const char *filter[] = {"All Files (*.*)", "*.*","Text Files (*.TXT)", "*.txt","HTML Files (*.HTM)", "*.htm","PNG Files (*.PNG)", "*.png","JPEG Files (*.JPG)", "*.jpg","BMP Files (*.BMP)", "*.bmp",""};static const wchar_t *wfilter[] = {L"All Files (*.*)", L"*.*",L"Text Files (*.TXT)", L"*.txt",L"HTML Files (*.HTM)", L"*.htm",L"PNG Files (*.PNG)", L"*.png",L"JPEG Files (*.JPG)", L"*.jpg",L"BMP Files (*.BMP)", L"*.bmp",L""};unsigned int TopmostDialogs = 0; /* May be MB_TOPMOST */static const char *userfilter;static const wchar_t *userfilterW;void setuserfilter(const char *uf){userfilter=uf;}void setuserfilterW(const wchar_t *uf){userfilterW=uf;}static HWND hModelessDlg = NULL;int myMessageBox(HWND h, const char *text, const char *caption, UINT type){if(localeCP != GetACP()) {int ntext = mbstowcs(NULL, text, 0);int ncaption = mbstowcs(NULL, caption, 0);if (ntext >= 0 && ncaption >= 0) {wchar_t wc[ntext+1], wcaption[ncaption+1];mbstowcs(wcaption, caption, ncaption+1);mbstowcs(wc, text, ntext+1);return MessageBoxW(h, wc, wcaption, type);} elsereturn 0;} elsereturn MessageBoxA(h, text, caption, type);}/** Error reporting dialog.*/void apperror(const char *errstr){if (! errstr)errstr = "Unspecified error";myMessageBox(0, errstr, "Graphics Library Error",MB_TASKMODAL | MB_ICONSTOP | MB_OK | TopmostDialogs);exitapp();}void askok(const char *info){if (! info)info = "";myMessageBox(0, info, "Information",MB_TASKMODAL | MB_ICONINFORMATION | MB_OK | TopmostDialogs);}int askokcancel(const char *question){int result;if (! question)question = "";result = myMessageBox(0, question, G_("Question"),MB_TASKMODAL | MB_ICONQUESTION | MB_OKCANCEL | TopmostDialogs);switch (result) {case IDOK: result = YES; break;case IDCANCEL:default: result = CANCEL; break;}return result;}int askyesno(const char *question){int result;if (! question)question = "";result = myMessageBox(0, question, G_("Question"),MB_TASKMODAL | MB_ICONQUESTION | MB_YESNO | TopmostDialogs);switch (result) {case IDYES: result = YES; break;case IDNO: result = NO; break;default: result = CANCEL; break;}return result;}int askyesnocancel(const char *question){int result;if (! question)question = "";result = myMessageBox(0, question, G_("Question"),MB_TASKMODAL | MB_ICONQUESTION | MB_YESNOCANCEL | MB_SETFOREGROUND | TopmostDialogs);switch (result) {case IDYES: result = YES; break;case IDNO: result = NO; break;case IDCANCEL:default: result = CANCEL; break;}return result;}/* This should always have a native encoded name, so don't need Unicode here */static char cod[MAX_PATH]=""; /*current open directory*/void askchangedir(){char *s, msg[MAX_PATH + 40];/* set cod to current directory */GetCurrentDirectory(MAX_PATH, cod);s = askcdstring(G_(" Change working directory to:"), cod);if (s && (SetCurrentDirectory(s) == FALSE)) {snprintf(msg, MAX_PATH + 40,G_("Unable to set '%s' as working directory"), s);askok(msg);}/* in every case reset cod (to new directory if all went okor to old since user may have edited it) */GetCurrentDirectory(MAX_PATH, cod);}char *askfilename(const char *title, const char *default_name){if (*askfilenames(title, default_name, 0, userfilter?userfilter:filter[0], 0,strbuf, BUFSIZE, NULL)) return strbuf;else return NULL;}char *askfilenamewithdir(const char *title, const char *default_name, const char *dir){if (*askfilenames(title, default_name, 0,userfilter ? userfilter : filter[0], 0,strbuf, BUFSIZE, dir)) return strbuf;else return NULL;}char *askfilenames(const char *title, const char *default_name, int multi,const char *filters, int filterindex,char *strbuf, int bufsize,const char *dir){int i;OPENFILENAME ofn;char cwd[MAX_PATH] = "";HWND prev = GetFocus();if (!default_name) default_name = "";strcpy(strbuf, default_name);GetCurrentDirectory(MAX_PATH, cwd);if (!cod[0]) strcpy(cod, cwd);ofn.lStructSize = sizeof(OPENFILENAME);ofn.hwndOwner = current_window ? current_window->handle : 0;ofn.hInstance = 0;ofn.lpstrFilter = filters;ofn.lpstrCustomFilter = NULL;ofn.nMaxCustFilter = 0;ofn.nFilterIndex = filterindex;ofn.lpstrFile = strbuf;ofn.nMaxFile = bufsize;ofn.lpstrFileTitle = NULL;ofn.nMaxFileTitle = _MAX_FNAME + _MAX_EXT;ofn.lpstrInitialDir = dir ? dir : cod;ofn.lpstrTitle = title;ofn.Flags = OFN_CREATEPROMPT | OFN_HIDEREADONLY | OFN_EXPLORER;if (multi) ofn.Flags |= OFN_ALLOWMULTISELECT;ofn.nFileOffset = 0;ofn.nFileExtension = 0;ofn.lpstrDefExt = "*";ofn.lCustData = 0L;ofn.lpfnHook = NULL;ofn.lpTemplateName = NULL;if (GetOpenFileName(&ofn) == 0) {if(!dir) GetCurrentDirectory(MAX_PATH, cod);SetCurrentDirectory(cwd);strbuf[0] = 0;strbuf[1] = 0;} else {if(!dir) GetCurrentDirectory(MAX_PATH, cod);SetCurrentDirectory(cwd);for (i = 0; i < 10; i++) if (peekevent()) doevent();}SetFocus(prev);return strbuf;}wchar_t *askfilenameW(const char *title, const char *default_name){wchar_t wtitle[1000], wdef_name[MAX_PATH];mbstowcs(wtitle, title, 1000);if (!default_name) wcscpy(wdef_name, L"");else mbstowcs(wdef_name, default_name, MAX_PATH);if (*askfilenamesW(wtitle, wdef_name, 0,userfilterW ? userfilterW : wfilter[0], 0,NULL)) return wcsbuf;else return NULL;}wchar_t *askfilenamesW(const wchar_t *title, const wchar_t *default_name,int multi,const wchar_t *filters, int filterindex,const wchar_t *dir){int i;OPENFILENAMEW ofn;char cwd[MAX_PATH];wchar_t wcod[MAX_PATH];HWND prev = GetFocus();if (!default_name) default_name = L"";memset(wcsbuf, 0, sizeof(wcsbuf));wcscpy(wcsbuf, default_name);GetCurrentDirectory(MAX_PATH, cwd);if (!strcmp(cod, "")) {if (!dir) GetCurrentDirectoryW(MAX_PATH, wcod); else wcscpy(wcod, dir);} elsembstowcs(wcod, cod, MAX_PATH);ofn.lStructSize = sizeof(OPENFILENAME);ofn.hwndOwner = current_window ? current_window->handle : 0;ofn.hInstance = 0;ofn.lpstrFilter = filters;ofn.lpstrCustomFilter = NULL;ofn.nMaxCustFilter = 0;ofn.nFilterIndex = filterindex;ofn.lpstrFile = wcsbuf;ofn.nMaxFile = 65520; /* precaution against overflow */ofn.lpstrFileTitle = NULL;ofn.nMaxFileTitle = _MAX_FNAME + _MAX_EXT;ofn.lpstrInitialDir = wcod;ofn.lpstrTitle = title;ofn.Flags = OFN_CREATEPROMPT | OFN_HIDEREADONLY | OFN_EXPLORER;if (multi) ofn.Flags |= OFN_ALLOWMULTISELECT;ofn.nFileOffset = 0;ofn.nFileExtension = 0;ofn.lpstrDefExt = L"*";ofn.lCustData = 0L;ofn.lpfnHook = NULL;ofn.lpTemplateName = NULL;if (GetOpenFileNameW(&ofn) == 0) {/* This could fail if the Unicode name is not a native name */DWORD res = GetCurrentDirectory(MAX_PATH, cod);if(res) strcpy(cod, cwd);SetCurrentDirectory(cwd);wcsbuf[0] = 0;wcsbuf[1] = 0;} else {DWORD res = GetCurrentDirectory(MAX_PATH, cod);if(res) strcpy(cod, cwd);SetCurrentDirectory(cwd);for (i = 0; i < 10; i++) if (peekevent()) doevent();}SetFocus(prev);return wcsbuf;}int countFilenames(const char *list){const char *temp;int count;count = 0;for (temp = list; *temp; temp += strlen(temp)+1) count++;return count;}char *askfilesave(const char *title, const char *default_name){return askfilesavewithdir(title, default_name, NULL);}wchar_t *askfilesaveW(const char *title, const char *default_name){int i;OPENFILENAMEW ofn;wchar_t cwd[MAX_PATH], wdef_name[MAX_PATH], wtitle[1000];if (!default_name) wcscpy(wdef_name, L"");else mbstowcs(wdef_name, default_name, MAX_PATH);wcscpy(wcsbuf, wdef_name);mbstowcs(wtitle, title, 1000);ofn.lStructSize = sizeof(OPENFILENAME);ofn.hwndOwner = current_window ? current_window->handle : 0;ofn.hInstance = 0;ofn.lpstrFilter = userfilterW ? userfilterW : wfilter[0];ofn.lpstrCustomFilter = NULL;ofn.nMaxCustFilter = 0;ofn.nFilterIndex = 0;ofn.lpstrFile = wcsbuf;ofn.nMaxFile = BUFSIZE;ofn.lpstrFileTitle = NULL;ofn.nMaxFileTitle = _MAX_FNAME + _MAX_EXT;if (GetCurrentDirectoryW(MAX_PATH, cwd))ofn.lpstrInitialDir = cwd;elseofn.lpstrInitialDir = NULL;ofn.lpstrTitle = wtitle;ofn.Flags = OFN_OVERWRITEPROMPT |OFN_NOCHANGEDIR | OFN_HIDEREADONLY;ofn.nFileOffset = 0;ofn.nFileExtension = 0;ofn.lpstrDefExt = NULL;ofn.lCustData = 0L;ofn.lpfnHook = NULL;ofn.lpTemplateName = NULL;if (GetSaveFileNameW(&ofn) == 0)return NULL;else {for (i = 0; i < 10; i++) if (peekevent()) doevent();return wcsbuf;}}char *askfilesavewithdir(const char *title, const char *default_name,const char *dir){int i;OPENFILENAME ofn;char cwd[MAX_PATH], *defext = NULL;if (!default_name) default_name = "";else if(default_name[0] == '|') {defext = (char *)default_name + 2;default_name = "";}strcpy(strbuf, default_name);ofn.lStructSize = sizeof(OPENFILENAME);ofn.hwndOwner = current_window ? current_window->handle : 0;ofn.hInstance = 0;ofn.lpstrFilter = userfilter?userfilter:filter[0];ofn.lpstrCustomFilter = NULL;ofn.nMaxCustFilter = 0;ofn.nFilterIndex = 0;ofn.lpstrFile = strbuf;ofn.nMaxFile = BUFSIZE;ofn.lpstrFileTitle = NULL;ofn.nMaxFileTitle = _MAX_FNAME + _MAX_EXT;if(dir && strlen(dir) > 0) {strcpy(cwd, dir);/* This should have been set to use backslashes in the caller */ofn.lpstrInitialDir = cwd;} else {if (GetCurrentDirectory(MAX_PATH, cwd))ofn.lpstrInitialDir = cwd;elseofn.lpstrInitialDir = NULL;}ofn.lpstrTitle = title;ofn.Flags = OFN_OVERWRITEPROMPT |OFN_NOCHANGEDIR | OFN_HIDEREADONLY;ofn.nFileOffset = 0;ofn.nFileExtension = 0;ofn.lpstrDefExt = defext;ofn.lCustData = 0L;ofn.lpfnHook = NULL;ofn.lpTemplateName = NULL;if (GetSaveFileName(&ofn) == 0)return NULL;else {for (i = 0; i < 10; i++) if (peekevent()) doevent();return strbuf;}}/** Input a string using a dialog box.*//** Dialog information structure:*/#define NOT_CHOSEN_YET -2typedef struct dialog_data_class {int hit;char * result;label question;field text, pass;button yes, no, cancel;} dialog_data;#define data(w) ((dialog_data *) (getdata(w)))/** Some strings to use:*//* static char * OKAY_STRING = "OK";static char * CANCEL_STRING = "Cancel";static char * BROWSE_STRING = "Browse"; */static const char * QUESTION_TITLE = "Question";static const char * PASSWORD_TITLE = "Password Entry";static void add_data(window w){dialog_data *d;d = create (dialog_data);if (! d)return;d->hit = NOT_CHOSEN_YET;setdata(w, d);}static char * get_dialog_string(window w){dialog_data *d = data(w);if (d->hit < YES) /* cancelled */return NULL;del_string(d->result);if (d->text) /* question dialog */d->result = new_string(GA_gettext(d->text));return d->result;}static void hit_button(control c){window w = parentwindow(c);dialog_data *d = data(w);int value = getvalue(c);d->hit = value;hide(w);}static void hit_key(window w, int key){button btn;char *name = NULL;w = parentwindow(w);if (data(w) == NULL)return;if ((btn = data(w)->yes) != NULL) {name = getname(btn);if ((key == '\n') || (tolower(name[0]) == tolower(key))){flashcontrol(btn);activatecontrol(btn);return;}}if ((btn = data(w)->cancel) != NULL) {name = getname(btn);if ((key == ESC) || (tolower(name[0]) == tolower(key))){flashcontrol(btn);activatecontrol(btn);return;}}if ((btn = data(w)->no) != NULL) {name = getname(btn);if ((key == ESC) || (tolower(name[0]) == tolower(key))){flashcontrol(btn);activatecontrol(btn);return;}}}/** Handle the events from a message dialog, hide the window afterwards.*/static int handle_message_dialog(window w){window old;dialog_data *d = data(w);old = currentdrawing();d->hit = NOT_CHOSEN_YET;show(w);while (d->hit == NOT_CHOSEN_YET) {waitevent();doevent();}hide(w);if (old) drawto(old);return d->hit;}static window init_askstr_dialog(const char *title, const char *question,const char *default_str){window win;dialog_data *d;int tw, bw, h, middle;if (! question)question= "";if (! default_str)default_str = "";tw = strwidth(SystemFont, G_("Cancel")) * 8;h = getheight(SystemFont);if (tw < 150) tw = 150;win = newwindow(title, rect(0,0,tw+30,h*9+12),Titlebar | Centered | Modal);setbackground(win, dialog_bg());add_data(win);d = data(win);d->question = newlabel(question, rect(10,h,tw+4,h*2+2),AlignLeft);if (title == PASSWORD_TITLE)d->text = newpassword(default_str, rect(10,h*4,tw+4,h*3/2));elsed->text = newfield(default_str, rect(10,h*4,tw+4,h*3/2));middle = (tw+30)/2;bw = strwidth(SystemFont, G_("Cancel")) * 3/2;d->yes = newbutton(G_("OK"),rect(middle-bw-10, h*7, bw, h+10), hit_button);setvalue(d->yes, YES);d->cancel = newbutton(G_("Cancel"),rect(middle+10, h*7, bw, h+10), hit_button);setvalue(d->cancel, CANCEL);setkeydown(win, hit_key);return win;}char *askstring(const char *question, const char *default_str){static window win = NULL;window prev = current_window;if (! win)win = init_askstr_dialog(QUESTION_TITLE, question, default_str);else {settext(data(win)->question, question);settext(data(win)->text, default_str);}if (TopmostDialogs & MB_TOPMOST)BringToTop(win, 1);handle_message_dialog(win);current_window = prev;return get_dialog_string(win);}char *askcdstring(const char *question, const char *default_str){LPMALLOC g_pMalloc;BROWSEINFO bi;LPITEMIDLIST pidlBrowse;browserInfo info;OSVERSIONINFOEX osvi;strncpy(info.question, question, 40 - 1);info.question[40 - 1] = '\0';strncpy(info.default_str, default_str, MAX_PATH - 1);info.default_str[MAX_PATH - 1] = '\0';/* Get the shell's allocator. */if (!SUCCEEDED(SHGetMalloc(&g_pMalloc))) return NULL;osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);GetVersionEx((OSVERSIONINFO *)&osvi);ZeroMemory(&bi, sizeof(bi));bi.hwndOwner = 0;if(osvi.dwMajorVersion >= 6) { /* future proof *//* CSIDL_DESKTOP gets mapped to the User's desktop in Vista(a bug). SHGetFolderLocation is Win2k or later */if (!SUCCEEDED(SHGetFolderLocation(NULL, CSIDL_DRIVES, NULL, 0,(LPITEMIDLIST *) &bi.pidlRoot)))return NULL;} /* else it is 0, which is CSIDL_DESKTOP */bi.pszDisplayName = strbuf;bi.lpszTitle = question;bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_USENEWUI;bi.lpfn = (BFFCALLBACK) InitBrowseCallbackProc;bi.lParam = (LPARAM) &info;/* Browse for a folder and return its PIDL. */pidlBrowse = SHBrowseForFolder(&bi);if (pidlBrowse != NULL) {SHGetPathFromIDList(pidlBrowse, strbuf);g_pMalloc->lpVtbl->Free(g_pMalloc, pidlBrowse);if (strbuf[0])return strbuf;}return NULL;}char *askpassword(const char *question, const char *default_str){static window win = NULL;window prev = current_window;if (! win)win = init_askstr_dialog(PASSWORD_TITLE, question, default_str);else {settext(data(win)->question, question);settext(data(win)->text, default_str);}if (TopmostDialogs & MB_TOPMOST)BringToTop(win, 1);handle_message_dialog(win);current_window = prev;return get_dialog_string(win);}char *askUserPass(const char *title){static window win = NULL;dialog_data *d;window prev = current_window;if (! win) {int tw, bw, h, middle;tw = strwidth(SystemFont, G_("Cancel")) * 8;h = getheight(SystemFont);if (tw < 150) tw = 150;win = newwindow(title, rect(0, 0, tw+30, h*9+12),Titlebar | Centered | Modal);setbackground(win, dialog_bg());add_data(win);d = data(win);d->question = newlabel(G_("User"), rect(10, h, tw+4, h*2+2), AlignLeft);bw = strwidth(SystemFont, G_("Password"));d->text = newfield("", rect(20+bw, h, tw-6-bw, h*3/2));newlabel(_("Password"), rect(10, h*4, tw+4, h*2+2), AlignLeft);d->pass = newpassword("", rect(20+bw, h*4, tw-6-bw, h*3/2));middle = (tw+30)/2;bw = strwidth(SystemFont, G_("Cancel")) * 3/2;d->yes = newbutton(G_("OK"),rect(middle-bw-10, h*7, bw, h+10), hit_button);setvalue(d->yes, YES);d->cancel = newbutton(G_("Cancel"),rect(middle+10, h*7, bw, h+10), hit_button);setvalue(d->cancel, CANCEL);setkeydown(win, hit_key);} else {d = data(win);settext(d->text, "");settext(d->pass, "");}if (TopmostDialogs & MB_TOPMOST)BringToTop(win, 1);handle_message_dialog(win);current_window = prev;{char *user, *pass;static char buf[1000];if (d->hit < YES) /* cancelled */ return "";if (d->text) user = new_string(GA_gettext(d->text));else return "";if (d->pass) pass = new_string(GA_gettext(d->pass));else return "";snprintf(buf, 1000, "%s:%s", user, pass);return buf;}return ""; /* -Wall */}int modeless_active(){if (hModelessDlg)return 1;return 0;}PROTECTEDHWND get_modeless(){return hModelessDlg;}void finddialog(textbox t){static FINDREPLACE fr;static char szFindWhat[80];fr.lStructSize = sizeof(fr);fr.hwndOwner = t->handle;fr.lpstrFindWhat = szFindWhat;fr.wFindWhatLen = 80;fr.Flags = FR_DOWN;fr.lCustData = 0 ;fr.lpfnHook = NULL ;fr.lpTemplateName = NULL ;hModelessDlg = FindText(&fr);}void replacedialog(textbox t){static FINDREPLACE fr;static char szFindWhat[80];static char szReplaceWith[80];fr.lStructSize = sizeof(fr);fr.hwndOwner = t->handle;fr.lpstrFindWhat = szFindWhat;fr.lpstrReplaceWith = szReplaceWith;fr.wFindWhatLen = 80;fr.wReplaceWithLen = 80;fr.Flags = FR_DOWN;fr.lCustData = 0 ;fr.lpfnHook = NULL ;fr.lpTemplateName = NULL ;hModelessDlg = ReplaceText(&fr);}#include <richedit.h>/* Find and select a string in a rich edit control */static int richeditfind(HWND hwnd, char *what, int matchcase,int wholeword, int down){long start, end;CHARRANGE sel;WPARAM w = 0;FINDTEXTEXW ft;sendmessage (hwnd, EM_EXGETSEL, 0, &sel) ;start = sel.cpMin;end = sel.cpMax;/* RichEdit20W (see newrichtextarea) requires a Unicode string. */int nwhat = mbstowcs(NULL, what, 0);wchar_t *wwhat = (wchar_t *) malloc((nwhat+1)*sizeof(wchar_t));mbstowcs(wwhat, what, nwhat+1);ft.lpstrText = wwhat;ft.chrgText.cpMin = start;ft.chrgText.cpMax = end;if (down) {w = w | FR_DOWN;ft.chrg.cpMin = end;ft.chrg.cpMax = -1;}else {ft.chrg.cpMin = start;ft.chrg.cpMax = 0;}if (matchcase) w = w | FR_MATCHCASE;if (wholeword) w = w | FR_WHOLEWORD;/* The cast is necessary, because EM_FINDTEXTEXW returns LONG (32-bit),but the rest of the 64-bit LRESULT is undefined (not all 1s for -1).Checking chrgText.cpMin and chrgText.cpMax is for safety only:returning 1 here by accident instead of 0 would lead to infinite loopduring replace all. */long res = (long) sendmessage (hwnd, EM_FINDTEXTEXW, w, &ft);if (res == -1 || (ft.chrgText.cpMin == -1 && ft.chrgText.cpMax == -1)) {free(wwhat);return 0;} else {sendmessage (hwnd, EM_EXSETSEL, 0, &(ft.chrgText));sendmessage (hwnd, EM_SCROLLCARET, 0, 0);}free(wwhat);return 1;}static int richeditreplace(HWND hwnd, char *what, char *replacewith,int matchcase, int wholeword, int down){/* If current selection is the find string, replace it and find next */long start, end;CHARRANGE sel;wchar_t *wbuf;textbox t = find_by_handle(hwnd);if (t) {sendmessage (hwnd, EM_EXGETSEL, 0, &sel) ;start = sel.cpMin;end = sel.cpMax;if (start < end) {/* RichEdit20W (see newrichtextarea) produces a Unicode string. */int nwhat = mbstowcs(NULL, what, 0);wchar_t *wwhat = (wchar_t *) malloc((nwhat+1)*sizeof(wchar_t));mbstowcs(wwhat, what, nwhat+1);wbuf = (wchar_t *) malloc((end - start + 1)*sizeof(wchar_t));sendmessage(hwnd, EM_GETSELTEXT, 0, wbuf);if (!wcscmp(wbuf, wwhat)) {checklimittext(t, strlen(replacewith) - strlen(what) + 2);sendmessage (hwnd, EM_REPLACESEL, 1, replacewith);}free(wwhat);free(wbuf);}/* else just find next */if (richeditfind(hwnd, what, matchcase, wholeword, down))return 1;}return 0;}PROTECTEDvoid handle_findreplace(HWND hwnd, LPFINDREPLACE pfr){CHARRANGE sel;int matchcase=0, wholeword=0, down=0;char buf[100];if (pfr->Flags & FR_MATCHCASE) matchcase = 1;if (pfr->Flags & FR_WHOLEWORD) wholeword = 1;if (pfr->Flags & FR_DOWN) down = 1;if (pfr->Flags & FR_FINDNEXT) {if (!richeditfind(hwnd, pfr->lpstrFindWhat, matchcase, wholeword, down)) {snprintf(buf, 100, G_("\"%s\" not found"), pfr->lpstrFindWhat);askok(buf);}}else if (pfr->Flags & FR_REPLACE) {if (!richeditreplace(hwnd, pfr->lpstrFindWhat, pfr->lpstrReplaceWith, matchcase, wholeword, down)) {snprintf(buf, 100, G_("\"%s\" not found"), pfr->lpstrFindWhat);askok(buf);}}else if (pfr->Flags & FR_REPLACEALL) {/* replace all in the whole buffer then return to original selection state */sendmessage (hwnd, EM_EXGETSEL, 0, &sel) ;sendmessage (hwnd, EM_SETSEL, 0, 0) ;while ( richeditreplace(hwnd, pfr->lpstrFindWhat, pfr->lpstrReplaceWith, matchcase, wholeword, down) ) ;sendmessage (hwnd, EM_EXSETSEL, 0, &sel) ;}else if (pfr->Flags & FR_DIALOGTERM)hModelessDlg = NULL;}