summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpatthoyts <patthoyts@users.sourceforge.net>2010-01-05 22:36:59 (GMT)
committerpatthoyts <patthoyts@users.sourceforge.net>2010-01-05 22:36:59 (GMT)
commit8d39ac13676ca900e69e4abfdf4604601c51fbf3 (patch)
treeef68b1f211f2ddd2007875e90afefb796263b6de
parentdda6e2358ef98e30c75799b489a68a0805e391b2 (diff)
downloadtk-8d39ac13676ca900e69e4abfdf4604601c51fbf3.zip
tk-8d39ac13676ca900e69e4abfdf4604601c51fbf3.tar.gz
tk-8d39ac13676ca900e69e4abfdf4604601c51fbf3.tar.bz2
Patch 289825: Enable unlimited multiple file selection from the open files dialog
-rw-r--r--ChangeLog5
-rw-r--r--win/tkWinDialog.c416
2 files changed, 309 insertions, 112 deletions
diff --git a/ChangeLog b/ChangeLog
index d3e2a58..f2096af 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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/win/tkWinDialog.c b/win/tkWinDialog.c
index 93d81b6..f22ea45 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.50.2.4 2009/10/22 10:27:58 dkf Exp $
+ * RCS: @(#) $Id: tkWinDialog.c,v 1.50.2.5 2010/01/05 22:36:59 patthoyts Exp $
*
*/
@@ -170,6 +170,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.
*/
@@ -186,7 +201,7 @@ static int GetFileNameW(ClientData clientData,
static int MakeFilter(Tcl_Interp *interp, Tcl_Obj *valuePtr,
Tcl_DString *dsPtr, Tcl_Obj *initialPtr,
int *index);
-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);
@@ -573,12 +588,14 @@ GetFileNameW(
{
OPENFILENAMEW ofn;
WCHAR file[TK_MULTI_MAX_PATH];
+ OFNData ofnData;
+ int cdlgerr;
int filterIndex, result, winCode, oldMode, i, multi = 0;
char *extension, *filter, *title;
Tk_Window tkwin;
HWND hWnd;
Tcl_Obj *filterObj, *initialTypeObj, *typeVariableObj;
- Tcl_DString utfFilterString, utfDirString;
+ Tcl_DString utfFilterString, utfDirString, ds;
Tcl_DString extString, filterString, dirString, titleString;
Tcl_Encoding unicodeEncoding = TkWinGetUnicodeEncoding();
ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
@@ -600,6 +617,7 @@ GetFileNameW(
result = TCL_ERROR;
file[0] = '\0';
+ ZeroMemory(&ofnData, sizeof(OFNData));
/*
* Parse the arguments.
@@ -674,9 +692,7 @@ GetFileNameW(
goto end;
}
break;
- case FILE_INITFILE: {
- Tcl_DString ds;
-
+ case FILE_INITFILE:
if (Tcl_TranslateFileName(interp, string, &ds) == NULL) {
goto end;
}
@@ -685,7 +701,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;
@@ -724,9 +739,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;
@@ -735,11 +750,19 @@ GetFileNameW(
}
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) {
@@ -813,32 +836,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') {
@@ -853,8 +887,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));
@@ -869,15 +903,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);
@@ -902,29 +933,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) {
@@ -941,6 +956,10 @@ GetFileNameW(
end:
Tcl_DStringFree(&utfDirString);
Tcl_DStringFree(&utfFilterString);
+ if (ofnData.dynFileBuffer != NULL) {
+ ckfree(ofnData.dynFileBuffer);
+ ofnData.dynFileBuffer = NULL;
+ }
return result;
}
@@ -950,8 +969,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.
@@ -972,9 +993,88 @@ OFNHookProcW(
ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
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
@@ -984,9 +1084,12 @@ OFNHookProcW(
ofnPtr = (OPENFILENAMEW *) TkWinGetUserData(hdlg);
if (ofnPtr != NULL) {
- hdlg = GetParent(hdlg);
- tsdPtr->debugInterp = (Tcl_Interp *) ofnPtr->lCustData;
- Tcl_DoWhenIdle(SetTkDialog, (ClientData) hdlg);
+ ofnData = (OFNData *) ofnPtr->lCustData;
+ if (ofnData->interp != NULL) {
+ hdlg = GetParent(hdlg);
+ tsdPtr->debugInterp = ofnData->interp;
+ Tcl_DoWhenIdle(SetTkDialog, hdlg);
+ }
TkWinSetUserData(hdlg, NULL);
}
}
@@ -1020,12 +1123,14 @@ GetFileNameA(
{
OPENFILENAME ofn;
TCHAR file[TK_MULTI_MAX_PATH], savePath[MAX_PATH];
+ OFNData ofnData;
+ int cdlgerr;
int filterIndex, result, winCode, oldMode, i, multi = 0;
char *extension, *filter, *title;
Tk_Window tkwin;
HWND hWnd;
Tcl_Obj *filterObj, *initialTypeObj, *typeVariableObj;
- Tcl_DString utfFilterString, utfDirString;
+ Tcl_DString utfFilterString, utfDirString, ds;
Tcl_DString extString, filterString, dirString, titleString;
ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
@@ -1046,6 +1151,7 @@ GetFileNameA(
result = TCL_ERROR;
file[0] = '\0';
+ ZeroMemory(&ofnData, sizeof(OFNData));
/*
* Parse the arguments.
@@ -1119,9 +1225,7 @@ GetFileNameA(
goto end;
}
break;
- case FILE_INITFILE: {
- Tcl_DString ds;
-
+ case FILE_INITFILE:
if (Tcl_TranslateFileName(interp, string, &ds) == NULL) {
goto end;
}
@@ -1130,7 +1234,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;
@@ -1162,6 +1265,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);
@@ -1176,12 +1280,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) {
@@ -1191,11 +1295,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) {
@@ -1267,28 +1379,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.
*/
@@ -1325,11 +1448,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);
@@ -1354,29 +1474,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) {
@@ -1393,6 +1497,10 @@ GetFileNameA(
end:
Tcl_DStringFree(&utfDirString);
Tcl_DStringFree(&utfFilterString);
+ if (ofnData.dynFileBuffer != NULL) {
+ ckfree(ofnData.dynFileBuffer);
+ ofnData.dynFileBuffer = NULL;
+ }
return result;
}
@@ -1400,10 +1508,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.
@@ -1415,7 +1525,7 @@ GetFileNameA(
*/
static UINT APIENTRY
-OFNHookProc(
+OFNHookProcA(
HWND hdlg, /* handle to child dialog window */
UINT uMsg, /* message identifier */
WPARAM wParam, /* message parameter */
@@ -1424,9 +1534,88 @@ OFNHookProc(
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;
+
+ 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
@@ -1437,11 +1626,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, (ClientData) hdlg);
TkWinSetUserData(hdlg, NULL);
}
}