1 /*
   2  * Copyright (c) 1996, 2020, 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     peer = (jobject)p;
 263 
 264     try {
 265         DASSERT(peer);
 266         target = env->GetObjectField(peer, AwtObject::targetID);
 267         parent = env->GetObjectField(peer, AwtFileDialog::parentID);
 268         if (parent != NULL) {
 269             awtParent = (AwtComponent *)JNI_GET_PDATA(parent);
 270         }
 271 //      DASSERT(awtParent);
 272         title = (jstring)(env)->GetObjectField(target, AwtDialog::titleID);
 273         HWND hwndOwner = awtParent ? awtParent->GetHWnd() : NULL;
 274 
 275         if (title == NULL || env->GetStringLength(title)==0) {
 276             title = JNU_NewStringPlatform(env, L" ");
 277             if (title == NULL) {
 278                 throw std::bad_alloc();
 279             }
 280         }
 281 
 282         JavaStringBuffer titleBuffer(env, title);
 283         directory =
 284             (jstring)env->GetObjectField(target, AwtFileDialog::dirID);
 285         JavaStringBuffer directoryBuffer(env, directory);
 286 
 287         multipleMode = env->CallBooleanMethod(peer, AwtFileDialog::isMultipleModeMID);
 288 
 289         UINT bufferLimit;
 290         if (multipleMode == JNI_TRUE) {
 291             bufferLimit = MULTIPLE_MODE_BUFFER_LIMIT;
 292         } else {
 293             bufferLimit = SINGLE_MODE_BUFFER_LIMIT;
 294         }
 295         LPTSTR fileBuffer = new TCHAR[bufferLimit];
 296         memset(fileBuffer, 0, bufferLimit * sizeof(TCHAR));
 297 
 298         file = (jstring)env->GetObjectField(target, AwtFileDialog::fileID);
 299         if (file != NULL) {
 300             LPCTSTR tmp = JNU_GetStringPlatformChars(env, file, NULL);
 301             _tcsncpy(fileBuffer, tmp, bufferLimit - 2); // the fileBuffer is double null terminated string
 302             JNU_ReleaseStringPlatformChars(env, file, tmp);
 303         } else {
 304             fileBuffer[0] = _T('\0');
 305         }
 306 
 307         ofn.lStructSize = sizeof(ofn);
 308         ofn.lpstrFilter = s_fileFilterString;
 309         ofn.nFilterIndex = 1;
 310         /*
 311           Fix for 6488834.
 312           To disable Win32 native parent modality we have to set
 313           hwndOwner field to either NULL or some hidden window. For
 314           parentless dialogs we use NULL to show them in the taskbar,
 315           and for all other dialogs AwtToolkit's HWND is used.
 316         */
 317         if (awtParent != NULL)
 318         {
 319             ofn.hwndOwner = AwtToolkit::GetInstance().GetHWnd();
 320         }
 321         else
 322         {
 323             ofn.hwndOwner = NULL;
 324         }
 325         ofn.lpstrFile = fileBuffer;
 326         ofn.nMaxFile = bufferLimit;
 327         ofn.lpstrTitle = titleBuffer;
 328         ofn.lpstrInitialDir = directoryBuffer;
 329         ofn.Flags = OFN_LONGNAMES | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY |
 330                     OFN_ENABLEHOOK | OFN_EXPLORER | OFN_ENABLESIZING;
 331         fileFilter = env->GetObjectField(peer,
 332         AwtFileDialog::fileFilterID);
 333         if (!JNU_IsNull(env,fileFilter)) {
 334             ofn.Flags |= OFN_ENABLEINCLUDENOTIFY;
 335         }
 336         ofn.lCustData = (LPARAM)peer;
 337         ofn.lpfnHook = (LPOFNHOOKPROC)FileDialogHookProc;
 338 
 339         if (multipleMode == JNI_TRUE) {
 340             ofn.Flags |= OFN_ALLOWMULTISELECT;
 341         }
 342 
 343         // Save current directory, so we can reset if it changes.
 344         currentDirectory = new TCHAR[MAX_PATH+1];
 345 
 346         VERIFY(::GetCurrentDirectory(MAX_PATH, currentDirectory) > 0);
 347 
 348         mode = env->GetIntField(target, AwtFileDialog::modeID);
 349 
 350         AwtDialog::CheckInstallModalHook();
 351 
 352         // show the Win32 file dialog
 353         if (mode == java_awt_FileDialog_LOAD) {
 354             result = ::GetOpenFileName(&ofn);
 355         } else {
 356             result = ::GetSaveFileName(&ofn);
 357         }
 358         // Fix for 4181310: FileDialog does not show up.
 359         // If the dialog is not shown because of invalid file name
 360         // replace the file name by empty string.
 361         if (!result) {
 362             dlgerr = ::CommDlgExtendedError();
 363             if (dlgerr == FNERR_INVALIDFILENAME) {
 364                 _tcscpy_s(fileBuffer, bufferLimit, TEXT(""));
 365                 if (mode == java_awt_FileDialog_LOAD) {
 366                     result = ::GetOpenFileName(&ofn);
 367                 } else {
 368                     result = ::GetSaveFileName(&ofn);
 369                 }
 370             }
 371         }
 372 
 373         AwtDialog::CheckUninstallModalHook();
 374 
 375         DASSERT(env->GetLongField(peer, AwtComponent::hwndID) == 0L);
 376 
 377         AwtDialog::ModalActivateNextWindow(NULL, target, peer);
 378 
 379         VERIFY(::SetCurrentDirectory(currentDirectory));
 380 
 381         // Report result to peer.
 382         if (result) {
 383             jint length = multipleMode
 384                     ? (jint)GetBufferLength(ofn.lpstrFile, ofn.nMaxFile)
 385                     : (jint)_tcslen(ofn.lpstrFile);
 386             jcharArray jnames = env->NewCharArray(length);
 387             if (jnames == NULL) {
 388                 throw std::bad_alloc();
 389             }
 390             env->SetCharArrayRegion(jnames, 0, length, (jchar*)ofn.lpstrFile);
 391 
 392             env->CallVoidMethod(peer, AwtFileDialog::handleSelectedMID, jnames);
 393             env->DeleteLocalRef(jnames);
 394         } else {
 395             env->CallVoidMethod(peer, AwtFileDialog::handleCancelMID);
 396         }
 397         DASSERT(!safe_ExceptionOccurred(env));
 398     } catch (...) {
 399 
 400         env->DeleteLocalRef(target);
 401         env->DeleteLocalRef(parent);
 402         env->DeleteLocalRef(title);
 403         env->DeleteLocalRef(directory);
 404         env->DeleteLocalRef(file);
 405         env->DeleteLocalRef(fileFilter);
 406         env->DeleteGlobalRef(peer);
 407 
 408         delete[] currentDirectory;
 409         if (ofn.lpstrFile)
 410             delete[] ofn.lpstrFile;
 411         throw;
 412     }
 413 
 414     env->DeleteLocalRef(target);
 415     env->DeleteLocalRef(parent);
 416     env->DeleteLocalRef(title);
 417     env->DeleteLocalRef(directory);
 418     env->DeleteLocalRef(file);
 419     env->DeleteLocalRef(fileFilter);
 420     env->DeleteGlobalRef(peer);
 421 
 422     delete[] currentDirectory;
 423     if (ofn.lpstrFile)
 424         delete[] ofn.lpstrFile;
 425 }
 426 
 427 BOOL AwtFileDialog::InheritsNativeMouseWheelBehavior() {return true;}
 428 
 429 void AwtFileDialog::_DisposeOrHide(void *param)
 430 {
 431     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 432 
 433     jobject self = (jobject)param;
 434 
 435     HWND hdlg = (HWND)(env->GetLongField(self, AwtComponent::hwndID));
 436     if (::IsWindow(hdlg))
 437     {
 438         ::SendMessage(hdlg, WM_COMMAND, MAKEWPARAM(IDCANCEL, 0),
 439                       (LPARAM)hdlg);
 440     }
 441 
 442     env->DeleteGlobalRef(self);
 443 }
 444 
 445 void AwtFileDialog::_ToFront(void *param)
 446 {
 447     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 448 
 449     jobject self = (jobject)param;
 450     HWND hdlg = (HWND)(env->GetLongField(self, AwtComponent::hwndID));
 451     if (::IsWindow(hdlg))
 452     {
 453         ::SetWindowPos(hdlg, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
 454     }
 455 
 456     env->DeleteGlobalRef(self);
 457 }
 458 
 459 void AwtFileDialog::_ToBack(void *param)
 460 {
 461     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 462 
 463     jobject self = (jobject)param;
 464     HWND hdlg = (HWND)(env->GetLongField(self, AwtComponent::hwndID));
 465     if (::IsWindow(hdlg))
 466     {
 467         ::SetWindowPos(hdlg, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
 468     }
 469 
 470     env->DeleteGlobalRef(self);
 471 }
 472 
 473 // Returns the length of the double null terminated output buffer
 474 UINT AwtFileDialog::GetBufferLength(LPTSTR buffer, UINT limit)
 475 {
 476     UINT index = 0;
 477     while ((index < limit) &&
 478            (buffer[index] != NULL || buffer[index+1] != NULL))
 479     {
 480         index++;
 481     }
 482     return index;
 483 }
 484 
 485 /************************************************************************
 486  * WFileDialogPeer native methods
 487  */
 488 
 489 extern "C" {
 490 
 491 JNIEXPORT void JNICALL
 492 Java_sun_awt_windows_WFileDialogPeer_initIDs(JNIEnv *env, jclass cls)
 493 {
 494     TRY;
 495 
 496     AwtFileDialog::parentID =
 497         env->GetFieldID(cls, "parent", "Lsun/awt/windows/WComponentPeer;");
 498     DASSERT(AwtFileDialog::parentID != NULL);
 499     CHECK_NULL(AwtFileDialog::parentID);
 500 
 501     AwtFileDialog::fileFilterID =
 502         env->GetFieldID(cls, "fileFilter", "Ljava/io/FilenameFilter;");
 503     DASSERT(AwtFileDialog::fileFilterID != NULL);
 504     CHECK_NULL(AwtFileDialog::fileFilterID);
 505 
 506     AwtFileDialog::setHWndMID = env->GetMethodID(cls, "setHWnd", "(J)V");
 507     DASSERT(AwtFileDialog::setHWndMID != NULL);
 508     CHECK_NULL(AwtFileDialog::setHWndMID);
 509 
 510     AwtFileDialog::handleSelectedMID =
 511         env->GetMethodID(cls, "handleSelected", "([C)V");
 512     DASSERT(AwtFileDialog::handleSelectedMID != NULL);
 513     CHECK_NULL(AwtFileDialog::handleSelectedMID);
 514 
 515     AwtFileDialog::handleCancelMID =
 516         env->GetMethodID(cls, "handleCancel", "()V");
 517     DASSERT(AwtFileDialog::handleCancelMID != NULL);
 518     CHECK_NULL(AwtFileDialog::handleCancelMID);
 519 
 520     AwtFileDialog::checkFilenameFilterMID =
 521         env->GetMethodID(cls, "checkFilenameFilter", "(Ljava/lang/String;)Z");
 522     DASSERT(AwtFileDialog::checkFilenameFilterMID != NULL);
 523     CHECK_NULL(AwtFileDialog::checkFilenameFilterMID);
 524 
 525     AwtFileDialog::isMultipleModeMID = env->GetMethodID(cls, "isMultipleMode", "()Z");
 526     DASSERT(AwtFileDialog::isMultipleModeMID != NULL);
 527     CHECK_NULL(AwtFileDialog::isMultipleModeMID);
 528 
 529     /* java.awt.FileDialog fields */
 530     cls = env->FindClass("java/awt/FileDialog");
 531     CHECK_NULL(cls);
 532 
 533     AwtFileDialog::modeID = env->GetFieldID(cls, "mode", "I");
 534     DASSERT(AwtFileDialog::modeID != NULL);
 535     CHECK_NULL(AwtFileDialog::modeID);
 536 
 537     AwtFileDialog::dirID = env->GetFieldID(cls, "dir", "Ljava/lang/String;");
 538     DASSERT(AwtFileDialog::dirID != NULL);
 539     CHECK_NULL(AwtFileDialog::dirID);
 540 
 541     AwtFileDialog::fileID = env->GetFieldID(cls, "file", "Ljava/lang/String;");
 542     DASSERT(AwtFileDialog::fileID != NULL);
 543     CHECK_NULL(AwtFileDialog::fileID);
 544 
 545     AwtFileDialog::filterID =
 546         env->GetFieldID(cls, "filter", "Ljava/io/FilenameFilter;");
 547     DASSERT(AwtFileDialog::filterID != NULL);
 548 
 549     CATCH_BAD_ALLOC;
 550 }
 551 
 552 JNIEXPORT void JNICALL
 553 Java_sun_awt_windows_WFileDialogPeer_setFilterString(JNIEnv *env, jclass cls,
 554                                                      jstring filterDescription)
 555 {
 556     TRY;
 557 
 558     AwtFileDialog::Initialize(env, filterDescription);
 559 
 560     CATCH_BAD_ALLOC;
 561 }
 562 
 563 JNIEXPORT void JNICALL
 564 Java_sun_awt_windows_WFileDialogPeer__1show(JNIEnv *env, jobject peer)
 565 {
 566     TRY;
 567 
 568     /*
 569      * Fix for 4906972.
 570      * 'peer' reference has to be global as it's used further in another thread.
 571      */
 572     jobject peerGlobal = env->NewGlobalRef(peer);
 573 
 574     if (!AwtToolkit::GetInstance().PostMessage(WM_AWT_INVOKE_METHOD,
 575                              (WPARAM)AwtFileDialog::Show, (LPARAM)peerGlobal)) {
 576         env->DeleteGlobalRef(peerGlobal);
 577     }
 578 
 579     CATCH_BAD_ALLOC;
 580 }
 581 
 582 JNIEXPORT void JNICALL
 583 Java_sun_awt_windows_WFileDialogPeer__1dispose(JNIEnv *env, jobject peer)
 584 {
 585     TRY_NO_VERIFY;
 586 
 587     jobject peerGlobal = env->NewGlobalRef(peer);
 588 
 589     AwtToolkit::GetInstance().SyncCall(AwtFileDialog::_DisposeOrHide,
 590         (void *)peerGlobal);
 591     // peerGlobal ref is deleted in _DisposeOrHide
 592 
 593     CATCH_BAD_ALLOC;
 594 }
 595 
 596 JNIEXPORT void JNICALL
 597 Java_sun_awt_windows_WFileDialogPeer__1hide(JNIEnv *env, jobject peer)
 598 {
 599     TRY;
 600 
 601     jobject peerGlobal = env->NewGlobalRef(peer);
 602 
 603     AwtToolkit::GetInstance().SyncCall(AwtFileDialog::_DisposeOrHide,
 604         (void *)peerGlobal);
 605     // peerGlobal ref is deleted in _DisposeOrHide
 606 
 607     CATCH_BAD_ALLOC;
 608 }
 609 
 610 JNIEXPORT void JNICALL
 611 Java_sun_awt_windows_WFileDialogPeer_toFront(JNIEnv *env, jobject peer)
 612 {
 613     TRY;
 614 
 615     AwtToolkit::GetInstance().SyncCall(AwtFileDialog::_ToFront,
 616                                        (void *)(env->NewGlobalRef(peer)));
 617     // global ref is deleted in _ToFront
 618 
 619     CATCH_BAD_ALLOC;
 620 }
 621 
 622 JNIEXPORT void JNICALL
 623 Java_sun_awt_windows_WFileDialogPeer_toBack(JNIEnv *env, jobject peer)
 624 {
 625     TRY;
 626 
 627     AwtToolkit::GetInstance().SyncCall(AwtFileDialog::_ToBack,
 628                                        (void *)(env->NewGlobalRef(peer)));
 629     // global ref is deleted in _ToBack
 630 
 631     CATCH_BAD_ALLOC;
 632 }
 633 
 634 int ScaleDownAbsX(int x, HWND hwnd) {
 635     int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(hwnd);
 636     Devices::InstanceAccess devices;
 637     AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
 638     return device == NULL ? x : device->ScaleDownAbsX(x);
 639 }
 640 
 641 int ScaleDownAbsY(int y, HWND hwnd) {
 642     int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(hwnd);
 643     Devices::InstanceAccess devices;
 644     AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
 645     return device == NULL ? y : device->ScaleDownAbsY(y);
 646 }
 647 
 648 jobject AwtFileDialog::_GetLocationOnScreen(void *param)
 649 {
 650     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 651 
 652     jobject result = NULL;
 653     HWND hwnd = (HWND)env->GetLongField((jobject)param, AwtComponent::hwndID);
 654 
 655     if (::IsWindow(hwnd))
 656     {
 657         RECT rect;
 658         VERIFY(::GetWindowRect(hwnd, &rect));
 659         result = JNU_NewObjectByName(env, "java/awt/Point", "(II)V",
 660                                      ScaleDownAbsX(rect.left, hwnd),
 661                                      ScaleDownAbsY(rect.top, hwnd));
 662     }
 663 
 664     if (result != NULL)
 665     {
 666         jobject resultRef = env->NewGlobalRef(result);
 667         env->DeleteLocalRef(result);
 668         return resultRef;
 669     }
 670     else
 671     {
 672         return NULL;
 673     }
 674 }
 675 
 676 /*
 677  * Class:     sun_awt_windows_WFileDialogPeer
 678  * Method:    getLocationOnScreen
 679  * Signature: ()Ljava/awt/Point;
 680  */
 681 JNIEXPORT jobject JNICALL
 682 Java_sun_awt_windows_WFileDialogPeer_getLocationOnScreen(JNIEnv *env,
 683                                                                  jobject peer) {
 684     TRY;
 685 
 686     jobject peerRef = env->NewGlobalRef(peer);
 687     jobject resultRef = (jobject)AwtToolkit::GetInstance().SyncCall(
 688         (void*(*)(void*))AwtFileDialog::_GetLocationOnScreen, (void *)peerRef);
 689     env->DeleteGlobalRef(peerRef);
 690 
 691     if (resultRef != NULL)
 692     {
 693         jobject result = env->NewLocalRef(resultRef);
 694         env->DeleteGlobalRef(resultRef);
 695         return result;
 696     }
 697 
 698     return NULL;
 699 
 700     CATCH_BAD_ALLOC_RET(NULL);
 701 }
 702 
 703 } /* extern "C" */