4671 lines
144 KiB
C
4671 lines
144 KiB
C
/*
|
|
* Common Item Dialog
|
|
*
|
|
* Copyright 2010,2011 David Hedberg
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#include <stdarg.h>
|
|
|
|
#define COBJMACROS
|
|
#define NONAMELESSUNION
|
|
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
#include "winuser.h"
|
|
#include "wingdi.h"
|
|
#include "winreg.h"
|
|
#include "shlwapi.h"
|
|
|
|
#include "commdlg.h"
|
|
#include "cdlg.h"
|
|
#include "filedlgbrowser.h"
|
|
|
|
#include "wine/debug.h"
|
|
#include "wine/list.h"
|
|
|
|
#define IDC_NAV_TOOLBAR 200
|
|
#define IDC_NAVBACK 201
|
|
#define IDC_NAVFORWARD 202
|
|
|
|
#include <initguid.h>
|
|
/* This seems to be another version of IID_IFileDialogCustomize. If
|
|
* there is any difference I have yet to find it. */
|
|
DEFINE_GUID(IID_IFileDialogCustomizeAlt, 0x8016B7B3, 0x3D49, 0x4504, 0xA0,0xAA, 0x2A,0x37,0x49,0x4E,0x60,0x6F);
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
|
|
|
|
static const WCHAR notifysink_childW[] = {'n','f','s','_','c','h','i','l','d',0};
|
|
static const WCHAR floatnotifysinkW[] = {'F','l','o','a','t','N','o','t','i','f','y','S','i','n','k',0};
|
|
static const WCHAR radiobuttonlistW[] = {'R','a','d','i','o','B','u','t','t','o','n','L','i','s','t',0};
|
|
|
|
enum ITEMDLG_TYPE {
|
|
ITEMDLG_TYPE_OPEN,
|
|
ITEMDLG_TYPE_SAVE
|
|
};
|
|
|
|
enum ITEMDLG_CCTRL_TYPE {
|
|
IDLG_CCTRL_MENU,
|
|
IDLG_CCTRL_PUSHBUTTON,
|
|
IDLG_CCTRL_COMBOBOX,
|
|
IDLG_CCTRL_RADIOBUTTONLIST,
|
|
IDLG_CCTRL_CHECKBUTTON,
|
|
IDLG_CCTRL_EDITBOX,
|
|
IDLG_CCTRL_SEPARATOR,
|
|
IDLG_CCTRL_TEXT,
|
|
IDLG_CCTRL_OPENDROPDOWN,
|
|
IDLG_CCTRL_VISUALGROUP
|
|
};
|
|
|
|
typedef struct cctrl_item {
|
|
DWORD id, parent_id;
|
|
LPWSTR label;
|
|
CDCONTROLSTATEF cdcstate;
|
|
HWND hwnd;
|
|
struct list entry;
|
|
} cctrl_item;
|
|
|
|
typedef struct {
|
|
HWND hwnd, wrapper_hwnd;
|
|
UINT id, dlgid;
|
|
enum ITEMDLG_CCTRL_TYPE type;
|
|
CDCONTROLSTATEF cdcstate;
|
|
struct list entry;
|
|
|
|
struct list sub_cctrls;
|
|
struct list sub_cctrls_entry;
|
|
struct list sub_items;
|
|
} customctrl;
|
|
|
|
typedef struct {
|
|
struct list entry;
|
|
IFileDialogEvents *pfde;
|
|
DWORD cookie;
|
|
} events_client;
|
|
|
|
typedef struct FileDialogImpl {
|
|
IFileDialog2 IFileDialog2_iface;
|
|
union {
|
|
IFileOpenDialog IFileOpenDialog_iface;
|
|
IFileSaveDialog IFileSaveDialog_iface;
|
|
} u;
|
|
enum ITEMDLG_TYPE dlg_type;
|
|
IExplorerBrowserEvents IExplorerBrowserEvents_iface;
|
|
IServiceProvider IServiceProvider_iface;
|
|
ICommDlgBrowser3 ICommDlgBrowser3_iface;
|
|
IOleWindow IOleWindow_iface;
|
|
IFileDialogCustomize IFileDialogCustomize_iface;
|
|
LONG ref;
|
|
|
|
FILEOPENDIALOGOPTIONS options;
|
|
COMDLG_FILTERSPEC *filterspecs;
|
|
UINT filterspec_count;
|
|
UINT filetypeindex;
|
|
|
|
struct list events_clients;
|
|
DWORD events_next_cookie;
|
|
|
|
IShellItemArray *psia_selection;
|
|
IShellItemArray *psia_results;
|
|
IShellItem *psi_defaultfolder;
|
|
IShellItem *psi_setfolder;
|
|
IShellItem *psi_folder;
|
|
|
|
HWND dlg_hwnd;
|
|
IExplorerBrowser *peb;
|
|
DWORD ebevents_cookie;
|
|
|
|
LPWSTR set_filename;
|
|
LPWSTR default_ext;
|
|
LPWSTR custom_title;
|
|
LPWSTR custom_okbutton;
|
|
LPWSTR custom_cancelbutton;
|
|
LPWSTR custom_filenamelabel;
|
|
|
|
UINT cctrl_width, cctrl_def_height, cctrls_cols;
|
|
UINT cctrl_indent, dpi_x, dpi_y;
|
|
HWND cctrls_hwnd;
|
|
struct list cctrls;
|
|
UINT_PTR cctrl_next_dlgid;
|
|
customctrl *cctrl_active_vg;
|
|
|
|
HMENU hmenu_opendropdown;
|
|
customctrl cctrl_opendropdown;
|
|
HFONT hfont_opendropdown;
|
|
BOOL opendropdown_has_selection;
|
|
DWORD opendropdown_selection;
|
|
|
|
GUID client_guid;
|
|
} FileDialogImpl;
|
|
|
|
/**************************************************************************
|
|
* Event wrappers.
|
|
*/
|
|
static HRESULT events_OnFileOk(FileDialogImpl *This)
|
|
{
|
|
events_client *cursor;
|
|
HRESULT hr = S_OK;
|
|
TRACE("%p\n", This);
|
|
|
|
LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
|
|
{
|
|
TRACE("Notifying %p\n", cursor);
|
|
hr = IFileDialogEvents_OnFileOk(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
|
|
if(FAILED(hr) && hr != E_NOTIMPL)
|
|
break;
|
|
}
|
|
|
|
if(hr == E_NOTIMPL)
|
|
hr = S_OK;
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT events_OnFolderChanging(FileDialogImpl *This, IShellItem *folder)
|
|
{
|
|
events_client *cursor;
|
|
HRESULT hr = S_OK;
|
|
TRACE("%p (%p)\n", This, folder);
|
|
|
|
LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
|
|
{
|
|
TRACE("Notifying %p\n", cursor);
|
|
hr = IFileDialogEvents_OnFolderChanging(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface, folder);
|
|
if(FAILED(hr) && hr != E_NOTIMPL)
|
|
break;
|
|
}
|
|
|
|
if(hr == E_NOTIMPL)
|
|
hr = S_OK;
|
|
|
|
return hr;
|
|
}
|
|
|
|
static void events_OnFolderChange(FileDialogImpl *This)
|
|
{
|
|
events_client *cursor;
|
|
TRACE("%p\n", This);
|
|
|
|
LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
|
|
{
|
|
TRACE("Notifying %p\n", cursor);
|
|
IFileDialogEvents_OnFolderChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
|
|
}
|
|
}
|
|
|
|
static void events_OnSelectionChange(FileDialogImpl *This)
|
|
{
|
|
events_client *cursor;
|
|
TRACE("%p\n", This);
|
|
|
|
LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
|
|
{
|
|
TRACE("Notifying %p\n", cursor);
|
|
IFileDialogEvents_OnSelectionChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
|
|
}
|
|
}
|
|
|
|
static void events_OnTypeChange(FileDialogImpl *This)
|
|
{
|
|
events_client *cursor;
|
|
TRACE("%p\n", This);
|
|
|
|
LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
|
|
{
|
|
TRACE("Notifying %p\n", cursor);
|
|
IFileDialogEvents_OnTypeChange(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface);
|
|
}
|
|
}
|
|
|
|
static HRESULT events_OnOverwrite(FileDialogImpl *This, IShellItem *shellitem)
|
|
{
|
|
events_client *cursor;
|
|
HRESULT hr = S_OK;
|
|
FDE_OVERWRITE_RESPONSE response = FDEOR_DEFAULT;
|
|
TRACE("%p %p\n", This, shellitem);
|
|
|
|
LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
|
|
{
|
|
TRACE("Notifying %p\n", cursor);
|
|
hr = IFileDialogEvents_OnOverwrite(cursor->pfde, (IFileDialog*)&This->IFileDialog2_iface, shellitem, &response);
|
|
TRACE("<-- hr=%x response=%u\n", hr, response);
|
|
if(FAILED(hr) && hr != E_NOTIMPL)
|
|
break;
|
|
}
|
|
|
|
if(hr == E_NOTIMPL)
|
|
hr = S_OK;
|
|
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
if (response == FDEOR_DEFAULT)
|
|
{
|
|
WCHAR buf[100];
|
|
int answer;
|
|
|
|
LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, buf, 100);
|
|
answer = MessageBoxW(This->dlg_hwnd, buf, This->custom_title,
|
|
MB_YESNO | MB_ICONEXCLAMATION);
|
|
if (answer == IDNO || answer == IDCANCEL)
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
else if (response == FDEOR_REFUSE)
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
static inline HRESULT get_cctrl_event(IFileDialogEvents *pfde, IFileDialogControlEvents **pfdce)
|
|
{
|
|
return IFileDialogEvents_QueryInterface(pfde, &IID_IFileDialogControlEvents, (void**)pfdce);
|
|
}
|
|
|
|
static HRESULT cctrl_event_OnButtonClicked(FileDialogImpl *This, DWORD ctl_id)
|
|
{
|
|
events_client *cursor;
|
|
TRACE("%p\n", This);
|
|
|
|
LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
|
|
{
|
|
IFileDialogControlEvents *pfdce;
|
|
if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
|
|
{
|
|
TRACE("Notifying %p\n", cursor);
|
|
IFileDialogControlEvents_OnButtonClicked(pfdce, &This->IFileDialogCustomize_iface, ctl_id);
|
|
IFileDialogControlEvents_Release(pfdce);
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT cctrl_event_OnItemSelected(FileDialogImpl *This, DWORD ctl_id, DWORD item_id)
|
|
{
|
|
events_client *cursor;
|
|
TRACE("%p %i %i\n", This, ctl_id, item_id);
|
|
|
|
LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
|
|
{
|
|
IFileDialogControlEvents *pfdce;
|
|
if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
|
|
{
|
|
TRACE("Notifying %p\n", cursor);
|
|
IFileDialogControlEvents_OnItemSelected(pfdce, &This->IFileDialogCustomize_iface, ctl_id, item_id);
|
|
IFileDialogControlEvents_Release(pfdce);
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT cctrl_event_OnCheckButtonToggled(FileDialogImpl *This, DWORD ctl_id, BOOL checked)
|
|
{
|
|
events_client *cursor;
|
|
TRACE("%p\n", This);
|
|
|
|
LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
|
|
{
|
|
IFileDialogControlEvents *pfdce;
|
|
if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
|
|
{
|
|
TRACE("Notifying %p\n", cursor);
|
|
IFileDialogControlEvents_OnCheckButtonToggled(pfdce, &This->IFileDialogCustomize_iface, ctl_id, checked);
|
|
IFileDialogControlEvents_Release(pfdce);
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT cctrl_event_OnControlActivating(FileDialogImpl *This,
|
|
DWORD ctl_id)
|
|
{
|
|
events_client *cursor;
|
|
TRACE("%p\n", This);
|
|
|
|
LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
|
|
{
|
|
IFileDialogControlEvents *pfdce;
|
|
if(SUCCEEDED(get_cctrl_event(cursor->pfde, &pfdce)))
|
|
{
|
|
TRACE("Notifying %p\n", cursor);
|
|
IFileDialogControlEvents_OnControlActivating(pfdce, &This->IFileDialogCustomize_iface, ctl_id);
|
|
IFileDialogControlEvents_Release(pfdce);
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Helper functions.
|
|
*/
|
|
static UINT get_file_name(FileDialogImpl *This, LPWSTR *str)
|
|
{
|
|
HWND hwnd_edit = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
|
|
UINT len;
|
|
|
|
if(!hwnd_edit)
|
|
{
|
|
if(This->set_filename)
|
|
{
|
|
len = lstrlenW(This->set_filename);
|
|
*str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
|
|
lstrcpyW(*str, This->set_filename);
|
|
return len;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
len = SendMessageW(hwnd_edit, WM_GETTEXTLENGTH, 0, 0);
|
|
*str = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
|
|
if(!*str)
|
|
return 0;
|
|
|
|
SendMessageW(hwnd_edit, WM_GETTEXT, len+1, (LPARAM)*str);
|
|
return len;
|
|
}
|
|
|
|
static BOOL set_file_name(FileDialogImpl *This, LPCWSTR str)
|
|
{
|
|
if(This->set_filename)
|
|
LocalFree(This->set_filename);
|
|
|
|
This->set_filename = str ? StrDupW(str) : NULL;
|
|
|
|
return SetDlgItemTextW(This->dlg_hwnd, IDC_FILENAME, This->set_filename);
|
|
}
|
|
|
|
static void fill_filename_from_selection(FileDialogImpl *This)
|
|
{
|
|
IShellItem *psi;
|
|
LPWSTR *names;
|
|
HRESULT hr;
|
|
UINT item_count, valid_count;
|
|
UINT len_total, i;
|
|
|
|
if(!This->psia_selection)
|
|
return;
|
|
|
|
hr = IShellItemArray_GetCount(This->psia_selection, &item_count);
|
|
if(FAILED(hr) || !item_count)
|
|
return;
|
|
|
|
names = HeapAlloc(GetProcessHeap(), 0, item_count*sizeof(LPWSTR));
|
|
|
|
/* Get names of the selected items */
|
|
valid_count = 0; len_total = 0;
|
|
for(i = 0; i < item_count; i++)
|
|
{
|
|
hr = IShellItemArray_GetItemAt(This->psia_selection, i, &psi);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
UINT attr;
|
|
|
|
hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &attr);
|
|
if(SUCCEEDED(hr) &&
|
|
(( (This->options & FOS_PICKFOLDERS) && !(attr & SFGAO_FOLDER)) ||
|
|
(!(This->options & FOS_PICKFOLDERS) && (attr & SFGAO_FOLDER))))
|
|
continue;
|
|
|
|
hr = IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &names[valid_count]);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
len_total += lstrlenW(names[valid_count]) + 3;
|
|
valid_count++;
|
|
}
|
|
IShellItem_Release(psi);
|
|
}
|
|
}
|
|
|
|
if(valid_count == 1)
|
|
{
|
|
set_file_name(This, names[0]);
|
|
CoTaskMemFree(names[0]);
|
|
}
|
|
else if(valid_count > 1)
|
|
{
|
|
LPWSTR string = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len_total);
|
|
LPWSTR cur_point = string;
|
|
|
|
for(i = 0; i < valid_count; i++)
|
|
{
|
|
LPWSTR file = names[i];
|
|
*cur_point++ = '\"';
|
|
lstrcpyW(cur_point, file);
|
|
cur_point += lstrlenW(file);
|
|
*cur_point++ = '\"';
|
|
*cur_point++ = ' ';
|
|
CoTaskMemFree(file);
|
|
}
|
|
*(cur_point-1) = '\0';
|
|
|
|
set_file_name(This, string);
|
|
HeapFree(GetProcessHeap(), 0, string);
|
|
}
|
|
|
|
HeapFree(GetProcessHeap(), 0, names);
|
|
return;
|
|
}
|
|
|
|
static LPWSTR get_first_ext_from_spec(LPWSTR buf, LPCWSTR spec)
|
|
{
|
|
WCHAR *endpos, *ext;
|
|
|
|
lstrcpyW(buf, spec);
|
|
if( (endpos = StrChrW(buf, ';')) )
|
|
*endpos = '\0';
|
|
|
|
ext = PathFindExtensionW(buf);
|
|
if(StrChrW(ext, '*'))
|
|
return NULL;
|
|
|
|
return ext;
|
|
}
|
|
|
|
static BOOL shell_item_exists(IShellItem* shellitem)
|
|
{
|
|
LPWSTR filename;
|
|
HRESULT hr;
|
|
BOOL result;
|
|
|
|
hr = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &filename);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
/* FIXME: Implement SFGAO_VALIDATE in Wine and use it instead. */
|
|
result = (GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES);
|
|
CoTaskMemFree(filename);
|
|
}
|
|
else
|
|
{
|
|
SFGAOF attributes;
|
|
result = SUCCEEDED(IShellItem_GetAttributes(shellitem, SFGAO_VALIDATE, &attributes));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static HRESULT on_default_action(FileDialogImpl *This)
|
|
{
|
|
IShellFolder *psf_parent, *psf_desktop;
|
|
LPITEMIDLIST *pidla;
|
|
LPITEMIDLIST current_folder;
|
|
LPWSTR fn_iter, files = NULL, tmp_files;
|
|
UINT file_count = 0, len, i;
|
|
int open_action;
|
|
HRESULT hr, ret = E_FAIL;
|
|
|
|
len = get_file_name(This, &tmp_files);
|
|
if(len)
|
|
{
|
|
UINT size_used;
|
|
file_count = COMDLG32_SplitFileNames(tmp_files, len, &files, &size_used);
|
|
CoTaskMemFree(tmp_files);
|
|
}
|
|
if(!file_count) return E_FAIL;
|
|
|
|
hr = SHGetIDListFromObject((IUnknown*)This->psi_folder, ¤t_folder);
|
|
if(FAILED(hr))
|
|
{
|
|
ERR("Failed to get pidl for current directory.\n");
|
|
HeapFree(GetProcessHeap(), 0, files);
|
|
return hr;
|
|
}
|
|
|
|
TRACE("Acting on %d file(s).\n", file_count);
|
|
|
|
pidla = HeapAlloc(GetProcessHeap(), 0, sizeof(LPITEMIDLIST) * file_count);
|
|
open_action = ONOPEN_OPEN;
|
|
fn_iter = files;
|
|
|
|
for(i = 0; i < file_count && open_action == ONOPEN_OPEN; i++)
|
|
{
|
|
WCHAR canon_filename[MAX_PATH];
|
|
psf_parent = NULL;
|
|
|
|
COMDLG32_GetCanonicalPath(current_folder, fn_iter, canon_filename);
|
|
|
|
if( (This->options & FOS_NOVALIDATE) &&
|
|
!(This->options & FOS_FILEMUSTEXIST) )
|
|
open_action = ONOPEN_OPEN;
|
|
else
|
|
open_action = ONOPEN_BROWSE;
|
|
|
|
open_action = FILEDLG95_ValidatePathAction(canon_filename, &psf_parent, This->dlg_hwnd,
|
|
This->options & ~FOS_FILEMUSTEXIST,
|
|
(This->dlg_type == ITEMDLG_TYPE_SAVE),
|
|
open_action);
|
|
|
|
/* Add the proper extension */
|
|
if(open_action == ONOPEN_OPEN)
|
|
{
|
|
static const WCHAR dotW[] = {'.',0};
|
|
|
|
if(This->dlg_type == ITEMDLG_TYPE_SAVE)
|
|
{
|
|
WCHAR extbuf[MAX_PATH], *newext = NULL;
|
|
|
|
if(This->filterspec_count)
|
|
{
|
|
newext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
|
|
}
|
|
else if(This->default_ext)
|
|
{
|
|
lstrcpyW(extbuf, dotW);
|
|
lstrcatW(extbuf, This->default_ext);
|
|
newext = extbuf;
|
|
}
|
|
|
|
if(newext)
|
|
{
|
|
WCHAR *ext = PathFindExtensionW(canon_filename);
|
|
if(lstrcmpW(ext, newext))
|
|
lstrcatW(canon_filename, newext);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( !(This->options & FOS_NOVALIDATE) && (This->options & FOS_FILEMUSTEXIST) &&
|
|
!PathFileExistsW(canon_filename))
|
|
{
|
|
if(This->default_ext)
|
|
{
|
|
lstrcatW(canon_filename, dotW);
|
|
lstrcatW(canon_filename, This->default_ext);
|
|
|
|
if(!PathFileExistsW(canon_filename))
|
|
{
|
|
FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
|
|
open_action = ONOPEN_BROWSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FILEDLG95_OnOpenMessage(This->dlg_hwnd, 0, IDS_FILENOTEXISTING);
|
|
open_action = ONOPEN_BROWSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pidla[i] = COMDLG32_SHSimpleIDListFromPathAW(canon_filename);
|
|
|
|
if(psf_parent && !(open_action == ONOPEN_BROWSE))
|
|
IShellFolder_Release(psf_parent);
|
|
|
|
fn_iter += (WCHAR)lstrlenW(fn_iter) + 1;
|
|
}
|
|
|
|
HeapFree(GetProcessHeap(), 0, files);
|
|
ILFree(current_folder);
|
|
|
|
if((This->options & FOS_PICKFOLDERS) && open_action == ONOPEN_BROWSE)
|
|
open_action = ONOPEN_OPEN; /* FIXME: Multiple folders? */
|
|
|
|
switch(open_action)
|
|
{
|
|
case ONOPEN_SEARCH:
|
|
FIXME("Filtering not implemented.\n");
|
|
break;
|
|
|
|
case ONOPEN_BROWSE:
|
|
hr = IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psf_parent, SBSP_DEFBROWSER);
|
|
if(FAILED(hr))
|
|
ERR("Failed to browse to directory: %08x\n", hr);
|
|
|
|
IShellFolder_Release(psf_parent);
|
|
break;
|
|
|
|
case ONOPEN_OPEN:
|
|
hr = SHGetDesktopFolder(&psf_desktop);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
if(This->psia_results)
|
|
{
|
|
IShellItemArray_Release(This->psia_results);
|
|
This->psia_results = NULL;
|
|
}
|
|
|
|
hr = SHCreateShellItemArray(NULL, psf_desktop, file_count, (PCUITEMID_CHILD_ARRAY)pidla,
|
|
&This->psia_results);
|
|
|
|
IShellFolder_Release(psf_desktop);
|
|
|
|
if(FAILED(hr))
|
|
break;
|
|
|
|
if(This->options & FOS_PICKFOLDERS)
|
|
{
|
|
SFGAOF attributes;
|
|
hr = IShellItemArray_GetAttributes(This->psia_results, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attributes);
|
|
if(hr != S_OK)
|
|
{
|
|
WCHAR buf[64];
|
|
LoadStringW(COMDLG32_hInstance, IDS_INVALID_FOLDERNAME, buf, ARRAY_SIZE(buf));
|
|
|
|
MessageBoxW(This->dlg_hwnd, buf, This->custom_title, MB_OK | MB_ICONEXCLAMATION);
|
|
|
|
IShellItemArray_Release(This->psia_results);
|
|
This->psia_results = NULL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if((This->options & FOS_OVERWRITEPROMPT) && This->dlg_type == ITEMDLG_TYPE_SAVE)
|
|
{
|
|
IShellItem *shellitem;
|
|
|
|
for (i=0; SUCCEEDED(hr) && i<file_count; i++)
|
|
{
|
|
hr = IShellItemArray_GetItemAt(This->psia_results, i, &shellitem);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (shell_item_exists(shellitem))
|
|
hr = events_OnOverwrite(This, shellitem);
|
|
|
|
IShellItem_Release(shellitem);
|
|
}
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
break;
|
|
}
|
|
|
|
if(events_OnFileOk(This) == S_OK)
|
|
ret = S_OK;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ERR("Failed.\n");
|
|
break;
|
|
}
|
|
|
|
/* Clean up */
|
|
for(i = 0; i < file_count; i++)
|
|
ILFree(pidla[i]);
|
|
HeapFree(GetProcessHeap(), 0, pidla);
|
|
|
|
/* Success closes the dialog */
|
|
return ret;
|
|
}
|
|
|
|
static void show_opendropdown(FileDialogImpl *This)
|
|
{
|
|
HWND open_hwnd;
|
|
RECT open_rc;
|
|
MSG msg;
|
|
|
|
open_hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
|
|
|
|
GetWindowRect(open_hwnd, &open_rc);
|
|
|
|
if (TrackPopupMenu(This->hmenu_opendropdown, 0, open_rc.left, open_rc.bottom, 0, This->dlg_hwnd, NULL) &&
|
|
PeekMessageW(&msg, This->dlg_hwnd, WM_MENUCOMMAND, WM_MENUCOMMAND, PM_REMOVE))
|
|
{
|
|
MENUITEMINFOW mii;
|
|
|
|
This->opendropdown_has_selection = TRUE;
|
|
|
|
mii.cbSize = sizeof(mii);
|
|
mii.fMask = MIIM_ID;
|
|
GetMenuItemInfoW((HMENU)msg.lParam, msg.wParam, TRUE, &mii);
|
|
This->opendropdown_selection = mii.wID;
|
|
|
|
if(SUCCEEDED(on_default_action(This)))
|
|
EndDialog(This->dlg_hwnd, S_OK);
|
|
else
|
|
This->opendropdown_has_selection = FALSE;
|
|
}
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Control item functions.
|
|
*/
|
|
|
|
static void item_free(cctrl_item *item)
|
|
{
|
|
DestroyWindow(item->hwnd);
|
|
HeapFree(GetProcessHeap(), 0, item->label);
|
|
HeapFree(GetProcessHeap(), 0, item);
|
|
}
|
|
|
|
static cctrl_item* get_item(customctrl* parent, DWORD itemid, CDCONTROLSTATEF visible_flags, DWORD* position)
|
|
{
|
|
DWORD dummy;
|
|
cctrl_item* item;
|
|
|
|
if (!position) position = &dummy;
|
|
|
|
*position = 0;
|
|
|
|
LIST_FOR_EACH_ENTRY(item, &parent->sub_items, cctrl_item, entry)
|
|
{
|
|
if (item->id == itemid)
|
|
return item;
|
|
|
|
if ((item->cdcstate & visible_flags) == visible_flags)
|
|
(*position)++;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static cctrl_item* get_first_item(customctrl* parent)
|
|
{
|
|
cctrl_item* item;
|
|
|
|
LIST_FOR_EACH_ENTRY(item, &parent->sub_items, cctrl_item, entry)
|
|
{
|
|
if ((item->cdcstate & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED))
|
|
return item;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static HRESULT add_item(customctrl* parent, DWORD itemid, LPCWSTR label, cctrl_item** result)
|
|
{
|
|
cctrl_item* item;
|
|
LPWSTR label_copy;
|
|
|
|
if (get_item(parent, itemid, 0, NULL))
|
|
return E_INVALIDARG;
|
|
|
|
item = HeapAlloc(GetProcessHeap(), 0, sizeof(*item));
|
|
label_copy = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(label)+1)*sizeof(WCHAR));
|
|
|
|
if (!item || !label_copy)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, item);
|
|
HeapFree(GetProcessHeap(), 0, label_copy);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
item->id = itemid;
|
|
item->parent_id = parent->id;
|
|
lstrcpyW(label_copy, label);
|
|
item->label = label_copy;
|
|
item->cdcstate = CDCS_VISIBLE|CDCS_ENABLED;
|
|
item->hwnd = NULL;
|
|
list_add_tail(&parent->sub_items, &item->entry);
|
|
|
|
*result = item;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Control functions.
|
|
*/
|
|
static inline customctrl *get_cctrl_from_dlgid(FileDialogImpl *This, DWORD dlgid)
|
|
{
|
|
customctrl *ctrl, *sub_ctrl;
|
|
|
|
LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
|
|
{
|
|
if(ctrl->dlgid == dlgid)
|
|
return ctrl;
|
|
|
|
LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
|
|
if(sub_ctrl->dlgid == dlgid)
|
|
return sub_ctrl;
|
|
}
|
|
|
|
ERR("Failed to find control with dialog id %d\n", dlgid);
|
|
return NULL;
|
|
}
|
|
|
|
static inline customctrl *get_cctrl(FileDialogImpl *This, DWORD ctlid)
|
|
{
|
|
customctrl *ctrl, *sub_ctrl;
|
|
|
|
LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
|
|
{
|
|
if(ctrl->id == ctlid)
|
|
return ctrl;
|
|
|
|
LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
|
|
if(sub_ctrl->id == ctlid)
|
|
return sub_ctrl;
|
|
}
|
|
|
|
if (This->hmenu_opendropdown && This->cctrl_opendropdown.id == ctlid)
|
|
return &This->cctrl_opendropdown;
|
|
|
|
TRACE("No existing control with control id %d\n", ctlid);
|
|
return NULL;
|
|
}
|
|
|
|
static void ctrl_resize(HWND hctrl, UINT min_width, UINT max_width, BOOL multiline)
|
|
{
|
|
LPWSTR text;
|
|
UINT len, final_width;
|
|
UINT lines, final_height;
|
|
SIZE size;
|
|
RECT rc;
|
|
HDC hdc;
|
|
WCHAR *c;
|
|
HFONT font;
|
|
|
|
TRACE("\n");
|
|
|
|
len = SendMessageW(hctrl, WM_GETTEXTLENGTH, 0, 0);
|
|
text = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*(len+1));
|
|
if(!text) return;
|
|
SendMessageW(hctrl, WM_GETTEXT, len+1, (LPARAM)text);
|
|
|
|
hdc = GetDC(hctrl);
|
|
font = (HFONT)SendMessageW(hctrl, WM_GETFONT, 0, 0);
|
|
font = SelectObject(hdc, font);
|
|
GetTextExtentPoint32W(hdc, text, lstrlenW(text), &size);
|
|
SelectObject(hdc, font);
|
|
ReleaseDC(hctrl, hdc);
|
|
|
|
if(len && multiline)
|
|
{
|
|
/* FIXME: line-wrap */
|
|
for(lines = 1, c = text; *c != '\0'; c++)
|
|
if(*c == '\n') lines++;
|
|
|
|
final_height = size.cy*lines + 2*4;
|
|
}
|
|
else
|
|
{
|
|
GetWindowRect(hctrl, &rc);
|
|
final_height = rc.bottom - rc.top;
|
|
}
|
|
|
|
final_width = min(max(size.cx, min_width) + 4, max_width);
|
|
SetWindowPos(hctrl, NULL, 0, 0, final_width, final_height,
|
|
SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
|
|
|
|
HeapFree(GetProcessHeap(), 0, text);
|
|
}
|
|
|
|
static UINT ctrl_get_height(customctrl *ctrl) {
|
|
RECT rc;
|
|
GetWindowRect(ctrl->wrapper_hwnd, &rc);
|
|
return rc.bottom - rc.top;
|
|
}
|
|
|
|
static void ctrl_free(customctrl *ctrl)
|
|
{
|
|
customctrl *sub_cur1, *sub_cur2;
|
|
cctrl_item *item_cur1, *item_cur2;
|
|
|
|
TRACE("Freeing control %p\n", ctrl);
|
|
if(ctrl->type == IDLG_CCTRL_MENU)
|
|
{
|
|
TBBUTTON tbb;
|
|
SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
|
|
DestroyMenu((HMENU)tbb.dwData);
|
|
}
|
|
|
|
LIST_FOR_EACH_ENTRY_SAFE(sub_cur1, sub_cur2, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
|
|
{
|
|
list_remove(&sub_cur1->sub_cctrls_entry);
|
|
ctrl_free(sub_cur1);
|
|
}
|
|
|
|
LIST_FOR_EACH_ENTRY_SAFE(item_cur1, item_cur2, &ctrl->sub_items, cctrl_item, entry)
|
|
{
|
|
list_remove(&item_cur1->entry);
|
|
item_free(item_cur1);
|
|
}
|
|
|
|
DestroyWindow(ctrl->hwnd);
|
|
HeapFree(GetProcessHeap(), 0, ctrl);
|
|
}
|
|
|
|
static void customctrl_resize(FileDialogImpl *This, customctrl *ctrl)
|
|
{
|
|
RECT rc;
|
|
UINT total_height;
|
|
UINT max_width, size;
|
|
customctrl *sub_ctrl;
|
|
|
|
switch(ctrl->type)
|
|
{
|
|
case IDLG_CCTRL_PUSHBUTTON:
|
|
case IDLG_CCTRL_COMBOBOX:
|
|
case IDLG_CCTRL_CHECKBUTTON:
|
|
case IDLG_CCTRL_TEXT:
|
|
size = MulDiv(160, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
|
|
ctrl_resize(ctrl->hwnd, size, size, TRUE);
|
|
GetWindowRect(ctrl->hwnd, &rc);
|
|
SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
|
|
SWP_NOZORDER|SWP_NOMOVE);
|
|
break;
|
|
case IDLG_CCTRL_VISUALGROUP:
|
|
total_height = 0;
|
|
ctrl_resize(ctrl->hwnd, 0, This->cctrl_indent, TRUE);
|
|
|
|
LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
|
|
{
|
|
customctrl_resize(This, sub_ctrl);
|
|
SetWindowPos(sub_ctrl->wrapper_hwnd, NULL, This->cctrl_indent, total_height, 0, 0,
|
|
SWP_NOZORDER|SWP_NOSIZE);
|
|
|
|
total_height += ctrl_get_height(sub_ctrl);
|
|
}
|
|
|
|
/* The label should be right adjusted */
|
|
{
|
|
UINT width, height;
|
|
|
|
GetWindowRect(ctrl->hwnd, &rc);
|
|
width = rc.right - rc.left;
|
|
height = rc.bottom - rc.top;
|
|
|
|
SetWindowPos(ctrl->hwnd, NULL, This->cctrl_indent - width, 0, width, height, SWP_NOZORDER);
|
|
}
|
|
|
|
/* Resize the wrapper window to fit all the sub controls */
|
|
SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, This->cctrl_width + This->cctrl_indent, total_height,
|
|
SWP_NOZORDER|SWP_NOMOVE);
|
|
break;
|
|
case IDLG_CCTRL_RADIOBUTTONLIST:
|
|
{
|
|
cctrl_item* item;
|
|
|
|
total_height = 0;
|
|
max_width = 0;
|
|
|
|
LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
|
|
{
|
|
size = MulDiv(160, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
|
|
ctrl_resize(item->hwnd, size, size, TRUE);
|
|
SetWindowPos(item->hwnd, NULL, 0, total_height, 0, 0,
|
|
SWP_NOZORDER|SWP_NOSIZE);
|
|
|
|
GetWindowRect(item->hwnd, &rc);
|
|
|
|
total_height += rc.bottom - rc.top;
|
|
max_width = max(rc.right - rc.left, max_width);
|
|
}
|
|
|
|
SetWindowPos(ctrl->hwnd, NULL, 0, 0, max_width, total_height,
|
|
SWP_NOZORDER|SWP_NOMOVE);
|
|
|
|
SetWindowPos(ctrl->wrapper_hwnd, NULL, 0, 0, max_width, total_height,
|
|
SWP_NOZORDER|SWP_NOMOVE);
|
|
|
|
break;
|
|
}
|
|
case IDLG_CCTRL_EDITBOX:
|
|
case IDLG_CCTRL_SEPARATOR:
|
|
case IDLG_CCTRL_MENU:
|
|
case IDLG_CCTRL_OPENDROPDOWN:
|
|
/* Nothing */
|
|
break;
|
|
}
|
|
}
|
|
|
|
static LRESULT notifysink_on_create(HWND hwnd, CREATESTRUCTW *crs)
|
|
{
|
|
FileDialogImpl *This = crs->lpCreateParams;
|
|
TRACE("%p\n", This);
|
|
|
|
SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
|
|
return TRUE;
|
|
}
|
|
|
|
static LRESULT notifysink_on_bn_clicked(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
|
|
{
|
|
customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
|
|
|
|
TRACE("%p, %lx\n", This, wparam);
|
|
|
|
if(ctrl)
|
|
{
|
|
if(ctrl->type == IDLG_CCTRL_CHECKBUTTON)
|
|
{
|
|
BOOL checked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
|
|
cctrl_event_OnCheckButtonToggled(This, ctrl->id, checked);
|
|
}
|
|
else
|
|
cctrl_event_OnButtonClicked(This, ctrl->id);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static LRESULT notifysink_on_cbn_selchange(FileDialogImpl *This, HWND hwnd, WPARAM wparam)
|
|
{
|
|
customctrl *ctrl = get_cctrl_from_dlgid(This, LOWORD(wparam));
|
|
TRACE("%p, %p (%lx)\n", This, ctrl, wparam);
|
|
|
|
if(ctrl)
|
|
{
|
|
UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
|
|
UINT selid = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
|
|
|
|
cctrl_event_OnItemSelected(This, ctrl->id, selid);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static LRESULT notifysink_on_tvn_dropdown(FileDialogImpl *This, LPARAM lparam)
|
|
{
|
|
NMTOOLBARW *nmtb = (NMTOOLBARW*)lparam;
|
|
customctrl *ctrl = get_cctrl_from_dlgid(This, GetDlgCtrlID(nmtb->hdr.hwndFrom));
|
|
POINT pt = { 0, nmtb->rcButton.bottom };
|
|
TBBUTTON tbb;
|
|
UINT idcmd;
|
|
|
|
TRACE("%p, %p (%lx)\n", This, ctrl, lparam);
|
|
|
|
if(ctrl)
|
|
{
|
|
cctrl_event_OnControlActivating(This,ctrl->id);
|
|
|
|
SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
|
|
ClientToScreen(ctrl->hwnd, &pt);
|
|
idcmd = TrackPopupMenu((HMENU)tbb.dwData, TPM_RETURNCMD, pt.x, pt.y, 0, This->dlg_hwnd, NULL);
|
|
if(idcmd)
|
|
cctrl_event_OnItemSelected(This, ctrl->id, idcmd);
|
|
}
|
|
|
|
return TBDDRET_DEFAULT;
|
|
}
|
|
|
|
static LRESULT notifysink_on_wm_command(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
|
|
{
|
|
switch(HIWORD(wparam))
|
|
{
|
|
case BN_CLICKED: return notifysink_on_bn_clicked(This, hwnd, wparam);
|
|
case CBN_SELCHANGE: return notifysink_on_cbn_selchange(This, hwnd, wparam);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static LRESULT notifysink_on_wm_notify(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
|
|
{
|
|
NMHDR *nmhdr = (NMHDR*)lparam;
|
|
|
|
switch(nmhdr->code)
|
|
{
|
|
case TBN_DROPDOWN: return notifysink_on_tvn_dropdown(This, lparam);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static LRESULT CALLBACK notifysink_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
|
|
{
|
|
FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
|
|
customctrl *ctrl;
|
|
HWND hwnd_child;
|
|
RECT rc;
|
|
|
|
switch(message)
|
|
{
|
|
case WM_NCCREATE: return notifysink_on_create(hwnd, (CREATESTRUCTW*)lparam);
|
|
case WM_COMMAND: return notifysink_on_wm_command(This, hwnd, wparam, lparam);
|
|
case WM_NOTIFY: return notifysink_on_wm_notify(This, hwnd, wparam, lparam);
|
|
case WM_SIZE:
|
|
hwnd_child = GetPropW(hwnd, notifysink_childW);
|
|
ctrl = (customctrl*)GetWindowLongPtrW(hwnd_child, GWLP_USERDATA);
|
|
if(ctrl && ctrl->type != IDLG_CCTRL_VISUALGROUP)
|
|
{
|
|
GetClientRect(hwnd, &rc);
|
|
SetWindowPos(hwnd_child, NULL, 0, 0, rc.right, rc.bottom, SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
return DefWindowProcW(hwnd, message, wparam, lparam);
|
|
}
|
|
|
|
static HRESULT cctrl_create_new(FileDialogImpl *This, DWORD id,
|
|
LPCWSTR text, LPCWSTR wndclass, DWORD ctrl_wsflags,
|
|
DWORD ctrl_exflags, UINT height, customctrl **ppctrl)
|
|
{
|
|
HWND ns_hwnd, control_hwnd, parent_hwnd;
|
|
DWORD wsflags = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS;
|
|
customctrl *ctrl;
|
|
|
|
if(get_cctrl(This, id))
|
|
return E_UNEXPECTED; /* Duplicate id */
|
|
|
|
if(This->cctrl_active_vg)
|
|
parent_hwnd = This->cctrl_active_vg->wrapper_hwnd;
|
|
else
|
|
parent_hwnd = This->cctrls_hwnd;
|
|
|
|
ns_hwnd = CreateWindowExW(0, floatnotifysinkW, NULL, wsflags,
|
|
0, 0, This->cctrl_width, height, parent_hwnd,
|
|
(HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, This);
|
|
control_hwnd = CreateWindowExW(ctrl_exflags, wndclass, text, wsflags | ctrl_wsflags,
|
|
0, 0, This->cctrl_width, height, ns_hwnd,
|
|
(HMENU)This->cctrl_next_dlgid, COMDLG32_hInstance, 0);
|
|
|
|
if(!ns_hwnd || !control_hwnd)
|
|
{
|
|
ERR("Failed to create wrapper (%p) or control (%p)\n", ns_hwnd, control_hwnd);
|
|
DestroyWindow(ns_hwnd);
|
|
DestroyWindow(control_hwnd);
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
SetPropW(ns_hwnd, notifysink_childW, control_hwnd);
|
|
|
|
ctrl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(customctrl));
|
|
if(!ctrl)
|
|
return E_OUTOFMEMORY;
|
|
|
|
ctrl->hwnd = control_hwnd;
|
|
ctrl->wrapper_hwnd = ns_hwnd;
|
|
ctrl->id = id;
|
|
ctrl->dlgid = This->cctrl_next_dlgid;
|
|
ctrl->cdcstate = CDCS_ENABLED | CDCS_VISIBLE;
|
|
list_init(&ctrl->sub_cctrls);
|
|
list_init(&ctrl->sub_items);
|
|
|
|
if(This->cctrl_active_vg)
|
|
list_add_tail(&This->cctrl_active_vg->sub_cctrls, &ctrl->sub_cctrls_entry);
|
|
else
|
|
list_add_tail(&This->cctrls, &ctrl->entry);
|
|
|
|
SetWindowLongPtrW(ctrl->hwnd, GWLP_USERDATA, (LPARAM)ctrl);
|
|
|
|
if(ppctrl) *ppctrl = ctrl;
|
|
|
|
This->cctrl_next_dlgid++;
|
|
return S_OK;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Container functions.
|
|
*/
|
|
static UINT ctrl_container_resize(FileDialogImpl *This, UINT container_width)
|
|
{
|
|
UINT container_height;
|
|
UINT column_width;
|
|
UINT nr_of_cols;
|
|
UINT max_control_height, total_height = 0;
|
|
UINT cur_col_pos, cur_row_pos;
|
|
customctrl *ctrl;
|
|
BOOL fits_height;
|
|
UINT cspacing = MulDiv(90, This->dpi_x, USER_DEFAULT_SCREEN_DPI); /* Columns are spaced with 90px */
|
|
UINT rspacing = MulDiv(4, This->dpi_y, USER_DEFAULT_SCREEN_DPI); /* Rows are spaced with 4 px. */
|
|
|
|
/* Given the new width of the container, this function determines the
|
|
* needed height of the container and places the controls according to
|
|
* the new layout. Returns the new height.
|
|
*/
|
|
|
|
TRACE("%p\n", This);
|
|
|
|
column_width = This->cctrl_width + cspacing;
|
|
nr_of_cols = (container_width - This->cctrl_indent + cspacing) / column_width;
|
|
|
|
/* We don't need to do anything unless the number of visible columns has changed. */
|
|
if(nr_of_cols == This->cctrls_cols)
|
|
{
|
|
RECT rc;
|
|
GetWindowRect(This->cctrls_hwnd, &rc);
|
|
return rc.bottom - rc.top;
|
|
}
|
|
|
|
This->cctrls_cols = nr_of_cols;
|
|
|
|
/* Get the size of the tallest control, and the total size of
|
|
* all the controls to figure out the number of slots we need.
|
|
*/
|
|
max_control_height = 0;
|
|
LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
|
|
{
|
|
if(ctrl->cdcstate & CDCS_VISIBLE)
|
|
{
|
|
UINT control_height = ctrl_get_height(ctrl);
|
|
max_control_height = max(max_control_height, control_height);
|
|
|
|
total_height += control_height + rspacing;
|
|
}
|
|
}
|
|
|
|
if(!total_height)
|
|
return 0;
|
|
|
|
container_height = max(total_height / nr_of_cols, max_control_height + rspacing);
|
|
TRACE("Guess: container_height: %d\n",container_height);
|
|
|
|
/* Incrementally increase container_height until all the controls
|
|
* fit.
|
|
*/
|
|
do {
|
|
UINT columns_needed = 1;
|
|
cur_row_pos = 0;
|
|
|
|
fits_height = TRUE;
|
|
LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
|
|
{
|
|
if(ctrl->cdcstate & CDCS_VISIBLE)
|
|
{
|
|
UINT control_height = ctrl_get_height(ctrl);
|
|
|
|
if(cur_row_pos + control_height > container_height)
|
|
{
|
|
if(++columns_needed > nr_of_cols)
|
|
{
|
|
container_height += 1;
|
|
fits_height = FALSE;
|
|
break;
|
|
}
|
|
cur_row_pos = 0;
|
|
}
|
|
|
|
cur_row_pos += control_height + rspacing;
|
|
}
|
|
}
|
|
} while(!fits_height);
|
|
|
|
TRACE("Final container height: %d\n", container_height);
|
|
|
|
/* Move the controls to their final destination
|
|
*/
|
|
cur_col_pos = 0, cur_row_pos = 0;
|
|
LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
|
|
{
|
|
if(ctrl->cdcstate & CDCS_VISIBLE)
|
|
{
|
|
RECT rc;
|
|
UINT control_height, control_indent;
|
|
GetWindowRect(ctrl->wrapper_hwnd, &rc);
|
|
control_height = rc.bottom - rc.top;
|
|
|
|
if(cur_row_pos + control_height > container_height)
|
|
{
|
|
cur_row_pos = 0;
|
|
cur_col_pos += This->cctrl_width + cspacing;
|
|
}
|
|
|
|
|
|
if(ctrl->type == IDLG_CCTRL_VISUALGROUP)
|
|
control_indent = 0;
|
|
else
|
|
control_indent = This->cctrl_indent;
|
|
|
|
SetWindowPos(ctrl->wrapper_hwnd, NULL, cur_col_pos + control_indent, cur_row_pos, 0, 0,
|
|
SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
|
|
|
|
cur_row_pos += control_height + rspacing;
|
|
}
|
|
}
|
|
|
|
/* Sanity check */
|
|
if(cur_row_pos + This->cctrl_width > container_width)
|
|
ERR("-- Failed to place controls properly.\n");
|
|
|
|
return container_height;
|
|
}
|
|
|
|
static void ctrl_set_font(customctrl *ctrl, HFONT font)
|
|
{
|
|
customctrl *sub_ctrl;
|
|
cctrl_item* item;
|
|
|
|
SendMessageW(ctrl->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
|
|
|
|
LIST_FOR_EACH_ENTRY(sub_ctrl, &ctrl->sub_cctrls, customctrl, sub_cctrls_entry)
|
|
{
|
|
ctrl_set_font(sub_ctrl, font);
|
|
}
|
|
|
|
if (ctrl->type == IDLG_CCTRL_RADIOBUTTONLIST)
|
|
{
|
|
LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
|
|
{
|
|
SendMessageW(item->hwnd, WM_SETFONT, (WPARAM)font, TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ctrl_container_reparent(FileDialogImpl *This, HWND parent)
|
|
{
|
|
LONG wndstyle;
|
|
|
|
if(parent)
|
|
{
|
|
customctrl *ctrl;
|
|
HFONT font;
|
|
|
|
wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
|
|
wndstyle &= ~(WS_POPUP);
|
|
wndstyle |= WS_CHILD;
|
|
SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
|
|
|
|
SetParent(This->cctrls_hwnd, parent);
|
|
ShowWindow(This->cctrls_hwnd, TRUE);
|
|
|
|
/* Set the fonts to match the dialog font. */
|
|
font = (HFONT)SendMessageW(parent, WM_GETFONT, 0, 0);
|
|
if(!font)
|
|
ERR("Failed to get font handle from dialog.\n");
|
|
|
|
LIST_FOR_EACH_ENTRY(ctrl, &This->cctrls, customctrl, entry)
|
|
{
|
|
if(font) ctrl_set_font(ctrl, font);
|
|
customctrl_resize(This, ctrl);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ShowWindow(This->cctrls_hwnd, FALSE);
|
|
|
|
wndstyle = GetWindowLongW(This->cctrls_hwnd, GWL_STYLE);
|
|
wndstyle &= ~(WS_CHILD);
|
|
wndstyle |= WS_POPUP;
|
|
SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, wndstyle);
|
|
|
|
SetParent(This->cctrls_hwnd, NULL);
|
|
}
|
|
}
|
|
|
|
static LRESULT ctrl_container_on_create(HWND hwnd, CREATESTRUCTW *crs)
|
|
{
|
|
FileDialogImpl *This = crs->lpCreateParams;
|
|
TRACE("%p\n", This);
|
|
|
|
SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
|
|
return TRUE;
|
|
}
|
|
|
|
static LRESULT ctrl_container_on_wm_destroy(FileDialogImpl *This)
|
|
{
|
|
customctrl *cur1, *cur2;
|
|
TRACE("%p\n", This);
|
|
|
|
LIST_FOR_EACH_ENTRY_SAFE(cur1, cur2, &This->cctrls, customctrl, entry)
|
|
{
|
|
list_remove(&cur1->entry);
|
|
ctrl_free(cur1);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static LRESULT CALLBACK ctrl_container_wndproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
|
|
{
|
|
FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
|
|
|
|
switch(umessage)
|
|
{
|
|
case WM_NCCREATE: return ctrl_container_on_create(hwnd, (CREATESTRUCTW*)lparam);
|
|
case WM_DESTROY: return ctrl_container_on_wm_destroy(This);
|
|
default: return DefWindowProcW(hwnd, umessage, wparam, lparam);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void radiobuttonlist_set_selected_item(FileDialogImpl *This, customctrl *ctrl, cctrl_item *item)
|
|
{
|
|
cctrl_item *cursor;
|
|
|
|
LIST_FOR_EACH_ENTRY(cursor, &ctrl->sub_items, cctrl_item, entry)
|
|
{
|
|
SendMessageW(cursor->hwnd, BM_SETCHECK, (cursor == item) ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
}
|
|
}
|
|
|
|
static LRESULT radiobuttonlist_on_bn_clicked(FileDialogImpl *This, HWND hwnd, HWND child)
|
|
{
|
|
DWORD ctrl_id = (DWORD)GetWindowLongPtrW(hwnd, GWLP_ID);
|
|
customctrl *ctrl;
|
|
cctrl_item *item;
|
|
BOOL found_item=FALSE;
|
|
|
|
ctrl = get_cctrl_from_dlgid(This, ctrl_id);
|
|
|
|
if (!ctrl)
|
|
{
|
|
ERR("Can't find this control\n");
|
|
return 0;
|
|
}
|
|
|
|
LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
|
|
{
|
|
if (item->hwnd == child)
|
|
{
|
|
found_item = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found_item)
|
|
{
|
|
ERR("Can't find control item\n");
|
|
return 0;
|
|
}
|
|
|
|
radiobuttonlist_set_selected_item(This, ctrl, item);
|
|
|
|
cctrl_event_OnItemSelected(This, ctrl->id, item->id);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static LRESULT radiobuttonlist_on_wm_command(FileDialogImpl *This, HWND hwnd, WPARAM wparam, LPARAM lparam)
|
|
{
|
|
switch(HIWORD(wparam))
|
|
{
|
|
case BN_CLICKED: return radiobuttonlist_on_bn_clicked(This, hwnd, (HWND)lparam);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static LRESULT CALLBACK radiobuttonlist_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
|
|
{
|
|
FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
|
|
|
|
switch(message)
|
|
{
|
|
case WM_COMMAND: return radiobuttonlist_on_wm_command(This, hwnd, wparam, lparam);
|
|
}
|
|
|
|
return DefWindowProcW(hwnd, message, wparam, lparam);
|
|
}
|
|
|
|
static HRESULT init_custom_controls(FileDialogImpl *This)
|
|
{
|
|
WNDCLASSW wc;
|
|
HDC hdc;
|
|
static const WCHAR ctrl_container_classname[] =
|
|
{'i','d','l','g','_','c','o','n','t','a','i','n','e','r','_','p','a','n','e',0};
|
|
|
|
InitCommonControlsEx(NULL);
|
|
|
|
if( !GetClassInfoW(COMDLG32_hInstance, ctrl_container_classname, &wc) )
|
|
{
|
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
|
wc.lpfnWndProc = ctrl_container_wndproc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = COMDLG32_hInstance;
|
|
wc.hIcon = 0;
|
|
wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
|
|
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
|
|
wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = ctrl_container_classname;
|
|
|
|
if(!RegisterClassW(&wc)) return E_FAIL;
|
|
}
|
|
|
|
This->cctrls_hwnd = CreateWindowExW(0, ctrl_container_classname, NULL,
|
|
WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
|
|
0, 0, 0, 0, NULL, 0,
|
|
COMDLG32_hInstance, This);
|
|
if(!This->cctrls_hwnd)
|
|
return E_FAIL;
|
|
|
|
hdc = GetDC(This->cctrls_hwnd);
|
|
This->dpi_x = GetDeviceCaps(hdc, LOGPIXELSX);
|
|
This->dpi_y = GetDeviceCaps(hdc, LOGPIXELSY);
|
|
ReleaseDC(This->cctrls_hwnd, hdc);
|
|
|
|
This->cctrl_width = MulDiv(160, This->dpi_x, USER_DEFAULT_SCREEN_DPI); /* Controls have a fixed width */
|
|
This->cctrl_indent = MulDiv(100, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
|
|
This->cctrl_def_height = MulDiv(23, This->dpi_y, USER_DEFAULT_SCREEN_DPI);
|
|
This->cctrls_cols = 0;
|
|
|
|
This->cctrl_next_dlgid = 0x2000;
|
|
list_init(&This->cctrls);
|
|
This->cctrl_active_vg = NULL;
|
|
|
|
SetWindowLongW(This->cctrls_hwnd, GWL_STYLE, WS_TABSTOP);
|
|
|
|
/* Register class for */
|
|
if( !GetClassInfoW(COMDLG32_hInstance, floatnotifysinkW, &wc) ||
|
|
wc.hInstance != COMDLG32_hInstance)
|
|
{
|
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
|
wc.lpfnWndProc = notifysink_proc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = COMDLG32_hInstance;
|
|
wc.hIcon = 0;
|
|
wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
|
|
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
|
|
wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = floatnotifysinkW;
|
|
|
|
if (!RegisterClassW(&wc))
|
|
ERR("Failed to register FloatNotifySink window class.\n");
|
|
}
|
|
|
|
if( !GetClassInfoW(COMDLG32_hInstance, radiobuttonlistW, &wc) ||
|
|
wc.hInstance != COMDLG32_hInstance)
|
|
{
|
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
|
wc.lpfnWndProc = radiobuttonlist_proc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = COMDLG32_hInstance;
|
|
wc.hIcon = 0;
|
|
wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
|
|
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
|
|
wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = radiobuttonlistW;
|
|
|
|
if (!RegisterClassW(&wc))
|
|
ERR("Failed to register RadioButtonList window class.\n");
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Window related functions.
|
|
*/
|
|
static BOOL update_open_dropdown(FileDialogImpl *This)
|
|
{
|
|
/* Show or hide the open dropdown button as appropriate */
|
|
BOOL show=FALSE, showing;
|
|
HWND open_hwnd, dropdown_hwnd;
|
|
|
|
if (This->hmenu_opendropdown)
|
|
{
|
|
INT num_visible_items=0;
|
|
cctrl_item* item;
|
|
|
|
LIST_FOR_EACH_ENTRY(item, &This->cctrl_opendropdown.sub_items, cctrl_item, entry)
|
|
{
|
|
if (item->cdcstate & CDCS_VISIBLE)
|
|
{
|
|
num_visible_items++;
|
|
if (num_visible_items >= 2)
|
|
{
|
|
show = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
open_hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
|
|
dropdown_hwnd = GetDlgItem(This->dlg_hwnd, psh1);
|
|
|
|
showing = (GetWindowLongPtrW(dropdown_hwnd, GWL_STYLE) & WS_VISIBLE) != 0;
|
|
|
|
if (showing != show)
|
|
{
|
|
RECT open_rc, dropdown_rc;
|
|
|
|
GetWindowRect(open_hwnd, &open_rc);
|
|
GetWindowRect(dropdown_hwnd, &dropdown_rc);
|
|
|
|
if (show)
|
|
{
|
|
ShowWindow(dropdown_hwnd, SW_SHOW);
|
|
|
|
SetWindowPos(open_hwnd, NULL, 0, 0,
|
|
(open_rc.right - open_rc.left) - (dropdown_rc.right - dropdown_rc.left),
|
|
open_rc.bottom - open_rc.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
|
|
}
|
|
else
|
|
{
|
|
ShowWindow(dropdown_hwnd, SW_HIDE);
|
|
|
|
SetWindowPos(open_hwnd, NULL, 0, 0,
|
|
(open_rc.right - open_rc.left) + (dropdown_rc.right - dropdown_rc.left),
|
|
open_rc.bottom - open_rc.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
|
|
}
|
|
}
|
|
|
|
return show;
|
|
}
|
|
|
|
static void update_layout(FileDialogImpl *This)
|
|
{
|
|
HDWP hdwp;
|
|
HWND hwnd;
|
|
RECT dialog_rc;
|
|
RECT cancel_rc, dropdown_rc, open_rc;
|
|
RECT filetype_rc, filename_rc, filenamelabel_rc;
|
|
RECT toolbar_rc, ebrowser_rc, customctrls_rc;
|
|
static const UINT vspacing = 4, hspacing = 4;
|
|
static const UINT min_width = 320, min_height = 200;
|
|
BOOL show_dropdown;
|
|
|
|
if (!GetClientRect(This->dlg_hwnd, &dialog_rc))
|
|
{
|
|
TRACE("Invalid dialog window, not updating layout\n");
|
|
return;
|
|
}
|
|
|
|
if(dialog_rc.right < min_width || dialog_rc.bottom < min_height)
|
|
{
|
|
TRACE("Dialog size (%d, %d) too small, not updating layout\n", dialog_rc.right, dialog_rc.bottom);
|
|
return;
|
|
}
|
|
|
|
/****
|
|
* Calculate the size of the dialog and all the parts.
|
|
*/
|
|
|
|
/* Cancel button */
|
|
hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL);
|
|
if(hwnd)
|
|
{
|
|
int cancel_width, cancel_height;
|
|
GetWindowRect(hwnd, &cancel_rc);
|
|
cancel_width = cancel_rc.right - cancel_rc.left;
|
|
cancel_height = cancel_rc.bottom - cancel_rc.top;
|
|
|
|
cancel_rc.left = dialog_rc.right - cancel_width - hspacing;
|
|
cancel_rc.top = dialog_rc.bottom - cancel_height - vspacing;
|
|
cancel_rc.right = cancel_rc.left + cancel_width;
|
|
cancel_rc.bottom = cancel_rc.top + cancel_height;
|
|
}
|
|
|
|
/* Open/Save dropdown */
|
|
show_dropdown = update_open_dropdown(This);
|
|
|
|
if(show_dropdown)
|
|
{
|
|
int dropdown_width, dropdown_height;
|
|
hwnd = GetDlgItem(This->dlg_hwnd, psh1);
|
|
|
|
GetWindowRect(hwnd, &dropdown_rc);
|
|
dropdown_width = dropdown_rc.right - dropdown_rc.left;
|
|
dropdown_height = dropdown_rc.bottom - dropdown_rc.top;
|
|
|
|
dropdown_rc.left = cancel_rc.left - dropdown_width - hspacing;
|
|
dropdown_rc.top = cancel_rc.top;
|
|
dropdown_rc.right = dropdown_rc.left + dropdown_width;
|
|
dropdown_rc.bottom = dropdown_rc.top + dropdown_height;
|
|
}
|
|
else
|
|
{
|
|
dropdown_rc.left = dropdown_rc.right = cancel_rc.left - hspacing;
|
|
dropdown_rc.top = cancel_rc.top;
|
|
dropdown_rc.bottom = cancel_rc.bottom;
|
|
}
|
|
|
|
/* Open/Save button */
|
|
hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
|
|
if(hwnd)
|
|
{
|
|
int open_width, open_height;
|
|
GetWindowRect(hwnd, &open_rc);
|
|
open_width = open_rc.right - open_rc.left;
|
|
open_height = open_rc.bottom - open_rc.top;
|
|
|
|
open_rc.left = dropdown_rc.left - open_width;
|
|
open_rc.top = dropdown_rc.top;
|
|
open_rc.right = open_rc.left + open_width;
|
|
open_rc.bottom = open_rc.top + open_height;
|
|
}
|
|
|
|
/* The filetype combobox. */
|
|
hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
|
|
if(hwnd)
|
|
{
|
|
int filetype_width, filetype_height;
|
|
GetWindowRect(hwnd, &filetype_rc);
|
|
|
|
filetype_width = filetype_rc.right - filetype_rc.left;
|
|
filetype_height = filetype_rc.bottom - filetype_rc.top;
|
|
|
|
filetype_rc.right = cancel_rc.right;
|
|
|
|
filetype_rc.left = filetype_rc.right - filetype_width;
|
|
filetype_rc.top = cancel_rc.top - filetype_height - vspacing;
|
|
filetype_rc.bottom = filetype_rc.top + filetype_height;
|
|
|
|
if(!This->filterspec_count)
|
|
filetype_rc.left = filetype_rc.right;
|
|
}
|
|
|
|
/* Filename label. */
|
|
hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC);
|
|
if(hwnd)
|
|
{
|
|
int filetypelabel_width, filetypelabel_height;
|
|
GetWindowRect(hwnd, &filenamelabel_rc);
|
|
|
|
filetypelabel_width = filenamelabel_rc.right - filenamelabel_rc.left;
|
|
filetypelabel_height = filenamelabel_rc.bottom - filenamelabel_rc.top;
|
|
|
|
filenamelabel_rc.left = 160; /* FIXME */
|
|
filenamelabel_rc.top = filetype_rc.top;
|
|
filenamelabel_rc.right = filenamelabel_rc.left + filetypelabel_width;
|
|
filenamelabel_rc.bottom = filenamelabel_rc.top + filetypelabel_height;
|
|
}
|
|
|
|
/* Filename edit box. */
|
|
hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME);
|
|
if(hwnd)
|
|
{
|
|
int filename_width, filename_height;
|
|
GetWindowRect(hwnd, &filename_rc);
|
|
|
|
filename_width = filetype_rc.left - filenamelabel_rc.right - hspacing*2;
|
|
filename_height = filename_rc.bottom - filename_rc.top;
|
|
|
|
filename_rc.left = filenamelabel_rc.right + hspacing;
|
|
filename_rc.top = filetype_rc.top;
|
|
filename_rc.right = filename_rc.left + filename_width;
|
|
filename_rc.bottom = filename_rc.top + filename_height;
|
|
}
|
|
|
|
hwnd = GetDlgItem(This->dlg_hwnd, IDC_NAV_TOOLBAR);
|
|
if(hwnd)
|
|
{
|
|
GetWindowRect(hwnd, &toolbar_rc);
|
|
MapWindowPoints(NULL, This->dlg_hwnd, (POINT*)&toolbar_rc, 2);
|
|
}
|
|
|
|
/* The custom controls */
|
|
customctrls_rc.left = dialog_rc.left + hspacing;
|
|
customctrls_rc.right = dialog_rc.right - hspacing;
|
|
customctrls_rc.bottom = filename_rc.top - vspacing;
|
|
customctrls_rc.top = customctrls_rc.bottom -
|
|
ctrl_container_resize(This, customctrls_rc.right - customctrls_rc.left);
|
|
|
|
/* The ExplorerBrowser control. */
|
|
ebrowser_rc.left = dialog_rc.left + hspacing;
|
|
ebrowser_rc.top = toolbar_rc.bottom + vspacing;
|
|
ebrowser_rc.right = dialog_rc.right - hspacing;
|
|
ebrowser_rc.bottom = customctrls_rc.top - vspacing;
|
|
|
|
/****
|
|
* Move everything to the right place.
|
|
*/
|
|
|
|
/* FIXME: The Save Dialog uses a slightly different layout. */
|
|
hdwp = BeginDeferWindowPos(7);
|
|
|
|
if(hdwp && This->peb)
|
|
IExplorerBrowser_SetRect(This->peb, &hdwp, ebrowser_rc);
|
|
|
|
if(hdwp && This->cctrls_hwnd)
|
|
DeferWindowPos(hdwp, This->cctrls_hwnd, NULL,
|
|
customctrls_rc.left, customctrls_rc.top,
|
|
customctrls_rc.right - customctrls_rc.left, customctrls_rc.bottom - customctrls_rc.top,
|
|
SWP_NOZORDER | SWP_NOACTIVATE);
|
|
|
|
/* The default controls */
|
|
if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE)) )
|
|
DeferWindowPos(hdwp, hwnd, NULL, filetype_rc.left, filetype_rc.top, 0, 0,
|
|
SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
|
|
|
|
if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
|
|
DeferWindowPos(hdwp, hwnd, NULL, filename_rc.left, filename_rc.top,
|
|
filename_rc.right - filename_rc.left, filename_rc.bottom - filename_rc.top,
|
|
SWP_NOZORDER | SWP_NOACTIVATE);
|
|
|
|
if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)) )
|
|
DeferWindowPos(hdwp, hwnd, NULL, filenamelabel_rc.left, filenamelabel_rc.top, 0, 0,
|
|
SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
|
|
|
|
if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDOK)) )
|
|
DeferWindowPos(hdwp, hwnd, NULL, open_rc.left, open_rc.top, 0, 0,
|
|
SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
|
|
|
|
if(hdwp && This->hmenu_opendropdown && (hwnd = GetDlgItem(This->dlg_hwnd, psh1)))
|
|
DeferWindowPos(hdwp, hwnd, NULL, dropdown_rc.left, dropdown_rc.top, 0, 0,
|
|
SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
|
|
|
|
if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL)) )
|
|
DeferWindowPos(hdwp, hwnd, NULL, cancel_rc.left, cancel_rc.top, 0, 0,
|
|
SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
|
|
|
|
if(hdwp)
|
|
EndDeferWindowPos(hdwp);
|
|
else
|
|
ERR("Failed to position dialog controls.\n");
|
|
|
|
return;
|
|
}
|
|
|
|
static HRESULT init_explorerbrowser(FileDialogImpl *This)
|
|
{
|
|
IShellItem *psi_folder;
|
|
IObjectWithSite *client;
|
|
FOLDERSETTINGS fos;
|
|
RECT rc = {0};
|
|
HRESULT hr;
|
|
|
|
/* Create ExplorerBrowser instance */
|
|
OleInitialize(NULL);
|
|
|
|
hr = CoCreateInstance(&CLSID_ExplorerBrowser, NULL, CLSCTX_INPROC_SERVER,
|
|
&IID_IExplorerBrowser, (void**)&This->peb);
|
|
if(FAILED(hr))
|
|
{
|
|
ERR("Failed to instantiate ExplorerBrowser control.\n");
|
|
return hr;
|
|
}
|
|
|
|
IExplorerBrowser_SetOptions(This->peb, EBO_SHOWFRAMES | EBO_NOBORDER);
|
|
|
|
hr = IExplorerBrowser_Initialize(This->peb, This->dlg_hwnd, &rc, NULL);
|
|
if(FAILED(hr))
|
|
{
|
|
ERR("Failed to initialize the ExplorerBrowser control.\n");
|
|
IExplorerBrowser_Release(This->peb);
|
|
This->peb = NULL;
|
|
return hr;
|
|
}
|
|
hr = IExplorerBrowser_Advise(This->peb, &This->IExplorerBrowserEvents_iface, &This->ebevents_cookie);
|
|
if(FAILED(hr))
|
|
ERR("Advise (ExplorerBrowser) failed.\n");
|
|
|
|
/* Get previous options? */
|
|
fos.ViewMode = fos.fFlags = 0;
|
|
if(!(This->options & FOS_ALLOWMULTISELECT))
|
|
fos.fFlags |= FWF_SINGLESEL;
|
|
|
|
IExplorerBrowser_SetFolderSettings(This->peb, &fos);
|
|
|
|
hr = IExplorerBrowser_QueryInterface(This->peb, &IID_IObjectWithSite, (void**)&client);
|
|
if (hr == S_OK)
|
|
{
|
|
hr = IObjectWithSite_SetSite(client, (IUnknown*)&This->IFileDialog2_iface);
|
|
IObjectWithSite_Release(client);
|
|
if(FAILED(hr))
|
|
ERR("SetSite failed, 0x%08x\n", hr);
|
|
}
|
|
|
|
/* Browse somewhere */
|
|
psi_folder = This->psi_setfolder ? This->psi_setfolder : This->psi_defaultfolder;
|
|
IExplorerBrowser_BrowseToObject(This->peb, (IUnknown*)psi_folder, SBSP_DEFBROWSER);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static void init_toolbar(FileDialogImpl *This, HWND hwnd)
|
|
{
|
|
HWND htoolbar;
|
|
TBADDBITMAP tbab;
|
|
TBBUTTON button[2];
|
|
|
|
htoolbar = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, TBSTYLE_FLAT | WS_CHILD | WS_VISIBLE,
|
|
0, 0, 0, 0,
|
|
hwnd, (HMENU)IDC_NAV_TOOLBAR, NULL, NULL);
|
|
|
|
tbab.hInst = HINST_COMMCTRL;
|
|
tbab.nID = IDB_HIST_LARGE_COLOR;
|
|
SendMessageW(htoolbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
|
|
|
|
button[0].iBitmap = HIST_BACK;
|
|
button[0].idCommand = IDC_NAVBACK;
|
|
button[0].fsState = TBSTATE_ENABLED;
|
|
button[0].fsStyle = BTNS_BUTTON;
|
|
button[0].dwData = 0;
|
|
button[0].iString = 0;
|
|
|
|
button[1].iBitmap = HIST_FORWARD;
|
|
button[1].idCommand = IDC_NAVFORWARD;
|
|
button[1].fsState = TBSTATE_ENABLED;
|
|
button[1].fsStyle = BTNS_BUTTON;
|
|
button[1].dwData = 0;
|
|
button[1].iString = 0;
|
|
|
|
SendMessageW(htoolbar, TB_ADDBUTTONSW, 2, (LPARAM)button);
|
|
SendMessageW(htoolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(24,24));
|
|
SendMessageW(htoolbar, TB_AUTOSIZE, 0, 0);
|
|
}
|
|
|
|
static void update_control_text(FileDialogImpl *This)
|
|
{
|
|
HWND hitem;
|
|
LPCWSTR custom_okbutton;
|
|
cctrl_item* item;
|
|
UINT min_width = MulDiv(50, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
|
|
UINT max_width = MulDiv(250, This->dpi_x, USER_DEFAULT_SCREEN_DPI);
|
|
|
|
if(This->custom_title)
|
|
SetWindowTextW(This->dlg_hwnd, This->custom_title);
|
|
|
|
if(This->hmenu_opendropdown && (item = get_first_item(&This->cctrl_opendropdown)))
|
|
custom_okbutton = item->label;
|
|
else
|
|
custom_okbutton = This->custom_okbutton;
|
|
|
|
if(custom_okbutton &&
|
|
(hitem = GetDlgItem(This->dlg_hwnd, IDOK)))
|
|
{
|
|
SetWindowTextW(hitem, custom_okbutton);
|
|
ctrl_resize(hitem, min_width, max_width, FALSE);
|
|
}
|
|
|
|
if(This->custom_cancelbutton &&
|
|
(hitem = GetDlgItem(This->dlg_hwnd, IDCANCEL)))
|
|
{
|
|
SetWindowTextW(hitem, This->custom_cancelbutton);
|
|
ctrl_resize(hitem, min_width, max_width, FALSE);
|
|
}
|
|
|
|
if(This->custom_filenamelabel &&
|
|
(hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAMESTATIC)))
|
|
{
|
|
SetWindowTextW(hitem, This->custom_filenamelabel);
|
|
ctrl_resize(hitem, min_width, max_width, FALSE);
|
|
}
|
|
}
|
|
|
|
static LRESULT CALLBACK dropdown_subclass_proc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
|
|
{
|
|
static const WCHAR prop_this[] = {'i','t','e','m','d','l','g','_','T','h','i','s',0};
|
|
static const WCHAR prop_oldwndproc[] = {'i','t','e','m','d','l','g','_','o','l','d','w','n','d','p','r','o','c',0};
|
|
|
|
if (umessage == WM_LBUTTONDOWN)
|
|
{
|
|
FileDialogImpl *This = GetPropW(hwnd, prop_this);
|
|
|
|
SendMessageW(hwnd, BM_SETCHECK, BST_CHECKED, 0);
|
|
show_opendropdown(This);
|
|
SendMessageW(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
return CallWindowProcW((WNDPROC)GetPropW(hwnd, prop_oldwndproc), hwnd, umessage, wparam, lparam);
|
|
}
|
|
|
|
static LRESULT on_wm_initdialog(HWND hwnd, LPARAM lParam)
|
|
{
|
|
FileDialogImpl *This = (FileDialogImpl*)lParam;
|
|
HWND hitem;
|
|
|
|
TRACE("(%p, %p)\n", This, hwnd);
|
|
|
|
SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
|
|
This->dlg_hwnd = hwnd;
|
|
|
|
hitem = GetDlgItem(This->dlg_hwnd, pshHelp);
|
|
if(hitem) ShowWindow(hitem, SW_HIDE);
|
|
|
|
hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPESTATIC);
|
|
if(hitem) ShowWindow(hitem, SW_HIDE);
|
|
|
|
/* Fill filetypes combobox, or hide it. */
|
|
hitem = GetDlgItem(This->dlg_hwnd, IDC_FILETYPE);
|
|
if(This->filterspec_count)
|
|
{
|
|
HDC hdc;
|
|
HFONT font;
|
|
SIZE size;
|
|
UINT i, maxwidth = 0;
|
|
|
|
hdc = GetDC(hitem);
|
|
font = (HFONT)SendMessageW(hitem, WM_GETFONT, 0, 0);
|
|
SelectObject(hdc, font);
|
|
|
|
for(i = 0; i < This->filterspec_count; i++)
|
|
{
|
|
SendMessageW(hitem, CB_ADDSTRING, 0, (LPARAM)This->filterspecs[i].pszName);
|
|
|
|
if(GetTextExtentPoint32W(hdc, This->filterspecs[i].pszName, lstrlenW(This->filterspecs[i].pszName), &size))
|
|
maxwidth = max(maxwidth, size.cx);
|
|
}
|
|
ReleaseDC(hitem, hdc);
|
|
|
|
if(maxwidth > 0)
|
|
{
|
|
maxwidth += GetSystemMetrics(SM_CXVSCROLL) + 4;
|
|
SendMessageW(hitem, CB_SETDROPPEDWIDTH, (WPARAM)maxwidth, 0);
|
|
}
|
|
else
|
|
ERR("Failed to calculate width of filetype dropdown\n");
|
|
|
|
SendMessageW(hitem, CB_SETCURSEL, This->filetypeindex, 0);
|
|
}
|
|
else
|
|
ShowWindow(hitem, SW_HIDE);
|
|
|
|
if(This->set_filename &&
|
|
(hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
|
|
SendMessageW(hitem, WM_SETTEXT, 0, (LPARAM)This->set_filename);
|
|
|
|
if(This->hmenu_opendropdown)
|
|
{
|
|
HWND dropdown_hwnd;
|
|
LOGFONTW lfw, lfw_marlett;
|
|
HFONT dialog_font;
|
|
static const WCHAR marlett[] = {'M','a','r','l','e','t','t',0};
|
|
static const WCHAR prop_this[] = {'i','t','e','m','d','l','g','_','T','h','i','s',0};
|
|
static const WCHAR prop_oldwndproc[] = {'i','t','e','m','d','l','g','_','o','l','d','w','n','d','p','r','o','c',0};
|
|
|
|
dropdown_hwnd = GetDlgItem(This->dlg_hwnd, psh1);
|
|
|
|
/* Change dropdown button font to Marlett */
|
|
dialog_font = (HFONT)SendMessageW(dropdown_hwnd, WM_GETFONT, 0, 0);
|
|
|
|
GetObjectW(dialog_font, sizeof(lfw), &lfw);
|
|
|
|
memset(&lfw_marlett, 0, sizeof(lfw_marlett));
|
|
lstrcpyW(lfw_marlett.lfFaceName, marlett);
|
|
lfw_marlett.lfHeight = lfw.lfHeight;
|
|
lfw_marlett.lfCharSet = SYMBOL_CHARSET;
|
|
|
|
This->hfont_opendropdown = CreateFontIndirectW(&lfw_marlett);
|
|
|
|
SendMessageW(dropdown_hwnd, WM_SETFONT, (LPARAM)This->hfont_opendropdown, 0);
|
|
|
|
/* Subclass button so we can handle LBUTTONDOWN */
|
|
SetPropW(dropdown_hwnd, prop_this, This);
|
|
SetPropW(dropdown_hwnd, prop_oldwndproc,
|
|
(HANDLE)SetWindowLongPtrW(dropdown_hwnd, GWLP_WNDPROC, (LONG_PTR)dropdown_subclass_proc));
|
|
}
|
|
|
|
ctrl_container_reparent(This, This->dlg_hwnd);
|
|
init_explorerbrowser(This);
|
|
init_toolbar(This, hwnd);
|
|
update_control_text(This);
|
|
update_layout(This);
|
|
|
|
if(This->filterspec_count)
|
|
events_OnTypeChange(This);
|
|
|
|
if ((hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)))
|
|
SetFocus(hitem);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static LRESULT on_wm_size(FileDialogImpl *This)
|
|
{
|
|
update_layout(This);
|
|
return FALSE;
|
|
}
|
|
|
|
static LRESULT on_wm_getminmaxinfo(FileDialogImpl *This, LPARAM lparam)
|
|
{
|
|
MINMAXINFO *mmi = (MINMAXINFO*)lparam;
|
|
TRACE("%p (%p)\n", This, mmi);
|
|
|
|
/* FIXME */
|
|
mmi->ptMinTrackSize.x = 640;
|
|
mmi->ptMinTrackSize.y = 480;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static LRESULT on_wm_destroy(FileDialogImpl *This)
|
|
{
|
|
TRACE("%p\n", This);
|
|
|
|
if(This->peb)
|
|
{
|
|
IExplorerBrowser_Destroy(This->peb);
|
|
IExplorerBrowser_Release(This->peb);
|
|
This->peb = NULL;
|
|
}
|
|
|
|
ctrl_container_reparent(This, NULL);
|
|
This->dlg_hwnd = NULL;
|
|
|
|
DeleteObject(This->hfont_opendropdown);
|
|
This->hfont_opendropdown = NULL;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static LRESULT on_idok(FileDialogImpl *This)
|
|
{
|
|
TRACE("%p\n", This);
|
|
|
|
if(SUCCEEDED(on_default_action(This)))
|
|
EndDialog(This->dlg_hwnd, S_OK);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static LRESULT on_idcancel(FileDialogImpl *This)
|
|
{
|
|
TRACE("%p\n", This);
|
|
|
|
EndDialog(This->dlg_hwnd, HRESULT_FROM_WIN32(ERROR_CANCELLED));
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static LRESULT on_command_opendropdown(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
|
|
{
|
|
if(HIWORD(wparam) == BN_CLICKED)
|
|
{
|
|
HWND hwnd = (HWND)lparam;
|
|
SendMessageW(hwnd, BM_SETCHECK, BST_CHECKED, 0);
|
|
show_opendropdown(This);
|
|
SendMessageW(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static LRESULT on_browse_back(FileDialogImpl *This)
|
|
{
|
|
TRACE("%p\n", This);
|
|
IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEBACK);
|
|
return FALSE;
|
|
}
|
|
|
|
static LRESULT on_browse_forward(FileDialogImpl *This)
|
|
{
|
|
TRACE("%p\n", This);
|
|
IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_NAVIGATEFORWARD);
|
|
return FALSE;
|
|
}
|
|
|
|
static LRESULT on_command_filetype(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
|
|
{
|
|
if(HIWORD(wparam) == CBN_SELCHANGE)
|
|
{
|
|
IShellView *psv;
|
|
HRESULT hr;
|
|
LPWSTR filename;
|
|
UINT prev_index = This->filetypeindex;
|
|
|
|
This->filetypeindex = SendMessageW((HWND)lparam, CB_GETCURSEL, 0, 0);
|
|
TRACE("File type selection changed to %d.\n", This->filetypeindex);
|
|
|
|
if(prev_index == This->filetypeindex)
|
|
return FALSE;
|
|
|
|
hr = IExplorerBrowser_GetCurrentView(This->peb, &IID_IShellView, (void**)&psv);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
IShellView_Refresh(psv);
|
|
IShellView_Release(psv);
|
|
}
|
|
|
|
if(This->dlg_type == ITEMDLG_TYPE_SAVE && get_file_name(This, &filename))
|
|
{
|
|
WCHAR buf[MAX_PATH], extbuf[MAX_PATH], *ext;
|
|
|
|
ext = get_first_ext_from_spec(extbuf, This->filterspecs[This->filetypeindex].pszSpec);
|
|
if(ext)
|
|
{
|
|
lstrcpyW(buf, filename);
|
|
|
|
if(PathMatchSpecW(buf, This->filterspecs[prev_index].pszSpec))
|
|
PathRemoveExtensionW(buf);
|
|
|
|
lstrcatW(buf, ext);
|
|
set_file_name(This, buf);
|
|
}
|
|
CoTaskMemFree(filename);
|
|
}
|
|
|
|
/* The documentation claims that OnTypeChange is called only
|
|
* when the dialog is opened, but this is obviously not the
|
|
* case. */
|
|
events_OnTypeChange(This);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static LRESULT on_wm_command(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
|
|
{
|
|
switch(LOWORD(wparam))
|
|
{
|
|
case IDOK: return on_idok(This);
|
|
case IDCANCEL: return on_idcancel(This);
|
|
case psh1: return on_command_opendropdown(This, wparam, lparam);
|
|
case IDC_NAVBACK: return on_browse_back(This);
|
|
case IDC_NAVFORWARD: return on_browse_forward(This);
|
|
case IDC_FILETYPE: return on_command_filetype(This, wparam, lparam);
|
|
default: TRACE("Unknown command.\n");
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static LRESULT CALLBACK itemdlg_dlgproc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
|
|
{
|
|
FileDialogImpl *This = (FileDialogImpl*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
|
|
|
|
switch(umessage)
|
|
{
|
|
case WM_INITDIALOG: return on_wm_initdialog(hwnd, lparam);
|
|
case WM_COMMAND: return on_wm_command(This, wparam, lparam);
|
|
case WM_SIZE: return on_wm_size(This);
|
|
case WM_GETMINMAXINFO: return on_wm_getminmaxinfo(This, lparam);
|
|
case WM_DESTROY: return on_wm_destroy(This);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static HRESULT create_dialog(FileDialogImpl *This, HWND parent)
|
|
{
|
|
INT_PTR res;
|
|
|
|
SetLastError(0);
|
|
res = DialogBoxParamW(COMDLG32_hInstance,
|
|
MAKEINTRESOURCEW(NEWFILEOPENV3ORD),
|
|
parent, itemdlg_dlgproc, (LPARAM)This);
|
|
This->dlg_hwnd = NULL;
|
|
if(res == -1)
|
|
{
|
|
ERR("Failed to show dialog (LastError: %d)\n", GetLastError());
|
|
return E_FAIL;
|
|
}
|
|
|
|
TRACE("Returning 0x%08x\n", (HRESULT)res);
|
|
return (HRESULT)res;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* IFileDialog implementation
|
|
*/
|
|
static inline FileDialogImpl *impl_from_IFileDialog2(IFileDialog2 *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialog2_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialog2_fnQueryInterface(IFileDialog2 *iface,
|
|
REFIID riid,
|
|
void **ppvObject)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialog2(iface);
|
|
TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
|
|
|
|
*ppvObject = NULL;
|
|
if(IsEqualGUID(riid, &IID_IUnknown) ||
|
|
IsEqualGUID(riid, &IID_IFileDialog) ||
|
|
IsEqualGUID(riid, &IID_IFileDialog2))
|
|
{
|
|
*ppvObject = iface;
|
|
}
|
|
else if(IsEqualGUID(riid, &IID_IFileOpenDialog) && This->dlg_type == ITEMDLG_TYPE_OPEN)
|
|
{
|
|
*ppvObject = &This->u.IFileOpenDialog_iface;
|
|
}
|
|
else if(IsEqualGUID(riid, &IID_IFileSaveDialog) && This->dlg_type == ITEMDLG_TYPE_SAVE)
|
|
{
|
|
*ppvObject = &This->u.IFileSaveDialog_iface;
|
|
}
|
|
else if(IsEqualGUID(riid, &IID_IExplorerBrowserEvents))
|
|
{
|
|
*ppvObject = &This->IExplorerBrowserEvents_iface;
|
|
}
|
|
else if(IsEqualGUID(riid, &IID_IServiceProvider))
|
|
{
|
|
*ppvObject = &This->IServiceProvider_iface;
|
|
}
|
|
else if(IsEqualGUID(&IID_ICommDlgBrowser3, riid) ||
|
|
IsEqualGUID(&IID_ICommDlgBrowser2, riid) ||
|
|
IsEqualGUID(&IID_ICommDlgBrowser, riid))
|
|
{
|
|
*ppvObject = &This->ICommDlgBrowser3_iface;
|
|
}
|
|
else if(IsEqualGUID(&IID_IOleWindow, riid))
|
|
{
|
|
*ppvObject = &This->IOleWindow_iface;
|
|
}
|
|
else if(IsEqualGUID(riid, &IID_IFileDialogCustomize) ||
|
|
IsEqualGUID(riid, &IID_IFileDialogCustomizeAlt))
|
|
{
|
|
*ppvObject = &This->IFileDialogCustomize_iface;
|
|
}
|
|
else
|
|
FIXME("Unknown interface requested: %s.\n", debugstr_guid(riid));
|
|
|
|
if(*ppvObject)
|
|
{
|
|
IUnknown_AddRef((IUnknown*)*ppvObject);
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG WINAPI IFileDialog2_fnAddRef(IFileDialog2 *iface)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialog2(iface);
|
|
LONG ref = InterlockedIncrement(&This->ref);
|
|
TRACE("%p - ref %d\n", This, ref);
|
|
|
|
return ref;
|
|
}
|
|
|
|
static ULONG WINAPI IFileDialog2_fnRelease(IFileDialog2 *iface)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialog2(iface);
|
|
LONG ref = InterlockedDecrement(&This->ref);
|
|
TRACE("%p - ref %d\n", This, ref);
|
|
|
|
if(!ref)
|
|
{
|
|
UINT i;
|
|
for(i = 0; i < This->filterspec_count; i++)
|
|
{
|
|
LocalFree((void*)This->filterspecs[i].pszName);
|
|
LocalFree((void*)This->filterspecs[i].pszSpec);
|
|
}
|
|
HeapFree(GetProcessHeap(), 0, This->filterspecs);
|
|
|
|
DestroyWindow(This->cctrls_hwnd);
|
|
|
|
if(This->psi_defaultfolder) IShellItem_Release(This->psi_defaultfolder);
|
|
if(This->psi_setfolder) IShellItem_Release(This->psi_setfolder);
|
|
if(This->psi_folder) IShellItem_Release(This->psi_folder);
|
|
if(This->psia_selection) IShellItemArray_Release(This->psia_selection);
|
|
if(This->psia_results) IShellItemArray_Release(This->psia_results);
|
|
|
|
LocalFree(This->set_filename);
|
|
LocalFree(This->default_ext);
|
|
LocalFree(This->custom_title);
|
|
LocalFree(This->custom_okbutton);
|
|
LocalFree(This->custom_cancelbutton);
|
|
LocalFree(This->custom_filenamelabel);
|
|
|
|
DestroyMenu(This->hmenu_opendropdown);
|
|
DeleteObject(This->hfont_opendropdown);
|
|
|
|
HeapFree(GetProcessHeap(), 0, This);
|
|
}
|
|
|
|
return ref;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialog2_fnShow(IFileDialog2 *iface, HWND hwndOwner)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialog2(iface);
|
|
TRACE("%p (%p)\n", iface, hwndOwner);
|
|
|
|
This->opendropdown_has_selection = FALSE;
|
|
|
|
return create_dialog(This, hwndOwner);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialog2_fnSetFileTypes(IFileDialog2 *iface, UINT cFileTypes,
|
|
const COMDLG_FILTERSPEC *rgFilterSpec)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialog2(iface);
|
|
UINT i;
|
|
TRACE("%p (%d, %p)\n", This, cFileTypes, rgFilterSpec);
|
|
|
|
if(This->filterspecs)
|
|
return E_UNEXPECTED;
|
|
|
|
if(!rgFilterSpec)
|
|
return E_INVALIDARG;
|
|
|
|
if(!cFileTypes)
|
|
return S_OK;
|
|
|
|
This->filterspecs = HeapAlloc(GetProcessHeap(), 0, sizeof(COMDLG_FILTERSPEC)*cFileTypes);
|
|
for(i = 0; i < cFileTypes; i++)
|
|
{
|
|
This->filterspecs[i].pszName = StrDupW(rgFilterSpec[i].pszName);
|
|
This->filterspecs[i].pszSpec = StrDupW(rgFilterSpec[i].pszSpec);
|
|
}
|
|
This->filterspec_count = cFileTypes;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialog2_fnSetFileTypeIndex(IFileDialog2 *iface, UINT iFileType)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialog2(iface);
|
|
TRACE("%p (%d)\n", This, iFileType);
|
|
|
|
if(!This->filterspecs)
|
|
return E_FAIL;
|
|
|
|
iFileType = max(iFileType, 1);
|
|
iFileType = min(iFileType, This->filterspec_count);
|
|
This->filetypeindex = iFileType-1;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialog2_fnGetFileTypeIndex(IFileDialog2 *iface, UINT *piFileType)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialog2(iface);
|
|
TRACE("%p (%p)\n", This, piFileType);
|
|
|
|
if(!piFileType)
|
|
return E_INVALIDARG;
|
|
|
|
if(This->filterspec_count == 0)
|
|
*piFileType = 0;
|
|
else
|
|
*piFileType = This->filetypeindex + 1;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialog2_fnAdvise(IFileDialog2 *iface, IFileDialogEvents *pfde, DWORD *pdwCookie)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialog2(iface);
|
|
events_client *client;
|
|
TRACE("%p (%p, %p)\n", This, pfde, pdwCookie);
|
|
|
|
if(!pfde || !pdwCookie)
|
|
return E_INVALIDARG;
|
|
|
|
client = HeapAlloc(GetProcessHeap(), 0, sizeof(events_client));
|
|
client->pfde = pfde;
|
|
client->cookie = ++This->events_next_cookie;
|
|
|
|
IFileDialogEvents_AddRef(pfde);
|
|
*pdwCookie = client->cookie;
|
|
|
|
list_add_tail(&This->events_clients, &client->entry);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialog2_fnUnadvise(IFileDialog2 *iface, DWORD dwCookie)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialog2(iface);
|
|
events_client *client, *found = NULL;
|
|
TRACE("%p (%d)\n", This, dwCookie);
|
|
|
|
LIST_FOR_EACH_ENTRY(client, &This->events_clients, events_client, entry)
|
|
{
|
|
if(client->cookie == dwCookie)
|
|
{
|
|
found = client;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(found)
|
|
{
|
|
list_remove(&found->entry);
|
|
IFileDialogEvents_Release(found->pfde);
|
|
HeapFree(GetProcessHeap(), 0, found);
|
|
return S_OK;
|
|
}
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialog2_fnSetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS fos)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialog2(iface);
|
|
TRACE("%p (0x%x)\n", This, fos);
|
|
|
|
if (fos & ~(FOS_OVERWRITEPROMPT | FOS_STRICTFILETYPES | FOS_NOCHANGEDIR | FOS_PICKFOLDERS | FOS_FORCEFILESYSTEM
|
|
| FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE | FOS_ALLOWMULTISELECT | FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST
|
|
| FOS_CREATEPROMPT | FOS_SHAREAWARE | FOS_NOREADONLYRETURN | FOS_NOTESTFILECREATE | FOS_HIDEMRUPLACES
|
|
| FOS_HIDEPINNEDPLACES | FOS_NODEREFERENCELINKS | FOS_DONTADDTORECENT | FOS_FORCESHOWHIDDEN
|
|
| FOS_DEFAULTNOMINIMODE | FOS_FORCEPREVIEWPANEON | FOS_SUPPORTSTREAMABLEITEMS))
|
|
{
|
|
WARN("Invalid option %#x\n", fos);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if( !(This->options & FOS_PICKFOLDERS) && (fos & FOS_PICKFOLDERS) )
|
|
{
|
|
WCHAR buf[30];
|
|
LoadStringW(COMDLG32_hInstance, IDS_SELECT_FOLDER, buf, ARRAY_SIZE(buf));
|
|
IFileDialog2_SetTitle(iface, buf);
|
|
}
|
|
|
|
This->options = fos;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialog2_fnGetOptions(IFileDialog2 *iface, FILEOPENDIALOGOPTIONS *pfos)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialog2(iface);
|
|
TRACE("%p (%p)\n", This, pfos);
|
|
|
|
if(!pfos)
|
|
return E_INVALIDARG;
|
|
|
|
*pfos = This->options;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialog2_fnSetDefaultFolder(IFileDialog2 *iface, IShellItem *psi)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialog2(iface);
|
|
TRACE("%p (%p)\n", This, psi);
|
|
if(This->psi_defaultfolder)
|
|
IShellItem_Release(This->psi_defaultfolder);
|
|
|
|
This->psi_defaultfolder = psi;
|
|
|
|
if(This->psi_defaultfolder)
|
|
IShellItem_AddRef(This->psi_defaultfolder);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialog2_fnSetFolder(IFileDialog2 *iface, IShellItem *psi)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialog2(iface);
|
|
TRACE("%p (%p)\n", This, psi);
|
|
if(This->psi_setfolder)
|
|
IShellItem_Release(This->psi_setfolder);
|
|
|
|
This->psi_setfolder = psi;
|
|
|
|
if(This->psi_setfolder)
|
|
IShellItem_AddRef(This->psi_setfolder);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialog2_fnGetFolder(IFileDialog2 *iface, IShellItem **ppsi)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialog2(iface);
|
|
TRACE("%p (%p)\n", This, ppsi);
|
|
if(!ppsi)
|
|
return E_INVALIDARG;
|
|
|
|
/* FIXME:
|
|
If the dialog is shown, return the current(ly selected) folder. */
|
|
|
|
*ppsi = NULL;
|
|
if(This->psi_folder)
|
|
*ppsi = This->psi_folder;
|
|
else if(This->psi_setfolder)
|
|
*ppsi = This->psi_setfolder;
|
|
else if(This->psi_defaultfolder)
|
|
*ppsi = This->psi_defaultfolder;
|
|
|
|
if(*ppsi)
|
|
{
|
|
IShellItem_AddRef(*ppsi);
|
|
return S_OK;
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialog2_fnGetCurrentSelection(IFileDialog2 *iface, IShellItem **ppsi)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialog2(iface);
|
|
HRESULT hr;
|
|
TRACE("%p (%p)\n", This, ppsi);
|
|
|
|
if(!ppsi)
|
|
return E_INVALIDARG;
|
|
|
|
if(This->psia_selection)
|
|
{
|
|
/* FIXME: Check filename edit box */
|
|
hr = IShellItemArray_GetItemAt(This->psia_selection, 0, ppsi);
|
|
return hr;
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialog2_fnSetFileName(IFileDialog2 *iface, LPCWSTR pszName)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialog2(iface);
|
|
TRACE("%p (%s)\n", iface, debugstr_w(pszName));
|
|
|
|
set_file_name(This, pszName);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialog2_fnGetFileName(IFileDialog2 *iface, LPWSTR *pszName)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialog2(iface);
|
|
TRACE("%p (%p)\n", iface, pszName);
|
|
|
|
if(!pszName)
|
|
return E_INVALIDARG;
|
|
|
|
*pszName = NULL;
|
|
get_file_name(This, pszName);
|
|
return *pszName ? S_OK : E_FAIL;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialog2_fnSetTitle(IFileDialog2 *iface, LPCWSTR pszTitle)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialog2(iface);
|
|
TRACE("%p (%s)\n", This, debugstr_w(pszTitle));
|
|
|
|
LocalFree(This->custom_title);
|
|
This->custom_title = StrDupW(pszTitle);
|
|
update_control_text(This);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialog2_fnSetOkButtonLabel(IFileDialog2 *iface, LPCWSTR pszText)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialog2(iface);
|
|
TRACE("%p (%s)\n", This, debugstr_w(pszText));
|
|
|
|
LocalFree(This->custom_okbutton);
|
|
This->custom_okbutton = StrDupW(pszText);
|
|
update_control_text(This);
|
|
update_layout(This);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialog2_fnSetFileNameLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialog2(iface);
|
|
TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
|
|
|
|
LocalFree(This->custom_filenamelabel);
|
|
This->custom_filenamelabel = StrDupW(pszLabel);
|
|
update_control_text(This);
|
|
update_layout(This);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialog2_fnGetResult(IFileDialog2 *iface, IShellItem **ppsi)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialog2(iface);
|
|
HRESULT hr;
|
|
TRACE("%p (%p)\n", This, ppsi);
|
|
|
|
if(!ppsi)
|
|
return E_INVALIDARG;
|
|
|
|
if(This->psia_results)
|
|
{
|
|
UINT item_count;
|
|
hr = IShellItemArray_GetCount(This->psia_results, &item_count);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
if(item_count != 1)
|
|
return E_FAIL;
|
|
|
|
/* Adds a reference. */
|
|
hr = IShellItemArray_GetItemAt(This->psia_results, 0, ppsi);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialog2_fnAddPlace(IFileDialog2 *iface, IShellItem *psi, FDAP fdap)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialog2(iface);
|
|
FIXME("stub - %p (%p, %d)\n", This, psi, fdap);
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialog2_fnSetDefaultExtension(IFileDialog2 *iface, LPCWSTR pszDefaultExtension)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialog2(iface);
|
|
TRACE("%p (%s)\n", This, debugstr_w(pszDefaultExtension));
|
|
|
|
LocalFree(This->default_ext);
|
|
This->default_ext = StrDupW(pszDefaultExtension);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialog2_fnClose(IFileDialog2 *iface, HRESULT hr)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialog2(iface);
|
|
TRACE("%p (0x%08x)\n", This, hr);
|
|
|
|
if(This->dlg_hwnd)
|
|
EndDialog(This->dlg_hwnd, hr);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialog2_fnSetClientGuid(IFileDialog2 *iface, REFGUID guid)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialog2(iface);
|
|
TRACE("%p (%s)\n", This, debugstr_guid(guid));
|
|
This->client_guid = *guid;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialog2_fnClearClientData(IFileDialog2 *iface)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialog2(iface);
|
|
FIXME("stub - %p\n", This);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialog2_fnSetFilter(IFileDialog2 *iface, IShellItemFilter *pFilter)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialog2(iface);
|
|
FIXME("stub - %p (%p)\n", This, pFilter);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialog2_fnSetCancelButtonLabel(IFileDialog2 *iface, LPCWSTR pszLabel)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialog2(iface);
|
|
TRACE("%p (%s)\n", This, debugstr_w(pszLabel));
|
|
|
|
LocalFree(This->custom_cancelbutton);
|
|
This->custom_cancelbutton = StrDupW(pszLabel);
|
|
update_control_text(This);
|
|
update_layout(This);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialog2_fnSetNavigationRoot(IFileDialog2 *iface, IShellItem *psi)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialog2(iface);
|
|
FIXME("stub - %p (%p)\n", This, psi);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static const IFileDialog2Vtbl vt_IFileDialog2 = {
|
|
IFileDialog2_fnQueryInterface,
|
|
IFileDialog2_fnAddRef,
|
|
IFileDialog2_fnRelease,
|
|
IFileDialog2_fnShow,
|
|
IFileDialog2_fnSetFileTypes,
|
|
IFileDialog2_fnSetFileTypeIndex,
|
|
IFileDialog2_fnGetFileTypeIndex,
|
|
IFileDialog2_fnAdvise,
|
|
IFileDialog2_fnUnadvise,
|
|
IFileDialog2_fnSetOptions,
|
|
IFileDialog2_fnGetOptions,
|
|
IFileDialog2_fnSetDefaultFolder,
|
|
IFileDialog2_fnSetFolder,
|
|
IFileDialog2_fnGetFolder,
|
|
IFileDialog2_fnGetCurrentSelection,
|
|
IFileDialog2_fnSetFileName,
|
|
IFileDialog2_fnGetFileName,
|
|
IFileDialog2_fnSetTitle,
|
|
IFileDialog2_fnSetOkButtonLabel,
|
|
IFileDialog2_fnSetFileNameLabel,
|
|
IFileDialog2_fnGetResult,
|
|
IFileDialog2_fnAddPlace,
|
|
IFileDialog2_fnSetDefaultExtension,
|
|
IFileDialog2_fnClose,
|
|
IFileDialog2_fnSetClientGuid,
|
|
IFileDialog2_fnClearClientData,
|
|
IFileDialog2_fnSetFilter,
|
|
IFileDialog2_fnSetCancelButtonLabel,
|
|
IFileDialog2_fnSetNavigationRoot
|
|
};
|
|
|
|
/**************************************************************************
|
|
* IFileOpenDialog
|
|
*/
|
|
static inline FileDialogImpl *impl_from_IFileOpenDialog(IFileOpenDialog *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileOpenDialog_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileOpenDialog_fnQueryInterface(IFileOpenDialog *iface,
|
|
REFIID riid, void **ppvObject)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
|
|
return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
|
|
}
|
|
|
|
static ULONG WINAPI IFileOpenDialog_fnAddRef(IFileOpenDialog *iface)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
|
|
return IFileDialog2_AddRef(&This->IFileDialog2_iface);
|
|
}
|
|
|
|
static ULONG WINAPI IFileOpenDialog_fnRelease(IFileOpenDialog *iface)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
|
|
return IFileDialog2_Release(&This->IFileDialog2_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileOpenDialog_fnShow(IFileOpenDialog *iface, HWND hwndOwner)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
|
|
return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileOpenDialog_fnSetFileTypes(IFileOpenDialog *iface, UINT cFileTypes,
|
|
const COMDLG_FILTERSPEC *rgFilterSpec)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
|
|
return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileOpenDialog_fnSetFileTypeIndex(IFileOpenDialog *iface, UINT iFileType)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
|
|
return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileOpenDialog_fnGetFileTypeIndex(IFileOpenDialog *iface, UINT *piFileType)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
|
|
return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileOpenDialog_fnAdvise(IFileOpenDialog *iface, IFileDialogEvents *pfde,
|
|
DWORD *pdwCookie)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
|
|
return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileOpenDialog_fnUnadvise(IFileOpenDialog *iface, DWORD dwCookie)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
|
|
return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileOpenDialog_fnSetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS fos)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
|
|
return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileOpenDialog_fnGetOptions(IFileOpenDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
|
|
return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileOpenDialog_fnSetDefaultFolder(IFileOpenDialog *iface, IShellItem *psi)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
|
|
return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileOpenDialog_fnSetFolder(IFileOpenDialog *iface, IShellItem *psi)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
|
|
return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileOpenDialog_fnGetFolder(IFileOpenDialog *iface, IShellItem **ppsi)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
|
|
return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileOpenDialog_fnGetCurrentSelection(IFileOpenDialog *iface, IShellItem **ppsi)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
|
|
return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileOpenDialog_fnSetFileName(IFileOpenDialog *iface, LPCWSTR pszName)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
|
|
return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileOpenDialog_fnGetFileName(IFileOpenDialog *iface, LPWSTR *pszName)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
|
|
return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileOpenDialog_fnSetTitle(IFileOpenDialog *iface, LPCWSTR pszTitle)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
|
|
return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileOpenDialog_fnSetOkButtonLabel(IFileOpenDialog *iface, LPCWSTR pszText)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
|
|
return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileOpenDialog_fnSetFileNameLabel(IFileOpenDialog *iface, LPCWSTR pszLabel)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
|
|
return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileOpenDialog_fnGetResult(IFileOpenDialog *iface, IShellItem **ppsi)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
|
|
return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileOpenDialog_fnAddPlace(IFileOpenDialog *iface, IShellItem *psi, FDAP fdap)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
|
|
return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileOpenDialog_fnSetDefaultExtension(IFileOpenDialog *iface,
|
|
LPCWSTR pszDefaultExtension)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
|
|
return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileOpenDialog_fnClose(IFileOpenDialog *iface, HRESULT hr)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
|
|
return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileOpenDialog_fnSetClientGuid(IFileOpenDialog *iface, REFGUID guid)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
|
|
return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileOpenDialog_fnClearClientData(IFileOpenDialog *iface)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
|
|
return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileOpenDialog_fnSetFilter(IFileOpenDialog *iface, IShellItemFilter *pFilter)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
|
|
return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileOpenDialog_fnGetResults(IFileOpenDialog *iface, IShellItemArray **ppenum)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
|
|
TRACE("%p (%p)\n", This, ppenum);
|
|
|
|
*ppenum = This->psia_results;
|
|
|
|
if(*ppenum)
|
|
{
|
|
IShellItemArray_AddRef(*ppenum);
|
|
return S_OK;
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileOpenDialog_fnGetSelectedItems(IFileOpenDialog *iface, IShellItemArray **ppsai)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileOpenDialog(iface);
|
|
TRACE("%p (%p)\n", This, ppsai);
|
|
|
|
if(This->psia_selection)
|
|
{
|
|
*ppsai = This->psia_selection;
|
|
IShellItemArray_AddRef(*ppsai);
|
|
return S_OK;
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
static const IFileOpenDialogVtbl vt_IFileOpenDialog = {
|
|
IFileOpenDialog_fnQueryInterface,
|
|
IFileOpenDialog_fnAddRef,
|
|
IFileOpenDialog_fnRelease,
|
|
IFileOpenDialog_fnShow,
|
|
IFileOpenDialog_fnSetFileTypes,
|
|
IFileOpenDialog_fnSetFileTypeIndex,
|
|
IFileOpenDialog_fnGetFileTypeIndex,
|
|
IFileOpenDialog_fnAdvise,
|
|
IFileOpenDialog_fnUnadvise,
|
|
IFileOpenDialog_fnSetOptions,
|
|
IFileOpenDialog_fnGetOptions,
|
|
IFileOpenDialog_fnSetDefaultFolder,
|
|
IFileOpenDialog_fnSetFolder,
|
|
IFileOpenDialog_fnGetFolder,
|
|
IFileOpenDialog_fnGetCurrentSelection,
|
|
IFileOpenDialog_fnSetFileName,
|
|
IFileOpenDialog_fnGetFileName,
|
|
IFileOpenDialog_fnSetTitle,
|
|
IFileOpenDialog_fnSetOkButtonLabel,
|
|
IFileOpenDialog_fnSetFileNameLabel,
|
|
IFileOpenDialog_fnGetResult,
|
|
IFileOpenDialog_fnAddPlace,
|
|
IFileOpenDialog_fnSetDefaultExtension,
|
|
IFileOpenDialog_fnClose,
|
|
IFileOpenDialog_fnSetClientGuid,
|
|
IFileOpenDialog_fnClearClientData,
|
|
IFileOpenDialog_fnSetFilter,
|
|
IFileOpenDialog_fnGetResults,
|
|
IFileOpenDialog_fnGetSelectedItems
|
|
};
|
|
|
|
/**************************************************************************
|
|
* IFileSaveDialog
|
|
*/
|
|
static inline FileDialogImpl *impl_from_IFileSaveDialog(IFileSaveDialog *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, FileDialogImpl, u.IFileSaveDialog_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnQueryInterface(IFileSaveDialog *iface,
|
|
REFIID riid,
|
|
void **ppvObject)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
|
|
}
|
|
|
|
static ULONG WINAPI IFileSaveDialog_fnAddRef(IFileSaveDialog *iface)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
return IFileDialog2_AddRef(&This->IFileDialog2_iface);
|
|
}
|
|
|
|
static ULONG WINAPI IFileSaveDialog_fnRelease(IFileSaveDialog *iface)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
return IFileDialog2_Release(&This->IFileDialog2_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnShow(IFileSaveDialog *iface, HWND hwndOwner)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
return IFileDialog2_Show(&This->IFileDialog2_iface, hwndOwner);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnSetFileTypes(IFileSaveDialog *iface, UINT cFileTypes,
|
|
const COMDLG_FILTERSPEC *rgFilterSpec)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
return IFileDialog2_SetFileTypes(&This->IFileDialog2_iface, cFileTypes, rgFilterSpec);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnSetFileTypeIndex(IFileSaveDialog *iface, UINT iFileType)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
return IFileDialog2_SetFileTypeIndex(&This->IFileDialog2_iface, iFileType);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnGetFileTypeIndex(IFileSaveDialog *iface, UINT *piFileType)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
return IFileDialog2_GetFileTypeIndex(&This->IFileDialog2_iface, piFileType);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnAdvise(IFileSaveDialog *iface, IFileDialogEvents *pfde,
|
|
DWORD *pdwCookie)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
return IFileDialog2_Advise(&This->IFileDialog2_iface, pfde, pdwCookie);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnUnadvise(IFileSaveDialog *iface, DWORD dwCookie)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
return IFileDialog2_Unadvise(&This->IFileDialog2_iface, dwCookie);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnSetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS fos)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
return IFileDialog2_SetOptions(&This->IFileDialog2_iface, fos);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnGetOptions(IFileSaveDialog *iface, FILEOPENDIALOGOPTIONS *pfos)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
return IFileDialog2_GetOptions(&This->IFileDialog2_iface, pfos);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnSetDefaultFolder(IFileSaveDialog *iface, IShellItem *psi)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
return IFileDialog2_SetDefaultFolder(&This->IFileDialog2_iface, psi);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnSetFolder(IFileSaveDialog *iface, IShellItem *psi)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
return IFileDialog2_SetFolder(&This->IFileDialog2_iface, psi);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnGetFolder(IFileSaveDialog *iface, IShellItem **ppsi)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
return IFileDialog2_GetFolder(&This->IFileDialog2_iface, ppsi);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnGetCurrentSelection(IFileSaveDialog *iface, IShellItem **ppsi)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
return IFileDialog2_GetCurrentSelection(&This->IFileDialog2_iface, ppsi);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnSetFileName(IFileSaveDialog *iface, LPCWSTR pszName)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
return IFileDialog2_SetFileName(&This->IFileDialog2_iface, pszName);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnGetFileName(IFileSaveDialog *iface, LPWSTR *pszName)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
return IFileDialog2_GetFileName(&This->IFileDialog2_iface, pszName);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnSetTitle(IFileSaveDialog *iface, LPCWSTR pszTitle)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
return IFileDialog2_SetTitle(&This->IFileDialog2_iface, pszTitle);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnSetOkButtonLabel(IFileSaveDialog *iface, LPCWSTR pszText)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
return IFileDialog2_SetOkButtonLabel(&This->IFileDialog2_iface, pszText);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnSetFileNameLabel(IFileSaveDialog *iface, LPCWSTR pszLabel)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
return IFileDialog2_SetFileNameLabel(&This->IFileDialog2_iface, pszLabel);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnGetResult(IFileSaveDialog *iface, IShellItem **ppsi)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
return IFileDialog2_GetResult(&This->IFileDialog2_iface, ppsi);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnAddPlace(IFileSaveDialog *iface, IShellItem *psi, FDAP fdap)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
return IFileDialog2_AddPlace(&This->IFileDialog2_iface, psi, fdap);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnSetDefaultExtension(IFileSaveDialog *iface,
|
|
LPCWSTR pszDefaultExtension)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
return IFileDialog2_SetDefaultExtension(&This->IFileDialog2_iface, pszDefaultExtension);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnClose(IFileSaveDialog *iface, HRESULT hr)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
return IFileDialog2_Close(&This->IFileDialog2_iface, hr);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnSetClientGuid(IFileSaveDialog *iface, REFGUID guid)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
return IFileDialog2_SetClientGuid(&This->IFileDialog2_iface, guid);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnClearClientData(IFileSaveDialog *iface)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
return IFileDialog2_ClearClientData(&This->IFileDialog2_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnSetFilter(IFileSaveDialog *iface, IShellItemFilter *pFilter)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
return IFileDialog2_SetFilter(&This->IFileDialog2_iface, pFilter);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnSetSaveAsItem(IFileSaveDialog* iface, IShellItem *psi)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
FIXME("stub - %p (%p)\n", This, psi);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnSetProperties(IFileSaveDialog* iface, IPropertyStore *pStore)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
FIXME("stub - %p (%p)\n", This, pStore);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnSetCollectedProperties(IFileSaveDialog* iface,
|
|
IPropertyDescriptionList *pList,
|
|
BOOL fAppendDefault)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
FIXME("stub - %p (%p, %d)\n", This, pList, fAppendDefault);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnGetProperties(IFileSaveDialog* iface, IPropertyStore **ppStore)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
FIXME("stub - %p (%p)\n", This, ppStore);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileSaveDialog_fnApplyProperties(IFileSaveDialog* iface,
|
|
IShellItem *psi,
|
|
IPropertyStore *pStore,
|
|
HWND hwnd,
|
|
IFileOperationProgressSink *pSink)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileSaveDialog(iface);
|
|
FIXME("%p (%p, %p, %p, %p)\n", This, psi, pStore, hwnd, pSink);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static const IFileSaveDialogVtbl vt_IFileSaveDialog = {
|
|
IFileSaveDialog_fnQueryInterface,
|
|
IFileSaveDialog_fnAddRef,
|
|
IFileSaveDialog_fnRelease,
|
|
IFileSaveDialog_fnShow,
|
|
IFileSaveDialog_fnSetFileTypes,
|
|
IFileSaveDialog_fnSetFileTypeIndex,
|
|
IFileSaveDialog_fnGetFileTypeIndex,
|
|
IFileSaveDialog_fnAdvise,
|
|
IFileSaveDialog_fnUnadvise,
|
|
IFileSaveDialog_fnSetOptions,
|
|
IFileSaveDialog_fnGetOptions,
|
|
IFileSaveDialog_fnSetDefaultFolder,
|
|
IFileSaveDialog_fnSetFolder,
|
|
IFileSaveDialog_fnGetFolder,
|
|
IFileSaveDialog_fnGetCurrentSelection,
|
|
IFileSaveDialog_fnSetFileName,
|
|
IFileSaveDialog_fnGetFileName,
|
|
IFileSaveDialog_fnSetTitle,
|
|
IFileSaveDialog_fnSetOkButtonLabel,
|
|
IFileSaveDialog_fnSetFileNameLabel,
|
|
IFileSaveDialog_fnGetResult,
|
|
IFileSaveDialog_fnAddPlace,
|
|
IFileSaveDialog_fnSetDefaultExtension,
|
|
IFileSaveDialog_fnClose,
|
|
IFileSaveDialog_fnSetClientGuid,
|
|
IFileSaveDialog_fnClearClientData,
|
|
IFileSaveDialog_fnSetFilter,
|
|
IFileSaveDialog_fnSetSaveAsItem,
|
|
IFileSaveDialog_fnSetProperties,
|
|
IFileSaveDialog_fnSetCollectedProperties,
|
|
IFileSaveDialog_fnGetProperties,
|
|
IFileSaveDialog_fnApplyProperties
|
|
};
|
|
|
|
/**************************************************************************
|
|
* IExplorerBrowserEvents implementation
|
|
*/
|
|
static inline FileDialogImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, FileDialogImpl, IExplorerBrowserEvents_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI IExplorerBrowserEvents_fnQueryInterface(IExplorerBrowserEvents *iface,
|
|
REFIID riid, void **ppvObject)
|
|
{
|
|
FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
|
|
TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject);
|
|
|
|
return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
|
|
}
|
|
|
|
static ULONG WINAPI IExplorerBrowserEvents_fnAddRef(IExplorerBrowserEvents *iface)
|
|
{
|
|
FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
|
|
TRACE("%p\n", This);
|
|
return IFileDialog2_AddRef(&This->IFileDialog2_iface);
|
|
}
|
|
|
|
static ULONG WINAPI IExplorerBrowserEvents_fnRelease(IExplorerBrowserEvents *iface)
|
|
{
|
|
FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
|
|
TRACE("%p\n", This);
|
|
return IFileDialog2_Release(&This->IFileDialog2_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationPending(IExplorerBrowserEvents *iface,
|
|
PCIDLIST_ABSOLUTE pidlFolder)
|
|
{
|
|
FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
|
|
IShellItem *psi;
|
|
HRESULT hr;
|
|
TRACE("%p (%p)\n", This, pidlFolder);
|
|
|
|
hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&psi);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
hr = events_OnFolderChanging(This, psi);
|
|
IShellItem_Release(psi);
|
|
|
|
/* The ExplorerBrowser treats S_FALSE as S_OK, we don't. */
|
|
if(hr == S_FALSE)
|
|
hr = E_FAIL;
|
|
|
|
return hr;
|
|
}
|
|
else
|
|
ERR("Failed to convert pidl (%p) to a shellitem.\n", pidlFolder);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IExplorerBrowserEvents_fnOnViewCreated(IExplorerBrowserEvents *iface,
|
|
IShellView *psv)
|
|
{
|
|
FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
|
|
TRACE("%p (%p)\n", This, psv);
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationComplete(IExplorerBrowserEvents *iface,
|
|
PCIDLIST_ABSOLUTE pidlFolder)
|
|
{
|
|
FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
|
|
HRESULT hr;
|
|
TRACE("%p (%p)\n", This, pidlFolder);
|
|
|
|
if(This->psi_folder)
|
|
IShellItem_Release(This->psi_folder);
|
|
|
|
hr = SHCreateItemFromIDList(pidlFolder, &IID_IShellItem, (void**)&This->psi_folder);
|
|
if(FAILED(hr))
|
|
{
|
|
ERR("Failed to get the current folder.\n");
|
|
This->psi_folder = NULL;
|
|
}
|
|
|
|
events_OnFolderChange(This);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationFailed(IExplorerBrowserEvents *iface,
|
|
PCIDLIST_ABSOLUTE pidlFolder)
|
|
{
|
|
FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface);
|
|
TRACE("%p (%p)\n", This, pidlFolder);
|
|
return S_OK;
|
|
}
|
|
|
|
static const IExplorerBrowserEventsVtbl vt_IExplorerBrowserEvents = {
|
|
IExplorerBrowserEvents_fnQueryInterface,
|
|
IExplorerBrowserEvents_fnAddRef,
|
|
IExplorerBrowserEvents_fnRelease,
|
|
IExplorerBrowserEvents_fnOnNavigationPending,
|
|
IExplorerBrowserEvents_fnOnViewCreated,
|
|
IExplorerBrowserEvents_fnOnNavigationComplete,
|
|
IExplorerBrowserEvents_fnOnNavigationFailed
|
|
};
|
|
|
|
/**************************************************************************
|
|
* IServiceProvider implementation
|
|
*/
|
|
static inline FileDialogImpl *impl_from_IServiceProvider(IServiceProvider *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, FileDialogImpl, IServiceProvider_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI IServiceProvider_fnQueryInterface(IServiceProvider *iface,
|
|
REFIID riid, void **ppvObject)
|
|
{
|
|
FileDialogImpl *This = impl_from_IServiceProvider(iface);
|
|
TRACE("%p\n", This);
|
|
return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
|
|
}
|
|
|
|
static ULONG WINAPI IServiceProvider_fnAddRef(IServiceProvider *iface)
|
|
{
|
|
FileDialogImpl *This = impl_from_IServiceProvider(iface);
|
|
TRACE("%p\n", This);
|
|
return IFileDialog2_AddRef(&This->IFileDialog2_iface);
|
|
}
|
|
|
|
static ULONG WINAPI IServiceProvider_fnRelease(IServiceProvider *iface)
|
|
{
|
|
FileDialogImpl *This = impl_from_IServiceProvider(iface);
|
|
TRACE("%p\n", This);
|
|
return IFileDialog2_Release(&This->IFileDialog2_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI IServiceProvider_fnQueryService(IServiceProvider *iface,
|
|
REFGUID guidService,
|
|
REFIID riid, void **ppv)
|
|
{
|
|
FileDialogImpl *This = impl_from_IServiceProvider(iface);
|
|
HRESULT hr = E_NOTIMPL;
|
|
TRACE("%p (%s, %s, %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
|
|
|
|
*ppv = NULL;
|
|
if(IsEqualGUID(guidService, &SID_STopLevelBrowser) && This->peb)
|
|
hr = IExplorerBrowser_QueryInterface(This->peb, riid, ppv);
|
|
else if(IsEqualGUID(guidService, &SID_SExplorerBrowserFrame))
|
|
hr = IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppv);
|
|
else
|
|
FIXME("Interface %s requested from unknown service %s\n",
|
|
debugstr_guid(riid), debugstr_guid(guidService));
|
|
|
|
return hr;
|
|
}
|
|
|
|
static const IServiceProviderVtbl vt_IServiceProvider = {
|
|
IServiceProvider_fnQueryInterface,
|
|
IServiceProvider_fnAddRef,
|
|
IServiceProvider_fnRelease,
|
|
IServiceProvider_fnQueryService
|
|
};
|
|
|
|
/**************************************************************************
|
|
* ICommDlgBrowser3 implementation
|
|
*/
|
|
static inline FileDialogImpl *impl_from_ICommDlgBrowser3(ICommDlgBrowser3 *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, FileDialogImpl, ICommDlgBrowser3_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI ICommDlgBrowser3_fnQueryInterface(ICommDlgBrowser3 *iface,
|
|
REFIID riid, void **ppvObject)
|
|
{
|
|
FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
|
|
TRACE("%p\n", This);
|
|
return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
|
|
}
|
|
|
|
static ULONG WINAPI ICommDlgBrowser3_fnAddRef(ICommDlgBrowser3 *iface)
|
|
{
|
|
FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
|
|
TRACE("%p\n", This);
|
|
return IFileDialog2_AddRef(&This->IFileDialog2_iface);
|
|
}
|
|
|
|
static ULONG WINAPI ICommDlgBrowser3_fnRelease(ICommDlgBrowser3 *iface)
|
|
{
|
|
FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
|
|
TRACE("%p\n", This);
|
|
return IFileDialog2_Release(&This->IFileDialog2_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI ICommDlgBrowser3_fnOnDefaultCommand(ICommDlgBrowser3 *iface,
|
|
IShellView *shv)
|
|
{
|
|
FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
|
|
HRESULT hr;
|
|
TRACE("%p (%p)\n", This, shv);
|
|
|
|
hr = on_default_action(This);
|
|
|
|
if(SUCCEEDED(hr))
|
|
EndDialog(This->dlg_hwnd, S_OK);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICommDlgBrowser3_fnOnStateChange(ICommDlgBrowser3 *iface,
|
|
IShellView *shv, ULONG uChange )
|
|
{
|
|
FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
|
|
IDataObject *new_selection;
|
|
HRESULT hr;
|
|
TRACE("%p (%p, %x)\n", This, shv, uChange);
|
|
|
|
switch(uChange)
|
|
{
|
|
case CDBOSC_SELCHANGE:
|
|
if(This->psia_selection)
|
|
{
|
|
IShellItemArray_Release(This->psia_selection);
|
|
This->psia_selection = NULL;
|
|
}
|
|
|
|
hr = IShellView_GetItemObject(shv, SVGIO_SELECTION, &IID_IDataObject, (void**)&new_selection);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
hr = SHCreateShellItemArrayFromDataObject(new_selection, &IID_IShellItemArray,
|
|
(void**)&This->psia_selection);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
fill_filename_from_selection(This);
|
|
events_OnSelectionChange(This);
|
|
}
|
|
|
|
IDataObject_Release(new_selection);
|
|
}
|
|
break;
|
|
default:
|
|
TRACE("Unhandled state change\n");
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI ICommDlgBrowser3_fnIncludeObject(ICommDlgBrowser3 *iface,
|
|
IShellView *shv, LPCITEMIDLIST pidl)
|
|
{
|
|
FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
|
|
IShellItem *psi;
|
|
LPWSTR filename;
|
|
LPITEMIDLIST parent_pidl;
|
|
HRESULT hr;
|
|
ULONG attr;
|
|
TRACE("%p (%p, %p)\n", This, shv, pidl);
|
|
|
|
if(!This->filterspec_count && !(This->options & FOS_PICKFOLDERS))
|
|
return S_OK;
|
|
|
|
hr = SHGetIDListFromObject((IUnknown*)shv, &parent_pidl);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
LPITEMIDLIST full_pidl = ILCombine(parent_pidl, pidl);
|
|
hr = SHCreateItemFromIDList(full_pidl, &IID_IShellItem, (void**)&psi);
|
|
ILFree(parent_pidl);
|
|
ILFree(full_pidl);
|
|
}
|
|
if(FAILED(hr))
|
|
{
|
|
ERR("Failed to get shellitem (%08x).\n", hr);
|
|
return S_OK;
|
|
}
|
|
|
|
hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER|SFGAO_LINK, &attr);
|
|
if(FAILED(hr) || (attr & (SFGAO_FOLDER | SFGAO_LINK)))
|
|
{
|
|
IShellItem_Release(psi);
|
|
return S_OK;
|
|
}
|
|
|
|
if((This->options & FOS_PICKFOLDERS) && !(attr & (SFGAO_FOLDER | SFGAO_LINK)))
|
|
{
|
|
IShellItem_Release(psi);
|
|
return S_FALSE;
|
|
}
|
|
|
|
hr = S_OK;
|
|
if(SUCCEEDED(IShellItem_GetDisplayName(psi, SIGDN_PARENTRELATIVEPARSING, &filename)))
|
|
{
|
|
if(!PathMatchSpecW(filename, This->filterspecs[This->filetypeindex].pszSpec))
|
|
hr = S_FALSE;
|
|
CoTaskMemFree(filename);
|
|
}
|
|
|
|
IShellItem_Release(psi);
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI ICommDlgBrowser3_fnNotify(ICommDlgBrowser3 *iface,
|
|
IShellView *ppshv, DWORD dwNotifyType)
|
|
{
|
|
FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
|
|
FIXME("Stub: %p (%p, 0x%x)\n", This, ppshv, dwNotifyType);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI ICommDlgBrowser3_fnGetDefaultMenuText(ICommDlgBrowser3 *iface,
|
|
IShellView *pshv,
|
|
LPWSTR pszText, int cchMax)
|
|
{
|
|
FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
|
|
FIXME("Stub: %p (%p, %p, %d)\n", This, pshv, pszText, cchMax);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI ICommDlgBrowser3_fnGetViewFlags(ICommDlgBrowser3 *iface, DWORD *pdwFlags)
|
|
{
|
|
FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
|
|
FIXME("Stub: %p (%p)\n", This, pdwFlags);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI ICommDlgBrowser3_fnOnColumnClicked(ICommDlgBrowser3 *iface,
|
|
IShellView *pshv, int iColumn)
|
|
{
|
|
FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
|
|
FIXME("Stub: %p (%p, %d)\n", This, pshv, iColumn);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI ICommDlgBrowser3_fnGetCurrentFilter(ICommDlgBrowser3 *iface,
|
|
LPWSTR pszFileSpec, int cchFileSpec)
|
|
{
|
|
FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
|
|
FIXME("Stub: %p (%p, %d)\n", This, pszFileSpec, cchFileSpec);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI ICommDlgBrowser3_fnOnPreviewCreated(ICommDlgBrowser3 *iface,
|
|
IShellView *pshv)
|
|
{
|
|
FileDialogImpl *This = impl_from_ICommDlgBrowser3(iface);
|
|
FIXME("Stub: %p (%p)\n", This, pshv);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static const ICommDlgBrowser3Vtbl vt_ICommDlgBrowser3 = {
|
|
ICommDlgBrowser3_fnQueryInterface,
|
|
ICommDlgBrowser3_fnAddRef,
|
|
ICommDlgBrowser3_fnRelease,
|
|
ICommDlgBrowser3_fnOnDefaultCommand,
|
|
ICommDlgBrowser3_fnOnStateChange,
|
|
ICommDlgBrowser3_fnIncludeObject,
|
|
ICommDlgBrowser3_fnNotify,
|
|
ICommDlgBrowser3_fnGetDefaultMenuText,
|
|
ICommDlgBrowser3_fnGetViewFlags,
|
|
ICommDlgBrowser3_fnOnColumnClicked,
|
|
ICommDlgBrowser3_fnGetCurrentFilter,
|
|
ICommDlgBrowser3_fnOnPreviewCreated
|
|
};
|
|
|
|
/**************************************************************************
|
|
* IOleWindow implementation
|
|
*/
|
|
static inline FileDialogImpl *impl_from_IOleWindow(IOleWindow *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, FileDialogImpl, IOleWindow_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI IOleWindow_fnQueryInterface(IOleWindow *iface, REFIID riid, void **ppvObject)
|
|
{
|
|
FileDialogImpl *This = impl_from_IOleWindow(iface);
|
|
return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
|
|
}
|
|
|
|
static ULONG WINAPI IOleWindow_fnAddRef(IOleWindow *iface)
|
|
{
|
|
FileDialogImpl *This = impl_from_IOleWindow(iface);
|
|
return IFileDialog2_AddRef(&This->IFileDialog2_iface);
|
|
}
|
|
|
|
static ULONG WINAPI IOleWindow_fnRelease(IOleWindow *iface)
|
|
{
|
|
FileDialogImpl *This = impl_from_IOleWindow(iface);
|
|
return IFileDialog2_Release(&This->IFileDialog2_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI IOleWindow_fnContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMOde)
|
|
{
|
|
FileDialogImpl *This = impl_from_IOleWindow(iface);
|
|
FIXME("Stub: %p (%d)\n", This, fEnterMOde);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI IOleWindow_fnGetWindow(IOleWindow *iface, HWND *phwnd)
|
|
{
|
|
FileDialogImpl *This = impl_from_IOleWindow(iface);
|
|
TRACE("%p (%p)\n", This, phwnd);
|
|
*phwnd = This->dlg_hwnd;
|
|
return S_OK;
|
|
}
|
|
|
|
static const IOleWindowVtbl vt_IOleWindow = {
|
|
IOleWindow_fnQueryInterface,
|
|
IOleWindow_fnAddRef,
|
|
IOleWindow_fnRelease,
|
|
IOleWindow_fnGetWindow,
|
|
IOleWindow_fnContextSensitiveHelp
|
|
};
|
|
|
|
/**************************************************************************
|
|
* IFileDialogCustomize implementation
|
|
*/
|
|
static inline FileDialogImpl *impl_from_IFileDialogCustomize(IFileDialogCustomize *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, FileDialogImpl, IFileDialogCustomize_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialogCustomize_fnQueryInterface(IFileDialogCustomize *iface,
|
|
REFIID riid, void **ppvObject)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
return IFileDialog2_QueryInterface(&This->IFileDialog2_iface, riid, ppvObject);
|
|
}
|
|
|
|
static ULONG WINAPI IFileDialogCustomize_fnAddRef(IFileDialogCustomize *iface)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
return IFileDialog2_AddRef(&This->IFileDialog2_iface);
|
|
}
|
|
|
|
static ULONG WINAPI IFileDialogCustomize_fnRelease(IFileDialogCustomize *iface)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
return IFileDialog2_Release(&This->IFileDialog2_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialogCustomize_fnEnableOpenDropDown(IFileDialogCustomize *iface,
|
|
DWORD dwIDCtl)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
MENUINFO mi;
|
|
TRACE("%p (%d)\n", This, dwIDCtl);
|
|
|
|
if (This->hmenu_opendropdown || get_cctrl(This, dwIDCtl))
|
|
return E_UNEXPECTED;
|
|
|
|
This->hmenu_opendropdown = CreatePopupMenu();
|
|
|
|
if (!This->hmenu_opendropdown)
|
|
return E_OUTOFMEMORY;
|
|
|
|
mi.cbSize = sizeof(mi);
|
|
mi.fMask = MIM_STYLE;
|
|
mi.dwStyle = MNS_NOTIFYBYPOS;
|
|
SetMenuInfo(This->hmenu_opendropdown, &mi);
|
|
|
|
This->cctrl_opendropdown.hwnd = NULL;
|
|
This->cctrl_opendropdown.wrapper_hwnd = NULL;
|
|
This->cctrl_opendropdown.id = dwIDCtl;
|
|
This->cctrl_opendropdown.dlgid = 0;
|
|
This->cctrl_opendropdown.type = IDLG_CCTRL_OPENDROPDOWN;
|
|
This->cctrl_opendropdown.cdcstate = CDCS_ENABLED | CDCS_VISIBLE;
|
|
list_init(&This->cctrl_opendropdown.sub_cctrls);
|
|
list_init(&This->cctrl_opendropdown.sub_items);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialogCustomize_fnAddMenu(IFileDialogCustomize *iface,
|
|
DWORD dwIDCtl,
|
|
LPCWSTR pszLabel)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
customctrl *ctrl;
|
|
TBBUTTON tbb;
|
|
HRESULT hr;
|
|
TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
|
|
|
|
hr = cctrl_create_new(This, dwIDCtl, NULL, TOOLBARCLASSNAMEW,
|
|
TBSTYLE_FLAT | CCS_NODIVIDER, 0,
|
|
This->cctrl_def_height, &ctrl);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
SendMessageW(ctrl->hwnd, TB_BUTTONSTRUCTSIZE, sizeof(tbb), 0);
|
|
ctrl->type = IDLG_CCTRL_MENU;
|
|
|
|
/* Add the actual button with a popup menu. */
|
|
tbb.iBitmap = I_IMAGENONE;
|
|
tbb.dwData = (DWORD_PTR)CreatePopupMenu();
|
|
tbb.iString = (DWORD_PTR)pszLabel;
|
|
tbb.fsState = TBSTATE_ENABLED;
|
|
tbb.fsStyle = BTNS_WHOLEDROPDOWN;
|
|
tbb.idCommand = 1;
|
|
|
|
SendMessageW(ctrl->hwnd, TB_ADDBUTTONSW, 1, (LPARAM)&tbb);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialogCustomize_fnAddPushButton(IFileDialogCustomize *iface,
|
|
DWORD dwIDCtl,
|
|
LPCWSTR pszLabel)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
customctrl *ctrl;
|
|
HRESULT hr;
|
|
TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
|
|
|
|
hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_MULTILINE, 0,
|
|
This->cctrl_def_height, &ctrl);
|
|
if(SUCCEEDED(hr))
|
|
ctrl->type = IDLG_CCTRL_PUSHBUTTON;
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialogCustomize_fnAddComboBox(IFileDialogCustomize *iface,
|
|
DWORD dwIDCtl)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
customctrl *ctrl;
|
|
HRESULT hr;
|
|
TRACE("%p (%d)\n", This, dwIDCtl);
|
|
|
|
hr = cctrl_create_new(This, dwIDCtl, NULL, WC_COMBOBOXW, CBS_DROPDOWNLIST, 0,
|
|
This->cctrl_def_height, &ctrl);
|
|
if(SUCCEEDED(hr))
|
|
ctrl->type = IDLG_CCTRL_COMBOBOX;
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialogCustomize_fnAddRadioButtonList(IFileDialogCustomize *iface,
|
|
DWORD dwIDCtl)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
customctrl *ctrl;
|
|
HRESULT hr;
|
|
TRACE("%p (%d)\n", This, dwIDCtl);
|
|
|
|
hr = cctrl_create_new(This, dwIDCtl, NULL, radiobuttonlistW, 0, 0, 0, &ctrl);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
ctrl->type = IDLG_CCTRL_RADIOBUTTONLIST;
|
|
SetWindowLongPtrW(ctrl->hwnd, GWLP_USERDATA, (LPARAM)This);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialogCustomize_fnAddCheckButton(IFileDialogCustomize *iface,
|
|
DWORD dwIDCtl,
|
|
LPCWSTR pszLabel,
|
|
BOOL bChecked)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
customctrl *ctrl;
|
|
HRESULT hr;
|
|
TRACE("%p (%d, %p, %d)\n", This, dwIDCtl, pszLabel, bChecked);
|
|
|
|
hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_BUTTONW, BS_AUTOCHECKBOX|BS_MULTILINE, 0,
|
|
This->cctrl_def_height, &ctrl);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
ctrl->type = IDLG_CCTRL_CHECKBUTTON;
|
|
SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialogCustomize_fnAddEditBox(IFileDialogCustomize *iface,
|
|
DWORD dwIDCtl,
|
|
LPCWSTR pszText)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
customctrl *ctrl;
|
|
HRESULT hr;
|
|
TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText);
|
|
|
|
hr = cctrl_create_new(This, dwIDCtl, pszText, WC_EDITW, ES_AUTOHSCROLL, WS_EX_CLIENTEDGE,
|
|
This->cctrl_def_height, &ctrl);
|
|
if(SUCCEEDED(hr))
|
|
ctrl->type = IDLG_CCTRL_EDITBOX;
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialogCustomize_fnAddSeparator(IFileDialogCustomize *iface,
|
|
DWORD dwIDCtl)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
customctrl *ctrl;
|
|
HRESULT hr;
|
|
TRACE("%p (%d)\n", This, dwIDCtl);
|
|
|
|
hr = cctrl_create_new(This, dwIDCtl, NULL, WC_STATICW, SS_ETCHEDHORZ, 0,
|
|
GetSystemMetrics(SM_CYEDGE), &ctrl);
|
|
if(SUCCEEDED(hr))
|
|
ctrl->type = IDLG_CCTRL_SEPARATOR;
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialogCustomize_fnAddText(IFileDialogCustomize *iface,
|
|
DWORD dwIDCtl,
|
|
LPCWSTR pszText)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
customctrl *ctrl;
|
|
HRESULT hr;
|
|
TRACE("%p (%d, %p)\n", This, dwIDCtl, pszText);
|
|
|
|
hr = cctrl_create_new(This, dwIDCtl, pszText, WC_STATICW, 0, 0,
|
|
This->cctrl_def_height, &ctrl);
|
|
if(SUCCEEDED(hr))
|
|
ctrl->type = IDLG_CCTRL_TEXT;
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialogCustomize_fnSetControlLabel(IFileDialogCustomize *iface,
|
|
DWORD dwIDCtl,
|
|
LPCWSTR pszLabel)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
customctrl *ctrl = get_cctrl(This, dwIDCtl);
|
|
TRACE("%p (%d, %p)\n", This, dwIDCtl, pszLabel);
|
|
|
|
if(!ctrl) return E_INVALIDARG;
|
|
|
|
switch(ctrl->type)
|
|
{
|
|
case IDLG_CCTRL_MENU:
|
|
case IDLG_CCTRL_PUSHBUTTON:
|
|
case IDLG_CCTRL_CHECKBUTTON:
|
|
case IDLG_CCTRL_TEXT:
|
|
case IDLG_CCTRL_VISUALGROUP:
|
|
SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszLabel);
|
|
break;
|
|
case IDLG_CCTRL_OPENDROPDOWN:
|
|
return E_NOTIMPL;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialogCustomize_fnGetControlState(IFileDialogCustomize *iface,
|
|
DWORD dwIDCtl,
|
|
CDCONTROLSTATEF *pdwState)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
customctrl *ctrl = get_cctrl(This, dwIDCtl);
|
|
TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwState);
|
|
|
|
if(!ctrl || ctrl->type == IDLG_CCTRL_OPENDROPDOWN) return E_NOTIMPL;
|
|
|
|
*pdwState = ctrl->cdcstate;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialogCustomize_fnSetControlState(IFileDialogCustomize *iface,
|
|
DWORD dwIDCtl,
|
|
CDCONTROLSTATEF dwState)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
customctrl *ctrl = get_cctrl(This,dwIDCtl);
|
|
TRACE("%p (%d, %x)\n", This, dwIDCtl, dwState);
|
|
|
|
if(ctrl && ctrl->hwnd)
|
|
{
|
|
LONG wndstyle = GetWindowLongW(ctrl->hwnd, GWL_STYLE);
|
|
|
|
if(dwState & CDCS_ENABLED)
|
|
wndstyle &= ~(WS_DISABLED);
|
|
else
|
|
wndstyle |= WS_DISABLED;
|
|
|
|
if(dwState & CDCS_VISIBLE)
|
|
wndstyle |= WS_VISIBLE;
|
|
else
|
|
wndstyle &= ~(WS_VISIBLE);
|
|
|
|
SetWindowLongW(ctrl->hwnd, GWL_STYLE, wndstyle);
|
|
|
|
/* We save the state separately since at least one application
|
|
* relies on being able to hide a control. */
|
|
ctrl->cdcstate = dwState;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialogCustomize_fnGetEditBoxText(IFileDialogCustomize *iface,
|
|
DWORD dwIDCtl,
|
|
WCHAR **ppszText)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
customctrl *ctrl = get_cctrl(This, dwIDCtl);
|
|
WCHAR len, *text;
|
|
TRACE("%p (%d, %p)\n", This, dwIDCtl, ppszText);
|
|
|
|
if(!ctrl || !ctrl->hwnd || !(len = SendMessageW(ctrl->hwnd, WM_GETTEXTLENGTH, 0, 0)))
|
|
return E_FAIL;
|
|
|
|
text = CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
|
|
if(!text) return E_FAIL;
|
|
|
|
SendMessageW(ctrl->hwnd, WM_GETTEXT, len+1, (LPARAM)text);
|
|
*ppszText = text;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialogCustomize_fnSetEditBoxText(IFileDialogCustomize *iface,
|
|
DWORD dwIDCtl,
|
|
LPCWSTR pszText)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
customctrl *ctrl = get_cctrl(This, dwIDCtl);
|
|
TRACE("%p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszText));
|
|
|
|
if(!ctrl || ctrl->type != IDLG_CCTRL_EDITBOX)
|
|
return E_FAIL;
|
|
|
|
SendMessageW(ctrl->hwnd, WM_SETTEXT, 0, (LPARAM)pszText);
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialogCustomize_fnGetCheckButtonState(IFileDialogCustomize *iface,
|
|
DWORD dwIDCtl,
|
|
BOOL *pbChecked)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
customctrl *ctrl = get_cctrl(This, dwIDCtl);
|
|
TRACE("%p (%d, %p)\n", This, dwIDCtl, pbChecked);
|
|
|
|
if(ctrl && ctrl->hwnd)
|
|
*pbChecked = (SendMessageW(ctrl->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialogCustomize_fnSetCheckButtonState(IFileDialogCustomize *iface,
|
|
DWORD dwIDCtl,
|
|
BOOL bChecked)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
customctrl *ctrl = get_cctrl(This, dwIDCtl);
|
|
TRACE("%p (%d, %d)\n", This, dwIDCtl, bChecked);
|
|
|
|
if(ctrl && ctrl->hwnd)
|
|
SendMessageW(ctrl->hwnd, BM_SETCHECK, bChecked ? BST_CHECKED:BST_UNCHECKED, 0);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static UINT get_combobox_index_from_id(HWND cb_hwnd, DWORD dwIDItem)
|
|
{
|
|
UINT count = SendMessageW(cb_hwnd, CB_GETCOUNT, 0, 0);
|
|
UINT i;
|
|
if(!count || (count == CB_ERR))
|
|
return -1;
|
|
|
|
for(i = 0; i < count; i++)
|
|
if(SendMessageW(cb_hwnd, CB_GETITEMDATA, i, 0) == dwIDItem)
|
|
return i;
|
|
|
|
TRACE("Item with id %d not found in combobox %p (item count: %d)\n", dwIDItem, cb_hwnd, count);
|
|
return -1;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialogCustomize_fnAddControlItem(IFileDialogCustomize *iface,
|
|
DWORD dwIDCtl,
|
|
DWORD dwIDItem,
|
|
LPCWSTR pszLabel)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
customctrl *ctrl = get_cctrl(This, dwIDCtl);
|
|
HRESULT hr;
|
|
TRACE("%p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
|
|
|
|
if(!ctrl) return E_FAIL;
|
|
|
|
switch(ctrl->type)
|
|
{
|
|
case IDLG_CCTRL_COMBOBOX:
|
|
{
|
|
UINT index;
|
|
cctrl_item* item;
|
|
|
|
hr = add_item(ctrl, dwIDItem, pszLabel, &item);
|
|
|
|
if (FAILED(hr)) return hr;
|
|
|
|
index = SendMessageW(ctrl->hwnd, CB_ADDSTRING, 0, (LPARAM)pszLabel);
|
|
SendMessageW(ctrl->hwnd, CB_SETITEMDATA, index, dwIDItem);
|
|
|
|
return S_OK;
|
|
}
|
|
case IDLG_CCTRL_MENU:
|
|
case IDLG_CCTRL_OPENDROPDOWN:
|
|
{
|
|
cctrl_item* item;
|
|
HMENU hmenu;
|
|
|
|
hr = add_item(ctrl, dwIDItem, pszLabel, &item);
|
|
|
|
if (FAILED(hr)) return hr;
|
|
|
|
if (ctrl->type == IDLG_CCTRL_MENU)
|
|
{
|
|
TBBUTTON tbb;
|
|
SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
|
|
hmenu = (HMENU)tbb.dwData;
|
|
}
|
|
else /* ctrl->type == IDLG_CCTRL_OPENDROPDOWN */
|
|
hmenu = This->hmenu_opendropdown;
|
|
|
|
AppendMenuW(hmenu, MF_STRING, dwIDItem, pszLabel);
|
|
return S_OK;
|
|
}
|
|
case IDLG_CCTRL_RADIOBUTTONLIST:
|
|
{
|
|
cctrl_item* item;
|
|
|
|
hr = add_item(ctrl, dwIDItem, pszLabel, &item);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
item->hwnd = CreateWindowExW(0, WC_BUTTONW, pszLabel,
|
|
WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|BS_RADIOBUTTON|BS_MULTILINE,
|
|
0, 0, 0, 0, ctrl->hwnd, ULongToHandle(dwIDItem), COMDLG32_hInstance, 0);
|
|
|
|
if (!item->hwnd)
|
|
{
|
|
ERR("Failed to create radio button\n");
|
|
list_remove(&item->entry);
|
|
item_free(item);
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return E_NOINTERFACE; /* win7 */
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialogCustomize_fnRemoveControlItem(IFileDialogCustomize *iface,
|
|
DWORD dwIDCtl,
|
|
DWORD dwIDItem)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
customctrl *ctrl = get_cctrl(This, dwIDCtl);
|
|
TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem);
|
|
|
|
if(!ctrl) return E_FAIL;
|
|
|
|
switch(ctrl->type)
|
|
{
|
|
case IDLG_CCTRL_COMBOBOX:
|
|
{
|
|
cctrl_item* item;
|
|
DWORD position;
|
|
|
|
item = get_item(ctrl, dwIDItem, CDCS_VISIBLE|CDCS_ENABLED, &position);
|
|
|
|
if ((item->cdcstate & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED))
|
|
{
|
|
if(SendMessageW(ctrl->hwnd, CB_DELETESTRING, position, 0) == CB_ERR)
|
|
return E_FAIL;
|
|
}
|
|
|
|
list_remove(&item->entry);
|
|
item_free(item);
|
|
|
|
return S_OK;
|
|
}
|
|
case IDLG_CCTRL_MENU:
|
|
case IDLG_CCTRL_OPENDROPDOWN:
|
|
{
|
|
HMENU hmenu;
|
|
cctrl_item* item;
|
|
|
|
item = get_item(ctrl, dwIDItem, 0, NULL);
|
|
|
|
if (!item)
|
|
return E_UNEXPECTED;
|
|
|
|
if (item->cdcstate & CDCS_VISIBLE)
|
|
{
|
|
if (ctrl->type == IDLG_CCTRL_MENU)
|
|
{
|
|
TBBUTTON tbb;
|
|
SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
|
|
hmenu = (HMENU)tbb.dwData;
|
|
}
|
|
else /* ctrl->type == IDLG_CCTRL_OPENDROPDOWN */
|
|
hmenu = This->hmenu_opendropdown;
|
|
|
|
if(!hmenu || !DeleteMenu(hmenu, dwIDItem, MF_BYCOMMAND))
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
list_remove(&item->entry);
|
|
item_free(item);
|
|
|
|
return S_OK;
|
|
}
|
|
case IDLG_CCTRL_RADIOBUTTONLIST:
|
|
{
|
|
cctrl_item* item;
|
|
|
|
item = get_item(ctrl, dwIDItem, 0, NULL);
|
|
|
|
if (!item)
|
|
return E_UNEXPECTED;
|
|
|
|
list_remove(&item->entry);
|
|
item_free(item);
|
|
|
|
return S_OK;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialogCustomize_fnRemoveAllControlItems(IFileDialogCustomize *iface,
|
|
DWORD dwIDCtl)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
TRACE("%p (%d)\n", This, dwIDCtl);
|
|
|
|
/* Not implemented by native */
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialogCustomize_fnGetControlItemState(IFileDialogCustomize *iface,
|
|
DWORD dwIDCtl,
|
|
DWORD dwIDItem,
|
|
CDCONTROLSTATEF *pdwState)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
customctrl *ctrl = get_cctrl(This, dwIDCtl);
|
|
TRACE("%p (%d, %d, %p)\n", This, dwIDCtl, dwIDItem, pdwState);
|
|
|
|
if(!ctrl) return E_FAIL;
|
|
|
|
switch(ctrl->type)
|
|
{
|
|
case IDLG_CCTRL_COMBOBOX:
|
|
case IDLG_CCTRL_MENU:
|
|
case IDLG_CCTRL_OPENDROPDOWN:
|
|
case IDLG_CCTRL_RADIOBUTTONLIST:
|
|
{
|
|
cctrl_item* item;
|
|
|
|
item = get_item(ctrl, dwIDItem, 0, NULL);
|
|
|
|
if (!item)
|
|
return E_UNEXPECTED;
|
|
|
|
*pdwState = item->cdcstate;
|
|
|
|
return S_OK;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemState(IFileDialogCustomize *iface,
|
|
DWORD dwIDCtl,
|
|
DWORD dwIDItem,
|
|
CDCONTROLSTATEF dwState)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
customctrl *ctrl = get_cctrl(This, dwIDCtl);
|
|
TRACE("%p (%d, %d, %x)\n", This, dwIDCtl, dwIDItem, dwState);
|
|
|
|
if(!ctrl) return E_FAIL;
|
|
|
|
switch(ctrl->type)
|
|
{
|
|
case IDLG_CCTRL_COMBOBOX:
|
|
{
|
|
cctrl_item* item;
|
|
BOOL visible, was_visible;
|
|
DWORD position;
|
|
|
|
item = get_item(ctrl, dwIDItem, CDCS_VISIBLE|CDCS_ENABLED, &position);
|
|
|
|
if (!item)
|
|
return E_UNEXPECTED;
|
|
|
|
visible = ((dwState & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED));
|
|
was_visible = ((item->cdcstate & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED));
|
|
|
|
if (visible && !was_visible)
|
|
{
|
|
SendMessageW(ctrl->hwnd, CB_INSERTSTRING, position, (LPARAM)item->label);
|
|
SendMessageW(ctrl->hwnd, CB_SETITEMDATA, position, dwIDItem);
|
|
}
|
|
else if (!visible && was_visible)
|
|
{
|
|
SendMessageW(ctrl->hwnd, CB_DELETESTRING, position, 0);
|
|
}
|
|
|
|
item->cdcstate = dwState;
|
|
|
|
return S_OK;
|
|
}
|
|
case IDLG_CCTRL_MENU:
|
|
case IDLG_CCTRL_OPENDROPDOWN:
|
|
{
|
|
HMENU hmenu;
|
|
cctrl_item* item;
|
|
CDCONTROLSTATEF prev_state;
|
|
DWORD position;
|
|
|
|
item = get_item(ctrl, dwIDItem, CDCS_VISIBLE, &position);
|
|
|
|
if (!item)
|
|
return E_UNEXPECTED;
|
|
|
|
prev_state = item->cdcstate;
|
|
|
|
if (ctrl->type == IDLG_CCTRL_MENU)
|
|
{
|
|
TBBUTTON tbb;
|
|
SendMessageW(ctrl->hwnd, TB_GETBUTTON, 0, (LPARAM)&tbb);
|
|
hmenu = (HMENU)tbb.dwData;
|
|
}
|
|
else /* ctrl->type == IDLG_CCTRL_OPENDROPDOWN */
|
|
hmenu = This->hmenu_opendropdown;
|
|
|
|
if (dwState & CDCS_VISIBLE)
|
|
{
|
|
if (prev_state & CDCS_VISIBLE)
|
|
{
|
|
/* change state */
|
|
EnableMenuItem(hmenu, dwIDItem,
|
|
MF_BYCOMMAND|((dwState & CDCS_ENABLED) ? MFS_ENABLED : MFS_DISABLED));
|
|
}
|
|
else
|
|
{
|
|
/* show item */
|
|
MENUITEMINFOW mii;
|
|
|
|
mii.cbSize = sizeof(mii);
|
|
mii.fMask = MIIM_ID|MIIM_STATE|MIIM_STRING;
|
|
mii.fState = (dwState & CDCS_ENABLED) ? MFS_ENABLED : MFS_DISABLED;
|
|
mii.wID = dwIDItem;
|
|
mii.dwTypeData = item->label;
|
|
|
|
InsertMenuItemW(hmenu, position, TRUE, &mii);
|
|
}
|
|
}
|
|
else if (prev_state & CDCS_VISIBLE)
|
|
{
|
|
/* hide item */
|
|
DeleteMenu(hmenu, dwIDItem, MF_BYCOMMAND);
|
|
}
|
|
|
|
item->cdcstate = dwState;
|
|
|
|
if (ctrl->type == IDLG_CCTRL_OPENDROPDOWN)
|
|
{
|
|
update_control_text(This);
|
|
update_layout(This);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
case IDLG_CCTRL_RADIOBUTTONLIST:
|
|
{
|
|
cctrl_item* item;
|
|
|
|
item = get_item(ctrl, dwIDItem, CDCS_VISIBLE, NULL);
|
|
|
|
if (!item)
|
|
return E_UNEXPECTED;
|
|
|
|
/* Oddly, native allows setting this but doesn't seem to do anything with it. */
|
|
item->cdcstate = dwState;
|
|
|
|
return S_OK;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialogCustomize_fnGetSelectedControlItem(IFileDialogCustomize *iface,
|
|
DWORD dwIDCtl,
|
|
DWORD *pdwIDItem)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
customctrl *ctrl = get_cctrl(This, dwIDCtl);
|
|
TRACE("%p (%d, %p)\n", This, dwIDCtl, pdwIDItem);
|
|
|
|
if(!ctrl) return E_FAIL;
|
|
|
|
switch(ctrl->type)
|
|
{
|
|
case IDLG_CCTRL_COMBOBOX:
|
|
{
|
|
UINT index = SendMessageW(ctrl->hwnd, CB_GETCURSEL, 0, 0);
|
|
if(index == CB_ERR)
|
|
return E_FAIL;
|
|
|
|
*pdwIDItem = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
|
|
return S_OK;
|
|
}
|
|
case IDLG_CCTRL_OPENDROPDOWN:
|
|
if (This->opendropdown_has_selection)
|
|
{
|
|
*pdwIDItem = This->opendropdown_selection;
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
/* Return first enabled item. */
|
|
cctrl_item* item = get_first_item(ctrl);
|
|
|
|
if (item)
|
|
{
|
|
*pdwIDItem = item->id;
|
|
return S_OK;
|
|
}
|
|
|
|
WARN("no enabled items in open dropdown\n");
|
|
return E_FAIL;
|
|
}
|
|
case IDLG_CCTRL_RADIOBUTTONLIST:
|
|
{
|
|
cctrl_item* item;
|
|
|
|
LIST_FOR_EACH_ENTRY(item, &ctrl->sub_items, cctrl_item, entry)
|
|
{
|
|
if (SendMessageW(item->hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED)
|
|
{
|
|
*pdwIDItem = item->id;
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
WARN("no checked items in radio button list\n");
|
|
return E_FAIL;
|
|
}
|
|
default:
|
|
FIXME("Unsupported control type %d\n", ctrl->type);
|
|
}
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialogCustomize_fnSetSelectedControlItem(IFileDialogCustomize *iface,
|
|
DWORD dwIDCtl,
|
|
DWORD dwIDItem)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
customctrl *ctrl = get_cctrl(This, dwIDCtl);
|
|
TRACE("%p (%d, %d)\n", This, dwIDCtl, dwIDItem);
|
|
|
|
if(!ctrl) return E_INVALIDARG;
|
|
|
|
switch(ctrl->type)
|
|
{
|
|
case IDLG_CCTRL_COMBOBOX:
|
|
{
|
|
UINT index = get_combobox_index_from_id(ctrl->hwnd, dwIDItem);
|
|
|
|
if(index == -1)
|
|
return E_INVALIDARG;
|
|
|
|
if(SendMessageW(ctrl->hwnd, CB_SETCURSEL, index, 0) == CB_ERR)
|
|
return E_FAIL;
|
|
|
|
return S_OK;
|
|
}
|
|
case IDLG_CCTRL_RADIOBUTTONLIST:
|
|
{
|
|
cctrl_item* item;
|
|
|
|
item = get_item(ctrl, dwIDItem, 0, NULL);
|
|
|
|
if (item)
|
|
{
|
|
radiobuttonlist_set_selected_item(This, ctrl, item);
|
|
return S_OK;
|
|
}
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
default:
|
|
FIXME("Unsupported control type %d\n", ctrl->type);
|
|
}
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialogCustomize_fnStartVisualGroup(IFileDialogCustomize *iface,
|
|
DWORD dwIDCtl,
|
|
LPCWSTR pszLabel)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
customctrl *vg;
|
|
HRESULT hr;
|
|
TRACE("%p (%d, %s)\n", This, dwIDCtl, debugstr_w(pszLabel));
|
|
|
|
if(This->cctrl_active_vg)
|
|
return E_UNEXPECTED;
|
|
|
|
hr = cctrl_create_new(This, dwIDCtl, pszLabel, WC_STATICW, 0, 0,
|
|
This->cctrl_def_height, &vg);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
vg->type = IDLG_CCTRL_VISUALGROUP;
|
|
This->cctrl_active_vg = vg;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialogCustomize_fnEndVisualGroup(IFileDialogCustomize *iface)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
TRACE("%p\n", This);
|
|
|
|
This->cctrl_active_vg = NULL;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialogCustomize_fnMakeProminent(IFileDialogCustomize *iface,
|
|
DWORD dwIDCtl)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
FIXME("stub - %p (%d)\n", This, dwIDCtl);
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IFileDialogCustomize_fnSetControlItemText(IFileDialogCustomize *iface,
|
|
DWORD dwIDCtl,
|
|
DWORD dwIDItem,
|
|
LPCWSTR pszLabel)
|
|
{
|
|
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
|
|
FIXME("stub - %p (%d, %d, %s)\n", This, dwIDCtl, dwIDItem, debugstr_w(pszLabel));
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static const IFileDialogCustomizeVtbl vt_IFileDialogCustomize = {
|
|
IFileDialogCustomize_fnQueryInterface,
|
|
IFileDialogCustomize_fnAddRef,
|
|
IFileDialogCustomize_fnRelease,
|
|
IFileDialogCustomize_fnEnableOpenDropDown,
|
|
IFileDialogCustomize_fnAddMenu,
|
|
IFileDialogCustomize_fnAddPushButton,
|
|
IFileDialogCustomize_fnAddComboBox,
|
|
IFileDialogCustomize_fnAddRadioButtonList,
|
|
IFileDialogCustomize_fnAddCheckButton,
|
|
IFileDialogCustomize_fnAddEditBox,
|
|
IFileDialogCustomize_fnAddSeparator,
|
|
IFileDialogCustomize_fnAddText,
|
|
IFileDialogCustomize_fnSetControlLabel,
|
|
IFileDialogCustomize_fnGetControlState,
|
|
IFileDialogCustomize_fnSetControlState,
|
|
IFileDialogCustomize_fnGetEditBoxText,
|
|
IFileDialogCustomize_fnSetEditBoxText,
|
|
IFileDialogCustomize_fnGetCheckButtonState,
|
|
IFileDialogCustomize_fnSetCheckButtonState,
|
|
IFileDialogCustomize_fnAddControlItem,
|
|
IFileDialogCustomize_fnRemoveControlItem,
|
|
IFileDialogCustomize_fnRemoveAllControlItems,
|
|
IFileDialogCustomize_fnGetControlItemState,
|
|
IFileDialogCustomize_fnSetControlItemState,
|
|
IFileDialogCustomize_fnGetSelectedControlItem,
|
|
IFileDialogCustomize_fnSetSelectedControlItem,
|
|
IFileDialogCustomize_fnStartVisualGroup,
|
|
IFileDialogCustomize_fnEndVisualGroup,
|
|
IFileDialogCustomize_fnMakeProminent,
|
|
IFileDialogCustomize_fnSetControlItemText
|
|
};
|
|
|
|
static HRESULT FileDialog_constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv, enum ITEMDLG_TYPE type)
|
|
{
|
|
FileDialogImpl *fdimpl;
|
|
HRESULT hr;
|
|
IShellFolder *psf;
|
|
TRACE("%p, %s, %p\n", pUnkOuter, debugstr_guid(riid), ppv);
|
|
|
|
if(!ppv)
|
|
return E_POINTER;
|
|
if(pUnkOuter)
|
|
return CLASS_E_NOAGGREGATION;
|
|
|
|
fdimpl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FileDialogImpl));
|
|
if(!fdimpl)
|
|
return E_OUTOFMEMORY;
|
|
|
|
fdimpl->ref = 1;
|
|
fdimpl->IFileDialog2_iface.lpVtbl = &vt_IFileDialog2;
|
|
fdimpl->IExplorerBrowserEvents_iface.lpVtbl = &vt_IExplorerBrowserEvents;
|
|
fdimpl->IServiceProvider_iface.lpVtbl = &vt_IServiceProvider;
|
|
fdimpl->ICommDlgBrowser3_iface.lpVtbl = &vt_ICommDlgBrowser3;
|
|
fdimpl->IOleWindow_iface.lpVtbl = &vt_IOleWindow;
|
|
fdimpl->IFileDialogCustomize_iface.lpVtbl = &vt_IFileDialogCustomize;
|
|
|
|
if(type == ITEMDLG_TYPE_OPEN)
|
|
{
|
|
fdimpl->dlg_type = ITEMDLG_TYPE_OPEN;
|
|
fdimpl->u.IFileOpenDialog_iface.lpVtbl = &vt_IFileOpenDialog;
|
|
fdimpl->options = FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_NOCHANGEDIR;
|
|
fdimpl->custom_title = fdimpl->custom_okbutton = NULL;
|
|
}
|
|
else
|
|
{
|
|
WCHAR buf[16];
|
|
fdimpl->dlg_type = ITEMDLG_TYPE_SAVE;
|
|
fdimpl->u.IFileSaveDialog_iface.lpVtbl = &vt_IFileSaveDialog;
|
|
fdimpl->options = FOS_OVERWRITEPROMPT | FOS_NOREADONLYRETURN | FOS_PATHMUSTEXIST | FOS_NOCHANGEDIR;
|
|
|
|
LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, ARRAY_SIZE(buf));
|
|
fdimpl->custom_title = StrDupW(buf);
|
|
fdimpl->custom_okbutton = StrDupW(buf);
|
|
}
|
|
|
|
list_init(&fdimpl->events_clients);
|
|
|
|
/* FIXME: The default folder setting should be restored for the
|
|
* application if it was previously set. */
|
|
SHGetDesktopFolder(&psf);
|
|
SHGetItemFromObject((IUnknown*)psf, &IID_IShellItem, (void**)&fdimpl->psi_defaultfolder);
|
|
IShellFolder_Release(psf);
|
|
|
|
hr = init_custom_controls(fdimpl);
|
|
if(FAILED(hr))
|
|
{
|
|
ERR("Failed to initialize custom controls (0x%08x).\n", hr);
|
|
IFileDialog2_Release(&fdimpl->IFileDialog2_iface);
|
|
return E_FAIL;
|
|
}
|
|
|
|
hr = IFileDialog2_QueryInterface(&fdimpl->IFileDialog2_iface, riid, ppv);
|
|
IFileDialog2_Release(&fdimpl->IFileDialog2_iface);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT FileOpenDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
|
|
{
|
|
return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_OPEN);
|
|
}
|
|
|
|
HRESULT FileSaveDialog_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
|
|
{
|
|
return FileDialog_constructor(pUnkOuter, riid, ppv, ITEMDLG_TYPE_SAVE);
|
|
}
|