From 159e8c69ce74a438bf8a4b81feebfd038d348638 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 7 Jun 2013 08:50:25 +0000 Subject: Fix [1913750]: tk_chooseDirectory -initialdir internationalization problem. (backported from Tk 8.6) --- ChangeLog | 5 + win/tkWinDialog.c | 919 +++++++++++------------------------------------------- 2 files changed, 187 insertions(+), 737 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5646282..561bda6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-06-07 Jan Nijtmans + + * win/tkWinDialog.c: [Bug 1913750]: tk_chooseDirectory -initialdir + internationalization problem. (backported from Tk 8.6) + 2013-06-05 Jan Nijtmans * generic/ttk/ttkScroll.c: [Bug 3613759]: ttk::entry and symbolic diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c index 069991b..f9bb10a 100644 --- a/win/tkWinDialog.c +++ b/win/tkWinDialog.c @@ -8,7 +8,6 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ - #define WINVER 0x0500 /* Requires Windows 2K definitions */ #define _WIN32_WINNT 0x0500 #include "tkWinInt.h" @@ -53,12 +52,12 @@ /* * The following structure is used by the new Tk_ChooseDirectoryObjCmd to pass - * data between it and its callback. Unqiue to Winodws platform. + * data between it and its callback. Unique to Windows platform. */ typedef struct ChooseDirData { - TCHAR utfInitDir[MAX_PATH]; /* Initial folder to use */ - TCHAR utfRetDir[MAX_PATH]; /* Returned folder to use */ + WCHAR initDir[MAX_PATH]; /* Initial folder to use */ + WCHAR retDir[MAX_PATH]; /* Returned folder to use */ Tcl_Interp *interp; int mustExist; /* True if file must exist to return from * callback */ @@ -132,14 +131,14 @@ static const struct {int type; int btnIds[3];} allowedTypes[] = { */ #define TkWinGetHInstance(from) \ - ((HINSTANCE) GetWindowLongPtr((from), GWLP_HINSTANCE)) + ((HINSTANCE) GetWindowLongPtrW((from), GWLP_HINSTANCE)) #define TkWinGetUserData(from) \ - GetWindowLongPtr((from), GWLP_USERDATA) + GetWindowLongPtrW((from), GWLP_USERDATA) #define TkWinSetUserData(to,what) \ - SetWindowLongPtr((to), GWLP_USERDATA, (LPARAM)(what)) + SetWindowLongPtrW((to), GWLP_USERDATA, (LPARAM)(what)) /* - * The value of TK_MULTI_MAX_PATH dictactes how many files can be retrieved + * The value of TK_MULTI_MAX_PATH dictates how many files can be retrieved * with tk_get*File -multiple 1. It must be allocated on the stack, so make it * large enough but not too large. - hobbs * @@ -163,18 +162,12 @@ typedef struct ChooseDir { * directory or return. */ int lastIdx; /* Last item that was selected in directory * browser listbox. */ - TCHAR path[MAX_PATH]; /* On return from choose directory dialog, - * holds the selected path. Cannot return - * selected path in ofnPtr->lpstrFile because - * the default dialog proc stores a '\0' in - * it, since, of course, no _file_ was - * selected. */ - OPENFILENAME *ofnPtr; /* pointer to the OFN structure */ + OPENFILENAMEW *ofnPtr; /* pointer to the OFN structure */ } ChooseDir; /* - * The following structure is used to pass information between GetFileName/W - * functions and OFN dialog hook procedures. [Bug 2896501, Patch 2898255] + * The following structure is used to pass information between GetFileName + * function and OFN dialog hook procedures. [Bug 2896501, Patch 2898255] */ typedef struct OFNData { @@ -183,8 +176,7 @@ typedef struct OFNData { int dynFileBufferSize; /* Dynamic filename buffer size, stored to * avoid shrinking and expanding the buffer * when selection changes */ - char *dynFileBuffer; /* Dynamic filename buffer, cast to WCHAR* in - * UNICODE procedures */ + WCHAR *dynFileBuffer; /* Dynamic filename buffer */ } OFNData; /* @@ -195,23 +187,18 @@ static UINT APIENTRY ChooseDirectoryValidateProc(HWND hdlg, UINT uMsg, LPARAM wParam, LPARAM lParam); static UINT CALLBACK ColorDlgHookProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); -static int GetFileNameA(ClientData clientData, - Tcl_Interp *interp, int objc, - Tcl_Obj *CONST objv[], int isOpen); -static int GetFileNameW(ClientData clientData, +static int GetFileName(ClientData clientData, Tcl_Interp *interp, int objc, - Tcl_Obj *CONST objv[], int isOpen); + Tcl_Obj *const objv[], int isOpen); static int MakeFilter(Tcl_Interp *interp, Tcl_Obj *valuePtr, Tcl_DString *dsPtr, Tcl_Obj *initialPtr, - int *index); -static UINT APIENTRY OFNHookProcA(HWND hdlg, UINT uMsg, WPARAM wParam, - LPARAM lParam); -static UINT APIENTRY OFNHookProcW(HWND hdlg, UINT uMsg, WPARAM wParam, + int *indexPtr); +static UINT APIENTRY OFNHookProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam); static LRESULT CALLBACK MsgBoxCBTProc(int nCode, WPARAM wParam, LPARAM lParam); static void SetTkDialog(ClientData clientData); -static char * ConvertExternalFilename(Tcl_Encoding encoding, - char *filename, Tcl_DString *dsPtr); +static const char *ConvertExternalFilename(WCHAR *filename, + Tcl_DString *dsPtr); /* *------------------------------------------------------------------------- @@ -252,10 +239,10 @@ EatSpuriousMessageBugFix(void) DWORD nTime = GetTickCount() + 250; while (GetTickCount() < nTime) { - if (PeekMessage(&msg, 0, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_NOREMOVE)){ + if (PeekMessageA(&msg, 0, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_NOREMOVE)){ break; } - PeekMessage(&msg, 0, WM_LBUTTONUP, WM_LBUTTONUP, PM_REMOVE); + PeekMessageA(&msg, 0, WM_LBUTTONUP, WM_LBUTTONUP, PM_REMOVE); } } @@ -312,16 +299,16 @@ Tk_ChooseColorObjCmd( ClientData clientData, /* Main window associated with interpreter. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ - Tcl_Obj *CONST objv[]) /* Argument objects. */ + Tcl_Obj *const objv[]) /* Argument objects. */ { Tk_Window tkwin = (Tk_Window) clientData, parent; HWND hWnd; int i, oldMode, winCode, result; - CHOOSECOLOR chooseColor; + CHOOSECOLORW chooseColor; static int inited = 0; static COLORREF dwCustColors[16]; static long oldColor; /* the color selected last time */ - static CONST char *optionStrings[] = { + static const char *optionStrings[] = { "-initialcolor", "-parent", "-title", NULL }; enum options { @@ -345,7 +332,7 @@ Tk_ChooseColorObjCmd( } parent = tkwin; - chooseColor.lStructSize = sizeof(CHOOSECOLOR); + chooseColor.lStructSize = sizeof(CHOOSECOLORW); chooseColor.hwndOwner = NULL; chooseColor.hInstance = NULL; chooseColor.rgbResult = oldColor; @@ -353,11 +340,11 @@ Tk_ChooseColorObjCmd( chooseColor.Flags = CC_RGBINIT | CC_FULLOPEN | CC_ENABLEHOOK; chooseColor.lCustData = (LPARAM) NULL; chooseColor.lpfnHook = (LPOFNHOOKPROC) ColorDlgHookProc; - chooseColor.lpTemplateName = (LPTSTR) interp; + chooseColor.lpTemplateName = (LPWSTR) interp; for (i = 1; i < objc; i += 2) { int index; - char *string; + const char *string; Tcl_Obj *optionPtr, *valuePtr; optionPtr = objv[i]; @@ -405,7 +392,7 @@ Tk_ChooseColorObjCmd( chooseColor.hwndOwner = hWnd; oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); - winCode = ChooseColor(&chooseColor); + winCode = ChooseColorW(&chooseColor); (void) Tcl_SetServiceMode(oldMode); /* @@ -473,7 +460,7 @@ ColorDlgHookProc( ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); const char *title; - CHOOSECOLOR *ccPtr; + CHOOSECOLORW *ccPtr; if (WM_INITDIALOG == uMsg) { @@ -481,14 +468,13 @@ ColorDlgHookProc( * Set the title string of the dialog. */ - ccPtr = (CHOOSECOLOR *) lParam; + ccPtr = (CHOOSECOLORW *) lParam; title = (const char *) ccPtr->lCustData; if ((title != NULL) && (title[0] != '\0')) { Tcl_DString ds; - (*tkWinProcs->setWindowText)(hDlg, - Tcl_WinUtfToTChar(title, -1, &ds)); + SetWindowTextW(hDlg, (WCHAR *)Tcl_WinUtfToTChar(title,-1,&ds)); Tcl_DStringFree(&ds); } if (tsdPtr->debugFlag) { @@ -522,13 +508,9 @@ Tk_GetOpenFileObjCmd( ClientData clientData, /* Main window associated with interpreter. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ - Tcl_Obj *CONST objv[]) /* Argument objects. */ + Tcl_Obj *const objv[]) /* Argument objects. */ { - if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) { - return GetFileNameW(clientData, interp, objc, objv, 1); - } else { - return GetFileNameA(clientData, interp, objc, objv, 1); - } + return GetFileName(clientData, interp, objc, objv, 1); } /* @@ -553,19 +535,15 @@ Tk_GetSaveFileObjCmd( ClientData clientData, /* Main window associated with interpreter. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ - Tcl_Obj *CONST objv[]) /* Argument objects. */ + Tcl_Obj *const objv[]) /* Argument objects. */ { - if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_NT) { - return GetFileNameW(clientData, interp, objc, objv, 0); - } else { - return GetFileNameA(clientData, interp, objc, objv, 0); - } + return GetFileName(clientData, interp, objc, objv, 0); } /* *---------------------------------------------------------------------- * - * GetFileNameW -- + * GetFileName -- * * Calls GetOpenFileName() or GetSaveFileName(). * @@ -579,11 +557,11 @@ Tk_GetSaveFileObjCmd( */ static int -GetFileNameW( +GetFileName( ClientData clientData, /* Main window associated with interpreter. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ - Tcl_Obj *CONST objv[], /* Argument objects. */ + Tcl_Obj *const objv[], /* Argument objects. */ int open) /* 1 to call GetOpenFileName(), 0 to call * GetSaveFileName(). */ { @@ -593,13 +571,12 @@ GetFileNameW( int cdlgerr; int filterIndex = 0, result = TCL_ERROR, winCode, oldMode, i, multi = 0; int confirmOverwrite = 1; - char *extension = NULL, *title = NULL; + const char *extension = NULL, *title = NULL; Tk_Window tkwin = (Tk_Window) clientData; HWND hWnd; Tcl_Obj *filterObj = NULL, *initialTypeObj = NULL, *typeVariableObj = NULL; Tcl_DString utfFilterString, utfDirString, ds; Tcl_DString extString, filterString, dirString, titleString; - Tcl_Encoding unicodeEncoding = TkWinGetUnicodeEncoding(); ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); enum options { @@ -607,10 +584,10 @@ GetFileNameW( FILE_TITLE, FILE_TYPEVARIABLE, FILE_MULTIPLE, FILE_CONFIRMOW }; struct Options { - CONST char *name; + const char *name; enum options value; }; - static CONST struct Options saveOptions[] = { + static const struct Options saveOptions[] = { {"-confirmoverwrite", FILE_CONFIRMOW}, {"-defaultextension", FILE_DEFAULT}, {"-filetypes", FILE_TYPES}, @@ -621,7 +598,7 @@ GetFileNameW( {"-typevariable", FILE_TYPEVARIABLE}, {NULL, FILE_DEFAULT/*ignored*/ } }; - static CONST struct Options openOptions[] = { + static const struct Options openOptions[] = { {"-defaultextension", FILE_DEFAULT}, {"-filetypes", FILE_TYPES}, {"-initialdir", FILE_INITDIR}, @@ -632,7 +609,7 @@ GetFileNameW( {"-typevariable", FILE_TYPEVARIABLE}, {NULL, FILE_DEFAULT/*ignored*/ } }; - CONST struct Options *options = open ? openOptions : saveOptions; + const struct Options *options = open ? openOptions : saveOptions; file[0] = '\0'; ZeroMemory(&ofnData, sizeof(OFNData)); @@ -645,7 +622,7 @@ GetFileNameW( for (i = 1; i < objc; i += 2) { int index; - char *string; + const char *string; Tcl_Obj *valuePtr = objv[i + 1]; if (Tcl_GetIndexFromObjStruct(interp, objv[i], options, @@ -679,9 +656,9 @@ GetFileNameW( if (Tcl_TranslateFileName(interp, string, &ds) == NULL) { goto end; } - Tcl_UtfToExternal(NULL, unicodeEncoding, Tcl_DStringValue(&ds), - Tcl_DStringLength(&ds), 0, NULL, (char *) file, - sizeof(file), NULL, NULL, NULL); + Tcl_UtfToExternal(NULL, TkWinGetUnicodeEncoding(), + Tcl_DStringValue(&ds), Tcl_DStringLength(&ds), 0, NULL, + (char *) file, sizeof(file), NULL, NULL, NULL); Tcl_DStringFree(&ds); break; case FILE_PARENT: @@ -728,11 +705,11 @@ GetFileNameW( } ofn.hwndOwner = hWnd; ofn.hInstance = TkWinGetHInstance(ofn.hwndOwner); - ofn.lpstrFile = (WCHAR *) file; + ofn.lpstrFile = file; ofn.nMaxFile = TK_MULTI_MAX_PATH; ofn.Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR | OFN_EXPLORER | OFN_ENABLEHOOK| OFN_ENABLESIZING; - ofn.lpfnHook = (LPOFNHOOKPROC) OFNHookProcW; + ofn.lpfnHook = (LPOFNHOOKPROC) OFNHookProc; ofn.lCustData = (LPARAM) &ofnData; if (open != 0) { @@ -751,24 +728,22 @@ GetFileNameW( * procedure when necessary */ - ofnData.dynFileBufferSize = 1024; - ofnData.dynFileBuffer = ckalloc(1024); + ofnData.dynFileBufferSize = 512; + ofnData.dynFileBuffer = (WCHAR *)ckalloc(512 * sizeof(WCHAR)); } if (extension != NULL) { - Tcl_UtfToExternalDString(unicodeEncoding, extension, -1, &extString); + Tcl_WinUtfToTChar(extension, -1, &extString); ofn.lpstrDefExt = (WCHAR *) Tcl_DStringValue(&extString); } - Tcl_UtfToExternalDString(unicodeEncoding, - Tcl_DStringValue(&utfFilterString), + Tcl_WinUtfToTChar(Tcl_DStringValue(&utfFilterString), Tcl_DStringLength(&utfFilterString), &filterString); ofn.lpstrFilter = (WCHAR *) Tcl_DStringValue(&filterString); ofn.nFilterIndex = filterIndex; if (Tcl_DStringValue(&utfDirString)[0] != '\0') { - Tcl_UtfToExternalDString(unicodeEncoding, - Tcl_DStringValue(&utfDirString), + Tcl_WinUtfToTChar(Tcl_DStringValue(&utfDirString), Tcl_DStringLength(&utfDirString), &dirString); } else { /* @@ -784,7 +759,7 @@ GetFileNameW( Tcl_DStringValue(&utfDirString), &cwd) == NULL)) { Tcl_ResetResult(interp); } else { - Tcl_UtfToExternalDString(unicodeEncoding, Tcl_DStringValue(&cwd), + Tcl_WinUtfToTChar(Tcl_DStringValue(&cwd), Tcl_DStringLength(&cwd), &dirString); } Tcl_DStringFree(&cwd); @@ -792,7 +767,7 @@ GetFileNameW( ofn.lpstrInitialDir = (WCHAR *) Tcl_DStringValue(&dirString); if (title != NULL) { - Tcl_UtfToExternalDString(unicodeEncoding, title, -1, &titleString); + Tcl_WinUtfToTChar(title, -1, &titleString); ofn.lpstrTitle = (WCHAR *) Tcl_DStringValue(&titleString); } @@ -858,7 +833,7 @@ GetFileNameW( * first element is the directory path. */ - WCHAR *files = (WCHAR *) ofnData.dynFileBuffer; + WCHAR *files = ofnData.dynFileBuffer; Tcl_Obj *returnList = Tcl_NewObj(); int count = 0; @@ -866,8 +841,7 @@ GetFileNameW( * Get directory. */ - (void) ConvertExternalFilename(unicodeEncoding, (char *) files, - &ds); + ConvertExternalFilename(files, &ds); while (*files != '\0') { while (*files != '\0') { @@ -879,8 +853,7 @@ GetFileNameW( Tcl_DString filenameBuf; count++; - (void) ConvertExternalFilename(unicodeEncoding, - (char *) files, &filenameBuf); + ConvertExternalFilename(files, &filenameBuf); fullnameObj = Tcl_NewStringObj(Tcl_DStringValue(&ds), Tcl_DStringLength(&ds)); @@ -906,8 +879,8 @@ GetFileNameW( Tcl_SetObjResult(interp, returnList); Tcl_DStringFree(&ds); } else { - Tcl_AppendResult(interp, ConvertExternalFilename(unicodeEncoding, - (char *) ofn.lpstrFile, &ds), NULL); + Tcl_AppendResult(interp, ConvertExternalFilename( + ofn.lpstrFile, &ds), NULL); gotFilename = (Tcl_DStringLength(&ds) > 0); Tcl_DStringFree(&ds); } @@ -932,8 +905,8 @@ GetFileNameW( } } else if (cdlgerr == FNERR_INVALIDFILENAME) { Tcl_SetResult(interp, "invalid filename \"", TCL_STATIC); - Tcl_AppendResult(interp, ConvertExternalFilename(unicodeEncoding, - (char *) ofn.lpstrFile, &ds), "\"", NULL); + Tcl_AppendResult(interp, ConvertExternalFilename( + ofn.lpstrFile, &ds), "\"", NULL); Tcl_DStringFree(&ds); } else { result = TCL_OK; @@ -954,7 +927,7 @@ GetFileNameW( Tcl_DStringFree(&utfDirString); Tcl_DStringFree(&utfFilterString); if (ofnData.dynFileBuffer != NULL) { - ckfree(ofnData.dynFileBuffer); + ckfree((char *)ofnData.dynFileBuffer); ofnData.dynFileBuffer = NULL; } @@ -964,7 +937,7 @@ GetFileNameW( /* *------------------------------------------------------------------------- * - * OFNHookProcW -- + * OFNHookProc -- * * Dialog box hook function. This is used to sets the "tk_dialog" * variable for test/debugging when the dialog is ready to receive @@ -981,7 +954,7 @@ GetFileNameW( */ static UINT APIENTRY -OFNHookProcW( +OFNHookProc( HWND hdlg, /* Handle to child dialog window. */ UINT uMsg, /* Message identifier */ WPARAM wParam, /* Message parameter */ @@ -998,14 +971,16 @@ OFNHookProcW( OFNOTIFYW *notifyPtr = (OFNOTIFYW *) lParam; /* - * This is weird... or not. The CDN_FILEOK is NOT sent when the selection - * exceeds declared buffer size (the nMaxFile member of the OPENFILENAMEW - * struct passed to GetOpenFileNameW function). So, we have to rely on - * the most recent CDN_SELCHANGE then. Unfortunately this means, that - * gathering the selected filenames happens twice when they fit into the - * declared buffer. Luckily, it's not frequent operation so it should - * not incur any noticeable delay. See [tktoolkit-Bugs-2987995] + * This is weird... or not. The CDN_FILEOK is NOT sent when the + * selection exceeds declared buffer size (the nMaxFile member of the + * OPENFILENAME struct passed to GetOpenFileName function). So, we + * have to rely on the most recent CDN_SELCHANGE then. Unfortunately + * this means, that gathering the selected filenames happens twice + * when they fit into the declared buffer. Luckily, it's not frequent + * operation so it should not incur any noticeable delay. See [Bug + * 2987995] */ + if (notifyPtr->hdr.code == CDN_FILEOK || notifyPtr->hdr.code == CDN_SELCHANGE) { int dirsize, selsize; @@ -1019,21 +994,23 @@ OFNHookProcW( ofnPtr = notifyPtr->lpOFN; ofnData = (OFNData *) ofnPtr->lCustData; - buffer = (WCHAR *) ofnData->dynFileBuffer; + buffer = ofnData->dynFileBuffer; hdlg = GetParent(hdlg); selsize = SendMessageW(hdlg, CDM_GETSPEC, 0, 0); dirsize = SendMessageW(hdlg, CDM_GETFOLDERPATH, 0, 0); - buffersize = (selsize + dirsize + 1) * 2; + buffersize = (selsize + dirsize + 1); /* - * Just empty the buffer if dirsize indicates an error [Bug 3071836] + * Just empty the buffer if dirsize indicates an error. [Bug + * 3071836] */ + if ((selsize > 1) && (dirsize > 0)) { if (ofnData->dynFileBufferSize < buffersize) { - buffer = (WCHAR *) ckrealloc((char *) buffer, buffersize); + buffer = (WCHAR *) ckrealloc((char *) buffer, buffersize * sizeof(WCHAR)); ofnData->dynFileBufferSize = buffersize; - ofnData->dynFileBuffer = (char *) buffer; + ofnData->dynFileBuffer = buffer; } SendMessageW(hdlg, CDM_GETFOLDERPATH, dirsize, (LPARAM) buffer); @@ -1050,7 +1027,7 @@ OFNHookProcW( BOOL findquote = TRUE; WCHAR *tmp = buffer; - while(*buffer != '\0') { + while (*buffer != '\0') { if (findquote) { if (*buffer == '"') { findquote = FALSE; @@ -1066,14 +1043,24 @@ OFNHookProcW( } *tmp = '\0'; /* Second NULL terminator. */ } else { - buffer[selsize] = '\0'; /* Second NULL terminator. */ - /* - * Replace directory terminating NULL with a backslash. + /* + * Replace directory terminating NULL with a with a backslash, + * but only if not an absolute path. */ - buffer--; - *buffer = '\\'; + Tcl_DString tmpfile; + ConvertExternalFilename(buffer, &tmpfile); + if (TCL_PATH_ABSOLUTE == + Tcl_GetPathType(Tcl_DStringValue(&tmpfile))) { + /* re-get the full path to the start of the buffer */ + buffer = (WCHAR *) ofnData->dynFileBuffer; + SendMessageW(hdlg, CDM_GETSPEC, selsize, (LPARAM) buffer); + } else { + *(buffer-1) = '\\'; + } + buffer[selsize] = '\0'; /* Second NULL terminator. */ + Tcl_DStringFree(&tmpfile); } } else { /* @@ -1109,557 +1096,6 @@ OFNHookProcW( /* *---------------------------------------------------------------------- * - * GetFileNameA -- - * - * Calls GetOpenFileName() or GetSaveFileName(). - * - * Results: - * See user documentation. - * - * Side effects: - * See user documentation. - * - *---------------------------------------------------------------------- - */ - -static int -GetFileNameA( - ClientData clientData, /* Main window associated with interpreter. */ - Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ - Tcl_Obj *CONST objv[], /* Argument objects. */ - int open) /* 1 to call GetOpenFileName(), 0 to call - * GetSaveFileName(). */ -{ - OPENFILENAME ofn; - TCHAR file[TK_MULTI_MAX_PATH], savePath[MAX_PATH]; - OFNData ofnData; - int cdlgerr; - int filterIndex = 0, result = TCL_ERROR, winCode, oldMode, i, multi = 0; - char *extension = NULL, *title = NULL; - Tk_Window tkwin = (Tk_Window) clientData; - HWND hWnd; - Tcl_Obj *filterObj = NULL, *initialTypeObj = NULL, *typeVariableObj = NULL; - Tcl_DString utfFilterString, utfDirString, ds; - Tcl_DString extString, filterString, dirString, titleString; - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - static CONST char *saveOptionStrings[] = { - "-defaultextension", "-filetypes", "-initialdir", "-initialfile", - "-parent", "-title", "-typevariable", NULL - }; - static CONST char *openOptionStrings[] = { - "-defaultextension", "-filetypes", "-initialdir", "-initialfile", - "-multiple", "-parent", "-title", "-typevariable", NULL - }; - CONST char **optionStrings; - - enum options { - FILE_DEFAULT, FILE_TYPES, FILE_INITDIR, FILE_INITFILE, - FILE_MULTIPLE, FILE_PARENT, FILE_TITLE, FILE_TYPEVARIABLE - }; - - file[0] = '\0'; - ZeroMemory(&ofnData, sizeof(OFNData)); - Tcl_DStringInit(&utfFilterString); - Tcl_DStringInit(&utfDirString); - - /* - * Parse the arguments. - */ - - if (open) { - optionStrings = openOptionStrings; - } else { - optionStrings = saveOptionStrings; - } - - for (i = 1; i < objc; i += 2) { - int index; - char *string; - Tcl_Obj *optionPtr, *valuePtr; - - optionPtr = objv[i]; - valuePtr = objv[i + 1]; - - if (Tcl_GetIndexFromObj(interp, optionPtr, optionStrings, "option", 0, - &index) != TCL_OK) { - goto end; - } - - /* - * We want to maximize code sharing between the open and save file - * dialog implementations; in particular, the switch statement below. - * We use different sets of option strings from the GetIndexFromObj - * call above, but a single enumeration for both. The save file dialog - * doesn't support -multiple, but it falls in the middle of the - * enumeration. Ultimately, this means that when the index found by - * GetIndexFromObj is >= FILE_MULTIPLE, when doing a save file dialog, - * we have to increment the index, so that it matches the open file - * dialog enumeration. - */ - - if (!open && index >= FILE_MULTIPLE) { - index++; - } - if (i + 1 == objc) { - string = Tcl_GetString(optionPtr); - Tcl_AppendResult(interp, "value for \"", string, "\" missing", - NULL); - goto end; - } - - string = Tcl_GetString(valuePtr); - switch ((enum options) index) { - case FILE_DEFAULT: - if (string[0] == '.') { - string++; - } - extension = string; - break; - case FILE_TYPES: - filterObj = valuePtr; - break; - case FILE_INITDIR: - Tcl_DStringFree(&utfDirString); - if (Tcl_TranslateFileName(interp, string, &utfDirString) == NULL) { - goto end; - } - break; - case FILE_INITFILE: - if (Tcl_TranslateFileName(interp, string, &ds) == NULL) { - goto end; - } - Tcl_UtfToExternal(NULL, NULL, Tcl_DStringValue(&ds), - Tcl_DStringLength(&ds), 0, NULL, (char *) file, - sizeof(file), NULL, NULL, NULL); - Tcl_DStringFree(&ds); - break; - case FILE_MULTIPLE: - if (Tcl_GetBooleanFromObj(interp, valuePtr, &multi) != TCL_OK) { - return TCL_ERROR; - } - break; - case FILE_PARENT: - tkwin = Tk_NameToWindow(interp, string, tkwin); - if (tkwin == NULL) { - goto end; - } - break; - case FILE_TITLE: - title = string; - break; - case FILE_TYPEVARIABLE: - typeVariableObj = valuePtr; - initialTypeObj = Tcl_ObjGetVar2(interp, typeVariableObj, NULL, - TCL_GLOBAL_ONLY); - break; - } - } - - if (MakeFilter(interp, filterObj, &utfFilterString, initialTypeObj, - &filterIndex) != TCL_OK) { - goto end; - } - - Tk_MakeWindowExist(tkwin); - hWnd = Tk_GetHWND(Tk_WindowId(tkwin)); - - ZeroMemory(&ofn, sizeof(OPENFILENAMEA)); - if (LOBYTE(LOWORD(GetVersion())) < 5) { - ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400; - } else { - ofn.lStructSize = sizeof(ofn); - } - ofn.hwndOwner = hWnd; - ofn.hInstance = TkWinGetHInstance(ofn.hwndOwner); - ofn.lpstrFilter = NULL; - ofn.lpstrCustomFilter = NULL; - ofn.nMaxCustFilter = 0; - ofn.lpstrFile = (LPTSTR) file; - ofn.nMaxFile = TK_MULTI_MAX_PATH; - ofn.lpstrFileTitle = NULL; - ofn.nMaxFileTitle = 0; - ofn.lpstrInitialDir = NULL; - ofn.lpstrTitle = NULL; - ofn.Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR - | OFN_EXPLORER | OFN_ENABLEHOOK; - ofn.nFileOffset = 0; - ofn.nFileExtension = 0; - ofn.lpstrDefExt = NULL; - ofn.lpfnHook = (LPOFNHOOKPROC) OFNHookProcA; - ofn.lCustData = (LPARAM) &ofnData; - ofn.lpTemplateName = NULL; - - if (open != 0) { - ofn.Flags |= OFN_FILEMUSTEXIST; - } else { - ofn.Flags |= OFN_OVERWRITEPROMPT; - } - - if (tsdPtr->debugFlag != 0) { - ofnData.interp = interp; - } - - if (multi != 0) { - ofn.Flags |= OFN_ALLOWMULTISELECT; - - /* - * Starting buffer size. The buffer will be expanded by the OFN dialog - * procedure when necessary - */ - - ofnData.dynFileBufferSize = 1024; - ofnData.dynFileBuffer = ckalloc(1024); - } - - if (extension != NULL) { - Tcl_UtfToExternalDString(NULL, extension, -1, &extString); - ofn.lpstrDefExt = (LPTSTR) Tcl_DStringValue(&extString); - } - Tcl_UtfToExternalDString(NULL, Tcl_DStringValue(&utfFilterString), - Tcl_DStringLength(&utfFilterString), &filterString); - ofn.lpstrFilter = (LPTSTR) Tcl_DStringValue(&filterString); - ofn.nFilterIndex = filterIndex; - - if (Tcl_DStringValue(&utfDirString)[0] != '\0') { - Tcl_UtfToExternalDString(NULL, Tcl_DStringValue(&utfDirString), - Tcl_DStringLength(&utfDirString), &dirString); - } else { - /* - * NT 5.0 changed the meaning of lpstrInitialDir, so we have to ensure - * that we set the [pwd] if the user didn't specify anything else. - */ - - Tcl_DString cwd; - - Tcl_DStringFree(&utfDirString); - if ((Tcl_GetCwd(interp, &utfDirString) == NULL) || - (Tcl_TranslateFileName(interp, - Tcl_DStringValue(&utfDirString), &cwd) == NULL)) { - Tcl_ResetResult(interp); - } else { - Tcl_UtfToExternalDString(NULL, Tcl_DStringValue(&cwd), - Tcl_DStringLength(&cwd), &dirString); - } - Tcl_DStringFree(&cwd); - } - ofn.lpstrInitialDir = (LPTSTR) Tcl_DStringValue(&dirString); - - if (title != NULL) { - Tcl_UtfToExternalDString(NULL, title, -1, &titleString); - ofn.lpstrTitle = (LPTSTR) Tcl_DStringValue(&titleString); - } - - /* - * Popup the dialog. - */ - - GetCurrentDirectory(MAX_PATH, savePath); - oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); - if (open != 0) { - winCode = GetOpenFileName(&ofn); - } else { - winCode = GetSaveFileName(&ofn); - } - Tcl_SetServiceMode(oldMode); - EatSpuriousMessageBugFix(); - SetCurrentDirectory(savePath); - - /* - * Ensure that hWnd is enabled, because it can happen that we have updated - * the wrapper of the parent, which causes us to leave this child disabled - * (Windows loses sync). - */ - - EnableWindow(hWnd, 1); - - /* - * Clear the interp result since anything may have happened during the - * modal loop. - */ - - Tcl_ResetResult(interp); - - /* - * Process the results. - * - * Use the CommDlgExtendedError() function to retrieve the error code. - * This function can return one of about two dozen codes; most of these - * indicate some sort of gross system failure (insufficient memory, bad - * window handles, etc.) Most of the error codes will be ignored; as we - * find we want specific error messages for particular errors, we can - * extend the code as needed. - */ - - cdlgerr = CommDlgExtendedError(); - - /* - * We now allow FNERR_BUFFERTOOSMALL when multiselection is enabled. The - * filename buffer has been dynamically allocated by the OFN dialog - * procedure to accomodate all selected files. - */ - - if ((winCode != 0) - || ((cdlgerr == FNERR_BUFFERTOOSMALL) - && (ofn.Flags & OFN_ALLOWMULTISELECT))) { - if (ofn.Flags & OFN_ALLOWMULTISELECT) { - /* - * The result in dynFileBuffer contains many items, separated by - * NUL characters. It is terminated with two nulls in a row. The - * first element is the directory path (if multiple files are - * selected) or the only returned file (if only a single file has - * been chosen). - */ - - char *files = ofnData.dynFileBuffer; - Tcl_Obj *returnList = Tcl_NewObj(); - int count = 0; - - /* - * Get directory. - */ - - (void) ConvertExternalFilename(NULL, (char *) files, &ds); - - while (*files != '\0') { - while (*files != '\0') { - files++; - } - files++; - if (*files != '\0') { - Tcl_Obj *fullnameObj; - Tcl_DString filename; - - count++; - (void) ConvertExternalFilename(NULL, (char *) files, - &filename); - fullnameObj = Tcl_NewStringObj(Tcl_DStringValue(&ds), - Tcl_DStringLength(&ds)); - Tcl_AppendToObj(fullnameObj, "/", -1); - Tcl_AppendToObj(fullnameObj, Tcl_DStringValue(&filename), - Tcl_DStringLength(&filename)); - Tcl_DStringFree(&filename); - Tcl_ListObjAppendElement(NULL, returnList, fullnameObj); - } - } - if (count == 0) { - /* - * Only one file was returned. - */ - - Tcl_ListObjAppendElement(NULL, returnList, Tcl_NewStringObj( - Tcl_DStringValue(&ds), Tcl_DStringLength(&ds))); - } - Tcl_SetObjResult(interp, returnList); - Tcl_DStringFree(&ds); - } else { - Tcl_AppendResult(interp, ConvertExternalFilename(NULL, - (char *) ofn.lpstrFile, &ds), NULL); - Tcl_DStringFree(&ds); - } - result = TCL_OK; - if ((ofn.nFilterIndex > 0) && - (Tcl_GetCharLength(Tcl_GetObjResult(interp)) > 0) && - typeVariableObj && filterObj) { - int listObjc, count; - Tcl_Obj **listObjv = NULL; - Tcl_Obj **typeInfo = NULL; - - if (Tcl_ListObjGetElements(interp, filterObj, &listObjc, - &listObjv) != TCL_OK) { - result = TCL_ERROR; - } else if (Tcl_ListObjGetElements(interp, - listObjv[ofn.nFilterIndex - 1], &count, - &typeInfo) != TCL_OK) { - result = TCL_ERROR; - } else if (Tcl_ObjSetVar2(interp, typeVariableObj, NULL, - typeInfo[0], TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) { - result = TCL_ERROR; - } - } - } else if (cdlgerr == FNERR_INVALIDFILENAME) { - Tcl_SetResult(interp, "invalid filename \"", TCL_STATIC); - Tcl_AppendResult(interp, ConvertExternalFilename(NULL, - (char *) ofn.lpstrFile, &ds), "\"", NULL); - Tcl_DStringFree(&ds); - } else { - result = TCL_OK; - } - - if (ofn.lpstrTitle != NULL) { - Tcl_DStringFree(&titleString); - } - if (ofn.lpstrInitialDir != NULL) { - Tcl_DStringFree(&dirString); - } - Tcl_DStringFree(&filterString); - if (ofn.lpstrDefExt != NULL) { - Tcl_DStringFree(&extString); - } - - end: - Tcl_DStringFree(&utfDirString); - Tcl_DStringFree(&utfFilterString); - if (ofnData.dynFileBuffer != NULL) { - ckfree(ofnData.dynFileBuffer); - ofnData.dynFileBuffer = NULL; - } - - return result; -} - -/* - *------------------------------------------------------------------------- - * - * OFNHookProcA -- - * - * Dialog box hook function. This is used to sets the "tk_dialog" - * variable for test/debugging when the dialog is ready to receive - * messages. When multiple file selection is enabled this function - * is used to process the list of names. - * - * Results: - * Returns 0 to allow default processing of messages to occur. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------- - */ - -static UINT APIENTRY -OFNHookProcA( - HWND hdlg, /* handle to child dialog window */ - UINT uMsg, /* message identifier */ - WPARAM wParam, /* message parameter */ - LPARAM lParam) /* message parameter */ -{ - ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - OPENFILENAME *ofnPtr; - OFNData *ofnData; - - if (uMsg == WM_INITDIALOG) { - TkWinSetUserData(hdlg, lParam); - } else if (uMsg == WM_NOTIFY) { - OFNOTIFY *notifyPtr = (OFNOTIFY *) lParam; - - /* - * This is weird... or not. The CDN_FILEOK is NOT sent when the selection - * exceeds declared buffer size (the nMaxFile member of the OPENFILENAMEW - * struct passed to GetOpenFileNameW function). So, we have to rely on - * the most recent CDN_SELCHANGE then. Unfortunately this means, that - * gathering the selected filenames happens twice when they fit into the - * declared buffer. Luckily, it's not frequent operation so it should - * not incur any noticeable delay. See [tktoolkit-Bugs-2987995] - */ - if (notifyPtr->hdr.code == CDN_FILEOK || - notifyPtr->hdr.code == CDN_SELCHANGE) { - int dirsize, selsize; - char *buffer; - int buffersize; - - /* - * Change of selection. Unscramble the unholy mess that's in the - * selection buffer, resizing it if necessary. - */ - - ofnPtr = notifyPtr->lpOFN; - ofnData = (OFNData *) ofnPtr->lCustData; - buffer = ofnData->dynFileBuffer; - hdlg = GetParent(hdlg); - - selsize = SendMessage(hdlg, CDM_GETSPEC, 0, 0); - dirsize = SendMessage(hdlg, CDM_GETFOLDERPATH, 0, 0); - buffersize = selsize + dirsize + 1; - - /* - * Just empty the buffer if dirsize indicates an error [Bug 3071836] - */ - if ((selsize > 1) && (dirsize > 0)) { - if (ofnData->dynFileBufferSize < buffersize) { - buffer = ckrealloc(buffer, buffersize); - ofnData->dynFileBufferSize = buffersize; - ofnData->dynFileBuffer = buffer; - } - - SendMessage(hdlg, CDM_GETFOLDERPATH, dirsize, (LPARAM) buffer); - buffer += dirsize; - SendMessage(hdlg, CDM_GETSPEC, selsize, (LPARAM) buffer); - - /* - * If there are multiple files, delete the quotes and change - * every second quote to NULL terminator. - */ - - if (buffer[0] == '"') { - BOOL findquote = TRUE; - char *tmp = buffer; - - while (*buffer != '\0') { - if (findquote) { - if (*buffer == '"') { - findquote = FALSE; - } - buffer++; - } else { - if (*buffer == '"') { - findquote = TRUE; - *buffer = '\0'; - } - *tmp++ = *buffer++; - } - } - *tmp = '\0'; /* Second NULL terminator. */ - } else { - buffer[selsize] = '\0'; /* Second NULL terminator. */ - - /* - * Replace directory terminating NULL with a backslash. - */ - - buffer--; - *buffer = '\\'; - } - - } else { - /* - * Nothing is selected, so just empty the string. - */ - - if (buffer != NULL) { - *buffer = '\0'; - } - } - } - } else if (uMsg == WM_WINDOWPOSCHANGED) { - /* - * This message is delivered at the right time to both old-style and - * explorer-style hook procs to enable Tk to set the debug - * information. Unhooks itself so it won't set the debug information - * every time it gets a WM_WINDOWPOSCHANGED message. - */ - - ofnPtr = (OPENFILENAME *) TkWinGetUserData(hdlg); - if (ofnPtr != NULL) { - ofnData = (OFNData *) ofnPtr->lCustData; - if (ofnData->interp != NULL) { - if (ofnPtr->Flags & OFN_EXPLORER) { - hdlg = GetParent(hdlg); - } - tsdPtr->debugInterp = ofnData->interp; - Tcl_DoWhenIdle(SetTkDialog, hdlg); - } - TkWinSetUserData(hdlg, NULL); - } - } - return 0; -} - -/* - *---------------------------------------------------------------------- - * * MakeFilter -- * * Allocate a buffer to store the filters in a format understood by @@ -1680,18 +1116,18 @@ MakeFilter( Tcl_Obj *valuePtr, /* Value of the -filetypes option */ Tcl_DString *dsPtr, /* Filled with windows filter string. */ Tcl_Obj *initialPtr, /* Initial type name */ - int *index) /* Index of initial type in filter string */ + int *indexPtr) /* Index of initial type in filter string */ { char *filterStr; char *p; - char *initial = NULL; + const char *initial = NULL; int pass; int ix = 0; /* index counter */ FileFilterList flist; FileFilter *filterPtr; if (initialPtr) { - initial = Tcl_GetStringFromObj(initialPtr, NULL); + initial = Tcl_GetString(initialPtr); } TkInitFileFilters(&flist); if (TkGetFileFilters(interp, &flist, valuePtr, 1) != TCL_OK) { @@ -1702,9 +1138,9 @@ MakeFilter( /* * Use "All Files (*.*) as the default filter if none is specified */ - char *defaultFilter = "All Files (*.*)"; + const char *defaultFilter = "All Files (*.*)"; - p = filterStr = (char*)ckalloc(30 * sizeof(char)); + p = filterStr = ckalloc(30); strcpy(p, defaultFilter); p+= strlen(defaultFilter); @@ -1744,16 +1180,18 @@ MakeFilter( for (filterPtr = flist.filters, p = filterStr; filterPtr; filterPtr = filterPtr->next) { - char *sep; + const char *sep; FileFilterClause *clausePtr; /* - * Check initial index for match, set index. Filter index is 1 + * Check initial index for match, set *indexPtr. Filter index is 1 * based so increment first */ + ix++; - if (index && initial && (strcmp(initial, filterPtr->name) == 0)) { - *index = ix; + if (indexPtr && initial + && (strcmp(initial, filterPtr->name) == 0)) { + *indexPtr = ix; } /* @@ -1889,22 +1327,23 @@ Tk_ChooseDirectoryObjCmd( ClientData clientData, /* Main window associated with interpreter. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ - Tcl_Obj *CONST objv[]) /* Argument objects. */ + Tcl_Obj *const objv[]) /* Argument objects. */ { - char path[MAX_PATH]; + WCHAR path[MAX_PATH]; int oldMode, result = TCL_ERROR, i; LPCITEMIDLIST pidl; /* Returned by browser */ - BROWSEINFO bInfo; /* Used by browser */ + BROWSEINFOW bInfo; /* Used by browser */ CHOOSEDIRDATA cdCBData; /* Structure to pass back and forth */ LPMALLOC pMalloc; /* Used by shell */ Tk_Window tkwin = (Tk_Window) clientData; HWND hWnd; - char *utfTitle = NULL;/* Title for window */ - TCHAR saveDir[MAX_PATH]; - Tcl_DString titleString; /* UTF Title */ + const char *utfTitle = NULL;/* Title for window */ + WCHAR saveDir[MAX_PATH]; + Tcl_DString titleString; /* Title */ Tcl_DString initDirString; /* Initial directory */ + Tcl_DString tempString; /* temporary */ Tcl_Obj *objPtr; - static CONST char *optionStrings[] = { + static const char *optionStrings[] = { "-initialdir", "-mustexist", "-parent", "-title", NULL }; enum options { @@ -1925,7 +1364,8 @@ Tk_ChooseDirectoryObjCmd( for (i = 1; i < objc; i += 2) { int index; - char *string; + const char *string; + const WCHAR *uniStr; Tcl_Obj *optionPtr, *valuePtr; optionPtr = objv[i]; @@ -1948,16 +1388,19 @@ Tk_ChooseDirectoryObjCmd( if (Tcl_TranslateFileName(interp,string,&initDirString) == NULL) { goto cleanup; } - string = Tcl_DStringValue(&initDirString); + Tcl_WinUtfToTChar(Tcl_DStringValue(&initDirString), -1, + &tempString); + uniStr = (WCHAR *) Tcl_DStringValue(&tempString); /* * Convert possible relative path to full path to keep dialog * happy. */ - GetFullPathName(string, MAX_PATH, saveDir, NULL); - lstrcpyn(cdCBData.utfInitDir, saveDir, MAX_PATH); + GetFullPathNameW(uniStr, MAX_PATH, saveDir, NULL); + wcsncpy(cdCBData.initDir, saveDir, MAX_PATH); Tcl_DStringFree(&initDirString); + Tcl_DStringFree(&tempString); break; case DIR_EXIST: if (Tcl_GetBooleanFromObj(interp, valuePtr, @@ -1991,16 +1434,16 @@ Tk_ChooseDirectoryObjCmd( bInfo.hwndOwner = hWnd; bInfo.pszDisplayName = path; bInfo.pidlRoot = NULL; - if (lstrlen(cdCBData.utfInitDir) == 0) { - GetCurrentDirectory(MAX_PATH, cdCBData.utfInitDir); + if (wcslen(cdCBData.initDir) == 0) { + GetCurrentDirectoryW(MAX_PATH, cdCBData.initDir); } bInfo.lParam = (LPARAM) &cdCBData; if (utfTitle != NULL) { - Tcl_UtfToExternalDString(NULL, utfTitle, -1, &titleString); - bInfo.lpszTitle = (LPTSTR) Tcl_DStringValue(&titleString); + Tcl_WinUtfToTChar(utfTitle, -1, &titleString); + bInfo.lpszTitle = (LPWSTR) Tcl_DStringValue(&titleString); } else { - bInfo.lpszTitle = "Please choose a directory, then select OK."; + bInfo.lpszTitle = L"Please choose a directory, then select OK."; } /* @@ -2033,15 +1476,16 @@ Tk_ChooseDirectoryObjCmd( */ oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); - GetCurrentDirectory(MAX_PATH, saveDir); + GetCurrentDirectoryW(MAX_PATH, saveDir); if (SHGetMalloc(&pMalloc) == NOERROR) { - pidl = SHBrowseForFolder(&bInfo); + pidl = SHBrowseForFolderW(&bInfo); /* - * This is a fix for Windows 2000, which seems to modify the folder name - * buffer even when the dialog is canceled (in this case the buffer - * contains garbage). See [Bug #3002230] + * This is a fix for Windows 2000, which seems to modify the folder + * name buffer even when the dialog is canceled (in this case the + * buffer contains garbage). See [Bug #3002230] */ + path[0] = '\0'; /* @@ -2049,17 +1493,17 @@ Tk_ChooseDirectoryObjCmd( */ if (pidl != NULL) { - if (!SHGetPathFromIDList(pidl, path)) { + if (!SHGetPathFromIDListW(pidl, path)) { Tcl_SetResult(interp, "Error: Not a file system folder\n", TCL_VOLATILE); - }; + } pMalloc->lpVtbl->Free(pMalloc, (void *) pidl); - } else if (lstrlen(cdCBData.utfRetDir) > 0) { - lstrcpy(path, cdCBData.utfRetDir); + } else if (wcslen(cdCBData.retDir) > 0) { + wcscpy(path, cdCBData.retDir); } pMalloc->lpVtbl->Release(pMalloc); } - SetCurrentDirectory(saveDir); + SetCurrentDirectoryW(saveDir); Tcl_SetServiceMode(oldMode); /* @@ -2079,7 +1523,7 @@ Tk_ChooseDirectoryObjCmd( if (*path) { Tcl_DString ds; - Tcl_AppendResult(interp, ConvertExternalFilename(NULL, (char *) path, + Tcl_AppendResult(interp, ConvertExternalFilename(path, &ds), NULL); Tcl_DStringFree(&ds); } @@ -2117,10 +1561,11 @@ ChooseDirectoryValidateProc( LPARAM lParam, LPARAM lpData) { - TCHAR selDir[MAX_PATH]; + WCHAR selDir[MAX_PATH]; CHOOSEDIRDATA *chooseDirSharedData = (CHOOSEDIRDATA *) lpData; + Tcl_DString tempString; Tcl_DString initDirString; - char string[MAX_PATH]; + WCHAR string[MAX_PATH]; ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); @@ -2128,7 +1573,7 @@ ChooseDirectoryValidateProc( tsdPtr->debugInterp = (Tcl_Interp *) chooseDirSharedData->interp; Tcl_DoWhenIdle(SetTkDialog, (ClientData) hwnd); } - chooseDirSharedData->utfRetDir[0] = '\0'; + chooseDirSharedData->retDir[0] = '\0'; switch (message) { case BFFM_VALIDATEFAILED: /* @@ -2140,21 +1585,25 @@ ChooseDirectoryValidateProc( * like ~ are converted correctly. */ + Tcl_WinTCharToUtf((TCHAR *) lParam, -1, &initDirString); if (Tcl_TranslateFileName(chooseDirSharedData->interp, - (char *) lParam, &initDirString) == NULL) { + Tcl_DStringValue(&initDirString), &tempString) == NULL) { /* * Should we expose the error (in the interp result) to the user * at this point? */ - chooseDirSharedData->utfRetDir[0] = '\0'; + chooseDirSharedData->retDir[0] = '\0'; return 1; } - lstrcpyn(string, Tcl_DStringValue(&initDirString), MAX_PATH); + Tcl_DStringFree(&initDirString); + Tcl_WinUtfToTChar(Tcl_DStringValue(&tempString), -1, &initDirString); + Tcl_DStringFree(&tempString); + wcsncpy(string, (WCHAR *) Tcl_DStringValue(&initDirString), + MAX_PATH); Tcl_DStringFree(&initDirString); - if (SetCurrentDirectory((char *)string) == 0) { - LPTSTR lpFilePart[MAX_PATH]; + if (SetCurrentDirectoryW(string) == 0) { /* * Get the full path name to the user entry, at this point it does @@ -2162,16 +1611,17 @@ ChooseDirectoryValidateProc( * it. */ - GetFullPathName(string, MAX_PATH, - chooseDirSharedData->utfRetDir, /*unused*/ lpFilePart); + GetFullPathNameW(string, MAX_PATH, + chooseDirSharedData->retDir, NULL); if (chooseDirSharedData->mustExist) { /* * User HAS to select a valid directory. */ - wsprintf(selDir, TEXT("Directory '%.200s' does not exist,\nplease select or enter an existing directory."), chooseDirSharedData->utfRetDir); - MessageBox(NULL, selDir, NULL, MB_ICONEXCLAMATION|MB_OK); - chooseDirSharedData->utfRetDir[0] = '\0'; + wsprintfW(selDir, L"Directory '%.200s' does not exist,\nplease select or enter an existing directory.", + chooseDirSharedData->retDir); + MessageBoxW(NULL, selDir, NULL, MB_ICONEXCLAMATION|MB_OK); + chooseDirSharedData->retDir[0] = '\0'; return 1; } } else { @@ -2180,7 +1630,7 @@ ChooseDirectoryValidateProc( * directory in utfRetDir. */ - GetCurrentDirectory(MAX_PATH, chooseDirSharedData->utfRetDir); + GetCurrentDirectoryW(MAX_PATH, chooseDirSharedData->retDir); return 0; } return 0; @@ -2195,13 +1645,13 @@ ChooseDirectoryValidateProc( * Not called when user changes edit box directly. */ - if (SHGetPathFromIDList((LPITEMIDLIST) lParam, selDir)) { - SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM) selDir); + if (SHGetPathFromIDListW((LPITEMIDLIST) lParam, selDir)) { + SendMessageW(hwnd, BFFM_SETSTATUSTEXTW, 0, (LPARAM) selDir); // enable the OK button - SendMessage(hwnd, BFFM_ENABLEOK, 0, (LPARAM) 1); + SendMessageW(hwnd, BFFM_ENABLEOK, 0, (LPARAM) 1); } else { // disable the OK button - SendMessage(hwnd, BFFM_ENABLEOK, 0, (LPARAM) 0); + SendMessageW(hwnd, BFFM_ENABLEOK, 0, (LPARAM) 0); } UpdateWindow(hwnd); return 1; @@ -2212,9 +1662,10 @@ ChooseDirectoryValidateProc( * specified parameter. */ - char *initDir = chooseDirSharedData->utfInitDir; + WCHAR *initDir = chooseDirSharedData->initDir; + + SetCurrentDirectoryW(initDir); - SetCurrentDirectory(initDir); if (*initDir == '\\') { /* * BFFM_SETSELECTION only understands UNC paths as pidls, so @@ -2228,27 +1679,23 @@ ChooseDirectoryValidateProc( if (SUCCEEDED(SHGetDesktopFolder(&psfFolder))) { LPITEMIDLIST pidlMain; ULONG ulCount, ulAttr; - Tcl_DString ds; - Tcl_UtfToExternalDString(TkWinGetUnicodeEncoding(), - initDir, -1, &ds); if (SUCCEEDED(psfFolder->lpVtbl->ParseDisplayName( psfFolder, hwnd, NULL, (WCHAR *) - Tcl_DStringValue(&ds), &ulCount,&pidlMain,&ulAttr)) + initDir, &ulCount,&pidlMain,&ulAttr)) && (pidlMain != NULL)) { - SendMessage(hwnd, BFFM_SETSELECTION, FALSE, + SendMessageW(hwnd, BFFM_SETSELECTIONW, FALSE, (LPARAM) pidlMain); pMalloc->lpVtbl->Free(pMalloc, pidlMain); } psfFolder->lpVtbl->Release(psfFolder); - Tcl_DStringFree(&ds); } pMalloc->lpVtbl->Release(pMalloc); } } else { - SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM) initDir); + SendMessageW(hwnd, BFFM_SETSELECTIONW, TRUE, (LPARAM) initDir); } - SendMessage(hwnd, BFFM_ENABLEOK, 0, (LPARAM) 1); + SendMessageW(hwnd, BFFM_ENABLEOK, 0, (LPARAM) 1); break; } @@ -2279,7 +1726,7 @@ Tk_MessageBoxObjCmd( ClientData clientData, /* Main window associated with interpreter. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ - Tcl_Obj *CONST objv[]) /* Argument objects. */ + Tcl_Obj *const objv[]) /* Argument objects. */ { Tk_Window tkwin = (Tk_Window) clientData, parent; HWND hWnd; @@ -2287,7 +1734,7 @@ Tk_MessageBoxObjCmd( int defaultBtn, icon, type; int i, oldMode, winCode; UINT flags; - static CONST char *optionStrings[] = { + static const char *optionStrings[] = { "-default", "-detail", "-icon", "-message", "-parent", "-title", "-type", NULL }; @@ -2298,7 +1745,6 @@ Tk_MessageBoxObjCmd( ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); - (void) TkWinGetUnicodeEncoding(); defaultBtn = -1; detailObj = NULL; icon = MB_ICONINFORMATION; @@ -2309,7 +1755,6 @@ Tk_MessageBoxObjCmd( for (i = 1; i < objc; i += 2) { int index; - char *string; Tcl_Obj *optionPtr, *valuePtr; optionPtr = objv[i]; @@ -2320,7 +1765,7 @@ Tk_MessageBoxObjCmd( return TCL_ERROR; } if (i + 1 == objc) { - string = Tcl_GetString(optionPtr); + const char *string = Tcl_GetString(optionPtr); Tcl_AppendResult(interp, "value for \"", string, "\" missing", NULL); return TCL_ERROR; @@ -2425,7 +1870,7 @@ Tk_MessageBoxObjCmd( tsdPtr->hSmallIcon = TkWinGetIcon(parent, ICON_SMALL); tsdPtr->hBigIcon = TkWinGetIcon(parent, ICON_BIG); - tsdPtr->hMsgBoxHook = SetWindowsHookEx(WH_CBT, MsgBoxCBTProc, NULL, + tsdPtr->hMsgBoxHook = SetWindowsHookExW(WH_CBT, MsgBoxCBTProc, NULL, GetCurrentThreadId()); winCode = MessageBoxW(hWnd, Tcl_GetUnicode(tmpObj), titleObj ? Tcl_GetUnicode(titleObj) : L"", flags); @@ -2453,7 +1898,7 @@ MsgBoxCBTProc( LPARAM lParam) { ThreadSpecificData *tsdPtr = (ThreadSpecificData *) - Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); if (nCode == HCBT_CREATEWND) { /* @@ -2469,9 +1914,9 @@ MsgBoxCBTProc( if (WC_DIALOG == lpcbtcreate->lpcs->lpszClass) { HWND hwnd = (HWND) wParam; - SendMessage(hwnd, WM_SETICON, ICON_SMALL, + SendMessageW(hwnd, WM_SETICON, ICON_SMALL, (LPARAM) tsdPtr->hSmallIcon); - SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM) tsdPtr->hBigIcon); + SendMessageW(hwnd, WM_SETICON, ICON_BIG, (LPARAM) tsdPtr->hBigIcon); } } @@ -2510,15 +1955,15 @@ SetTkDialog( /* * Factored out a common pattern in use in this file. */ -static char * + +static const char * ConvertExternalFilename( - Tcl_Encoding encoding, - char *filename, + WCHAR *filename, Tcl_DString *dsPtr) { char *p; - Tcl_ExternalToUtfDString(encoding, filename, -1, dsPtr); + Tcl_WinTCharToUtf((TCHAR *) filename, -1, dsPtr); for (p = Tcl_DStringValue(dsPtr); *p != '\0'; p++) { /* * Change the pathname to the Tcl "normalized" pathname, where back -- cgit v0.12