1 /*
   2  * Copyright (c) 1996, 2014, 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     }
 111 
 112     WNDPROC lpfnWndProc = (WNDPROC)(::GetProp(hWnd, NativeDialogWndProcProp));
 113     return ComCtl32Util::GetInstance().DefWindowProc(lpfnWndProc, hWnd, message, wParam, lParam);
 114 }
 115 
 116 static UINT_PTR CALLBACK
 117 FileDialogHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
 118 {
 119     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 120 
 121     TRY;
 122 
 123     HWND parent = ::GetParent(hdlg);
 124 
 125     switch(uiMsg) {
 126         case WM_INITDIALOG: {
 127             OPENFILENAME *ofn = (OPENFILENAME *)lParam;
 128             jobject peer = (jobject)(ofn->lCustData);
 129             env->CallVoidMethod(peer, AwtFileDialog::setHWndMID,
 130                                 (jlong)parent);
 131             ::SetProp(parent, ModalDialogPeerProp, reinterpret_cast<HANDLE>(peer));
 132 
 133             // fix for 4508670 - disable CS_SAVEBITS
 134             DWORD style = ::GetClassLong(hdlg,GCL_STYLE);
 135             ::SetClassLong(hdlg,GCL_STYLE,style & ~CS_SAVEBITS);
 136 
 137             // set appropriate icon for parentless dialogs
 138             jobject awtParent = env->GetObjectField(peer, AwtFileDialog::parentID);
 139             if (awtParent == NULL) {
 140                 ::SendMessage(parent, WM_SETICON, (WPARAM)ICON_BIG,
 141                               (LPARAM)AwtToolkit::GetInstance().GetAwtIcon());
 142             } else {
 143                 env->DeleteLocalRef(awtParent);
 144             }
 145 
 146             // subclass dialog's parent to receive additional messages
 147             WNDPROC lpfnWndProc = ComCtl32Util::GetInstance().SubclassHWND(parent,
 148                                                                            FileDialogWndProc);
 149             ::SetProp(parent, NativeDialogWndProcProp, reinterpret_cast<HANDLE>(lpfnWndProc));
 150 
 151             ::SetProp(parent, OpenFileNameProp, (void *)lParam);
 152 
 153             break;
 154         }
 155         case WM_DESTROY: {
 156             HIMC hIMC = ::ImmGetContext(hdlg);
 157             if (hIMC != NULL) {
 158                 ::ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
 159                 ::ImmReleaseContext(hdlg, hIMC);
 160             }
 161 
 162             WNDPROC lpfnWndProc = (WNDPROC)(::GetProp(parent, NativeDialogWndProcProp));
 163             ComCtl32Util::GetInstance().UnsubclassHWND(parent,
 164                                                        FileDialogWndProc,
 165                                                        lpfnWndProc);
 166             ::RemoveProp(parent, ModalDialogPeerProp);
 167             ::RemoveProp(parent, NativeDialogWndProcProp);
 168             ::RemoveProp(parent, OpenFileNameProp);
 169             break;
 170         }
 171         case WM_NOTIFY: {
 172             OFNOTIFYEX *notifyEx = (OFNOTIFYEX *)lParam;
 173             if (notifyEx) {
 174                 jobject peer = (jobject)(::GetProp(parent, ModalDialogPeerProp));
 175                 if (notifyEx->hdr.code == CDN_INCLUDEITEM) {
 176                     LPITEMIDLIST pidl = (LPITEMIDLIST)notifyEx->pidl;
 177                     // Get the filename and directory
 178                     TCHAR szPath[MAX_PATH];
 179                     if (!::SHGetPathFromIDList(pidl, szPath)) {
 180                         return TRUE;
 181                     }
 182                     jstring strPath = JNU_NewStringPlatform(env, szPath);
 183                     if (strPath == NULL) {
 184                         throw std::bad_alloc();
 185                     }
 186                     // Call FilenameFilter.accept with path and filename
 187                     UINT uRes = (env->CallBooleanMethod(peer,
 188                         AwtFileDialog::checkFilenameFilterMID, strPath) == JNI_TRUE);
 189                     env->DeleteLocalRef(strPath);
 190                     return uRes;
 191                 } else if (notifyEx->hdr.code == CDN_FILEOK) {
 192                     // This notification is sent when user selects some file and presses
 193                     // OK button; it is not sent when no file is selected. So it's time
 194                     // to unblock all the windows blocked by this dialog as it will
 195                     // be closed soon
 196                     env->CallVoidMethod(peer, AwtFileDialog::setHWndMID, (jlong)0);
 197                 } else if (notifyEx->hdr.code == CDN_SELCHANGE) {
 198                     // reallocate the buffer if the buffer is too small
 199                     LPOPENFILENAME lpofn = (LPOPENFILENAME)GetProp(parent, OpenFileNameProp);
 200 
 201                     UINT nLength = CommDlg_OpenSave_GetSpec(parent, NULL, 0) +
 202                                    CommDlg_OpenSave_GetFolderPath(parent, NULL, 0);
 203 
 204                     if (lpofn->nMaxFile < nLength)
 205                     {
 206                         // allocate new buffer
 207                         LPTSTR newBuffer = new TCHAR[nLength];
 208 
 209                         if (newBuffer) {
 210                             memset(newBuffer, 0, nLength * sizeof(TCHAR));
 211                             LPTSTR oldBuffer = lpofn->lpstrFile;
 212                             lpofn->lpstrFile = newBuffer;
 213                             lpofn->nMaxFile = nLength;
 214                             // free the previously allocated buffer
 215                             if (oldBuffer) {
 216                                 delete[] oldBuffer;
 217                             }
 218 
 219                         }
 220                     }
 221                 }
 222             }
 223             break;
 224         }
 225     }
 226 
 227     return FALSE;
 228 
 229     CATCH_BAD_ALLOC_RET(TRUE);
 230 }
 231 
 232 void
 233 AwtFileDialog::Show(void *p)
 234 {
 235     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 236     jobject peer;
 237     LPTSTR fileBuffer = NULL;
 238     LPTSTR currentDirectory = NULL;
 239     jint mode = 0;
 240     BOOL result = FALSE;
 241     DWORD dlgerr;
 242     jstring directory = NULL;
 243     jstring title = NULL;
 244     jstring file = NULL;
 245     jobject fileFilter = NULL;
 246     jobject target = NULL;
 247     jobject parent = NULL;
 248     AwtComponent* awtParent = NULL;
 249     jboolean multipleMode = JNI_FALSE;
 250 
 251     OPENFILENAME ofn;
 252     memset(&ofn, 0, sizeof(ofn));
 253 
 254     /*
 255      * There's a situation (see bug 4906972) when InvokeFunction (by which this method is called)
 256      * returnes earlier than this method returnes. Probably it's caused due to ReplyMessage system call.
 257      * So for the avoidance of this mistiming we need to make new global reference here
 258      * (not local as it's used by the hook) and then manage it independently of the calling thread.
 259      */
 260     peer = env->NewGlobalRef((jobject)p);
 261 
 262     try {
 263         DASSERT(peer);
 264         target = env->GetObjectField(peer, AwtObject::targetID);
 265         parent = env->GetObjectField(peer, AwtFileDialog::parentID);
 266         if (parent != NULL) {
 267             awtParent = (AwtComponent *)JNI_GET_PDATA(parent);
 268         }
 269 //      DASSERT(awtParent);
 270         title = (jstring)(env)->GetObjectField(target, AwtDialog::titleID);
 271         HWND hwndOwner = awtParent ? awtParent->GetHWnd() : NULL;
 272 
 273         if (title == NULL || env->GetStringLength(title)==0) {
 274             title = JNU_NewStringPlatform(env, L" ");
 275             if (title == NULL) {
 276                 throw std::bad_alloc();
 277             }
 278         }
 279 
 280         JavaStringBuffer titleBuffer(env, title);
 281         directory =
 282             (jstring)env->GetObjectField(target, AwtFileDialog::dirID);
 283         JavaStringBuffer directoryBuffer(env, directory);
 284 
 285         multipleMode = env->CallBooleanMethod(peer, AwtFileDialog::isMultipleModeMID);
 286 
 287         UINT bufferLimit;
 288         if (multipleMode == JNI_TRUE) {
 289             bufferLimit = MULTIPLE_MODE_BUFFER_LIMIT;
 290         } else {
 291             bufferLimit = SINGLE_MODE_BUFFER_LIMIT;
 292         }
 293         LPTSTR fileBuffer = new TCHAR[bufferLimit];
 294         memset(fileBuffer, 0, bufferLimit * sizeof(TCHAR));
 295 
 296         file = (jstring)env->GetObjectField(target, AwtFileDialog::fileID);
 297         if (file != NULL) {
 298             LPCTSTR tmp = JNU_GetStringPlatformChars(env, file, NULL);
 299             _tcsncpy(fileBuffer, tmp, bufferLimit - 2); // the fileBuffer is double null terminated string
 300             JNU_ReleaseStringPlatformChars(env, file, tmp);
 301         } else {
 302             fileBuffer[0] = _T('\0');
 303         }
 304 
 305         ofn.lStructSize = sizeof(ofn);
 306         ofn.lpstrFilter = s_fileFilterString;
 307         ofn.nFilterIndex = 1;
 308         /*
 309           Fix for 6488834.
 310           To disable Win32 native parent modality we have to set
 311           hwndOwner field to either NULL or some hidden window. For
 312           parentless dialogs we use NULL to show them in the taskbar,
 313           and for all other dialogs AwtToolkit's HWND is used.
 314         */
 315         if (awtParent != NULL)
 316         {
 317             ofn.hwndOwner = AwtToolkit::GetInstance().GetHWnd();
 318         }
 319         else
 320         {
 321             ofn.hwndOwner = NULL;
 322         }
 323         ofn.lpstrFile = fileBuffer;
 324         ofn.nMaxFile = bufferLimit;
 325         ofn.lpstrTitle = titleBuffer;
 326         ofn.lpstrInitialDir = directoryBuffer;
 327         ofn.Flags = OFN_LONGNAMES | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY |
 328                     OFN_ENABLEHOOK | OFN_EXPLORER | OFN_ENABLESIZING;
 329         fileFilter = env->GetObjectField(peer,
 330         AwtFileDialog::fileFilterID);
 331         if (!JNU_IsNull(env,fileFilter)) {
 332             ofn.Flags |= OFN_ENABLEINCLUDENOTIFY;
 333         }
 334         ofn.lCustData = (LPARAM)peer;
 335         ofn.lpfnHook = (LPOFNHOOKPROC)FileDialogHookProc;
 336 
 337         if (multipleMode == JNI_TRUE) {
 338             ofn.Flags |= OFN_ALLOWMULTISELECT;
 339         }
 340 
 341         // Save current directory, so we can reset if it changes.
 342         currentDirectory = new TCHAR[MAX_PATH+1];
 343 
 344         VERIFY(::GetCurrentDirectory(MAX_PATH, currentDirectory) > 0);
 345 
 346         mode = env->GetIntField(target, AwtFileDialog::modeID);
 347 
 348         AwtDialog::CheckInstallModalHook();
 349 
 350         // show the Win32 file dialog
 351         if (mode == java_awt_FileDialog_LOAD) {
 352             result = ::GetOpenFileName(&ofn);
 353         } else {
 354             result = ::GetSaveFileName(&ofn);
 355         }
 356         // Fix for 4181310: FileDialog does not show up.
 357         // If the dialog is not shown because of invalid file name
 358         // replace the file name by empty string.
 359         if (!result) {
 360             dlgerr = ::CommDlgExtendedError();
 361             if (dlgerr == FNERR_INVALIDFILENAME) {
 362                 _tcscpy_s(fileBuffer, bufferLimit, TEXT(""));
 363                 if (mode == java_awt_FileDialog_LOAD) {
 364                     result = ::GetOpenFileName(&ofn);
 365                 } else {
 366                     result = ::GetSaveFileName(&ofn);
 367                 }
 368             }
 369         }
 370 
 371         AwtDialog::CheckUninstallModalHook();
 372 
 373         DASSERT(env->GetLongField(peer, AwtComponent::hwndID) == 0L);
 374 
 375         AwtDialog::ModalActivateNextWindow(NULL, target, peer);
 376 
 377         VERIFY(::SetCurrentDirectory(currentDirectory));
 378 
 379         // Report result to peer.
 380         if (result) {
 381             jint length = multipleMode
 382                     ? (jint)GetBufferLength(ofn.lpstrFile, ofn.nMaxFile)
 383                     : (jint)_tcslen(ofn.lpstrFile);
 384             jcharArray jnames = env->NewCharArray(length);
 385             if (jnames == NULL) {
 386                 throw std::bad_alloc();
 387             }
 388             env->SetCharArrayRegion(jnames, 0, length, (jchar*)ofn.lpstrFile);
 389 
 390             env->CallVoidMethod(peer, AwtFileDialog::handleSelectedMID, jnames);
 391             env->DeleteLocalRef(jnames);
 392         } else {
 393             env->CallVoidMethod(peer, AwtFileDialog::handleCancelMID);
 394         }
 395         DASSERT(!safe_ExceptionOccurred(env));
 396     } catch (...) {
 397 
 398         env->DeleteLocalRef(target);
 399         env->DeleteLocalRef(parent);
 400         env->DeleteLocalRef(title);
 401         env->DeleteLocalRef(directory);
 402         env->DeleteLocalRef(file);
 403         env->DeleteLocalRef(fileFilter);
 404         env->DeleteGlobalRef(peer);
 405 
 406         delete[] currentDirectory;
 407         if (ofn.lpstrFile)
 408             delete[] ofn.lpstrFile;
 409         throw;
 410     }
 411 
 412     env->DeleteLocalRef(target);
 413     env->DeleteLocalRef(parent);
 414     env->DeleteLocalRef(title);
 415     env->DeleteLocalRef(directory);
 416     env->DeleteLocalRef(file);
 417     env->DeleteLocalRef(fileFilter);
 418     env->DeleteGlobalRef(peer);
 419 
 420     delete[] currentDirectory;
 421     if (ofn.lpstrFile)
 422         delete[] ofn.lpstrFile;
 423 }
 424 
 425 BOOL AwtFileDialog::InheritsNativeMouseWheelBehavior() {return true;}
 426 
 427 void AwtFileDialog::_DisposeOrHide(void *param)
 428 {
 429     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 430 
 431     jobject self = (jobject)param;
 432 
 433     HWND hdlg = (HWND)(env->GetLongField(self, AwtComponent::hwndID));
 434     if (::IsWindow(hdlg))
 435     {
 436         ::SendMessage(hdlg, WM_COMMAND, MAKEWPARAM(IDCANCEL, 0),
 437                       (LPARAM)hdlg);
 438     }
 439 
 440     env->DeleteGlobalRef(self);
 441 }
 442 
 443 void AwtFileDialog::_ToFront(void *param)
 444 {
 445     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 446 
 447     jobject self = (jobject)param;
 448     HWND hdlg = (HWND)(env->GetLongField(self, AwtComponent::hwndID));
 449     if (::IsWindow(hdlg))
 450     {
 451         ::SetWindowPos(hdlg, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
 452     }
 453 
 454     env->DeleteGlobalRef(self);
 455 }
 456 
 457 void AwtFileDialog::_ToBack(void *param)
 458 {
 459     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 460 
 461     jobject self = (jobject)param;
 462     HWND hdlg = (HWND)(env->GetLongField(self, AwtComponent::hwndID));
 463     if (::IsWindow(hdlg))
 464     {
 465         ::SetWindowPos(hdlg, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
 466     }
 467 
 468     env->DeleteGlobalRef(self);
 469 }
 470 
 471 // Returns the length of the double null terminated output buffer
 472 UINT AwtFileDialog::GetBufferLength(LPTSTR buffer, UINT limit)
 473 {
 474     UINT index = 0;
 475     while ((index < limit) &&
 476            (buffer[index] != NULL || buffer[index+1] != NULL))
 477     {
 478         index++;
 479     }
 480     return index;
 481 }
 482 
 483 /************************************************************************
 484  * WFileDialogPeer native methods
 485  */
 486 
 487 extern "C" {
 488 
 489 JNIEXPORT void JNICALL
 490 Java_sun_awt_windows_WFileDialogPeer_initIDs(JNIEnv *env, jclass cls)
 491 {
 492     TRY;
 493 
 494     AwtFileDialog::parentID =
 495         env->GetFieldID(cls, "parent", "Lsun/awt/windows/WComponentPeer;");
 496     DASSERT(AwtFileDialog::parentID != NULL);
 497     CHECK_NULL(AwtFileDialog::parentID);
 498 
 499     AwtFileDialog::fileFilterID =
 500         env->GetFieldID(cls, "fileFilter", "Ljava/io/FilenameFilter;");
 501     DASSERT(AwtFileDialog::fileFilterID != NULL);
 502     CHECK_NULL(AwtFileDialog::fileFilterID);
 503 
 504     AwtFileDialog::setHWndMID = env->GetMethodID(cls, "setHWnd", "(J)V");
 505     DASSERT(AwtFileDialog::setHWndMID != NULL);
 506     CHECK_NULL(AwtFileDialog::setHWndMID);
 507 
 508     AwtFileDialog::handleSelectedMID =
 509         env->GetMethodID(cls, "handleSelected", "([C)V");
 510     DASSERT(AwtFileDialog::handleSelectedMID != NULL);
 511     CHECK_NULL(AwtFileDialog::handleSelectedMID);
 512 
 513     AwtFileDialog::handleCancelMID =
 514         env->GetMethodID(cls, "handleCancel", "()V");
 515     DASSERT(AwtFileDialog::handleCancelMID != NULL);
 516     CHECK_NULL(AwtFileDialog::handleCancelMID);
 517 
 518     AwtFileDialog::checkFilenameFilterMID =
 519         env->GetMethodID(cls, "checkFilenameFilter", "(Ljava/lang/String;)Z");
 520     DASSERT(AwtFileDialog::checkFilenameFilterMID != NULL);
 521     CHECK_NULL(AwtFileDialog::checkFilenameFilterMID);
 522 
 523     AwtFileDialog::isMultipleModeMID = env->GetMethodID(cls, "isMultipleMode", "()Z");
 524     DASSERT(AwtFileDialog::isMultipleModeMID != NULL);
 525     CHECK_NULL(AwtFileDialog::isMultipleModeMID);
 526 
 527     /* java.awt.FileDialog fields */
 528     cls = env->FindClass("java/awt/FileDialog");
 529     CHECK_NULL(cls);
 530 
 531     AwtFileDialog::modeID = env->GetFieldID(cls, "mode", "I");
 532     DASSERT(AwtFileDialog::modeID != NULL);
 533     CHECK_NULL(AwtFileDialog::modeID);
 534 
 535     AwtFileDialog::dirID = env->GetFieldID(cls, "dir", "Ljava/lang/String;");
 536     DASSERT(AwtFileDialog::dirID != NULL);
 537     CHECK_NULL(AwtFileDialog::dirID);
 538 
 539     AwtFileDialog::fileID = env->GetFieldID(cls, "file", "Ljava/lang/String;");
 540     DASSERT(AwtFileDialog::fileID != NULL);
 541     CHECK_NULL(AwtFileDialog::fileID);
 542 
 543     AwtFileDialog::filterID =
 544         env->GetFieldID(cls, "filter", "Ljava/io/FilenameFilter;");
 545     DASSERT(AwtFileDialog::filterID != NULL);
 546 
 547     CATCH_BAD_ALLOC;
 548 }
 549 
 550 JNIEXPORT void JNICALL
 551 Java_sun_awt_windows_WFileDialogPeer_setFilterString(JNIEnv *env, jclass cls,
 552                                                      jstring filterDescription)
 553 {
 554     TRY;
 555 
 556     AwtFileDialog::Initialize(env, filterDescription);
 557 
 558     CATCH_BAD_ALLOC;
 559 }
 560 
 561 JNIEXPORT void JNICALL
 562 Java_sun_awt_windows_WFileDialogPeer__1show(JNIEnv *env, jobject peer)
 563 {
 564     TRY;
 565 
 566     /*
 567      * Fix for 4906972.
 568      * 'peer' reference has to be global as it's used further in another thread.
 569      */
 570     jobject peerGlobal = env->NewGlobalRef(peer);
 571 
 572     if (!AwtToolkit::GetInstance().PostMessage(WM_AWT_INVOKE_METHOD,
 573                              (WPARAM)AwtFileDialog::Show, (LPARAM)peerGlobal)) {
 574         env->DeleteGlobalRef(peerGlobal);
 575     }
 576 
 577     CATCH_BAD_ALLOC;
 578 }
 579 
 580 JNIEXPORT void JNICALL
 581 Java_sun_awt_windows_WFileDialogPeer__1dispose(JNIEnv *env, jobject peer)
 582 {
 583     TRY_NO_VERIFY;
 584 
 585     jobject peerGlobal = env->NewGlobalRef(peer);
 586 
 587     AwtToolkit::GetInstance().SyncCall(AwtFileDialog::_DisposeOrHide,
 588         (void *)peerGlobal);
 589     // peerGlobal ref is deleted in _DisposeOrHide
 590 
 591     CATCH_BAD_ALLOC;
 592 }
 593 
 594 JNIEXPORT void JNICALL
 595 Java_sun_awt_windows_WFileDialogPeer__1hide(JNIEnv *env, jobject peer)
 596 {
 597     TRY;
 598 
 599     jobject peerGlobal = env->NewGlobalRef(peer);
 600 
 601     AwtToolkit::GetInstance().SyncCall(AwtFileDialog::_DisposeOrHide,
 602         (void *)peerGlobal);
 603     // peerGlobal ref is deleted in _DisposeOrHide
 604 
 605     CATCH_BAD_ALLOC;
 606 }
 607 
 608 JNIEXPORT void JNICALL
 609 Java_sun_awt_windows_WFileDialogPeer_toFront(JNIEnv *env, jobject peer)
 610 {
 611     TRY;
 612 
 613     AwtToolkit::GetInstance().SyncCall(AwtFileDialog::_ToFront,
 614                                        (void *)(env->NewGlobalRef(peer)));
 615     // global ref is deleted in _ToFront
 616 
 617     CATCH_BAD_ALLOC;
 618 }
 619 
 620 JNIEXPORT void JNICALL
 621 Java_sun_awt_windows_WFileDialogPeer_toBack(JNIEnv *env, jobject peer)
 622 {
 623     TRY;
 624 
 625     AwtToolkit::GetInstance().SyncCall(AwtFileDialog::_ToBack,
 626                                        (void *)(env->NewGlobalRef(peer)));
 627     // global ref is deleted in _ToBack
 628 
 629     CATCH_BAD_ALLOC;
 630 }
 631 
 632 } /* extern "C" */