Может ли "Отчет об ошибках Windows" использоваться для нефатальных проблем Java?

Мне было интересно, можно ли использовать Windows Error Reporting из "внутри" программы Java?

Другими словами, используйте механизм, чтобы сообщать об исключениях в центральное место, не имея фактического сбоя JVM (что, на мой взгляд, является тем, что вызывает это в первую очередь).

Идея здесь состоит в том, чтобы упростить сбор отчетов об ошибках от пользователей Windows.


Я бы тоже хотел услышать, если он может быть частью контролируемого отключения. То есть а не сбой JVM, но обычный, контролируемый выход из программы Java.


Подумав об этом, я думаю, что для наших целей было бы достаточно создать набор текстовых файлов (или, возможно, только канал в одном текстовом потоке), в крошечное приложение Windows, расположенное внутри нашей части файловой системы. Упомянутое приложение Windows затем резко разбивается и вызывает отправку отчета, включая текст, предоставленный нами. Будет ли это работать?

Ответ 1

Вы можете определенно использовать API отчетов об ошибках Windows, который отправляется в wer.dll как часть Win32 API.

Лучший способ вызова DLL-функций из Java - это активно разработанный Java Native Access project.

Чтобы сделать необходимые вызовы API Win32, нам нужно научить JNA по крайней мере этим функциям:

HRESULT WINAPI WerReportCreate(
  __in      PCWSTR pwzEventType,
  __in      WER_REPORT_TYPE repType,
  __in_opt  PWER_REPORT_INFORMATION pReportInformation,
  __out     HREPORT *phReportHandle
);

HRESULT WINAPI WerReportSubmit(
  __in       HREPORT hReportHandle,
  __in       WER_CONSENT consent,
  __in       DWORD dwFlags,
  __out_opt  PWER_SUBMIT_RESULT pSubmitResult
);

а также эту структуру:

typedef struct _WER_REPORT_INFORMATION {
  DWORD  dwSize;
  HANDLE hProcess;
  WCHAR  wzConsentKey[64];
  WCHAR  wzFriendlyEventName[128];
  WCHAR  wzApplicationName[128];
  WCHAR  wzApplicationPath[MAX_PATH];
  WCHAR  wzDescription[512];
  HWND   hwndParent;
} WER_REPORT_INFORMATION, *PWER_REPORT_INFORMATION;

Чтобы сделать это, мы создадим WER.java:

package com.sun.jna.platform.win32;

import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.platform.win32.WinNT.HRESULT;
import com.sun.jna.ptr.PointerByReference;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;

public interface Wer extends StdCallLibrary {
    Wer INSTANCE = (Wer) Native.loadLibrary("wer", Wer.class,
                                                W32APIOptions.DEFAULT_OPTIONS);

    public static class HREPORT extends HANDLE {
        public HREPORT() { }
        public HREPORT(Pointer p) { super(p); }
        public HREPORT(int value) { super(new Pointer(value)); }
    }

    public static class HREPORTByReference extends ByReference {
        public HREPORTByReference() {
            this(null);
        }

        public HREPORTByReference(HREPORT h) {
            super(Pointer.SIZE);
            setValue(h);
        }

        public void setValue(HREPORT h) {
            getPointer().setPointer(0, h != null ? h.getPointer() : null);
        }

        public HREPORT getValue() {
            Pointer p = getPointer().getPointer(0);
            if (p == null)
                return null;
            if (WinBase.INVALID_HANDLE_VALUE.getPointer().equals(p)) 
                return (HKEY) WinBase.INVALID_HANDLE_VALUE;
            HREPORT h = new HREPORT();
            h.setPointer(p);
            return h;
        }
    }

    public class WER_REPORT_INFORMATION extends Structure {
        public DWORD dwSize;
        public HANDLE hProcess;
        public char[] wzConsentKey = new char[64];
        public char[] wzFriendlyEventName = new char[128];
        public char[] wzApplicationName = new char[MAX_PATH];
        public char[] wzDescription = new char[512];
        public HWND hwndParent;

        dwSize = new DWORD(size());
    }

    public abstract class WER_REPORT_TYPE {
        public static final int WerReportNonCritical = 0;
        public static final int WerReportCritical = 1;
        public static final int WerReportApplicationCrash = 2;
        public static final int WerReportApplicationHang = 3;
        public static final int WerReportKernel = 4;
        public static final int WerReportInvalid = 5;
    }

    HRESULT WerReportCreate(String pwzEventType, int repType, WER_REPORT_INFORMATION pReportInformation, HREPORTByReference phReportHandle);
    HRESULT WerReportSubmit(HREPORT hReportHandle, int consent, DWORD dwFlags, WER_SUBMIT_RESULT.ByReference pSubmitResult);
}

Я просто сбил это с MS dcoumentation за несколько минут - на случай, если он неполный или неправильный, есть несколько примеров и довольно хорошая документация на веб-сайте JNA.

Чтобы запустить JNA, вам понадобятся jna.jar и platform.jar, которые вы также можете захватить с веб-сайта JNA.

Ответ 2

Мне приходилось программировать межоперационную совместимость между Java и .NET в прошлом, поэтому я начал делать некоторые исследования по использованию .NET для взаимодействия с WER с намерением увидеть, возможно ли взаимодействовать с WER в .NET, которое вы могли бы затем связать с Java. Интересно, что я столкнулся с этим сообщением в SOF - Есть ли .NET API для отчетов об ошибках Windows

У этого сообщения есть хорошая информация, связанная с взаимодействием с WER.

Я знаю, что сообщение вращается вокруг .NET с помощью WER, но поскольку вы пытаетесь взаимодействовать с собственными функциями Windows, я рекомендую использовать .NET для взаимодействия с ним, так как намного проще взаимодействовать с родными ресурсами Windows, используя .NET, чем с Java (и обычно это занимает половину кода, который он будет использовать в Java). Затем вы могли бы взаимодействовать с .NET-приложением (может быть, лучше всего настроен как служба Windows) с Java (например, вы могли бы использовать временные файлы триггеров в приложении .NET, чтобы указать, когда приложение .NET выполняется с ним обработчик, приложение Java затем может исследовать, когда будет создан этот "триггерный" файл и продолжит оттуда...).

В соответствии с принятым ответом в этой публикации рекомендуется использовать Windows Quality Online Services вместо того, чтобы программировать что-то для взаимодействия с WER, поскольку, как представляется, WER не предназначен для использования другими приложениями.

Ответ 3

Вы можете взаимодействовать с собственными функциями библиотеки WER.

Вот соответствующая документация MSDN:

Возможно, кто-то, у кого больше опыта работы с Java-interop, может предоставить вам примеры кода, я, скорее всего, скорее .NET.

EDIT:

Я сделал еще несколько исследований, и я думаю, вы могли бы попробовать использовать GlueGen или SWIG для создания привязок Java. Вам нужно загрузить SDK Windows, чтобы получить файл заголовка werapi, если вы хотите сгенерировать привязки.

Ответ 4

Вы хотите сказать, что вместо создаваемых файлов hs_err_pid *.log WER должен регистрировать журналы с ним? Или вы намерены регистрировать подробное сообщение об исключении из любого исключения, которое может обрабатываться в программах Java в WER?

Если случай равен 1, то, очевидно, вы не можете сделать это аккуратно. У вас может быть отдельный демон, который работает все время, чтобы искать hs_err_pid *.log created- > интерпретировать его с помощью внешних библиотек- > использовать предлагаемые выше API WER для записи в рекордерах WER.

Если случай 2-го, тогда вы можете сделать вызов JNI и выполнить вызовы, сделанные в API WER, для записи информации в WER.