Windows Common Item对话框:ctypes + COM访问冲突 [英] Windows Common Item Dialog: ctypes + COM access violation
问题描述
我正在尝试使用ctypes
模块来调用Windows的 MSDN文档.它唯一的依赖项是comtypes.GUID
模块.
I am trying to use the ctypes
module to make calls to Windows' Common Item Dialog API. The code shown below is roughly based on the steps outlined in the MSDN documentation. Its only dependency is the comtypes.GUID
module.
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)
:
Everything works as intended until the first call to show(0)
:
WindowsError: exception: access violation reading 0xXXXXXXXX
(输出可能会有所不同.)为了进行比较,我在AutoHotkey_L中执行了相同的步骤,该步骤可以直接访问COM.
(Output may vary.) For comparison, I have carried out the same steps in AutoHotkey_L, which has direct access to COM.
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版本会引发访问冲突.
The resulting macro pops up an Open File dialog, as expected. The vtable pointer offsets are the same in both cases, but only the Python version throws up an access violation.
任何人都可以对此有所了解吗?
Can anyone shed some light on this?
[我很抱歉没有在适当的位置添加更多的超链接,但是作为一个新用户,我一次只能限制两个.]
[I apologize for not adding more hyperlinks where appropriate, but as a new user I am limited to two at a time.]
背景: 我将一个轻量级模块放在一起,该模块提供一个本机保存/打开文件对话框,供在Python脚本中使用.到目前为止,我还找不到纯Python的实现.现有的依赖于UI工具包,例如Tkinter或wxPython.
Background: I am putting together a lightweight module which provides a native save/open file dialog for use in Python scripts. So far I have been unable to find an implementation in pure Python. Those that exist rely on UI toolkits such as Tkinter or wxPython.
推荐答案
以下是解决方法:
COM方法带有一个附加参数:'this'指针.当您从C ++调用该方法时,它是隐式的,在C(和ctypes)中,您必须自己提供它.
COM methods take an additional parameter: The 'this' pointer. It is implicit when you call the method from C++, in C (and in ctypes) you must supply it yourself.
更改行
func_proto = ctypes.WINFUNCTYPE(HRESULT, HWND)
进入
func_proto = ctypes.WINFUNCTYPE(HRESULT, c_long, HWND)
和这一行
show(0)
进入
show(ptr, 0)
您的代码将可用.
这篇关于Windows Common Item对话框:ctypes + COM访问冲突的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!