我有一个 Java Swing 应用程序,其中包含一些通过 JNI 添加的本机功能。此应用程序所做的一件事是显示文件系统的树形视图。我试图编写一个小 JNI,以便在 Windows 系统上,我可以提供一个“属性...”上下文菜单项,该菜单项显示来自 Windows 的标准文件“属性”对话框。
我在互联网上搜索了执行此操作所需的 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的话,在“InvokeCommand成功!”之后会弹出属性对话框 消息框。
我注意到的另一件事是,当未定义 DEBUG 时,我调用此方法(并且不显示属性对话框),如果我打开不同的“本机”窗口,它将稍后显示在应用程序中。例如,我有通过 SHFileOperation 打开本机删除对话框的代码(有效);一旦我显示该对话框,任何最初未显示的文件属性对话框都会突然出现。
好像我在错误的线程上做事。EDT 不是我想从中显示本机窗口的线程吗?但我很困惑,因为删除对话框再次正常工作。