mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2026-01-20 23:41:44 +01:00
JRE-1216 Implement Windows native file dialogs with the new Common Item Dialog API
Add implementation of file dialogs with the new Common Items Dialog API
(cherry picked from commit e2fb4ced09)
This commit is contained in:
committed by
Nikita Gubarkov
parent
72a9ce1b0c
commit
5e1bd422fa
@@ -95,6 +95,10 @@ final class WFileDialogPeer extends WWindowPeer implements FileDialogPeer {
|
||||
_dispose();
|
||||
}
|
||||
|
||||
private static boolean useCommonItemDialog() {
|
||||
return Boolean.getBoolean("sun.awt.windows.useCommonItemDialog");
|
||||
}
|
||||
|
||||
private native void _show();
|
||||
private native void _hide();
|
||||
|
||||
|
||||
@@ -27,11 +27,13 @@
|
||||
#include "awt_FileDialog.h"
|
||||
#include "awt_Dialog.h"
|
||||
#include "awt_Toolkit.h"
|
||||
#include "awt_ole.h"
|
||||
#include "ComCtl32Util.h"
|
||||
#include <commdlg.h>
|
||||
#include <cderr.h>
|
||||
#include <shlobj.h>
|
||||
|
||||
#include <shlwapi.h>
|
||||
#include <shobjidl.h>
|
||||
|
||||
/************************************************************************
|
||||
* AwtFileDialog fields
|
||||
@@ -52,11 +54,92 @@ jfieldID AwtFileDialog::dirID;
|
||||
jfieldID AwtFileDialog::fileID;
|
||||
jfieldID AwtFileDialog::filterID;
|
||||
|
||||
class CoTaskStringHolder {
|
||||
public:
|
||||
CoTaskStringHolder() : m_str(NULL) {}
|
||||
|
||||
CoTaskStringHolder& operator=(CoTaskStringHolder& other) {
|
||||
Clean();
|
||||
m_str = other.m_str;
|
||||
other.m_str = NULL;
|
||||
return *this;
|
||||
}
|
||||
|
||||
LPTSTR* operator&() {
|
||||
return &m_str;
|
||||
}
|
||||
|
||||
operator bool() {
|
||||
return m_str != NULL;
|
||||
}
|
||||
|
||||
operator LPTSTR() {
|
||||
return m_str;
|
||||
}
|
||||
|
||||
~CoTaskStringHolder() {
|
||||
Clean();
|
||||
}
|
||||
private:
|
||||
LPTSTR m_str;
|
||||
|
||||
void Clean() {
|
||||
if (m_str)
|
||||
::CoTaskMemFree(m_str);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class SmartHolderBase {
|
||||
public:
|
||||
SmartHolderBase() : m_pointer(NULL) {}
|
||||
|
||||
SmartHolderBase& operator=(const SmartHolderBase&) = delete;
|
||||
|
||||
void Attach(T* other) {
|
||||
Clean();
|
||||
m_pointer = other;
|
||||
}
|
||||
|
||||
operator bool() {
|
||||
return m_pointer != NULL;
|
||||
}
|
||||
|
||||
operator T*() {
|
||||
return m_pointer;
|
||||
}
|
||||
|
||||
~SmartHolderBase() {
|
||||
Clean();
|
||||
}
|
||||
protected:
|
||||
T* m_pointer;
|
||||
|
||||
virtual void Clean() {
|
||||
if (m_pointer)
|
||||
delete m_pointer;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class SmartHolder : public SmartHolderBase<T> {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class SmartHolder<T[]> : public SmartHolderBase<T> {
|
||||
virtual void Clean() {
|
||||
if (m_pointer)
|
||||
delete [] m_pointer;
|
||||
}
|
||||
};
|
||||
|
||||
/* Localized filter string */
|
||||
#define MAX_FILTER_STRING 128
|
||||
static TCHAR s_fileFilterString[MAX_FILTER_STRING];
|
||||
/* Non-localized suffix of the filter string */
|
||||
static const TCHAR s_additionalString[] = TEXT(" (*.*)\0*.*\0");
|
||||
static SmartHolder<COMDLG_FILTERSPEC> s_fileFilterSpec;
|
||||
static UINT s_fileFilterCount;
|
||||
|
||||
// Default limit of the output buffer.
|
||||
#define SINGLE_MODE_BUFFER_LIMIT MAX_PATH+1
|
||||
@@ -65,8 +148,45 @@ static const TCHAR s_additionalString[] = TEXT(" (*.*)\0*.*\0");
|
||||
// The name of the property holding the pointer to the OPENFILENAME structure.
|
||||
static LPCTSTR OpenFileNameProp = TEXT("AWT_OFN");
|
||||
|
||||
_COM_SMARTPTR_TYPEDEF(IFileDialog, __uuidof(IFileDialog));
|
||||
_COM_SMARTPTR_TYPEDEF(IFileDialogEvents, __uuidof(IFileDialogEvents));
|
||||
_COM_SMARTPTR_TYPEDEF(IShellItem, __uuidof(IShellItem));
|
||||
_COM_SMARTPTR_TYPEDEF(IFileOpenDialog, __uuidof(IFileOpenDialog));
|
||||
_COM_SMARTPTR_TYPEDEF(IShellItemArray, __uuidof(IShellItemArray));
|
||||
_COM_SMARTPTR_TYPEDEF(IOleWindowPtr, __uuidof(IOleWindowPtr));
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
COMDLG_FILTERSPEC *CreateFilterSpec(UINT *count) {
|
||||
UINT filterCount = 0;
|
||||
for (UINT index = 0; index < MAX_FILTER_STRING - 1; index++) {
|
||||
if (s_fileFilterString[index] == _T('\0')) {
|
||||
filterCount++;
|
||||
if (s_fileFilterString[index + 1] == _T('\0'))
|
||||
break;
|
||||
}
|
||||
}
|
||||
filterCount /= 2;
|
||||
COMDLG_FILTERSPEC *filterSpec = new COMDLG_FILTERSPEC[filterCount];
|
||||
UINT currentIndex = 0;
|
||||
TCHAR *currentStart = s_fileFilterString;
|
||||
for (UINT index = 0; index < MAX_FILTER_STRING - 1; index++) {
|
||||
if (s_fileFilterString[index] == _T('\0')) {
|
||||
if (currentIndex & 1) {
|
||||
filterSpec[currentIndex / 2].pszSpec = currentStart;
|
||||
} else {
|
||||
filterSpec[currentIndex / 2].pszName = currentStart;
|
||||
}
|
||||
currentStart = s_fileFilterString + index + 1;
|
||||
currentIndex++;
|
||||
if (s_fileFilterString[index + 1] == _T('\0'))
|
||||
break;
|
||||
}
|
||||
}
|
||||
*count = filterCount;
|
||||
return filterSpec;
|
||||
}
|
||||
|
||||
void
|
||||
AwtFileDialog::Initialize(JNIEnv *env, jstring filterDescription)
|
||||
{
|
||||
@@ -86,6 +206,7 @@ AwtFileDialog::Initialize(JNIEnv *env, jstring filterDescription)
|
||||
}
|
||||
DASSERT(s + sizeof(s_additionalString) < s_fileFilterString + MAX_FILTER_STRING);
|
||||
memcpy(s, s_additionalString, sizeof(s_additionalString));
|
||||
s_fileFilterSpec.Attach(CreateFilterSpec(&s_fileFilterCount));
|
||||
}
|
||||
|
||||
LRESULT CALLBACK FileDialogWndProc(HWND hWnd, UINT message,
|
||||
@@ -237,12 +358,237 @@ FileDialogHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
|
||||
CATCH_BAD_ALLOC_RET(TRUE);
|
||||
}
|
||||
|
||||
struct FileDialogData {
|
||||
IFileDialogPtr fileDialog;
|
||||
SmartHolder<TCHAR[]> result;
|
||||
UINT resultSize;
|
||||
jobject peer;
|
||||
};
|
||||
|
||||
HRESULT GetSelectedResults(FileDialogData *data) {
|
||||
OLE_TRY
|
||||
|
||||
IFileOpenDialogPtr fileOpenDialog;
|
||||
UINT currentOffset = 0;
|
||||
IShellItemArrayPtr psia;
|
||||
DWORD itemsCount;
|
||||
|
||||
OLE_HRT(data->fileDialog->QueryInterface(IID_PPV_ARGS(&fileOpenDialog)))
|
||||
OLE_HRT(fileOpenDialog->GetSelectedItems(&psia));
|
||||
OLE_HRT(psia->GetCount(&itemsCount));
|
||||
|
||||
UINT maxBufferSize = (MAX_PATH + 1) * itemsCount + 1;
|
||||
data->result.Attach(new TCHAR[maxBufferSize]);
|
||||
data->resultSize = maxBufferSize;
|
||||
LPTSTR resultBuffer = data->result;
|
||||
for (DWORD i = 0; i < itemsCount; i++) {
|
||||
IShellItemPtr psi;
|
||||
OLE_HRT(psia->GetItemAt(i, &psi));
|
||||
if (i == 0 && itemsCount > 1) {
|
||||
IShellItemPtr psiParent;
|
||||
CoTaskStringHolder filePath;
|
||||
OLE_HRT(psi->GetParent(&psiParent));
|
||||
OLE_HRT(psiParent->GetDisplayName(SIGDN_FILESYSPATH, &filePath));
|
||||
size_t filePathLength = _tcslen(filePath);
|
||||
_tcsncpy(resultBuffer + currentOffset, filePath, filePathLength);
|
||||
resultBuffer[currentOffset + filePathLength] = _T('\0');
|
||||
currentOffset += filePathLength + 1;
|
||||
}
|
||||
|
||||
CoTaskStringHolder filePath;
|
||||
SIGDN displayForm = itemsCount > 1 ? SIGDN_PARENTRELATIVE : SIGDN_FILESYSPATH;
|
||||
OLE_HRT(psi->GetDisplayName(displayForm, &filePath));
|
||||
size_t filePathLength = _tcslen(filePath);
|
||||
_tcsncpy(resultBuffer + currentOffset, filePath, filePathLength);
|
||||
resultBuffer[currentOffset + filePathLength] = _T('\0');
|
||||
currentOffset += filePathLength + 1;
|
||||
}
|
||||
resultBuffer[currentOffset] = _T('\0');
|
||||
resultBuffer[currentOffset + 1] = _T('\0');
|
||||
data->fileDialog->Close(S_OK);
|
||||
|
||||
OLE_CATCH
|
||||
OLE_RETURN_HR
|
||||
}
|
||||
|
||||
LRESULT CALLBACK
|
||||
FileDialogSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
|
||||
{
|
||||
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
|
||||
|
||||
TRY;
|
||||
|
||||
HWND parent = ::GetParent(hWnd);
|
||||
|
||||
switch (uMsg) {
|
||||
case WM_COMMAND: {
|
||||
if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDOK) {
|
||||
OLE_TRY
|
||||
OLE_HRT(GetSelectedResults((FileDialogData*) dwRefData));
|
||||
OLE_CATCH
|
||||
}
|
||||
if (LOWORD(wParam) == IDCANCEL) {
|
||||
jobject peer = (jobject) (::GetProp(hWnd, ModalDialogPeerProp));
|
||||
env->CallVoidMethod(peer, AwtFileDialog::setHWndMID, (jlong) 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_SETICON: {
|
||||
return 0;
|
||||
}
|
||||
case WM_DESTROY: {
|
||||
HIMC hIMC = ::ImmGetContext(hWnd);
|
||||
if (hIMC != NULL) {
|
||||
::ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
|
||||
::ImmReleaseContext(hWnd, hIMC);
|
||||
}
|
||||
|
||||
RemoveWindowSubclass(hWnd, &FileDialogSubclassProc, uIdSubclass);
|
||||
|
||||
::RemoveProp(parent, ModalDialogPeerProp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
|
||||
|
||||
CATCH_BAD_ALLOC_RET(TRUE);
|
||||
}
|
||||
|
||||
class CDialogEventHandler : public IFileDialogEvents
|
||||
{
|
||||
public:
|
||||
IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv)
|
||||
{
|
||||
static const QITAB qit[] = {
|
||||
QITABENT(CDialogEventHandler, IFileDialogEvents),
|
||||
{ 0 },
|
||||
};
|
||||
return QISearch(this, qit, riid, ppv);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&m_refCount);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) Release()
|
||||
{
|
||||
long retVal = InterlockedDecrement(&m_refCount);
|
||||
if (!retVal)
|
||||
delete this;
|
||||
return retVal;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP OnFolderChange(IFileDialog *fileDialog) {
|
||||
if (!m_activated) {
|
||||
InitDialog(fileDialog);
|
||||
m_activated = true;
|
||||
}
|
||||
return S_OK;
|
||||
};
|
||||
|
||||
IFACEMETHODIMP OnFileOk(IFileDialog *) {
|
||||
if (!data->result) {
|
||||
OLE_TRY
|
||||
OLE_HRT(GetSelectedResults(data));
|
||||
OLE_CATCH
|
||||
}
|
||||
return S_OK;
|
||||
};
|
||||
|
||||
IFACEMETHODIMP OnFolderChanging(IFileDialog *, IShellItem *) { return S_OK; };
|
||||
IFACEMETHODIMP OnHelp(IFileDialog *) { return S_OK; };
|
||||
IFACEMETHODIMP OnSelectionChange(IFileDialog *) { return S_OK; };
|
||||
IFACEMETHODIMP OnShareViolation(IFileDialog *, IShellItem *, FDE_SHAREVIOLATION_RESPONSE *) { return S_OK; };
|
||||
IFACEMETHODIMP OnTypeChange(IFileDialog *pfd) { return S_OK; };
|
||||
IFACEMETHODIMP OnOverwrite(IFileDialog *, IShellItem *, FDE_OVERWRITE_RESPONSE *) { return S_OK; };
|
||||
|
||||
CDialogEventHandler(FileDialogData *data) : data(data), m_refCount(1), m_activated(false) { };
|
||||
private:
|
||||
~CDialogEventHandler() { };
|
||||
FileDialogData *data;
|
||||
bool m_activated;
|
||||
long m_refCount;
|
||||
|
||||
void InitDialog(IFileDialog *fileDialog) {
|
||||
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
|
||||
|
||||
TRY;
|
||||
OLE_TRY
|
||||
|
||||
IOleWindowPtr pWindow;
|
||||
OLE_HR = fileDialog->QueryInterface(IID_PPV_ARGS(&pWindow));
|
||||
if (!SUCCEEDED(OLE_HR))
|
||||
return;
|
||||
|
||||
HWND hdlg;
|
||||
OLE_HRT(pWindow->GetWindow(&hdlg));
|
||||
|
||||
HWND parent = ::GetParent(hdlg);
|
||||
jobject peer = data->peer;
|
||||
env->CallVoidMethod(peer, AwtFileDialog::setHWndMID, (jlong)parent);
|
||||
::SetProp(parent, ModalDialogPeerProp, reinterpret_cast<HANDLE>(peer));
|
||||
|
||||
// fix for 4508670 - disable CS_SAVEBITS
|
||||
DWORD style = ::GetClassLong(hdlg, GCL_STYLE);
|
||||
::SetClassLong(hdlg, GCL_STYLE, style & ~CS_SAVEBITS);
|
||||
|
||||
// set appropriate icon for parentless dialogs
|
||||
jobject awtParent = env->GetObjectField(peer, AwtFileDialog::parentID);
|
||||
if (awtParent == NULL) {
|
||||
::SendMessage(parent, WM_SETICON, (WPARAM)ICON_BIG,
|
||||
(LPARAM)AwtToolkit::GetInstance().GetAwtIcon());
|
||||
} else {
|
||||
AwtWindow *awtWindow = (AwtWindow *)JNI_GET_PDATA(awtParent);
|
||||
::SendMessage(parent, WM_SETICON, (WPARAM)ICON_BIG,
|
||||
(LPARAM)(awtWindow->GetHIcon()));
|
||||
::SendMessage(parent, WM_SETICON, (WPARAM)ICON_SMALL,
|
||||
(LPARAM)(awtWindow->GetHIconSm()));
|
||||
env->DeleteLocalRef(awtParent);
|
||||
}
|
||||
|
||||
SetWindowSubclass(hdlg, &FileDialogSubclassProc, 0, (DWORD_PTR) data);
|
||||
|
||||
OLE_CATCH
|
||||
CATCH_BAD_ALLOC;
|
||||
}
|
||||
};
|
||||
|
||||
HRESULT CDialogEventHandler_CreateInstance(FileDialogData *data, REFIID riid, void **ppv)
|
||||
{
|
||||
OLE_TRY
|
||||
IFileDialogEventsPtr dlg(new CDialogEventHandler(data), false);
|
||||
OLE_HRT(dlg->QueryInterface(riid, ppv));
|
||||
OLE_CATCH
|
||||
OLE_RETURN_HR
|
||||
}
|
||||
|
||||
HRESULT CreateShellItem(LPTSTR path, IShellItem *shellItem) {
|
||||
size_t pathLength = _tcslen(path);
|
||||
for (size_t index = 0; index < pathLength; index++) {
|
||||
if (path[index] == _T('/'))
|
||||
path[index] = _T('\\');
|
||||
}
|
||||
|
||||
return ::SHCreateItemInKnownFolder(FOLDERID_ComputerFolder, 0, path, IID_PPV_ARGS(&shellItem));
|
||||
}
|
||||
|
||||
CoTaskStringHolder GetShortName(LPTSTR path) {
|
||||
CoTaskStringHolder shortName;
|
||||
OLE_TRY
|
||||
IShellItemPtr shellItem;
|
||||
OLE_HRT(CreateShellItem(path, shellItem));
|
||||
OLE_HRT(shellItem->GetDisplayName(SIGDN_PARENTRELATIVE, &shortName));
|
||||
OLE_CATCH
|
||||
return SUCCEEDED(OLE_HR) ? shortName : CoTaskStringHolder();
|
||||
}
|
||||
|
||||
void
|
||||
AwtFileDialog::Show(void *p)
|
||||
{
|
||||
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
|
||||
jobject peer;
|
||||
LPTSTR fileBuffer = NULL;
|
||||
LPTSTR currentDirectory = NULL;
|
||||
jint mode = 0;
|
||||
BOOL result = FALSE;
|
||||
@@ -256,13 +602,24 @@ AwtFileDialog::Show(void *p)
|
||||
AwtComponent* awtParent = NULL;
|
||||
jboolean multipleMode = JNI_FALSE;
|
||||
|
||||
OLE_DECL
|
||||
OLEHolder _ole_;
|
||||
IFileDialogPtr pfd;
|
||||
IFileDialogEventsPtr pfde;
|
||||
IShellItemPtr psiResult;
|
||||
FileDialogData data;
|
||||
DWORD dwCookie;
|
||||
|
||||
OPENFILENAME ofn;
|
||||
memset(&ofn, 0, sizeof(ofn));
|
||||
|
||||
peer = (jobject)p;
|
||||
|
||||
static BOOL useCommonItemDialog = JNU_CallStaticMethodByName(env, NULL,
|
||||
"sun/awt/windows/WFileDialogPeer", "useCommonItemDialog", "()Z").z == JNI_TRUE;
|
||||
try {
|
||||
DASSERT(peer);
|
||||
|
||||
target = env->GetObjectField(peer, AwtObject::targetID);
|
||||
parent = env->GetObjectField(peer, AwtFileDialog::parentID);
|
||||
if (parent != NULL) {
|
||||
@@ -304,68 +661,132 @@ AwtFileDialog::Show(void *p)
|
||||
fileBuffer[0] = _T('\0');
|
||||
}
|
||||
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
ofn.lpstrFilter = s_fileFilterString;
|
||||
ofn.nFilterIndex = 1;
|
||||
/*
|
||||
Fix for 6488834.
|
||||
To disable Win32 native parent modality we have to set
|
||||
hwndOwner field to either NULL or some hidden window. For
|
||||
parentless dialogs we use NULL to show them in the taskbar,
|
||||
and for all other dialogs AwtToolkit's HWND is used.
|
||||
*/
|
||||
if (awtParent != NULL)
|
||||
{
|
||||
ofn.hwndOwner = AwtToolkit::GetInstance().GetHWnd();
|
||||
}
|
||||
else
|
||||
{
|
||||
ofn.hwndOwner = NULL;
|
||||
}
|
||||
ofn.lpstrFile = fileBuffer;
|
||||
ofn.nMaxFile = bufferLimit;
|
||||
ofn.lpstrTitle = titleBuffer;
|
||||
ofn.lpstrInitialDir = directoryBuffer;
|
||||
ofn.Flags = OFN_LONGNAMES | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY |
|
||||
OFN_ENABLEHOOK | OFN_EXPLORER | OFN_ENABLESIZING;
|
||||
fileFilter = env->GetObjectField(peer,
|
||||
AwtFileDialog::fileFilterID);
|
||||
if (!JNU_IsNull(env,fileFilter)) {
|
||||
ofn.Flags |= OFN_ENABLEINCLUDENOTIFY;
|
||||
}
|
||||
ofn.lCustData = (LPARAM)peer;
|
||||
ofn.lpfnHook = (LPOFNHOOKPROC)FileDialogHookProc;
|
||||
fileFilter = env->GetObjectField(peer, AwtFileDialog::fileFilterID);
|
||||
|
||||
if (multipleMode == JNI_TRUE) {
|
||||
ofn.Flags |= OFN_ALLOWMULTISELECT;
|
||||
if (!useCommonItemDialog) {
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
ofn.lpstrFilter = s_fileFilterString;
|
||||
ofn.nFilterIndex = 1;
|
||||
/*
|
||||
Fix for 6488834.
|
||||
To disable Win32 native parent modality we have to set
|
||||
hwndOwner field to either NULL or some hidden window. For
|
||||
parentless dialogs we use NULL to show them in the taskbar,
|
||||
and for all other dialogs AwtToolkit's HWND is used.
|
||||
*/
|
||||
if (awtParent != NULL) {
|
||||
ofn.hwndOwner = AwtToolkit::GetInstance().GetHWnd();
|
||||
} else {
|
||||
ofn.hwndOwner = NULL;
|
||||
}
|
||||
ofn.lpstrFile = fileBuffer;
|
||||
ofn.nMaxFile = bufferLimit;
|
||||
ofn.lpstrTitle = titleBuffer;
|
||||
ofn.lpstrInitialDir = directoryBuffer;
|
||||
ofn.Flags = OFN_LONGNAMES | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY |
|
||||
OFN_ENABLEHOOK | OFN_EXPLORER | OFN_ENABLESIZING;
|
||||
|
||||
if (!JNU_IsNull(env,fileFilter)) {
|
||||
ofn.Flags |= OFN_ENABLEINCLUDENOTIFY;
|
||||
}
|
||||
ofn.lCustData = (LPARAM)peer;
|
||||
ofn.lpfnHook = (LPOFNHOOKPROC)FileDialogHookProc;
|
||||
|
||||
if (multipleMode == JNI_TRUE) {
|
||||
ofn.Flags |= OFN_ALLOWMULTISELECT;
|
||||
}
|
||||
|
||||
// Save current directory, so we can reset if it changes.
|
||||
currentDirectory = new TCHAR[MAX_PATH+1];
|
||||
|
||||
VERIFY(::GetCurrentDirectory(MAX_PATH, currentDirectory) > 0);
|
||||
}
|
||||
|
||||
// Save current directory, so we can reset if it changes.
|
||||
currentDirectory = new TCHAR[MAX_PATH+1];
|
||||
|
||||
VERIFY(::GetCurrentDirectory(MAX_PATH, currentDirectory) > 0);
|
||||
|
||||
mode = env->GetIntField(target, AwtFileDialog::modeID);
|
||||
|
||||
AwtDialog::CheckInstallModalHook();
|
||||
|
||||
// show the Win32 file dialog
|
||||
if (mode == java_awt_FileDialog_LOAD) {
|
||||
result = ::GetOpenFileName(&ofn);
|
||||
} else {
|
||||
result = ::GetSaveFileName(&ofn);
|
||||
if (useCommonItemDialog) {
|
||||
OLE_NEXT_TRY
|
||||
GUID fileDialogMode = mode == java_awt_FileDialog_LOAD ? CLSID_FileOpenDialog : CLSID_FileSaveDialog;
|
||||
OLE_HRT(pfd.CreateInstance(fileDialogMode));
|
||||
|
||||
data.fileDialog = pfd;
|
||||
data.peer = peer;
|
||||
OLE_HRT(CDialogEventHandler_CreateInstance(&data, IID_PPV_ARGS(&pfde)));
|
||||
OLE_HRT(pfd->Advise(pfde, &dwCookie));
|
||||
|
||||
DWORD dwFlags;
|
||||
OLE_HRT(pfd->GetOptions(&dwFlags));
|
||||
dwFlags |= FOS_FORCEFILESYSTEM;
|
||||
if (multipleMode == JNI_TRUE) {
|
||||
dwFlags |= FOS_ALLOWMULTISELECT;
|
||||
}
|
||||
OLE_HRT(pfd->SetOptions(dwFlags));
|
||||
|
||||
OLE_HRT(pfd->SetTitle(titleBuffer));
|
||||
|
||||
OLE_HRT(pfd->SetFileTypes(s_fileFilterCount, s_fileFilterSpec));
|
||||
OLE_HRT(pfd->SetFileTypeIndex(1));
|
||||
|
||||
IShellItemPtr directoryItem;
|
||||
if (SUCCEEDED(CreateShellItem(directoryBuffer, directoryItem))) {
|
||||
pfd->SetFolder(directoryItem);
|
||||
}
|
||||
CoTaskStringHolder shortName = GetShortName(fileBuffer);
|
||||
if (shortName) {
|
||||
OLE_HRT(pfd->SetFileName(shortName));
|
||||
}
|
||||
OLE_CATCH
|
||||
}
|
||||
// Fix for 4181310: FileDialog does not show up.
|
||||
// If the dialog is not shown because of invalid file name
|
||||
// replace the file name by empty string.
|
||||
if (!result) {
|
||||
dlgerr = ::CommDlgExtendedError();
|
||||
if (dlgerr == FNERR_INVALIDFILENAME) {
|
||||
_tcscpy_s(fileBuffer, bufferLimit, TEXT(""));
|
||||
if (mode == java_awt_FileDialog_LOAD) {
|
||||
result = ::GetOpenFileName(&ofn);
|
||||
} else {
|
||||
result = ::GetSaveFileName(&ofn);
|
||||
|
||||
if (useCommonItemDialog && SUCCEEDED(OLE_HR)) {
|
||||
if (mode == java_awt_FileDialog_LOAD) {
|
||||
result = SUCCEEDED(pfd->Show(NULL)) && data.result;
|
||||
if (!result) {
|
||||
OLE_NEXT_TRY
|
||||
OLE_HRT(pfd->GetResult(&psiResult));
|
||||
CoTaskStringHolder filePath;
|
||||
OLE_HRT(psiResult->GetDisplayName(SIGDN_FILESYSPATH, &filePath));
|
||||
size_t filePathLength = _tcslen(filePath);
|
||||
data.result.Attach(new TCHAR[filePathLength + 1]);
|
||||
_tcscpy_s(data.result, filePathLength + 1, filePath);
|
||||
OLE_CATCH
|
||||
result = SUCCEEDED(OLE_HR);
|
||||
}
|
||||
} else {
|
||||
result = SUCCEEDED(pfd->Show(NULL));
|
||||
if (result) {
|
||||
OLE_NEXT_TRY
|
||||
OLE_HRT(pfd->GetResult(&psiResult));
|
||||
CoTaskStringHolder filePath;
|
||||
OLE_HRT(psiResult->GetDisplayName(SIGDN_FILESYSPATH, &filePath));
|
||||
size_t filePathLength = _tcslen(filePath);
|
||||
data.result.Attach(new TCHAR[filePathLength + 1]);
|
||||
_tcscpy_s(data.result, filePathLength + 1, filePath);
|
||||
OLE_CATCH
|
||||
result = SUCCEEDED(OLE_HR);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// show the Win32 file dialog
|
||||
if (mode == java_awt_FileDialog_LOAD) {
|
||||
result = ::GetOpenFileName(&ofn);
|
||||
} else {
|
||||
result = ::GetSaveFileName(&ofn);
|
||||
}
|
||||
// Fix for 4181310: FileDialog does not show up.
|
||||
// If the dialog is not shown because of invalid file name
|
||||
// replace the file name by empty string.
|
||||
if (!result) {
|
||||
dlgerr = ::CommDlgExtendedError();
|
||||
if (dlgerr == FNERR_INVALIDFILENAME) {
|
||||
_tcscpy_s(fileBuffer, bufferLimit, TEXT(""));
|
||||
if (mode == java_awt_FileDialog_LOAD) {
|
||||
result = ::GetOpenFileName(&ofn);
|
||||
} else {
|
||||
result = ::GetSaveFileName(&ofn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -376,19 +797,31 @@ AwtFileDialog::Show(void *p)
|
||||
|
||||
AwtDialog::ModalActivateNextWindow(NULL, target, peer);
|
||||
|
||||
VERIFY(::SetCurrentDirectory(currentDirectory));
|
||||
if (useCommonItemDialog) {
|
||||
VERIFY(::SetCurrentDirectory(currentDirectory));
|
||||
}
|
||||
|
||||
// Report result to peer.
|
||||
if (result) {
|
||||
jint length = multipleMode
|
||||
? (jint)GetBufferLength(ofn.lpstrFile, ofn.nMaxFile)
|
||||
: (jint)_tcslen(ofn.lpstrFile);
|
||||
jint length;
|
||||
if (useCommonItemDialog) {
|
||||
length = (jint) GetBufferLength(data.result, data.resultSize);
|
||||
} else {
|
||||
length = multipleMode
|
||||
? (jint) GetBufferLength(ofn.lpstrFile, ofn.nMaxFile)
|
||||
: (jint) _tcslen(ofn.lpstrFile);
|
||||
}
|
||||
|
||||
jcharArray jnames = env->NewCharArray(length);
|
||||
if (jnames == NULL) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
env->SetCharArrayRegion(jnames, 0, length, (jchar*)ofn.lpstrFile);
|
||||
|
||||
if (useCommonItemDialog) {
|
||||
env->SetCharArrayRegion(jnames, 0, length, (jchar *) (LPTSTR) data.result);
|
||||
} else {
|
||||
env->SetCharArrayRegion(jnames, 0, length, (jchar *) ofn.lpstrFile);
|
||||
}
|
||||
env->CallVoidMethod(peer, AwtFileDialog::handleSelectedMID, jnames);
|
||||
env->DeleteLocalRef(jnames);
|
||||
} else {
|
||||
@@ -397,6 +830,12 @@ AwtFileDialog::Show(void *p)
|
||||
DASSERT(!safe_ExceptionOccurred(env));
|
||||
} catch (...) {
|
||||
|
||||
if (useCommonItemDialog) {
|
||||
if (pfd) {
|
||||
pfd->Unadvise(dwCookie);
|
||||
}
|
||||
}
|
||||
|
||||
env->DeleteLocalRef(target);
|
||||
env->DeleteLocalRef(parent);
|
||||
env->DeleteLocalRef(title);
|
||||
@@ -411,6 +850,12 @@ AwtFileDialog::Show(void *p)
|
||||
throw;
|
||||
}
|
||||
|
||||
if (useCommonItemDialog) {
|
||||
if (pfd) {
|
||||
pfd->Unadvise(dwCookie);
|
||||
}
|
||||
}
|
||||
|
||||
env->DeleteLocalRef(target);
|
||||
env->DeleteLocalRef(parent);
|
||||
env->DeleteLocalRef(title);
|
||||
|
||||
@@ -180,4 +180,24 @@ struct CLogEntryPoint0 {
|
||||
#define _VE _variant_t()
|
||||
#define _VB(b) _variant_t(bool(b))
|
||||
|
||||
struct OLEHolder
|
||||
{
|
||||
OLEHolder()
|
||||
: m_hr(::OleInitialize(NULL))
|
||||
{
|
||||
if (SUCCEEDED(m_hr)) {
|
||||
STRACE(_T("{OLE"));
|
||||
}
|
||||
}
|
||||
|
||||
~OLEHolder(){
|
||||
if (SUCCEEDED(m_hr)) {
|
||||
::OleUninitialize();
|
||||
STRACE(_T("}OLE"));
|
||||
}
|
||||
}
|
||||
operator bool() const { return TRUE==SUCCEEDED(m_hr); }
|
||||
HRESULT m_hr;
|
||||
};
|
||||
|
||||
#endif//AWT_OLE_H
|
||||
|
||||
Reference in New Issue
Block a user