0

まず、次の 2 つの同様の質問を見つけました。

Python ctypes で Windows API に構造を渡す

ctypes と関数への参照渡し

最初のものには受け入れられた答えがなく、別のプロセスで何かをしているとは思いません。2 つ目は、pointer() と byref() を指摘しているだけで、どちらも使用しようとしても役に立ちませんでした。

さて、私の質問に進みます:

独自の pReportInformation (最初のデータ値が独自のサイズである構造体へのポインター) を使用して関数 WERReportCreate を呼び出そうとしています。これは、やり方によってはさまざまな方法で失敗しますが、正しく行う方法がわかりません。要件の 1 つは、構造体がそれ自体のサイズを認識しているということであり、これをプログラムで決定する方法がわかりません (ただし、それが唯一の問題である場合は、今までに正しい値を推測していたと思います)。 )。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 を渡すと機能するが、実際に (私の?) 構造体を渡すと機能しないという事実は、次の 3 つの問題のうちの 1 つを抱えていることを示唆しています。 wzConsentKey が正しく定義されている)、または構造体のサイズを正しく把握していない (実際には struct.calcsize をさまざまなオプションで使用して初期推測を取得し、ランダムに 1 を加算および減算しています)、または (参照を正しく渡していません) ?) 構造に。

ここで行き止まりになりました。任意の助けをいただければ幸いです (私の質問の明確さ、書式設定、または品質を改善する方法についての提案も同様です。これが私の最初の投稿です)。

4

2 に答える 2

3

投稿された質問に対する一般的な短い答えは次のとおりです。構造に正しい情報を入れていることを確認してください。それ以外は、提供されたコードは、構造を作成して渡す良い例です。これが私の問題を具体的に解決したものです:

提供されたコードには 2 つの問題がありました。まず、Mark Tolonen が指摘したように、間違ったサイズを渡していました。ctypes.sizeof(ReportInfo) を使用すると、その問題が解決しました。2 つ目の問題は、プロセス ハンドルが必要なプロセス ID を使用していたことです。OpenProcess を使用して、「プロセス」引数の代わりに有効なプロセス ハンドルを取得すると、2 番目の問題が解決されました。

将来的に同様の問題をデバッグする場合は、HRESULTS を整数ではなく 16 進数として出力して、リターン コードをよりよく理解してください。

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

これにより、私の場合、次の結果が得られました。

Return Code 80070057

私の元のエラーのために、そして

Return Code 80070006

2番目のエラー。http://msdn.microsoft.com/en-us/library/bb446131.aspxの情報を使用すると、前半がメタデータで、後半が実際のエラー コードであることがわかりました。16 進数のエラー コード部分を 10 進数に変換した後、http://msdn.microsoft.com/en-us/library/bb202810.aspxを使用してそれを特定しました。

エラー コード 87 (16 進数で 57) は、「パラメーターが正しくありません」(サイズが間違っている) を意味し、

エラー コード 6 (16 進数で 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 に答える