mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-06 09:29:38 +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
This commit is contained in:
committed by
Vitaly Provodin
parent
ce23ff88d6
commit
93261b19f9
@@ -36,6 +36,7 @@ import java.util.ResourceBundle;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.Vector;
|
||||
import sun.awt.AWTAccessor;
|
||||
import sun.security.action.GetBooleanAction;
|
||||
|
||||
final class WFileDialogPeer extends WWindowPeer implements FileDialogPeer {
|
||||
|
||||
@@ -97,6 +98,10 @@ final class WFileDialogPeer extends WWindowPeer implements FileDialogPeer {
|
||||
_dispose();
|
||||
}
|
||||
|
||||
private static boolean useCommonItemDialog() {
|
||||
return AccessController.doPrivileged(new GetBooleanAction("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);
|
||||
|
||||
@@ -183,11 +183,20 @@ struct CLogEntryPoint0 {
|
||||
struct OLEHolder
|
||||
{
|
||||
OLEHolder()
|
||||
: m_hr(::OleInitialize(NULL))
|
||||
{}
|
||||
: m_hr(::OleInitialize(NULL))
|
||||
{
|
||||
if (SUCCEEDED(m_hr)) {
|
||||
STRACE(_T("{OLE"));
|
||||
}
|
||||
}
|
||||
|
||||
~OLEHolder(){}
|
||||
operator bool() const { return S_OK==SUCCEEDED(m_hr); }
|
||||
~OLEHolder(){
|
||||
if (SUCCEEDED(m_hr)) {
|
||||
::OleUninitialize();
|
||||
STRACE(_T("}OLE"));
|
||||
}
|
||||
}
|
||||
operator bool() const { return TRUE==SUCCEEDED(m_hr); }
|
||||
HRESULT m_hr;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user