首先,我发现了以下两个类似的问题:
Passing Structure to Windows API in python ctypes
ctypes and passing a by reference to a function
第一个没有接受的答案,我不认为我在不同的进程中做任何事情。第二个简单地指出了指针()和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
当我传入null时它工作的事实,但是当我实际传递我的(引用我的?)结构时,它表明我有三个问题之一:我没有正确地创建结构(我是不确定wzConsentKey是否正确定义),或者我没有正确计算结构的大小(我实际上是使用struct.calcsize和各种选项来获得初始猜测,并且随机地添加和减去1),或者我没有正确地通过(参考?)结构。
这是我遇到了一个deadend的地方。任何帮助将不胜感激(以及如何提高我的问题的清晰度,格式或质量的建议;这是我的第一篇文章)。
答案 0 :(得分: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)。
答案 1 :(得分: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)
像这样呼叫WerReportCreate
。 byref
将指针传递给ReportInfo
实例。
werinfo = genReportInfo()
res = ctypes.windll.wer.WerReportCreate(u'pwzEventType', 2, ctypes.byref(werinfo), ctypes.byref(reporthandle))
我认为这对你有用。我没有wer.dll
所以我无法测试它。