diff options
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | tests/winDialog.test | 3 | ||||
-rw-r--r-- | win/tkWinDialog.c | 416 |
3 files changed, 310 insertions, 114 deletions
@@ -1,3 +1,8 @@ +2010-01-05 Pat Thoyts <patthoyts@users.sourceforge.net> + + * win/tkWinDialog.c: [Patch 2898255] Enable unlimited multiple + file selection from the open files dialog (pawlak,fellows,thoyts) + 2010-01-05 Donal K. Fellows <dkf@users.sf.net> * generic/tkMenu.c (MenuWidgetObjCmd): [Bug 220950]: Do not delete diff --git a/tests/winDialog.test b/tests/winDialog.test index f176e92..30649bf 100644 --- a/tests/winDialog.test +++ b/tests/winDialog.test @@ -7,7 +7,7 @@ # Copyright (c) 1998-1999 by Scriptics Corporation. # Copyright (c) 1998-1999 ActiveState Corporation. # -# RCS: @(#) $Id: winDialog.test,v 1.25 2008/12/10 13:41:19 patthoyts Exp $ +# RCS: @(#) $Id: winDialog.test,v 1.26 2010/01/05 21:50:54 patthoyts Exp $ package require tcltest 2.2 namespace import ::tcltest::* @@ -168,7 +168,6 @@ test winDialog-1.7 {Tk_ChooseColorObjCmd: -parent} -constraints { test winDialog-2.1 {ColorDlgHookProc} -constraints {emptyTest nt} -body {} - test winDialog-3.1 {Tk_GetOpenFileObjCmd} -constraints { nt testwinevent english } -body { diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c index 3c9312d..fd06861 100644 --- a/win/tkWinDialog.c +++ b/win/tkWinDialog.c @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkWinDialog.c,v 1.67 2010/01/03 00:19:25 patthoyts Exp $ + * RCS: @(#) $Id: tkWinDialog.c,v 1.68 2010/01/05 21:50:54 patthoyts Exp $ * */ @@ -171,6 +171,21 @@ typedef struct ChooseDir { } ChooseDir; /* + * The following structure is used to pass information between GetFileName/W + * functions and OFN dialog hook procedures. [Bug 2896501, Patch 2898255] + */ + +typedef struct OFNData { + Tcl_Interp *interp; /* Interp, used only if debug is turned on, + * for setting the "tk_dialog" variable. */ + 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 */ +} OFNData; + +/* * Definitions of functions used only in this file. */ @@ -187,7 +202,7 @@ static int GetFileNameW(ClientData clientData, static int MakeFilter(Tcl_Interp *interp, Tcl_Obj *valuePtr, Tcl_DString *dsPtr, Tcl_Obj *initialPtr, int *indexPtr); -static UINT APIENTRY OFNHookProc(HWND hdlg, UINT uMsg, WPARAM wParam, +static UINT APIENTRY OFNHookProcA(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam); static UINT APIENTRY OFNHookProcW(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam); @@ -571,12 +586,14 @@ GetFileNameW( { OPENFILENAMEW ofn; WCHAR file[TK_MULTI_MAX_PATH]; + OFNData ofnData; + int cdlgerr; int filterIndex = 0, result = TCL_ERROR, winCode, oldMode, i, multi = 0; const char *extension = NULL, *filter = NULL, *title = NULL; Tk_Window tkwin = clientData; HWND hWnd; Tcl_Obj *filterObj=NULL, *initialTypeObj=NULL, *typeVariableObj=NULL; - Tcl_DString utfFilterString, utfDirString; + Tcl_DString utfFilterString, utfDirString, ds; Tcl_DString extString, filterString, dirString, titleString; Tcl_Encoding unicodeEncoding = TkWinGetUnicodeEncoding(); ThreadSpecificData *tsdPtr = (ThreadSpecificData *) @@ -596,6 +613,7 @@ GetFileNameW( }; file[0] = '\0'; + ZeroMemory(&ofnData, sizeof(OFNData)); Tcl_DStringInit(&utfFilterString); Tcl_DStringInit(&utfDirString); @@ -662,9 +680,7 @@ GetFileNameW( goto end; } break; - case FILE_INITFILE: { - Tcl_DString ds; - + case FILE_INITFILE: if (Tcl_TranslateFileName(interp, string, &ds) == NULL) { goto end; } @@ -673,7 +689,6 @@ GetFileNameW( sizeof(file), NULL, NULL, NULL); Tcl_DStringFree(&ds); break; - } case FILE_MULTIPLE: if (Tcl_GetBooleanFromObj(interp, valuePtr, &multi) != TCL_OK) { return TCL_ERROR; @@ -712,9 +727,9 @@ GetFileNameW( ofn.lpstrFile = (WCHAR *) file; ofn.nMaxFile = TK_MULTI_MAX_PATH; ofn.Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR - | OFN_EXPLORER; + | OFN_EXPLORER | OFN_ENABLEHOOK; ofn.lpfnHook = (LPOFNHOOKPROC) OFNHookProcW; - ofn.lCustData = (LPARAM) interp; + ofn.lCustData = (LPARAM) &ofnData; if (open != 0) { ofn.Flags |= OFN_FILEMUSTEXIST; @@ -722,10 +737,18 @@ GetFileNameW( ofn.Flags |= OFN_OVERWRITEPROMPT; } if (tsdPtr->debugFlag != 0) { - ofn.Flags |= OFN_ENABLEHOOK; + 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) { @@ -799,32 +822,43 @@ GetFileNameW( /* * 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 more specific error messages for particular errors, we can + * extend the code as needed. */ - if (winCode != 0) { + 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 custData->szFile contains many items, separated - * with null characters. It is terminated with two nulls in a row. - * The first element is the directory path. + * 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. */ - WCHAR *files; - Tcl_DString dirBuf; - Tcl_Obj *returnList; + WCHAR *files = (WCHAR *) ofnData.dynFileBuffer; + Tcl_Obj *returnList = Tcl_NewObj(); int count = 0; - returnList = Tcl_NewObj(); - Tcl_IncrRefCount(returnList); - - files = ofn.lpstrFile; - /* * Get directory. */ (void) ConvertExternalFilename(unicodeEncoding, (char *) files, - &dirBuf); + &ds); while (*files != '\0') { while (*files != '\0') { @@ -839,8 +873,8 @@ GetFileNameW( (void) ConvertExternalFilename(unicodeEncoding, (char *) files, &filenameBuf); - fullnameObj = Tcl_NewStringObj(Tcl_DStringValue(&dirBuf), - Tcl_DStringLength(&dirBuf)); + fullnameObj = Tcl_NewStringObj(Tcl_DStringValue(&ds), + Tcl_DStringLength(&ds)); Tcl_AppendToObj(fullnameObj, "/", -1); Tcl_AppendToObj(fullnameObj, Tcl_DStringValue(&filenameBuf), Tcl_DStringLength(&filenameBuf)); @@ -855,15 +889,12 @@ GetFileNameW( */ Tcl_ListObjAppendElement(NULL, returnList, - Tcl_NewStringObj(Tcl_DStringValue(&dirBuf), - Tcl_DStringLength(&dirBuf))); + Tcl_NewStringObj(Tcl_DStringValue(&ds), + Tcl_DStringLength(&ds))); } Tcl_SetObjResult(interp, returnList); - Tcl_DecrRefCount(returnList); - Tcl_DStringFree(&dirBuf); + Tcl_DStringFree(&ds); } else { - Tcl_DString ds; - Tcl_AppendResult(interp, ConvertExternalFilename(unicodeEncoding, (char *) ofn.lpstrFile, &ds), NULL); Tcl_DStringFree(&ds); @@ -888,29 +919,13 @@ GetFileNameW( result = TCL_ERROR; } } + } else if (cdlgerr == FNERR_INVALIDFILENAME) { + Tcl_SetResult(interp, "invalid filename \"", TCL_STATIC); + Tcl_AppendResult(interp, ConvertExternalFilename(unicodeEncoding, + (char *) ofn.lpstrFile, &ds), "\"", NULL); + Tcl_DStringFree(&ds); } else { - /* - * 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 more specific error messages for - * particular errors, we can extend the code as needed. - * - * We could also check for FNERR_BUFFERTOOSMALL, but we can't really - * do anything about it when it happens. - */ - - if (CommDlgExtendedError() == FNERR_INVALIDFILENAME) { - Tcl_DString ds; - - Tcl_SetResult(interp, "invalid filename \"", TCL_STATIC); - Tcl_AppendResult(interp, ConvertExternalFilename(unicodeEncoding, - (char *) ofn.lpstrFile, &ds), "\"", NULL); - Tcl_DStringFree(&ds); - } else { - result = TCL_OK; - } + result = TCL_OK; } if (ofn.lpstrTitle != NULL) { @@ -927,6 +942,10 @@ GetFileNameW( end: Tcl_DStringFree(&utfDirString); Tcl_DStringFree(&utfFilterString); + if (ofnData.dynFileBuffer != NULL) { + ckfree(ofnData.dynFileBuffer); + ofnData.dynFileBuffer = NULL; + } return result; } @@ -936,8 +955,10 @@ GetFileNameW( * * OFNHookProcW -- * - * Hook function called only if debugging is turned on. Sets the - * "tk_dialog" variable when the dialog is ready to receive messages. + * 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. @@ -958,9 +979,88 @@ OFNHookProcW( ThreadSpecificData *tsdPtr = Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); OPENFILENAMEW *ofnPtr; + OFNData *ofnData; if (uMsg == WM_INITDIALOG) { TkWinSetUserData(hdlg, lParam); + } else if (uMsg == WM_NOTIFY) { + OFNOTIFYW *notifyPtr = (OFNOTIFYW *) lParam; + + if (notifyPtr->hdr.code == CDN_SELCHANGE) { + int dirsize, selsize; + WCHAR *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 = (WCHAR *) ofnData->dynFileBuffer; + hdlg = GetParent(hdlg); + + selsize = SendMessageW(hdlg, CDM_GETSPEC, 0, 0); + dirsize = SendMessageW(hdlg, CDM_GETFOLDERPATH, 0, 0); + buffersize = (selsize + dirsize + 1) * 2; + + if (selsize > 1) { + if (ofnData->dynFileBufferSize < buffersize) { + buffer = (WCHAR *) ckrealloc((char *) buffer, buffersize); + ofnData->dynFileBufferSize = buffersize; + ofnData->dynFileBuffer = (char *) buffer; + } + + SendMessageW(hdlg, CDM_GETFOLDERPATH, dirsize, (int) buffer); + buffer += dirsize; + + SendMessageW(hdlg, CDM_GETSPEC, selsize, (int) buffer); + + /* + * If there are multiple files, delete the quotes and change + * every second quote to NULL terminator + */ + + if (buffer[0] == '"') { + BOOL findquote = TRUE; + WCHAR *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 enable Tk to set the @@ -970,9 +1070,12 @@ OFNHookProcW( ofnPtr = (OPENFILENAMEW *) TkWinGetUserData(hdlg); if (ofnPtr != NULL) { - hdlg = GetParent(hdlg); - tsdPtr->debugInterp = (Tcl_Interp *) ofnPtr->lCustData; - Tcl_DoWhenIdle(SetTkDialog, hdlg); + ofnData = (OFNData *) ofnPtr->lCustData; + if (ofnData->interp != NULL) { + hdlg = GetParent(hdlg); + tsdPtr->debugInterp = ofnData->interp; + Tcl_DoWhenIdle(SetTkDialog, hdlg); + } TkWinSetUserData(hdlg, NULL); } } @@ -1006,12 +1109,14 @@ GetFileNameA( { 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; const char *extension = NULL, *filter = NULL, *title = NULL; Tk_Window tkwin = clientData; HWND hWnd; Tcl_Obj *filterObj=NULL, *initialTypeObj=NULL, *typeVariableObj=NULL; - Tcl_DString utfFilterString, utfDirString; + Tcl_DString utfFilterString, utfDirString, ds; Tcl_DString extString, filterString, dirString, titleString; ThreadSpecificData *tsdPtr = Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); @@ -1030,6 +1135,7 @@ GetFileNameA( }; file[0] = '\0'; + ZeroMemory(&ofnData, sizeof(OFNData)); Tcl_DStringInit(&utfFilterString); Tcl_DStringInit(&utfDirString); @@ -1095,9 +1201,7 @@ GetFileNameA( goto end; } break; - case FILE_INITFILE: { - Tcl_DString ds; - + case FILE_INITFILE: if (Tcl_TranslateFileName(interp, string, &ds) == NULL) { goto end; } @@ -1106,7 +1210,6 @@ GetFileNameA( sizeof(file), NULL, NULL, NULL); Tcl_DStringFree(&ds); break; - } case FILE_MULTIPLE: if (Tcl_GetBooleanFromObj(interp, valuePtr, &multi) != TCL_OK) { return TCL_ERROR; @@ -1138,6 +1241,7 @@ GetFileNameA( Tk_MakeWindowExist(tkwin); hWnd = Tk_GetHWND(Tk_WindowId(tkwin)); + ZeroMemory(&ofn, sizeof(OPENFILENAMEA)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hWnd; ofn.hInstance = TkWinGetHInstance(ofn.hwndOwner); @@ -1151,12 +1255,12 @@ GetFileNameA( ofn.lpstrInitialDir = NULL; ofn.lpstrTitle = NULL; ofn.Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR - | OFN_EXPLORER; + | OFN_EXPLORER | OFN_ENABLEHOOK; ofn.nFileOffset = 0; ofn.nFileExtension = 0; ofn.lpstrDefExt = NULL; - ofn.lpfnHook = (LPOFNHOOKPROC) OFNHookProc; - ofn.lCustData = (LPARAM) interp; + ofn.lpfnHook = (LPOFNHOOKPROC) OFNHookProcA; + ofn.lCustData = (LPARAM) &ofnData; ofn.lpTemplateName = NULL; if (open != 0) { @@ -1166,11 +1270,19 @@ GetFileNameA( } if (tsdPtr->debugFlag != 0) { - ofn.Flags |= OFN_ENABLEHOOK; + 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) { @@ -1243,28 +1355,39 @@ GetFileNameA( /* * 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) { + if ((winCode != 0) + || ((cdlgerr == FNERR_BUFFERTOOSMALL) + && (ofn.Flags & OFN_ALLOWMULTISELECT))) { if (ofn.Flags & OFN_ALLOWMULTISELECT) { /* - * The result in custData->szFile contains many items, separated - * with null characters. It is terminated with two nulls in a row. - * The first element is the directory path (if multiple files are + * 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; - Tcl_DString ds; - Tcl_Obj *returnList; + char *files = ofnData.dynFileBuffer; + Tcl_Obj *returnList = Tcl_NewObj(); int count = 0; - returnList = Tcl_NewObj(); - Tcl_IncrRefCount(returnList); - - files = ofn.lpstrFile; - /* * Get directory. */ @@ -1301,11 +1424,8 @@ GetFileNameA( Tcl_DStringValue(&ds), Tcl_DStringLength(&ds))); } Tcl_SetObjResult(interp, returnList); - Tcl_DecrRefCount(returnList); Tcl_DStringFree(&ds); } else { - Tcl_DString ds; - Tcl_AppendResult(interp, ConvertExternalFilename(NULL, (char *) ofn.lpstrFile, &ds), NULL); Tcl_DStringFree(&ds); @@ -1330,29 +1450,13 @@ GetFileNameA( 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 { - /* - * 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. - * - * We could also check for FNERR_BUFFERTOOSMALL, but we can't really - * do anything about it when it happens. - */ - - if (CommDlgExtendedError() == FNERR_INVALIDFILENAME) { - Tcl_DString ds; - - Tcl_SetResult(interp, "invalid filename \"", TCL_STATIC); - Tcl_AppendResult(interp, ConvertExternalFilename(NULL, - (char *) ofn.lpstrFile, &ds), "\"", NULL); - Tcl_DStringFree(&ds); - } else { - result = TCL_OK; - } + result = TCL_OK; } if (ofn.lpstrTitle != NULL) { @@ -1369,6 +1473,10 @@ GetFileNameA( end: Tcl_DStringFree(&utfDirString); Tcl_DStringFree(&utfFilterString); + if (ofnData.dynFileBuffer != NULL) { + ckfree(ofnData.dynFileBuffer); + ofnData.dynFileBuffer = NULL; + } return result; } @@ -1376,10 +1484,12 @@ GetFileNameA( /* *------------------------------------------------------------------------- * - * OFNHookProc -- + * OFNHookProcA -- * - * Hook function called only if debugging is turned on. Sets the - * "tk_dialog" variable when the dialog is ready to receive messages. + * 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. @@ -1391,7 +1501,7 @@ GetFileNameA( */ static UINT APIENTRY -OFNHookProc( +OFNHookProcA( HWND hdlg, /* handle to child dialog window */ UINT uMsg, /* message identifier */ WPARAM wParam, /* message parameter */ @@ -1400,9 +1510,88 @@ OFNHookProc( ThreadSpecificData *tsdPtr = 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; + + if (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; + + if (selsize > 1) { + if (ofnData->dynFileBufferSize < buffersize) { + buffer = ckrealloc(buffer, buffersize); + ofnData->dynFileBufferSize = buffersize; + ofnData->dynFileBuffer = buffer; + } + + SendMessage(hdlg, CDM_GETFOLDERPATH, dirsize, (int) buffer); + buffer += dirsize; + SendMessage(hdlg, CDM_GETSPEC, selsize, (int) 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 @@ -1413,11 +1602,14 @@ OFNHookProc( ofnPtr = (OPENFILENAME *) TkWinGetUserData(hdlg); if (ofnPtr != NULL) { - if (ofnPtr->Flags & OFN_EXPLORER) { - hdlg = GetParent(hdlg); + ofnData = (OFNData *) ofnPtr->lCustData; + if (ofnData->interp != NULL) { + if (ofnPtr->Flags & OFN_EXPLORER) { + hdlg = GetParent(hdlg); + } + tsdPtr->debugInterp = ofnData->interp; + Tcl_DoWhenIdle(SetTkDialog, hdlg); } - tsdPtr->debugInterp = (Tcl_Interp *) ofnPtr->lCustData; - Tcl_DoWhenIdle(SetTkDialog, hdlg); TkWinSetUserData(hdlg, NULL); } } |