2

私は現在モジュールに取り込んでおり、を使用して既に受け取ったハンドルでctypesuser32 関数を呼び出そうとしています。今回は、さらに一歩進んで、 で関数を呼び出す代わりに関数プロトタイプを使用したいと思いました。引数を出力パラメータとして宣言するのに問題がありますが。GetWindowTextHWNDFindWindowctypes.windll.user32.GetWindowTextlpString

私の最初の試みはこのように見えました:

GetWindowText = cfunc("GetWindowTextA",windll.user32,c_int,
                  ("hWnd",HWND,1),
                  ("lpString",LPCSTR,2),
                  ("nMaxCount",c_int,1)
                  )

ここでcfunc見つけた小さなラッパーです)

このプロトタイプは、呼び出されるとすぐに次の例外を生成します。

    chars,name = user32.GetWindowText(handle,255)
TypeError: c_char_p 'out' parameter must be passed as default value

どの出力変数も型でなければならないと考えたPOINTER(...)ので、定義を次のように変更しました。

GetWindowText = cfunc("GetWindowTextA",windll.user32,c_int,
                      ("hWnd",HWND,1),
                      ("lpString",POINTER(c_char),2),
                      ("nMaxCount",c_int,1)
                      )

しかし、これも例外をもたらします:

    chars,name = user32.GetWindowText(handle,255)
ctypes.ArgumentError: argument 2: <type 'exceptions.TypeError'>: wrong type

GetWindowTextプロトタイピングを使用して関数を正しく呼び出す方法を誰かが知っていることを願っていますctypes

編集:

さらなる調査により、少なくとも何らかの形で機能させることができました。私が最初に修正した問題は、cfunc()which の使用法に間違った呼び出し指定子があったことでした。その関数の正確なコピーを定義して名前をwinfunc()付けreturn CFUNCTYPE(result, *atypes)((name, dll), tuple(aflags))return WINFUNCTYPE(result, *atypes)((name, dll), tuple(aflags)).

その後、プロトタイピングをさらに検証しました。いくらか渡すと、呼び出し時にオブジェクトが作成("someParameter",POINTER(aType),2)され、そのオブジェクトへのポインターが関数に渡されます。返されたタプルで、オブジェクトにアクセスできます。これは別の問題を引き起こします。cstring は文字の配列です。そのため、ctypes に を作成するように指示する必要があります。これは、次のようなことを意味します。WINFUNCTYPEaTypeaTypec_char array

GetWindowText = winfunc("GetWindowTextA",windll.user32,c_int,
                  ("hWnd",HWND,1),
                  ("lpString",POINTER(c_char*255),2),
                  ("nMaxCount",c_int,1)
                  )

うまく動作します。しかし残念なことに、ctypes は で指定されたサイズを無視して常に 255 文字の長さの cstring へのポインターを渡すようになりましたnMaxCount

私の意見では、出力パラメーターとして定義された動的にサイズ設定された cstring でその関数を機能させる方法はないと思います。唯一の可能性は、出力パラメーター機能を使用せずにLPCSTR入力パラメーターとして定義することです。次に、呼び出し先は自分でバッファーを作成し、ctypes.create_string_buffer()それを関数に渡す必要があります (C の場合と同様)。

4

2 に答える 2

3

出力パラメーター用の文字列バッファーを作成する必要があります。関数をラップして、ある程度透明にすることができます。

# python3
from ctypes import *

_GetWindowText = WinDLL('user32').GetWindowTextW
_GetWindowText.argtypes = [c_void_p,c_wchar_p,c_int]
_GetWindowText.restype = c_int

def GetWindowText(h):
    b = create_unicode_buffer(255)
    _GetWindowText(h,b,255)
    return b.value

FindWindow = WinDLL('user32').FindWindowW
FindWindow.argtypes = [c_wchar_p,c_wchar_p]
FindWindow.restype = c_void_p

h = FindWindow(None,'Untitled - Notepad')
print(GetWindowText(h))

または、この場合はpywin32を使用できます:

import win32gui
h = win32gui.FindWindow(None,'Untitled - Notepad')
print(win32gui.GetWindowText(h))
于 2012-06-05T21:20:36.133 に答える
1

うん。呼び出しごとにバッファを作成する必要があります。関数定義に任せたら、後でバッファにアクセスするにはどうすればよいでしょうか?

また、単にorではなく、 でポインターc_charを期待するように指示する必要があるようです。なぜそれが起こるのか分かりません。POINTER(c_char)c_char_pLPSTR

とにかく、これはうまくいくはずです:

from ctypes import *
from ctypes.wintypes import *

# defs

FindWindowF = WINFUNCTYPE(HWND, LPSTR, LPSTR)
FindWindow = FindWindowF(windll.user32.FindWindowA)

GetWindowTextF = WINFUNCTYPE(c_int, HWND, POINTER(c_char), c_int)
GetWindowText = GetWindowTextF(windll.user32.GetWindowTextA)

# code

text = create_string_buffer(255)

hwnd = FindWindow(None, 'Untitled - Notepad')
GetWindowText(hwnd, text, sizeof(text))

print text.value
于 2012-06-05T21:03:21.733 に答える