Как правильно (используя python) правильно создать и передать структуру ctypes в функцию WER API?

Прежде всего, я нашел следующие два похожих вопроса:

Передача структуры в Windows API в Python ctypes

ctypes и передача по ссылке на функцию

Первый не имеет принятого ответа, и я не думаю, что я делаю что-то в отдельных процессах. Второй просто указывает указатель () и byref(), которые я пытался использовать безрезультатно.

Теперь по моему вопросу:

Я пытаюсь вызвать функцию WERReportCreate со своим собственным pReportInformation (который является указателем на структуру, первое значение данных которого имеет свой собственный размер). Это происходит по-разному, в зависимости от того, как я это делаю, но я не уверен, как это сделать правильно. Это усложняется тем фактом, что одно из требований состоит в том, что структура знает свой собственный размер, который я не знаю, как программно определить (хотя, если бы это было единственной проблемой, я думаю, что я бы уже угадал правильное значение). Соответствующая информация от WER API показана ниже:

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

(полная информация на http://msdn.microsoft.com/en-us/library/windows/desktop/bb513625%28v=vs.85%29.aspx)

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;

(полная информация на http://msdn.microsoft.com/en-us/library/windows/desktop/bb513637%28v=vs.85%29.aspx)

Это код, который я пробовал:

import ctypes
import ctypes.wintypes

class ReportInfo( ctypes.Structure):
    _fields_ = [ ("dwSize", ctypes.wintypes.DWORD),
                 ("hProcess", ctypes.wintypes.HANDLE),
                 ("wzConsentKey", ctypes.wintypes.WCHAR * 64),
                 ("wzFriendlyEventName", ctypes.wintypes.WCHAR * 128),
                 ("wzApplicationName", ctypes.wintypes.WCHAR * 128),
                 ("wzApplicationPath", ctypes.wintypes.WCHAR * ctypes.wintypes.MAX_PATH),
                 ("wzDescription", ctypes.wintypes.WCHAR * 512),
                 ("hwndParent", ctypes.wintypes.HWND) ]

def genReportInfo():
    import os
    size = 32 #Complete SWAG, have tried many values
    process = os.getpid()
    parentwindow = ctypes.windll.user32.GetParent(process)
    werreportinfopointer = ctypes.POINTER(ReportInfo)
    p_werinfo = werreportinfopointer()
    p_werinfo = ReportInfo(size, process, "consentkey", "friendlyeventname", "appname", "apppath", "desc", parentwindow)
    return p_werinfo

if __name__ == '__main__':
    reporthandle = ctypes.wintypes.HANDLE()
    res = ctypes.wintypes.HRESULT()

            ### First pass  NULL in as optional parameter to get default behavior ###
    p_werinfo = None
    res = ctypes.windll.wer.WerReportCreate(u'pwzEventType', 2, p_werinfo, ctypes.byref(reporthandle))
    print "Return Code",res,"\nHandle",reporthandle #Return Code 0, reporthandle is correct (verified by submitting report in a different test)

    p_werinfo = genReportInfo() # Create our own struct

            ### Try Again Using Our Own Struct (via 'byref')  ###      
    res = ctypes.windll.wer.WerReportCreate(u'pwzEventType', 2, ctypes.byref(p_werinfo), ctypes.byref(reporthandle))
    print "Return Code",res,"\nHandle",reporthandle #Return Code Nonzero, reporthandle is None

            ### Try Again Using Our Own Struct (directly)  ###
    res = ctypes.windll.wer.WerReportCreate(u'pwzEventType', 2, p_werinfo, ctypes.byref(reporthandle))
    print "Return Code",res,"\nHandle",reporthandle #Exception Occurs, Execution halts  

И это вывод, который я получаю:

Return Code 0
Handle c_void_p(26085328)
Return Code -2147024809
Handle c_void_p(None)
Traceback (most recent call last):
  File "test.py", line 40, in <module>
    res = ctypes.windll.wer.WerReportCreate(u'pwzEventType', s.byref(reporthandle))
WindowsError: exception: access violation writing 0x0000087C

Тот факт, что это работает, когда я передаю нулевое значение, но не когда я фактически передаю свою (ссылку на мою?) Структуру, наводит на мысль, что у меня есть одна из трех проблем: я не создаю структуру правильно (я не уверен, что wzConsentKey определен правильно), или я неправильно вычисляю размер структуры (на самом деле я использую struct.calcsize с различными опциями для получения начальных догадок и случайным образом добавляя и вычитая 1), или я неправильно передаю (ссылка к?) структуре.

Вот где я попал в тупик. Буду признателен за любую помощь (а также предложения о том, как улучшить ясность, форматирование или качество моего вопроса; это мой первый пост).

2 ответа

Решение

Общий короткий ответ на опубликованный вопрос: убедитесь, что вы вводите правильную информацию в структуру, кроме того, предоставленный код является хорошим примером создания и передачи структуры. Вот что конкретно решило мою проблему:

С предоставленным кодом было две проблемы: во-первых, как отметил Марк Толонен, я передавал неверный размер. Использование ctypes.sizeof(ReportInfo) решило эту проблему. Вторая проблема заключалась в том, что я использовал идентификатор процесса, для которого требовался дескриптор процесса. Использование OpenProcess для получения правильного дескриптора процесса вместо моего аргумента "process" решило вторую проблему.

Любой, кто будет устранять подобные проблемы в будущем, печатает HRESULTS в виде шестнадцатеричных чисел, а не целых чисел, чтобы лучше понять коды возврата:

print "Return Code %08x" % (res & 0xffffffff)

В моем случае это дало следующие результаты:

Return Code 80070057

за мою первоначальную ошибку, и

Return Code 80070006

за вторую ошибку. Используя информацию по адресу http://msdn.microsoft.com/en-us/library/bb446131.aspx, я увидел, что первая половина была метаданными, а вторая половина была моим настоящим кодом ошибки. После преобразования части кода ошибки шестнадцатеричного числа обратно в десятичное число я использовал http://msdn.microsoft.com/en-us/library/bb202810.aspx чтобы определить, что

Код ошибки 87 (57 в шестнадцатеричном формате) означал "Неверный параметр" (неверный размер) и

Код ошибки 6 (6 в шестнадцатеричном формате) означал "Неверный дескриптор" (я передавал идентификатор процесса).

Ты можешь использовать ctypes.sizeof(ReportInfo) получить размер в байтах структуры.

Просто создайте ReportInfo экземпляр с genReportInfo, Вам не нужен указатель на этом этапе:

def genReportInfo():
    import os
    size = ctypes.sizeof(ReportInfo)
    process = os.getpid()
    parentwindow = ctypes.windll.user32.GetParent(process)
    return ReportInfo(size, process, "consentkey", "friendlyeventname", "appname", "apppath", "desc", parentwindow)

Вызов WerReportCreate как это. byref передает указатель на ReportInfo пример.

werinfo = genReportInfo()
res = ctypes.windll.wer.WerReportCreate(u'pwzEventType', 2, ctypes.byref(werinfo), ctypes.byref(reporthandle))

Я думаю, что это будет работать для вас. У меня нет wer.dll поэтому я не могу это проверить.

Другие вопросы по тегам