Windows Common Item对话框:ctypes + COM访问冲突 [英] Windows Common Item Dialog: ctypes + COM access violation

查看:172
本文介绍了Windows Common Item对话框:ctypes + COM访问冲突的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆