1 /*
   2  * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include "awt.h"
  27 #include "awt_FileDialog.h"
  28 #include "awt_Dialog.h"
  29 #include "awt_Toolkit.h"
  30 #include "ComCtl32Util.h"
  31 #include <commdlg.h>
  32 #include <cderr.h>
  33 #include <shlobj.h>
  34 
  35 
  36 /************************************************************************
  37  * AwtFileDialog fields
  38  */
  39 
  40 /* WFileDialogPeer ids */
  41 jfieldID AwtFileDialog::parentID;
  42 jfieldID AwtFileDialog::fileFilterID;
  43 jmethodID AwtFileDialog::setHWndMID;
  44 jmethodID AwtFileDialog::handleSelectedMID;
  45 jmethodID AwtFileDialog::handleCancelMID;
  46 jmethodID AwtFileDialog::checkFilenameFilterMID;
  47 jmethodID AwtFileDialog::isMultipleModeMID;
  48 
  49 /* FileDialog ids */
  50 jfieldID AwtFileDialog::modeID;
  51 jfieldID AwtFileDialog::dirID;
  52 jfieldID AwtFileDialog::fileID;
  53 jfieldID AwtFileDialog::filterID;
  54 
  55 /* Localized filter string */
  56 #define MAX_FILTER_STRING       128
  57 static TCHAR s_fileFilterString[MAX_FILTER_STRING];
  58 /* Non-localized suffix of the filter string */
  59 static const TCHAR s_additionalString[] = TEXT(" (*.*)\0*.*\0");
  60 
  61 // Default limit of the output buffer.
  62 #define SINGLE_MODE_BUFFER_LIMIT     MAX_PATH+1
  63 #define MULTIPLE_MODE_BUFFER_LIMIT   32768
  64 
  65 // The name of the property holding the pointer to the OPENFILENAME structure.
  66 static LPCTSTR OpenFileNameProp = TEXT("AWT_OFN");
  67 
  68 /***********************************************************************/
  69 
  70 void
  71 AwtFileDialog::Initialize(JNIEnv *env, jstring filterDescription)
  72 {
  73     int length = env->GetStringLength(filterDescription);
  74     DASSERT(length + 1 < MAX_FILTER_STRING);
  75     LPCTSTR tmp = JNU_GetStringPlatformChars(env, filterDescription, NULL);
  76     _tcscpy_s(s_fileFilterString, MAX_FILTER_STRING, tmp);
  77     JNU_ReleaseStringPlatformChars(env, filterDescription, tmp);
  78 
  79     //AdditionalString should be terminated by two NULL characters (Windows
  80     //requirement), so we have to organize the following cycle and use memcpy
  81     //unstead of, for example, strcat.
  82     LPTSTR s = s_fileFilterString;
  83     while (*s) {
  84         ++s;
  85         DASSERT(s < s_fileFilterString + MAX_FILTER_STRING);
  86     }
  87     DASSERT(s + sizeof(s_additionalString) < s_fileFilterString + MAX_FILTER_STRING);
  88     memcpy(s, s_additionalString, sizeof(s_additionalString));
  89 }
  90 
  91 LRESULT CALLBACK FileDialogWndProc(HWND hWnd, UINT message,
  92                                         WPARAM wParam, LPARAM lParam)
  93 {
  94     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
  95 
  96     switch (message) {
  97         case WM_COMMAND: {
  98             if (LOWORD(wParam) == IDCANCEL)
  99             {
 100                 // Unlike Print/Page dialogs, we only handle IDCANCEL here and
 101                 // don't handle IDOK. This is because user can press OK button
 102                 // when no file is selected, and the dialog is not closed. So
 103                 // OK button is handled in the CDN_FILEOK notification handler
 104                 // (see FileDialogHookProc below)
 105                 jobject peer = (jobject)(::GetProp(hWnd, ModalDialogPeerProp));
 106                 env->CallVoidMethod(peer, AwtFileDialog::setHWndMID, (jlong)0);
 107             }
 108             break;
 109         }
 110         case WM_SETICON: {
 111             return 0;
 112         }
 113     }
 114 
 115     WNDPROC lpfnWndProc = (WNDPROC)(::GetProp(hWnd, NativeDialogWndProcProp));
 116     return ComCtl32Util::GetInstance().DefWindowProc(lpfnWndProc, hWnd, message, wParam, lParam);
 117 }
 118 
 119 static UINT_PTR CALLBACK
 120 FileDialogHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
 121 {
 122     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 123 
 124     TRY;
 125 
 126     HWND parent = ::GetParent(hdlg);
 127 
 128     switch(uiMsg) {
 129         case WM_INITDIALOG: {
 130             OPENFILENAME *ofn = (OPENFILENAME *)lParam;
 131             jobject peer = (jobject)(ofn->lCustData);
 132             env->CallVoidMethod(peer, AwtFileDialog::setHWndMID,
 133                                 (jlong)parent);
 134             ::SetProp(parent, ModalDialogPeerProp, reinterpret_cast<HANDLE>(peer));
 135 
 136             // fix for 4508670 - disable CS_SAVEBITS
 137             DWORD style = ::GetClassLong(hdlg,GCL_STYLE);
 138             ::SetClassLong(hdlg,GCL_STYLE,style & ~CS_SAVEBITS);
 139 
 140             // set appropriate icon for parentless dialogs
 141             jobject awtParent = env->GetObjectField(peer, AwtFileDialog::parentID);
 142             if (awtParent == NULL) {
 143                 ::SendMessage(parent, WM_SETICON, (WPARAM)ICON_BIG,
 144                               (LPARAM)AwtToolkit::GetInstance().GetAwtIcon());
 145             } else {
 146                 AwtWindow *awtWindow = (AwtWindow *)JNI_GET_PDATA(awtParent);
 147                 ::SendMessage(parent, WM_SETICON, (WPARAM)ICON_BIG,
 148                                                (LPARAM)(awtWindow->GetHIcon()));
 149                 ::SendMessage(parent, WM_SETICON, (WPARAM)ICON_SMALL,
 150                                              (LPARAM)(awtWindow->GetHIconSm()));
 151                 env->DeleteLocalRef(awtParent);
 152             }
 153 
 154             // subclass dialog's parent to receive additional messages
 155             WNDPROC lpfnWndProc = ComCtl32Util::GetInstance().SubclassHWND(parent,
 156                                                                            FileDialogWndProc);
 157             ::SetProp(parent, NativeDialogWndProcProp, reinterpret_cast<HANDLE>(lpfnWndProc));
 158 
 159             ::SetProp(parent, OpenFileNameProp, (void *)lParam);
 160 
 161             break;
 162         }
 163         case WM_DESTROY: {
 164             HIMC hIMC = ::ImmGetContext(hdlg);
 165             if (hIMC != NULL) {
 166                 ::ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
 167                 ::ImmReleaseContext(hdlg, hIMC);
 168             }
 169 
 170             WNDPROC lpfnWndProc = (WNDPROC)(::GetProp(parent, NativeDialogWndProcProp));
 171             ComCtl32Util::GetInstance().UnsubclassHWND(parent,
 172                                                        FileDialogWndProc,
 173                                                        lpfnWndProc);
 174             ::RemoveProp(parent, ModalDialogPeerProp);
 175             ::RemoveProp(parent, NativeDialogWndProcProp);
 176             ::RemoveProp(parent, OpenFileNameProp);
 177             break;
 178         }
 179         case WM_NOTIFY: {
 180             OFNOTIFYEX *notifyEx = (OFNOTIFYEX *)lParam;
 181             if (notifyEx) {
 182                 jobject peer = (jobject)(::GetProp(parent, ModalDialogPeerProp));
 183                 if (notifyEx->hdr.code == CDN_INCLUDEITEM) {
 184                     LPITEMIDLIST pidl = (LPITEMIDLIST)notifyEx->pidl;
 185                     // Get the filename and directory
 186                     TCHAR szPath[MAX_PATH];
 187                     if (!::SHGetPathFromIDList(pidl, szPath)) {
 188                         return TRUE;
 189                     }
 190                     jstring strPath = JNU_NewStringPlatform(env, szPath);
 191                     if (strPath == NULL) {
 192                         throw std::bad_alloc();
 193                     }
 194                     // Call FilenameFilter.accept with path and filename
 195                     UINT uRes = (env->CallBooleanMethod(peer,
 196                         AwtFileDialog::checkFilenameFilterMID, strPath) == JNI_TRUE);
 197                     env->DeleteLocalRef(strPath);
 198                     return uRes;
 199                 } else if (notifyEx->hdr.code == CDN_FILEOK) {
 200                     // This notification is sent when user selects some file and presses
 201                     // OK button; it is not sent when no file is selected. So it's time
 202                     // to unblock all the windows blocked by this dialog as it will
 203                     // be closed soon
 204                     env->CallVoidMethod(peer, AwtFileDialog::setHWndMID, (jlong)0);
 205                 } else if (notifyEx->hdr.code == CDN_SELCHANGE) {
 206                     // reallocate the buffer if the buffer is too small
 207                     LPOPENFILENAME lpofn = (LPOPENFILENAME)GetProp(parent, OpenFileNameProp);
 208 
 209                     UINT nLength = CommDlg_OpenSave_GetSpec(parent, NULL, 0) +
 210                                    CommDlg_OpenSave_GetFolderPath(parent, NULL, 0);
 211 
 212                     if (lpofn->nMaxFile < nLength)
 213                     {
 214                         // allocate new buffer
 215                         LPTSTR newBuffer = new TCHAR[nLength];
 216 
 217                         if (newBuffer) {
 218                             memset(newBuffer, 0, nLength * sizeof(TCHAR));
 219                             LPTSTR oldBuffer = lpofn->lpstrFile;
 220                             lpofn->lpstrFile = newBuffer;
 221                             lpofn->nMaxFile = nLength;
 222                             // free the previously allocated buffer
 223                             if (oldBuffer) {
 224                                 delete[] oldBuffer;
 225                             }
 226 
 227                         }
 228                     }
 229                 }
 230             }
 231             break;
 232         }
 233     }
 234 
 235     return FALSE;
 236 
 237     CATCH_BAD_ALLOC_RET(TRUE);
 238 }
 239 
 240 void
 241 AwtFileDialog::Show(void *p)
 242 {
 243     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 244     jobject peer;
 245     LPTSTR fileBuffer = NULL;
 246     LPTSTR currentDirectory = NULL;
 247     jint mode = 0;
 248     BOOL result = FALSE;
 249     DWORD dlgerr;
 250     jstring directory = NULL;
 251     jstring title = NULL;
 252     jstring file = NULL;
 253     jobject fileFilter = NULL;
 254     jobject target = NULL;
 255     jobject parent = NULL;
 256     AwtComponent* awtParent = NULL;
 257     jboolean multipleMode = JNI_FALSE;
 258 
 259     OPENFILENAME ofn;
 260     memset(&ofn, 0, sizeof(ofn));
 261 
 262     /*
 263      * There's a situation (see bug 4906972) when InvokeFunction (by which this method is called)
 264      * returnes earlier than this method returnes. Probably it's caused due to ReplyMessage system call.
 265      * So for the avoidance of this mistiming we need to make new global reference here
 266      * (not local as it's used by the hook) and then manage it independently of the calling thread.
 267      */
 268     peer = env->NewGlobalRef((jobject)p);
 269 
 270     try {
 271         DASSERT(peer);
 272         target = env->GetObjectField(peer, AwtObject::targetID);
 273         parent = env->GetObjectField(peer, AwtFileDialog::parentID);
 274         if (parent != NULL) {
 275             awtParent = (AwtComponent *)JNI_GET_PDATA(parent);
 276         }
 277 //      DASSERT(awtParent);
 278         title = (jstring)(env)->GetObjectField(target, AwtDialog::titleID);
 279         HWND hwndOwner = awtParent ? awtParent->GetHWnd() : NULL;
 280 
 281         if (title == NULL || env->GetStringLength(title)==0) {
 282             title = JNU_NewStringPlatform(env, L" ");
 283             if (title == NULL) {
 284                 throw std::bad_alloc();
 285             }
 286         }
 287 
 288         JavaStringBuffer titleBuffer(env, title);
 289         directory =
 290             (jstring)env->GetObjectField(target, AwtFileDialog::dirID);
 291         JavaStringBuffer directoryBuffer(env, directory);
 292 
 293         multipleMode = env->CallBooleanMethod(peer, AwtFileDialog::isMultipleModeMID);
 294 
 295         UINT bufferLimit;
 296         if (multipleMode == JNI_TRUE) {
 297             bufferLimit = MULTIPLE_MODE_BUFFER_LIMIT;
 298         } else {
 299             bufferLimit = SINGLE_MODE_BUFFER_LIMIT;
 300         }
 301         LPTSTR fileBuffer = new TCHAR[bufferLimit];
 302         memset(fileBuffer, 0, bufferLimit * sizeof(TCHAR));
 303 
 304         file = (jstring)env->GetObjectField(target, AwtFileDialog::fileID);
 305         if (file != NULL) {
 306             LPCTSTR tmp = JNU_GetStringPlatformChars(env, file, NULL);
 307             _tcsncpy(fileBuffer, tmp, bufferLimit - 2); // the fileBuffer is double null terminated string
 308             JNU_ReleaseStringPlatformChars(env, file, tmp);
 309         } else {
 310             fileBuffer[0] = _T('\0');
 311         }
 312 
 313         ofn.lStructSize = sizeof(ofn);
 314         ofn.lpstrFilter = s_fileFilterString;
 315         ofn.nFilterIndex = 1;
 316         /*
 317           Fix for 6488834.
 318           To disable Win32 native parent modality we have to set
 319           hwndOwner field to either NULL or some hidden window. For
 320           parentless dialogs we use NULL to show them in the taskbar,
 321           and for all other dialogs AwtToolkit's HWND is used.
 322         */
 323         if (awtParent != NULL)
 324         {
 325             ofn.hwndOwner = AwtToolkit::GetInstance().GetHWnd();
 326         }
 327         else
 328         {
 329             ofn.hwndOwner = NULL;
 330         }
 331         ofn.lpstrFile = fileBuffer;
 332         ofn.nMaxFile = bufferLimit;
 333         ofn.lpstrTitle = titleBuffer;
 334         ofn.lpstrInitialDir = directoryBuffer;
 335         ofn.Flags = OFN_LONGNAMES | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY |
 336                     OFN_ENABLEHOOK | OFN_EXPLORER | OFN_ENABLESIZING;
 337         fileFilter = env->GetObjectField(peer,
 338         AwtFileDialog::fileFilterID);
 339         if (!JNU_IsNull(env,fileFilter)) {
 340             ofn.Flags |= OFN_ENABLEINCLUDENOTIFY;
 341         }
 342         ofn.lCustData = (LPARAM)peer;
 343         ofn.lpfnHook = (LPOFNHOOKPROC)FileDialogHookProc;
 344 
 345         if (multipleMode == JNI_TRUE) {
 346             ofn.Flags |= OFN_ALLOWMULTISELECT;
 347         }
 348 
 349         // Save current directory, so we can reset if it changes.
 350         currentDirectory = new TCHAR[MAX_PATH+1];
 351 
 352         VERIFY(::GetCurrentDirectory(MAX_PATH, currentDirectory) > 0);
 353 
 354         mode = env->GetIntField(target, AwtFileDialog::modeID);
 355 
 356         AwtDialog::CheckInstallModalHook();
 357 
 358         // show the Win32 file dialog
 359         if (mode == java_awt_FileDialog_LOAD) {
 360             result = ::GetOpenFileName(&ofn);
 361         } else {
 362             result = ::GetSaveFileName(&ofn);
 363         }
 364         // Fix for 4181310: FileDialog does not show up.
 365         // If the dialog is not shown because of invalid file name
 366         // replace the file name by empty string.
 367         if (!result) {
 368             dlgerr = ::CommDlgExtendedError();
 369             if (dlgerr == FNERR_INVALIDFILENAME) {
 370                 _tcscpy_s(fileBuffer, bufferLimit, TEXT(""));
 371                 if (mode == java_awt_FileDialog_LOAD) {
 372                     result = ::GetOpenFileName(&ofn);
 373                 } else {
 374                     result = ::GetSaveFileName(&ofn);
 375                 }
 376             }
 377         }
 378 
 379         AwtDialog::CheckUninstallModalHook();
 380 
 381         DASSERT(env->GetLongField(peer, AwtComponent::hwndID) == 0L);
 382 
 383         AwtDialog::ModalActivateNextWindow(NULL, target, peer);
 384 
 385         VERIFY(::SetCurrentDirectory(currentDirectory));
 386 
 387         // Report result to peer.
 388         if (result) {
 389             jint length = multipleMode
 390                     ? (jint)GetBufferLength(ofn.lpstrFile, ofn.nMaxFile)
 391                     : (jint)_tcslen(ofn.lpstrFile);
 392             jcharArray jnames = env->NewCharArray(length);
 393             if (jnames == NULL) {
 394                 throw std::bad_alloc();
 395             }
 396             env->SetCharArrayRegion(jnames, 0, length, (jchar*)ofn.lpstrFile);
 397 
 398             env->CallVoidMethod(peer, AwtFileDialog::handleSelectedMID, jnames);
 399             env->DeleteLocalRef(jnames);
 400         } else {
 401             env->CallVoidMethod(peer, AwtFileDialog::handleCancelMID);
 402         }
 403         DASSERT(!safe_ExceptionOccurred(env));
 404     } catch (...) {
 405 
 406         env->DeleteLocalRef(target);
 407         env->DeleteLocalRef(parent);
 408         env->DeleteLocalRef(title);
 409         env->DeleteLocalRef(directory);
 410         env->DeleteLocalRef(file);
 411         env->DeleteLocalRef(fileFilter);
 412         env->DeleteGlobalRef(peer);
 413 
 414         delete[] currentDirectory;
 415         if (ofn.lpstrFile)
 416             delete[] ofn.lpstrFile;
 417         throw;
 418     }
 419 
 420     env->DeleteLocalRef(target);
 421     env->DeleteLocalRef(parent);
 422     env->DeleteLocalRef(title);
 423     env->DeleteLocalRef(directory);
 424     env->DeleteLocalRef(file);
 425     env->DeleteLocalRef(fileFilter);
 426     env->DeleteGlobalRef(peer);
 427 
 428     delete[] currentDirectory;
 429     if (ofn.lpstrFile)
 430         delete[] ofn.lpstrFile;
 431 }
 432 
 433 BOOL AwtFileDialog::InheritsNativeMouseWheelBehavior() {return true;}
 434 
 435 void AwtFileDialog::_DisposeOrHide(void *param)
 436 {
 437     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 438 
 439     jobject self = (jobject)param;
 440 
 441     HWND hdlg = (HWND)(env->GetLongField(self, AwtComponent::hwndID));
 442     if (::IsWindow(hdlg))
 443     {
 444         ::SendMessage(hdlg, WM_COMMAND, MAKEWPARAM(IDCANCEL, 0),
 445                       (LPARAM)hdlg);
 446     }
 447 
 448     env->DeleteGlobalRef(self);
 449 }
 450 
 451 void AwtFileDialog::_ToFront(void *param)
 452 {
 453     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 454 
 455     jobject self = (jobject)param;
 456     HWND hdlg = (HWND)(env->GetLongField(self, AwtComponent::hwndID));
 457     if (::IsWindow(hdlg))
 458     {
 459         ::SetWindowPos(hdlg, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
 460     }
 461 
 462     env->DeleteGlobalRef(self);
 463 }
 464 
 465 void AwtFileDialog::_ToBack(void *param)
 466 {
 467     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 468 
 469     jobject self = (jobject)param;
 470     HWND hdlg = (HWND)(env->GetLongField(self, AwtComponent::hwndID));
 471     if (::IsWindow(hdlg))
 472     {
 473         ::SetWindowPos(hdlg, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
 474     }
 475 
 476     env->DeleteGlobalRef(self);
 477 }
 478 
 479 // Returns the length of the double null terminated output buffer
 480 UINT AwtFileDialog::GetBufferLength(LPTSTR buffer, UINT limit)
 481 {
 482     UINT index = 0;
 483     while ((index < limit) &&
 484            (buffer[index] != NULL || buffer[index+1] != NULL))
 485     {
 486         index++;
 487     }
 488     return index;
 489 }
 490 
 491 /************************************************************************
 492  * WFileDialogPeer native methods
 493  */
 494 
 495 extern "C" {
 496 
 497 JNIEXPORT void JNICALL
 498 Java_sun_awt_windows_WFileDialogPeer_initIDs(JNIEnv *env, jclass cls)
 499 {
 500     TRY;
 501 
 502     AwtFileDialog::parentID =
 503         env->GetFieldID(cls, "parent", "Lsun/awt/windows/WComponentPeer;");
 504     DASSERT(AwtFileDialog::parentID != NULL);
 505     CHECK_NULL(AwtFileDialog::parentID);
 506 
 507     AwtFileDialog::fileFilterID =
 508         env->GetFieldID(cls, "fileFilter", "Ljava/io/FilenameFilter;");
 509     DASSERT(AwtFileDialog::fileFilterID != NULL);
 510     CHECK_NULL(AwtFileDialog::fileFilterID);
 511 
 512     AwtFileDialog::setHWndMID = env->GetMethodID(cls, "setHWnd", "(J)V");
 513     DASSERT(AwtFileDialog::setHWndMID != NULL);
 514     CHECK_NULL(AwtFileDialog::setHWndMID);
 515 
 516     AwtFileDialog::handleSelectedMID =
 517         env->GetMethodID(cls, "handleSelected", "([C)V");
 518     DASSERT(AwtFileDialog::handleSelectedMID != NULL);
 519     CHECK_NULL(AwtFileDialog::handleSelectedMID);
 520 
 521     AwtFileDialog::handleCancelMID =
 522         env->GetMethodID(cls, "handleCancel", "()V");
 523     DASSERT(AwtFileDialog::handleCancelMID != NULL);
 524     CHECK_NULL(AwtFileDialog::handleCancelMID);
 525 
 526     AwtFileDialog::checkFilenameFilterMID =
 527         env->GetMethodID(cls, "checkFilenameFilter", "(Ljava/lang/String;)Z");
 528     DASSERT(AwtFileDialog::checkFilenameFilterMID != NULL);
 529     CHECK_NULL(AwtFileDialog::checkFilenameFilterMID);
 530 
 531     AwtFileDialog::isMultipleModeMID = env->GetMethodID(cls, "isMultipleMode", "()Z");
 532     DASSERT(AwtFileDialog::isMultipleModeMID != NULL);
 533     CHECK_NULL(AwtFileDialog::isMultipleModeMID);
 534 
 535     /* java.awt.FileDialog fields */
 536     cls = env->FindClass("java/awt/FileDialog");
 537     CHECK_NULL(cls);
 538 
 539     AwtFileDialog::modeID = env->GetFieldID(cls, "mode", "I");
 540     DASSERT(AwtFileDialog::modeID != NULL);
 541     CHECK_NULL(AwtFileDialog::modeID);
 542 
 543     AwtFileDialog::dirID = env->GetFieldID(cls, "dir", "Ljava/lang/String;");
 544     DASSERT(AwtFileDialog::dirID != NULL);
 545     CHECK_NULL(AwtFileDialog::dirID);
 546 
 547     AwtFileDialog::fileID = env->GetFieldID(cls, "file", "Ljava/lang/String;");
 548     DASSERT(AwtFileDialog::fileID != NULL);
 549     CHECK_NULL(AwtFileDialog::fileID);
 550 
 551     AwtFileDialog::filterID =
 552         env->GetFieldID(cls, "filter", "Ljava/io/FilenameFilter;");
 553     DASSERT(AwtFileDialog::filterID != NULL);
 554 
 555     CATCH_BAD_ALLOC;
 556 }
 557 
 558 JNIEXPORT void JNICALL
 559 Java_sun_awt_windows_WFileDialogPeer_setFilterString(JNIEnv *env, jclass cls,
 560                                                      jstring filterDescription)
 561 {
 562     TRY;
 563 
 564     AwtFileDialog::Initialize(env, filterDescription);
 565 
 566     CATCH_BAD_ALLOC;
 567 }
 568 
 569 JNIEXPORT void JNICALL
 570 Java_sun_awt_windows_WFileDialogPeer__1show(JNIEnv *env, jobject peer)
 571 {
 572     TRY;
 573 
 574     /*
 575      * Fix for 4906972.
 576      * 'peer' reference has to be global as it's used further in another thread.
 577      */
 578     jobject peerGlobal = env->NewGlobalRef(peer);
 579 
 580     if (!AwtToolkit::GetInstance().PostMessage(WM_AWT_INVOKE_METHOD,
 581                              (WPARAM)AwtFileDialog::Show, (LPARAM)peerGlobal)) {
 582         env->DeleteGlobalRef(peerGlobal);
 583     }
 584 
 585     CATCH_BAD_ALLOC;
 586 }
 587 
 588 JNIEXPORT void JNICALL
 589 Java_sun_awt_windows_WFileDialogPeer__1dispose(JNIEnv *env, jobject peer)
 590 {
 591     TRY_NO_VERIFY;
 592 
 593     jobject peerGlobal = env->NewGlobalRef(peer);
 594 
 595     AwtToolkit::GetInstance().SyncCall(AwtFileDialog::_DisposeOrHide,
 596         (void *)peerGlobal);
 597     // peerGlobal ref is deleted in _DisposeOrHide
 598 
 599     CATCH_BAD_ALLOC;
 600 }
 601 
 602 JNIEXPORT void JNICALL
 603 Java_sun_awt_windows_WFileDialogPeer__1hide(JNIEnv *env, jobject peer)
 604 {
 605     TRY;
 606 
 607     jobject peerGlobal = env->NewGlobalRef(peer);
 608 
 609     AwtToolkit::GetInstance().SyncCall(AwtFileDialog::_DisposeOrHide,
 610         (void *)peerGlobal);
 611     // peerGlobal ref is deleted in _DisposeOrHide
 612 
 613     CATCH_BAD_ALLOC;
 614 }
 615 
 616 JNIEXPORT void JNICALL
 617 Java_sun_awt_windows_WFileDialogPeer_toFront(JNIEnv *env, jobject peer)
 618 {
 619     TRY;
 620 
 621     AwtToolkit::GetInstance().SyncCall(AwtFileDialog::_ToFront,
 622                                        (void *)(env->NewGlobalRef(peer)));
 623     // global ref is deleted in _ToFront
 624 
 625     CATCH_BAD_ALLOC;
 626 }
 627 
 628 JNIEXPORT void JNICALL
 629 Java_sun_awt_windows_WFileDialogPeer_toBack(JNIEnv *env, jobject peer)
 630 {
 631     TRY;
 632 
 633     AwtToolkit::GetInstance().SyncCall(AwtFileDialog::_ToBack,
 634                                        (void *)(env->NewGlobalRef(peer)));
 635     // global ref is deleted in _ToBack
 636 
 637     CATCH_BAD_ALLOC;
 638 }
 639 
 640 int ScaleDownX(int x, HWND hwnd) {
 641     int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(hwnd);
 642     Devices::InstanceAccess devices;
 643     AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
 644     return device == NULL ? x : device->ScaleDownX(x);
 645 }
 646 
 647 int ScaleDownY(int y, HWND hwnd) {
 648     int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(hwnd);
 649     Devices::InstanceAccess devices;
 650     AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
 651     return device == NULL ? y : device->ScaleDownY(y);
 652 }
 653 
 654 jobject AwtFileDialog::_GetLocationOnScreen(void *param)
 655 {
 656     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 657 
 658     jobject result = NULL;
 659     HWND hwnd = (HWND)env->GetLongField((jobject)param, AwtComponent::hwndID);
 660 
 661     if (::IsWindow(hwnd))
 662     {
 663         RECT rect;
 664         VERIFY(::GetWindowRect(hwnd, &rect));
 665         result = JNU_NewObjectByName(env, "java/awt/Point", "(II)V",
 666                        ScaleDownX(rect.left, hwnd), ScaleDownY(rect.top, hwnd));
 667     }
 668 
 669     if (result != NULL)
 670     {
 671         jobject resultRef = env->NewGlobalRef(result);
 672         env->DeleteLocalRef(result);
 673         return resultRef;
 674     }
 675     else
 676     {
 677         return NULL;
 678     }
 679 }
 680 
 681 /*
 682  * Class:     sun_awt_windows_WFileDialogPeer
 683  * Method:    getLocationOnScreen
 684  * Signature: ()Ljava/awt/Point;
 685  */
 686 JNIEXPORT jobject JNICALL
 687 Java_sun_awt_windows_WFileDialogPeer_getLocationOnScreen(JNIEnv *env,
 688                                                                  jobject peer) {
 689     TRY;
 690 
 691     jobject peerRef = env->NewGlobalRef(peer);
 692     jobject resultRef = (jobject)AwtToolkit::GetInstance().SyncCall(
 693         (void*(*)(void*))AwtFileDialog::_GetLocationOnScreen, (void *)peerRef);
 694     env->DeleteGlobalRef(peerRef);
 695 
 696     if (resultRef != NULL)
 697     {
 698         jobject result = env->NewLocalRef(resultRef);
 699         env->DeleteGlobalRef(resultRef);
 700         return result;
 701     }
 702 
 703     return NULL;
 704 
 705     CATCH_BAD_ALLOC_RET(NULL);
 706 }
 707 
 708 } /* extern "C" */