#java #windows #swing #heap-corruption
#java #Windows #swing #повреждение кучи
Вопрос:
В настоящее время я работаю над реализацией перетаскивания из Outlook в Swing (в Windows) с помощью Swing dropptarget. Поскольку перетаскивание Outlook автоматически не работает с Swing, я отладил его и обнаружил, что он использовал FileNameW
native для события. Для поддержки этого я использую этот код:
private static final String nativeFileNameW = "FileNameW";
private static final DataFlavor fileNameWFlavor = new DataFlavor(InputStream.class, nativeFileNameW);
public void installFileNameWFlavorIfWindows(DropTarget dt) {
FlavorMap fm = dt.getFlavorMap();
if (!(fm instanceof SystemFlavorMap)) {
fm = SystemFlavorMap.getDefaultFlavorMap();
}
if (fm instanceof SystemFlavorMap) {
SystemFlavorMap sysFM = (SystemFlavorMap) fm;
sysFM.addFlavorForUnencodedNative(nativeFileNameW, fileNameWFlavor);
sysFM.addUnencodedNativeForFlavor(fileNameWFlavor, nativeFileNameW);
dt.setFlavorMap(sysFM);
}
}
Кажется, это работает нормально, но я не уверен, что это правильный подход, поскольку я не смог найти никаких ресурсов по этой проблеме.
В событии drop теперь я могу получить входной поток, когда электронное письмо Outlook отбрасывается в компонент Swing. Я использую следующий код в своем методе drop (реальный метод более сложный, потому что он также обрабатывает другие данные, но этот пример здесь может воспроизвести ошибку):
public void drop(DropTargetDropEvent dtde) {
Transferable transfer = dtde.getTransferable();
boolean accepted = false;
if (transfer.isDataFlavorSupported(fileNameWFlavor)) {
accepted = true;
dtde.acceptDrop(DnDConstants.ACTION_COPY);
try (InputStream is = (InputStream) transfer.getTransferData(fileNameWFlavor)) {
//Do something with InputStream
} catch (UnsupportedFlavorException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
dtde.dropComplete(accepted);
}
Я использую оператор try with resource, чтобы убедиться, что поток закрыт после события drop. Я хочу закрыть поток, чтобы убедиться, что после завершения удаления нет открытых дескрипторов файлов или аналогичных собственных ресурсов, которые могут быть ограничены.
Входной поток для удаления из Outlook является экземпляром WDropTargetContextPeerFileStream
, и при вызове метода close происходит сбой в собственном методе freeStgMedium
, который должен освободить собственную структуру данных Windows.
Я не получаю никаких сообщений об ошибках в командной строке.
Программа завершается с кодом ошибки -1073740940
, который, по-видимому, указывает на ошибку повреждения кучи.
Есть ли что-то, чего мне не хватает? Этот входной поток не должен быть закрыт или есть ошибка ранее.
Я использую JDK от Azul, Zulu 8.48.0.53 (Java 8u265).
Я также пробовал это с Zulu 11, Oracle Java 8 и сборкой Redhat Openjdk 8, все они завершаются одинаково.
Обновление: я думаю, что я отследил ошибку до собственного кода JDK, который получает данные.
Код JDK создает STGMEDIUM
объект в стеке и передает указатель на него методу Windows IDataObject::GetData()
. Этот метод записывает свои данные обратно в STGMEDIUM*
параметр.
Это не должно быть проблемой, поскольку все примеры этой функции Windows делали это одинаково. Но похоже, что Outlook не инициализирует переменную-член IUnknown *STGMEDIUM::pUnkForRelease
, а вместо этого полагается на вызывающий объект для заполнения структуры данных нулем (или Outlook имеет ошибку).
Когда собственные ресурсы освобождаются Java, он вызывает ReleaseStgMedium
, который пытается вызвать Release
pUnkForRelease
указатель, если это не так NULL
, что вызывает ошибку.
На данный момент я просто не закрываю входной поток и допускаю утечку дескриптора файла, что не оптимально, но я не вижу другого решения.
Если я найду реальное решение этой ошибки, я напишу обновление / ответ здесь.
Комментарии:
1.
FileNameW
похоже, вы на самом деле получаете не специальный элемент, а просто имя файла. Вы пытались получить его через встроенныйDataFlavor.javaFileListFlavor
вместо этого?2. По умолчанию собственное имя файла не связано ни с каким DataFlavor, иначе мне не нужно было бы этого делать (полный код предпочитает использовать javaFileListFlavor, потому что он также поддерживает удаление из других почтовых клиентов, которые все работают с этим). Я получаю рабочий входной поток и могу использовать данные, которые являются правильным сообщением электронной почты Outlook. Единственная проблема заключается в том, что кажется, что я не могу закрыть InputStream, потому что некоторые собственные ресурсы выходят из строя при удалении.
3. Я никогда не видел ни одного (реального) примера кода
SystemFlavorMap
и долго задавался вопросом, использовал ли кто-нибудь его на практике. Поэтому я не удивлюсь, если вы обнаружите ошибку, которую никто раньше не замечал, просто потому, что никто никогда не пробовал это.4. Я тоже не знаю, я просто обработал этот код, проверив, какой тип FlavorMap я получаю (потому что сама FlavorMap не предоставляет методов настройки) и использовал это. Но я считаю, что часть с FlavorMap работает правильно, поскольку я получаю InputStream и, похоже, создает WDropTargetContextPeer, но некоторые собственные данные кажутся неверными, и я понятия не имею, что. У вас есть какие-либо идеи, могу ли я отладить этот машинный код? Я посмотрю, смогу ли я найти машинный код и выяснить, что он должен делать, но я не очень уверен в своих навыках работы с библиотеками Windows