8

このモジュールを使用して、ctypesWindowsのCommon ItemDialogAPIを呼び出そうとしています。以下に示すコードは、 MSDNドキュメントで概説されている手順に大まかに基づいています。その唯一の依存関係はcomtypes.GUIDモジュールです。

import ctypes
from ctypes import byref, POINTER, c_int, c_long
from ctypes.wintypes import HWND, HRESULT
from comtypes import GUID

CLSID_FileOpenDialog = '{DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7}'
IID_IFileDialog = '{42F85136-DB7E-439C-85F1-E4075D135FC8}'
#IID_IFileOpenDialog = '{D57C7288-D4AD-4768-BE02-9D969532D960}'
CLSCTX_SERVER = 5
COINIT_APARTMENTTHREADED = 2
FOS_PICKFOLDERS = 32
FOS_FORCEFILESYSTEM = 64

ole32 = ctypes.windll.ole32
CoCreateInstance = ole32.CoCreateInstance
CoInitializeEx = ole32.CoInitializeEx

CoInitializeEx(None, COINIT_APARTMENTTHREADED)

ptr = c_int()
error = CoCreateInstance(
    byref(GUID(CLSID_FileOpenDialog)), None, CLSCTX_SERVER,
    byref(GUID(IID_IFileDialog)), byref(ptr))
assert error == 0

ptr = ptr.value
c_long_p = ctypes.POINTER(ctypes.c_int)
print('Pointer to COM object: %s' % ptr)
vtable = ctypes.cast(ptr, c_long_p).contents.value
print('Pointer to vtable: %s' % vtable)

func_proto = ctypes.WINFUNCTYPE(HRESULT, HWND)

# Calculating function pointer offset: 3rd entry in vtable; 32-bit => 4 bytes
show_p = ctypes.cast(vtable + 3*4, c_long_p).contents.value
print('Pointer to show(): %s' % show_p)
show = func_proto(show_p)
show(0)

show(0):への最初の呼び出しまで、すべてが意図したとおりに機能します。

 WindowsError: exception: access violation reading 0xXXXXXXXX

(出力は異なる場合があります。)比較のために、COMに直接アクセスできるAutoHotkey_Lで同じ手順を実行しました。

CLSID := "{DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7}"
IID := "{42F85136-DB7E-439C-85F1-E4075D135FC8}"

ptr := ComObjCreate(CLSID, IID)
vtable := NumGet(ptr + 0, 0, "Ptr")
    show := NumGet(vtbl + 0, 3 * A_PtrSize, "Ptr")

MsgBox ptr: %ptr% vtable: %vtable% show: %A_PtrSize%

DllCall(show, "Ptr", ptr, "Ptr", 44)

結果のマクロは、期待どおりに[ファイルを開く]ダイアログをポップアップします。vtableポインターのオフセットはどちらの場合も同じですが、Pythonバージョンのみがアクセス違反をスローします。

誰かがこれに光を当てることができますか?

[必要に応じてハイパーリンクを追加しなかったことをお詫びしますが、新しいユーザーとして、一度に2つに制限されています。]

背景:Pythonスクリプトで使用するためのネイティブの保存/ファイルを開くダイアログを提供する軽量モジュールをまとめています。これまでのところ、純粋なPythonでの実装を見つけることができませんでした。存在するものは、TkinterやwxPythonなどのUIツールキットに依存しています。

4

1 に答える 1

6

解決策は次のとおりです。

COMメソッドは追加のパラメーターを取ります:'this'ポインター。C ++からメソッドを呼び出す場合は暗黙的ですが、C(およびctypes)では自分でメソッドを指定する必要があります。

行を変更します

func_proto = ctypes.WINFUNCTYPE(HRESULT, HWND)

の中へ

func_proto = ctypes.WINFUNCTYPE(HRESULT, c_long, HWND)

そしてこの行

show(0)

の中へ

show(ptr, 0)

そしてあなたのコードは動作します。

于 2012-09-28T11:09:15.937 に答える