1

JNIを介していくつかのネイティブ機能が追加されたJavaSwingアプリケーションがあります。このアプリケーションが行うことの1つは、ファイルシステムのツリービューを表示することです。Windowsシステムで、Windowsの標準ファイルの[プロパティ]ダイアログを表示する[プロパティ...]コンテキストメニュー項目を提供できるように、小さなJNIを作成しようとしていました。

私はこれを行うために必要なWin32コードのためにインターネットをこすり落とし、これを思いついた:

JNIEXPORT jboolean JNICALL Java_com_foobar_showFilePropertiesDialogImpl
  (JNIEnv *env, jobject obj, jlong hwnd, jstring fileName)
{
    LPITEMIDLIST pidl;
    LPCITEMIDLIST pidlItem;
    HRESULT hr;
    IShellFolder *pFolder;
    IContextMenu *pContextMenu;
    CMINVOKECOMMANDINFO cmi;
    const wchar_t *pszFile;

    if (!coInitialized)
    {
#ifdef DEBUG
        MessageBoxW(NULL, L"Initializing COM (should happen just once)...", L"Initializing COM...", MB_OK);
#endif
        CoInitialize(NULL);
        coInitialized = true;
    }

    /* Get the name of the file. */
    pszFile = (wchar_t *)env->GetStringChars(fileName, NULL);
    if (pszFile==NULL) { /* Exception occurred */
        return JNI_FALSE;
    }

    hr = SHGetDesktopFolder(&pFolder);
    if (FAILED(hr))
    {
        env->ReleaseStringChars(fileName, (const jchar *)pszFile);
        return JNI_FALSE;
    }

    hr = pFolder->ParseDisplayName(HWND_DESKTOP, NULL, (LPTSTR)pszFile, NULL, &pidl, NULL);
    pFolder->Release();
    if (FAILED(hr))
    {
        env->ReleaseStringChars(fileName, (const jchar *)pszFile);
        return JNI_FALSE;
    }

    hr = SHBindToParent(pidl, IID_IShellFolder, (void **)&pFolder, &pidlItem);
    if (FAILED(hr))
    {
        SHFree(pidl);
        env->ReleaseStringChars(fileName, (const jchar *)pszFile);
        return JNI_FALSE;
    }

    hr = pFolder->GetUIObjectOf(HWND_DESKTOP, 1, (LPCITEMIDLIST *)&pidlItem, IID_IContextMenu, NULL, (void **)&pContextMenu);
    pFolder->Release();
    if(SUCCEEDED(hr))
    {
        ZeroMemory(&cmi, sizeof(cmi));
        cmi.cbSize = sizeof(cmi);
        if (hwnd>0)
        {
            cmi.hwnd = (HWND)hwnd;
        }
        cmi.lpVerb = "properties";
        cmi.nShow = SW_SHOWNORMAL;
        hr = pContextMenu->InvokeCommand(&cmi);
#ifdef DEBUG
        if (FAILED(hr))
        {
            wchar_t msg[2048];
            wsprintf(msg, L"InvokeCommand failed: %d - %x", SUCCEEDED(hr), hr);
            MessageBoxW(NULL, pszFile, msg, MB_OK);
        }
        else
        {
            MessageBoxW(NULL, L"InvokeCommand successful!", L"InvokeCommand Status", MB_OK);
        }
#endif
    }

    pContextMenu->Release();
    SHFree(pidl);
    env->ReleaseStringChars(fileName, (const jchar *)pszFile);

    return JNI_TRUE;
}

Javaから、EDTからこのメソッドを実行します。残念ながら、DEBUGが定義されていない場合、プロパティダイアログは表示されません。DEBUGを定義すると、「InvokeCommandsuccessful!」の後にプロパティダイアログがポップアップするようです。メッセージボックス。

もう1つ気付いたのは、DEBUGが定義されていない場合、このメソッドを呼び出すと(プロパティダイアログは表示されません)、別の「ネイティブ」ウィンドウを開くと、後でアプリケーションに表示されますたとえば、SHFileOperationを介してネイティブの削除ダイアログを開くコードがあります(これは機能します)。そのダイアログを表示するとすぐに、元々表示されていなかったファイルプロパティダイアログが突然表示されます。

おそらく間違ったスレッドで何かをしているようです。EDTは、ネイティブウィンドウを表示したいスレッドではありませんか?しかし、ここでも削除ダイアログが正常に機能しているため、混乱しています。

4

1 に答える 1

0

シェルインターフェイスを手動で掘り下げる代わりに、代わりに使用しShellExecute()てみて、OSに重い作業を任せてください。

JNIEXPORT jboolean JNICALL Java_com_foobar_showFilePropertiesDialogImpl 
  (JNIEnv *env, jobject obj, jlong hwnd, jstring fileName) 
{ 
    /* Get the name of the file. */ 
    const wchar_t *pszFile = (wchar_t *)env->GetStringChars(fileName, NULL); 
    if (pszFile==NULL) { /* Exception occurred */ 
        return JNI_FALSE; 
    } 

    int iErr = (int) ShellExecuteW((HWND)hwnd, L"properties", pszFile, NULL, NULL, SW_SHOWNORMAL);
    env->ReleaseStringChars(fileName, (const jchar *)pszFile); 

    /*
    wchar_t msg[36];
    if (iErr > 32)
        wsprintfW(msg, L"ShellExecute successful!"); 
    else 
        wsprintfW(msg, L"ShellExecute failed: %d", iErr); 
    MessageBoxW((HWND)hwnd, pszFile, msg, MB_OK); 
    */

    return JNI_TRUE; 
} 
于 2012-09-21T19:45:47.260 に答える