Сбой Java при закрытии WDropTargetContextPeerFileStream с повреждением кучи

#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