Note that there are some explanatory texts on larger screens.

plurals
  1. POWindows Common Item Dialog: ctypes + COM access violation
    primarykey
    data
    text
    <p>I am trying to use the <code>ctypes</code> module to make calls to Windows' <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/bb776913%28v=vs.85%29.aspx" rel="noreferrer">Common Item Dialog API</a>. The code shown below is roughly based on the steps outlined in the <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ff485843%28v=vs.85%29.aspx" rel="noreferrer">MSDN documentation</a>. Its only dependency is the <code>comtypes.GUID</code> module.</p> <pre><code>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 =&gt; 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) </code></pre> <p>Everything works as intended until the first call to <code>show(0)</code>:</p> <pre><code> WindowsError: exception: access violation reading 0xXXXXXXXX </code></pre> <p>(Output may vary.) For comparison, I have carried out the same steps in AutoHotkey_L, which has direct access to COM.</p> <pre><code>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) </code></pre> <p>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.</p> <p>Can anyone shed some light on this?</p> <p>[I apologize for not adding more hyperlinks where appropriate, but as a new user I am limited to two at a time.]</p> <p><strong>Background</strong>: 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.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload