summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2012-06-21 22:21:02 +0000
committerGuy Harris <guy@alum.mit.edu>2012-06-21 22:21:02 +0000
commit204ea39c5d87a834580531f32916fa0d8bec53c3 (patch)
treea2e44f8ce3a82fba36b5f9aab2141be842be21cc
parenta0148735c18d44b75a26f3d265c70aabcf0aefd6 (diff)
downloadwireshark-204ea39c5d87a834580531f32916fa0d8bec53c3.tar.gz
Move a bunch of common code in the file chooser dialog loops into a
routine to run a file chooser dialog. On Windows, add to that code to resolve shell links ("shortcuts"), adopted from the Sylpheed mail reader. (That code requires a pile of OLE stuff, so link with the OLE library.) Make it a bit easier to configure ui/gtk/capture_file_dlg.c to use GTK+ dialogs on Windows, but continue to default to using the Win32 dialogs, at least for now. svn path=/trunk/; revision=43439
-rw-r--r--Makefile.nmake2
-rw-r--r--ui/gtk/capture_file_dlg.c169
-rw-r--r--ui/gtk/file_dlg.c123
-rw-r--r--ui/gtk/file_dlg.h9
4 files changed, 180 insertions, 123 deletions
diff --git a/Makefile.nmake b/Makefile.nmake
index 10b3652309..a6ecdf8897 100644
--- a/Makefile.nmake
+++ b/Makefile.nmake
@@ -73,7 +73,7 @@ dumpcap_OBJECTS = $(dumpcap_SOURCES:.c=.obj)
randpkt_OBJECTS = $(randpkt_SOURCES:.c=.obj)
wireshark_LIBS= wiretap\wiretap-$(WTAP_VERSION).lib \
- wsock32.lib user32.lib shell32.lib comctl32.lib \
+ wsock32.lib user32.lib shell32.lib comctl32.lib ole32.lib \
$(GTHREAD_LIBS) \
$(HHC_LIBS) \
wsutil\libwsutil.lib \
diff --git a/ui/gtk/capture_file_dlg.c b/ui/gtk/capture_file_dlg.c
index fecdee1fb8..dafe457845 100644
--- a/ui/gtk/capture_file_dlg.c
+++ b/ui/gtk/capture_file_dlg.c
@@ -47,7 +47,6 @@
#include <wsutil/file_util.h>
#include "ui/alert_box.h"
-#include "ui/last_open_dir.h"
#include "ui/recent.h"
#include "ui/simple_dialog.h"
#include "ui/ui_util.h"
@@ -70,7 +69,11 @@
#include "ui/gtk/range_utils.h"
#include "ui/gtk/filter_autocomplete.h"
-#if _WIN32
+#ifdef _WIN32
+#define USE_WIN32_FILE_DIALOGS
+#endif
+
+#ifdef USE_WIN32_FILE_DIALOGS
#include <gdk/gdkwin32.h>
#include <windows.h>
#include "ui/win32/file_dlg_win32.h"
@@ -422,9 +425,9 @@ preview_new(void)
static void
file_open_cmd(GtkWidget *w)
{
-#if _WIN32
+#ifdef USE_WIN32_FILE_DIALOGS
win32_open_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)));
-#else /* _WIN32 */
+#else /* USE_WIN32_FILE_DIALOGS */
GtkWidget *file_open_w;
GtkWidget *main_hb, *main_vb, *filter_hbox, *filter_bt, *filter_te,
*m_resolv_cb, *n_resolv_cb, *t_resolv_cb, *prev;
@@ -541,26 +544,12 @@ file_open_cmd(GtkWidget *w)
* Loop until the user either selects a file or gives up.
*/
for (;;) {
- if (gtk_dialog_run(GTK_DIALOG(file_open_w)) != GTK_RESPONSE_ACCEPT) {
- /* They clicked "Cancel" or closed the dialog or.... */
- window_destroy(file_open_w);
+ cf_name = file_selection_run(file_open_w);
+ if (cf_name == NULL) {
+ /* User cancelled or closed the dialog. */
return;
}
- cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_open_w));
-
- /* Perhaps the user specified a directory instead of a file.
- Check whether they did. */
- if (test_for_directory(cf_name) == EISDIR) {
- /* It's a directory - set the file selection box to display that
- directory, and go back and re-run it; don't try to open the
- directory as a capture file. */
- set_last_open_dir(cf_name);
- g_free(cf_name);
- file_selection_set_current_folder(file_open_w, get_last_open_dir());
- continue;
- }
-
/* Get the specified read filter and try to compile it. */
rfilter = gtk_entry_get_text(GTK_ENTRY(filter_te));
if (!dfilter_compile(rfilter, &rfcode)) {
@@ -633,7 +622,7 @@ file_open_cmd(GtkWidget *w)
g_free(cf_name);
return;
}
-#endif /* _WIN32 */
+#endif /* USE_WIN32_FILE_DIALOGS */
}
void
@@ -648,11 +637,11 @@ file_open_cmd_cb(GtkWidget *widget, gpointer data _U_) {
static void
file_merge_cmd(GtkWidget *w)
{
-#if _WIN32
+#ifdef USE_WIN32_FILE_DIALOGS
win32_merge_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)));
new_packet_list_freeze();
new_packet_list_thaw();
-#else /* _WIN32 */
+#else /* USE_WIN32_FILE_DIALOGS */
GtkWidget *file_merge_w;
GtkWidget *main_hb, *main_vb, *ft_hb, *ft_lb, *ft_combo_box, *filter_hbox,
*filter_bt, *filter_te, *prepend_rb, *chrono_rb,
@@ -794,26 +783,12 @@ file_merge_cmd(GtkWidget *w)
* Loop until the user either selects a file or gives up.
*/
for (;;) {
- if (gtk_dialog_run(GTK_DIALOG(file_merge_w)) != GTK_RESPONSE_ACCEPT) {
- /* They clicked "Cancel" or closed the dialog or.... */
- window_destroy(file_merge_w);
+ cf_name = file_selection_run(file_merge_w);
+ if (cf_name == NULL) {
+ /* User cancelled or closed the dialog. */
return;
}
- cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_merge_w));
-
- /* Perhaps the user specified a directory instead of a file.
- Check whether they did. */
- if (test_for_directory(cf_name) == EISDIR) {
- /* It's a directory - set the file selection box to display that
- directory, and go back and re-run it; don't try to open the
- directory as a capture file. */
- set_last_open_dir(cf_name);
- g_free(cf_name);
- file_selection_set_current_folder(file_merge_w, get_last_open_dir());
- continue;
- }
-
/* Get the specified read filter and try to compile it. */
rfilter = gtk_entry_get_text(GTK_ENTRY(filter_te));
if (!dfilter_compile(rfilter, &rfcode)) {
@@ -903,7 +878,7 @@ file_merge_cmd(GtkWidget *w)
set_last_open_dir(s);
return;
}
-#endif /* _WIN32 */
+#endif /* USE_WIN32_FILE_DIALOGS */
}
void
@@ -1594,9 +1569,9 @@ static void
do_file_save_as(capture_file *cf, gboolean must_support_comments,
gboolean dont_reopen)
{
-#if _WIN32
+#ifdef USE_WIN32_FILE_DIALOGS
win32_save_as_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)));
-#else /* _WIN32 */
+#else /* USE_WIN32_FILE_DIALOGS */
GtkWidget *file_save_as_w;
GtkWidget *main_vb, *ft_hb, *ft_lb, *ft_combo_box, *compressed_cb;
char *cf_name;
@@ -1648,26 +1623,12 @@ do_file_save_as(capture_file *cf, gboolean must_support_comments,
* Loop until the user either selects a file or gives up.
*/
for (;;) {
- if (gtk_dialog_run(GTK_DIALOG(file_save_as_w)) != GTK_RESPONSE_ACCEPT) {
- /* They clicked "Cancel" or closed the dialog or.... */
- window_destroy(file_save_as_w);
+ cf_name = file_selection_run(file_save_as_w);
+ if (cf_name == NULL) {
+ /* User cancelled or closed the dialog. */
return;
}
- cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_save_as_w));
-
- /* Perhaps the user specified a directory instead of a file.
- Check whether they did. */
- if (test_for_directory(cf_name) == EISDIR) {
- /* It's a directory - set the file selection box to display that
- directory, and go back and re-run it; don't try to write onto
- the directory (which won't work anyway). */
- set_last_open_dir(cf_name);
- g_free(cf_name);
- file_selection_set_current_folder(file_save_as_w, get_last_open_dir());
- continue;
- }
-
/* If the file has comments, does the format the user selected
support them? If not, ask the user whether they want to
discard the comments or choose a different format. */
@@ -1704,6 +1665,7 @@ do_file_save_as(capture_file *cf, gboolean must_support_comments,
return;
}
+#ifndef _WIN32
/* If the file exists and it's user-immutable or not writable,
ask the user whether they want to override that. */
if (!file_target_unwritable_ui(file_save_as_w, cf_name)) {
@@ -1711,6 +1673,7 @@ do_file_save_as(capture_file *cf, gboolean must_support_comments,
g_free(cf_name);
continue;
}
+#endif
/* Attempt to save the file */
g_free(cf_name);
@@ -1733,7 +1696,7 @@ do_file_save_as(capture_file *cf, gboolean must_support_comments,
return;
}
}
-#endif /* _WIN32 */
+#endif /* USE_WIN32_FILE_DIALOGS */
}
void
@@ -1806,9 +1769,9 @@ file_save_as_cb(GtkWidget *fs, gboolean discard_comments,
void
file_export_specified_packets_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
{
-#if _WIN32
+#ifdef USE_WIN32_FILE_DIALOGS
win32_export_specified_packets_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)));
-#else /* _WIN32 */
+#else /* USE_WIN32_FILE_DIALOGS */
GtkWidget *file_export_specified_packets_w;
GtkWidget *main_vb, *ft_hb, *ft_lb, *ft_combo_box, *range_fr, *range_tb,
*compressed_cb;
@@ -1881,26 +1844,12 @@ file_export_specified_packets_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
* Loop until the user either selects a file or gives up.
*/
for (;;) {
- if (gtk_dialog_run(GTK_DIALOG(file_export_specified_packets_w)) != GTK_RESPONSE_ACCEPT) {
- /* They clicked "Cancel" or closed the dialog or.... */
- window_destroy(file_export_specified_packets_w);
+ cf_name = file_selection_run(file_export_specified_packets_w);
+ if (cf_name == NULL) {
+ /* User cancelled or closed the dialog. */
return;
}
- cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_export_specified_packets_w));
-
- /* Perhaps the user specified a directory instead of a file.
- Check whether they did. */
- if (test_for_directory(cf_name) == EISDIR) {
- /* It's a directory - set the file selection box to display that
- directory, and go back and re-run it; don't try to write onto
- the directory (which won't work anyway). */
- set_last_open_dir(cf_name);
- g_free(cf_name);
- file_selection_set_current_folder(file_export_specified_packets_w, get_last_open_dir());
- continue;
- }
-
/* Check whether the range is valid. */
if (!range_check_validity_modal(file_export_specified_packets_w, &range)) {
/* The range isn't valid; the user was told that, and dismissed
@@ -1935,6 +1884,7 @@ file_export_specified_packets_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
continue;
}
+#ifndef _WIN32
/* If the file exists and it's user-immutable or not writable,
ask the user whether they want to override that. */
if (!file_target_unwritable_ui(file_export_specified_packets_w, cf_name)) {
@@ -1942,6 +1892,7 @@ file_export_specified_packets_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
g_free(cf_name);
continue;
}
+#endif
/* attempt to export the packets */
g_free(cf_name);
@@ -1961,7 +1912,7 @@ file_export_specified_packets_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
return;
}
}
-#endif /* _WIN32 */
+#endif /* USE_WIN32_FILE_DIALOGS */
}
/* all tests ok, we only have to write out the packets */
@@ -2062,9 +2013,9 @@ color_global_cb(GtkWidget *widget _U_, gpointer data)
void
file_color_import_cmd_cb(GtkWidget *color_filters, gpointer filter_list _U_)
{
-#if _WIN32
+#ifdef USE_WIN32_FILE_DIALOGS
win32_import_color_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)), color_filters);
-#else /* _WIN32 */
+#else /* USE_WIN32_FILE_DIALOGS */
GtkWidget *main_vb, *cfglobal_but;
gchar *cf_name, *s;
@@ -2090,26 +2041,12 @@ file_color_import_cmd_cb(GtkWidget *color_filters, gpointer filter_list _U_)
* Loop until the user either selects a file or gives up.
*/
for (;;) {
- if (gtk_dialog_run(GTK_DIALOG(file_color_import_w)) != GTK_RESPONSE_ACCEPT) {
- /* They clicked "Cancel" or closed the dialog or.... */
- window_destroy(file_color_import_w);
+ cf_name = file_selection_run(file_color_import_w);
+ if (cf_name == NULL) {
+ /* User cancelled or closed the dialog. */
return;
}
- cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_color_import_w));
-
- /* Perhaps the user specified a directory instead of a file.
- Check whether they did. */
- if (test_for_directory(cf_name) == EISDIR) {
- /* It's a directory - set the file selection box to display that
- directory, and go back and re-run it; don't try to open the
- directory as a color filter file. */
- set_last_open_dir(cf_name);
- g_free(cf_name);
- file_selection_set_current_folder(file_color_import_w, get_last_open_dir());
- continue;
- }
-
/* Try to open the color filter file. */
if (!color_filters_import(cf_name, color_filters)) {
/* We couldn't open it; don't dismiss the open dialog box,
@@ -2132,7 +2069,7 @@ file_color_import_cmd_cb(GtkWidget *color_filters, gpointer filter_list _U_)
g_free(cf_name);
return;
}
-#endif /* _WIN32 */
+#endif /* USE_WIN32_FILE_DIALOGS */
}
/*
@@ -2167,9 +2104,9 @@ color_toggle_selected_cb(GtkWidget *widget, gpointer data _U_)
void
file_color_export_cmd_cb(GtkWidget *w _U_, gpointer filter_list)
{
-#if _WIN32
+#if USE_WIN32_FILE_DIALOGS
win32_export_color_file(GDK_WINDOW_HWND(gtk_widget_get_window(top_level)), filter_list);
-#else /* _WIN32 */
+#else /* USE_WIN32_FILE_DIALOGS */
GtkWidget *file_color_export_w;
GtkWidget *main_vb, *cfglobal_but;
GtkWidget *cfselect_cb;
@@ -2207,26 +2144,13 @@ file_color_export_cmd_cb(GtkWidget *w _U_, gpointer filter_list)
* Loop until the user either selects a file or gives up.
*/
for (;;) {
- if (gtk_dialog_run(GTK_DIALOG(file_color_export_w)) != GTK_RESPONSE_ACCEPT) {
- /* They clicked "Cancel" or closed the dialog or.... */
- window_destroy(file_color_export_w);
+ cf_name = file_selection_run(file_color_export_w);
+ if (cf_name == NULL) {
+ /* User cancelled or closed the dialog. */
return;
}
- cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_color_export_w));
-
- /* Perhaps the user specified a directory instead of a file.
- Check whether they did. */
- if (test_for_directory(cf_name) == EISDIR) {
- /* It's a directory - set the file selection box to display that
- directory, and go back and re-run it; don't try to write onto
- the directory (which wn't work anyway). */
- set_last_open_dir(cf_name);
- g_free(cf_name);
- file_selection_set_current_folder(file_color_export_w, get_last_open_dir());
- continue;
- }
-
+#ifndef _WIN32
/* If the file exists and it's user-immutable or not writable,
ask the user whether they want to override that. */
if (!file_target_unwritable_ui(file_color_export_w, cf_name)) {
@@ -2234,6 +2158,7 @@ file_color_export_cmd_cb(GtkWidget *w _U_, gpointer filter_list)
g_free(cf_name);
continue;
}
+#endif
/* Write out the filters (all, or only the ones that are currently
displayed or selected) to the file with the specified name. */
@@ -2253,5 +2178,5 @@ file_color_export_cmd_cb(GtkWidget *w _U_, gpointer filter_list)
set_last_open_dir(dirname);
g_free(cf_name);
}
-#endif /* _WIN32 */
+#endif /* USE_WIN32_FILE_DIALOGS */
}
diff --git a/ui/gtk/file_dlg.c b/ui/gtk/file_dlg.c
index 1173e6eab0..d633e80cc8 100644
--- a/ui/gtk/file_dlg.c
+++ b/ui/gtk/file_dlg.c
@@ -22,6 +22,15 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+/*
+ * Code to handle Windows shortcuts courtesy of:
+ *
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2012 Hiroyuki Yamamoto
+ *
+ * licensed under the GPL2 or later.
+ */
+
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
@@ -30,12 +39,22 @@
#include <gtk/gtk.h>
+#ifdef _WIN32
+# define COBJMACROS
+# include <windows.h>
+# include <objbase.h>
+# include <objidl.h>
+# include <shlobj.h>
+#endif
+
#include <wsutil/file_util.h>
#ifndef _WIN32
#include <epan/filesystem.h>
#endif
+#include "ui/last_open_dir.h"
+
#include "ui/gtk/gtkglobals.h"
#include "ui/gtk/gui_utils.h"
#include "ui/gtk/file_dlg.h"
@@ -157,6 +176,110 @@ file_selection_set_extra_widget(GtkWidget *fs, GtkWidget *extra)
gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(fs), extra);
}
+#ifdef _WIN32
+static gchar *filesel_get_link(const gchar *link_file)
+{
+ WIN32_FIND_DATAW wfd;
+ IShellLinkW *psl;
+ IPersistFile *ppf;
+ wchar_t *wlink_file;
+ wchar_t wtarget[MAX_PATH];
+ gchar *target = NULL;
+
+ wtarget[0] = 0L;
+
+ CoInitialize(NULL);
+ if (S_OK == CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IShellLinkW, (void **)&psl)) {
+ if (S_OK == IShellLinkW_QueryInterface(psl, &IID_IPersistFile,
+ (void **)&ppf)) {
+ wlink_file = g_utf8_to_utf16(link_file, -1, NULL, NULL, NULL);
+ if (S_OK == IPersistFile_Load(ppf, wlink_file, STGM_READ)) {
+ if (S_OK == IShellLinkW_GetPath(psl, wtarget, MAX_PATH, &wfd,
+ SLGP_UNCPRIORITY)) {
+ target = g_utf16_to_utf8(wtarget, -1, NULL, NULL, NULL);
+ }
+ }
+ IPersistFile_Release(ppf);
+ g_free(wlink_file);
+ }
+ IShellLinkW_Release(psl);
+ }
+ CoUninitialize();
+
+ return target;
+}
+#endif /* _WIN32 */
+
+/* Run the dialog, and handle some common operations, such as, if the
+ user selects a directory, browsing that directory, and handling
+ shortcuts on Windows.
+
+ Returns NULL if the user decided not to open/write to a file,
+ returns the pathname of the selected file if they selected a
+ file. */
+gchar *
+file_selection_run(GtkWidget *fs)
+{
+ gchar *cf_name;
+#ifdef _WIN32
+ gchar *target;
+ const gchar *ext;
+#endif
+
+ for (;;) {
+ if (gtk_dialog_run(GTK_DIALOG(fs)) != GTK_RESPONSE_ACCEPT) {
+ /* They clicked "Cancel" or closed the dialog or...;
+ destroy the dialog and tell our caller the user decided
+ not to do anything with the file. */
+ window_destroy(fs);
+ return NULL;
+ }
+
+ cf_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs));
+
+ /* Perhaps the user specified a directory instead of a file.
+ Check whether they did. */
+ if (test_for_directory(cf_name) == EISDIR) {
+ /* It's a directory - set the file selection box to display that
+ directory, and go back and re-run it; don't try to open the
+ directory as a file (you'll get crap if you get anything) or
+ write to it (which won't work anyway). */
+ set_last_open_dir(cf_name);
+ g_free(cf_name);
+ file_selection_set_current_folder(fs, get_last_open_dir());
+ continue;
+ }
+
+#ifdef _WIN32
+ /* Perhaps the user specified a "shortcut" instead of a file.
+ Check whether they did. */
+ if ((ext = strrchr(cf_name, '.')) && g_ascii_strcasecmp(ext, ".lnk") == 0) {
+ /* It ends with ".lnk", so it might be a shortcut. */
+ target = filesel_get_link(cf_name);
+ if (target != NULL) {
+ /* We resolved it, so it must've been a shortcut. */
+ g_free(cf_name);
+ if (test_for_directory(target)) {
+ /* It's a shortcut that points to a directory; treat it the same
+ way we treat a directory. */
+ set_last_open_dir(target);
+ g_free(target);
+ file_selection_set_current_folder(fs, get_last_open_dir());
+ continue;
+ }
+ /* It's a shortcut that points to a file; act as if the target
+ is what's selected. */
+ cf_name = target;
+ }
+ }
+#endif
+ break;
+ }
+
+ return cf_name;
+}
+
#ifndef _WIN32
/* If the specified file doesn't exist, return TRUE.
If it exists and is neither user-immutable nor not writable, return
diff --git a/ui/gtk/file_dlg.h b/ui/gtk/file_dlg.h
index 9ee50f1afd..47da219e77 100644
--- a/ui/gtk/file_dlg.h
+++ b/ui/gtk/file_dlg.h
@@ -85,6 +85,15 @@ extern gboolean file_selection_set_current_folder(GtkWidget *fs, const gchar *fi
*/
extern void file_selection_set_extra_widget(GtkWidget *fs, GtkWidget *extra);
+/** Run the dialog, and handle some common operations, such as, if the
+ * user selects a directory, browsing that directory, and handling
+ * shortcuts on Windows.
+ * @param fs the file selection dialog from file_selection_new()
+ * @return the pathname of the selected file if the user selected a
+ * file, NULL if they cancelled or closed the dialog.
+ */
+extern gchar *file_selection_run(GtkWidget *fs);
+
#ifndef _WIN32
/** If the specified file doesn't exist, return TRUE.
* If it exists and is neither user-immutable nor not writable, return