0

首先,我发现了以下两个类似的问题:

在python ctypes中将结构传递给Windows API

ctypes 并通过引用传递一个函数

第一个没有公认的答案,我认为我没有在单独的进程中做任何事情。第二个简单地指出了pointer() 和byref(),这两个我都试过没有用。

现在,关于我的问题:

我试图用我自己的 pReportInformation 调用函数 WERReportCreate (这是一个指向其第一个数据值是它自己的大小的结构的指针)。这会以各种方式失败,具体取决于我的处理方式,但我不确定如何正确执行。由于其中一个要求是结构知道它自己的大小,我不确定如何以编程方式确定(尽管如果这是唯一的问题,我想我现在已经猜到了正确的值,这一事实使情况变得复杂) )。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),或者我没有正确传递(参考到?)结构。

这是我遇到死胡同的地方。任何帮助将不胜感激(以及如何提高我的问题的清晰度、格式或质量的建议;这是我的第一篇文章)。

4

2 回答 2

3

对发布的问题的一般简短回答是:确保将正确的信息放入结构中,除此之外,提供的代码是创建和传递结构的一个很好的例子。这是专门解决我的问题的方法:

提供的代码存在两个问题:首先,正如 Mark Tolonen 所指出的,我传递的大小不正确。使用 ctypes.sizeof(ReportInfo) 解决了这个问题。第二个问题是我使用了需要进程句柄的进程 ID。使用 OpenProcess 获取有效的进程句柄来代替我的“进程”参数解决了第二个问题。

对于将来调试类似问题的任何人,将 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)表示“句柄无效”(我正在传递进程 ID)。

于 2012-07-24T17:03:41.610 回答
2

您可以使用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)

像这样打电话WerReportCreatebyref将指针传递给ReportInfo实例。

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

我认为这对你有用。我没有,wer.dll所以无法测试。

于 2012-07-24T02:08:09.370 回答