Using COM interface in python - python

I want to show/hide tabtip.exe on demand. I was able to toggle it using code given to me here.
import win32gui
from ctypes import HRESULT
from ctypes.wintypes import HWND
from comtypes import IUnknown, GUID, COMMETHOD
import comtypes.client
class ITipInvocation(IUnknown):
_iid_ = GUID("{37c994e7-432b-4834-a2f7-dce1f13b834b}")
_methods_ = [
COMMETHOD([], HRESULT, "Toggle",
( ['in'], HWND, "hwndDesktop" )
)
]
dtwin = win32gui.GetDesktopWindow();
ctsdk = comtypes.client.CreateObject("{4ce576fa-83dc-4F88-951c-9d0782b4e376}", interface=ITipInvocation)
ctsdk.Toggle(dtwin);
comtypes.CoUninitialize()
But it toggle the keyboard, I want show and hide functions separate. I am trying to use this method but can't understand how can I implement it in python. Any guide would be appreciated.
Side Note:
I am new to COM and win32Api. I have been reading a lot MSDN documentation and posts on it. But there are very few available regarding these topic. If you know any good tutorial on "Using COM interface in python", it would be grateful.

Related

How to install cairo and rsvg for python

I understand that Stackoverflow is for help with code, but I figured I'd ask anyways.
I found from the post here that it is possible to put a .svg file into a tkinter window, but after days of searching, I still can't find any place where I could install cairo and rsvg from.
I am currently using Windows 10 with python 3.6.
EDIT:
I have found out how to install cairo and rsvg. Cairo is working but
rsvg is not. I have managed to put SVGs in Tkinter with cairo and not rsvg, though. For
anyone curious about this, you may want to check post out:
Putting .SVG images into tkinter Frame.
Thanks in advance.
Edit: Ok, so pip won't work for installing pycairo. Found that out.
And the other options haven't worked for me either. I am about to be
away from my computer, but I'll give you some of the things I found.
This
This
and
This
Sorry I couldn't be more help. Hope you figure it out!
First, use pip install pycairo
Unfortunately, rsvg is unavailable for windows, but cairographics.org have a simple wrapper.
Save the following as rsvg.py in the same folder as your script:
#some code to give rsvg.render_cairo(ctx) ability
#on windows.
import os
try:
import rsvg
WINDOWS=False
except ImportError:
print"Warning, could not import 'rsvg'"
if os.name == 'nt':
print "Detected windows, creating rsvg."
#some workarounds for windows
from ctypes import *
l=CDLL('librsvg-2-2.dll')
g=CDLL('libgobject-2.0-0.dll')
g.g_type_init()
class rsvgHandle():
class RsvgDimensionData(Structure):
_fields_ = [("width", c_int),
("height", c_int),
("em",c_double),
("ex",c_double)]
class PycairoContext(Structure):
_fields_ = [("PyObject_HEAD", c_byte * object.__basicsize__),
("ctx", c_void_p),
("base", c_void_p)]
def __init__(self, path):
self.path = path
error = ''
self.handle = l.rsvg_handle_new_from_file(self.path,error)
def get_dimension_data(self):
svgDim = self.RsvgDimensionData()
l.rsvg_handle_get_dimensions(self.handle,byref(svgDim))
return (svgDim.width,svgDim.height)
def render_cairo(self, ctx):
ctx.save()
z = self.PycairoContext.from_address(id(ctx))
l.rsvg_handle_render_cairo(self.handle, z.ctx)
ctx.restore()
class rsvgClass():
def Handle(self,file):
return rsvgHandle(file)
In your script, do from rsvg import * and when you need to use it, run:
rC = rsvgClass()
h = rC.Handle("YOUR-FILE-HERE.svg")
s = cairo.ImageSurface(cairo.FORMAT_ARGB32, 100, 100)
ctx = cairo.Context(s)
h.render_cairo(ctx)

Python win32 API to mimic AutoHotKey Tooltip UI

I would like to mimic the tooltip functionality found in AutoHotKey.
AutoHotKey code:
infoTooltip() {
MouseGetPos, xPos, yPos, winId
PixelGetColor, color, %xPos%, %yPos%, RGB
WinGetTitle, winTitle, ahk_id %winId%
ToolTip "%winTitle%"`n%xPos% %yPos% %color%
}
Looks like this when called inside a loop and will follow mouse around:
References found from googling:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms632680(v=vs.85).aspx
How to use Windows ToolTip Control without bounding to a tool
My Python code attempt so far:
import win32con, win32gui
from win32api import GetModuleHandle
from commctrl import (TOOLTIPS_CLASS, TTS_ALWAYSTIP, TTS_NOPREFIX, TTM_ADDTOOL, TTM_SETMAXTIPWIDTH)
class TooltipWindow:
def __init__(self):
win32gui.InitCommonControls() # Loads COMCTL32.DLL (Shell Common Controls Library)
self.hwnd = win32gui.CreateWindowEx(
win32con.WS_EX_CLIENTEDGE | win32con.WS_EX_TOPMOST,
TOOLTIPS_CLASS,
"MyTooltipWindow",
win32con.WS_POPUP | TTS_ALWAYSTIP | TTS_NOPREFIX | win32con.WS_BORDER,
win32con.CW_USEDEFAULT,
win32con.CW_USEDEFAULT,
win32con.CW_USEDEFAULT,
win32con.CW_USEDEFAULT,
None,
None,
GetModuleHandle(None),
None
)
win32gui.SendMessage(self.hwnd, TTM_ADDTOOL, None, ???)
tooltip = TooltipWindow()
I have no idea how to translate the TOOLINFO struct to the lparam argument. Also, going in blind trying to get most of this code working as this is my first real win32gui project.
Any help is appreciated, thank you!
Have you considered instead doing a Dll import? It's definitely worth lugging around the .dll it if you are planning on using more authotkey functionality.
import ctypes
dll = ctypes.cdll.LoadLibrary("AutoHotkey.dll")
dll.ahktextdll(u"")
dll.ahkExec('MouseGetPos, xPos, yPos, winId' \
'\n PixelGetColor, color, %xPos%, %yPos%, RGB' \
'\n WinGetTitle, winTitle, ahk_id %winId%' \
'\n ToolTip "%winTitle%"`n%xPos% %yPos% %color%')

creating an object from a ctype.c_void_pointer

I am doing the following in python
import ctypes, ctypes.util
from gi.repository import WebKit, JSCore, GLib, Gtk
import sys
webkit = ctypes.CDLL(ctypes.util.find_library('webkitgtk-3.0'))
jscore = ctypes.CDLL(ctypes.util.find_library('javascriptcoregtk-3.0'))
def inject_js(view, frame):
"""
void
evalscript(WebKitWebFrame *frame, JSContextRef js, char *script, char* scriptname) {
JSStringRef jsscript, jsscriptname;
JSValueRef exception = NULL;
jsscript = JSStringCreateWithUTF8CString(script);
jsscriptname = JSStringCreateWithUTF8CString(scriptname);
JSEvaluateScript(js, jsscript, JSContextGetGlobalObject(js), jsscriptname, 0, &exception);
JSStringRelease(jsscript);
JSStringRelease(jsscriptname);
}
"""
offset = sys.getsizeof(object())
frame = ctypes.POINTER(ctypes.c_void_p).from_address(id(frame) + offset)
adr = webkit.webkit_web_frame_get_global_context(c_frame)
js = ctypes.cast(js_ctx_adr, ctypes.c_void_p)
js_objref_adr = jscore.JSContextGetGlobalObject(js_ctx_ref) #segfaults here
window = Gtk.Window()
view = WebKit.WebView()
window.add(view)
window.show_all()
view.connect('document-load-finished', inject_js)
view.load_uri("http://google.com")
mainloop = GLib.MainLoop()
mainloop.run()
I am trying to use ctypes to access a non-introspectable method, so far I am successful in creating a pointer to gtk/gobject stuff. However the js intance I am trying to cast should not be a pointer but rather the object itself, or something similar.
==> WebKitWebFrame *frame, JSContextRef js (not a pointer)
How can I do that. Right now it just segfaults
The argument types and return type need to be setup explicitly on ctypes functions. ctypes uses a default return type of "C int", which is likely why the segfault is occurring. See: Specifying the required argument types
jscore.JSContextGetGlobalObject.argtypes = [ctypes.c_void_p]
jscore.JSContextGetGlobalObject.restype = ctypes.c_void_p
webkit.webkit_web_frame_get_global_context.argtypes = [ctypes.c_void_p]
webkit.webkit_web_frame_get_global_context.restype = ctypes.c_void_p
JSContextRef and JSGlobalContextRef are typedefs to opaque struct pointers, so using c_void_p can work as the argument type: JavaScriptCore/API/JSBase.h
I think the use of sys.getsizeof(object()) and from_address is ok. It is used in the PyGObject unittests because it ensures the code will run correctly with debug builds of Python (where the PyObject struct has some extra fields and is of a different size). See: git.gnome.org/browse/pygobject/tree/tests/test_everything.py?id=3.9.90#n36
As a side note, PyGObject exposes a pointer to the underlying GObject as a PyCapsule via the attribute "__gpointer__". Unfortunately, this is not very useful because ctypes does not marshal the pointer held in PyCapsules automatically, nor does the pointer address seem accessible on the PyCapsule in Python.
With the argtypes/restype setup mentioned (and variable name fixes), the callback no longer segfaults:
def inject_js(view, frame):
offset = sys.getsizeof(object())
c_frame = ctypes.c_void_p.from_address(id(frame) + offset)
js_ctx_ptr = webkit.webkit_web_frame_get_global_context(c_frame)
js_obj_ptr = jscore.JSContextGetGlobalObject(js_ctx_ptr)

How to self-handling cookies in PyObjC

I'm implementing a minimal browser in PyObjC for my study.
First, I googled about the way to use webkit from pyobjc and wrote code like below:
#coding: utf-8
import Foundation
import WebKit
import AppKit
import objc
def main():
app = AppKit.NSApplication.sharedApplication()
rect = Foundation.NSMakeRect(100,350,600,800)
win = AppKit.NSWindow.alloc()
win.initWithContentRect_styleMask_backing_defer_(
rect,
AppKit.NSTitledWindowMask |
AppKit.NSClosableWindowMask |
AppKit.NSResizableWindowMask |
AppKit.NSMiniaturizableWindowMask,
AppKit.NSBackingStoreBuffered,
False)
win.display()
win.orderFrontRegardless()
webview = WebKit.WebView.alloc()
webview.initWithFrame_(rect)
pageurl = Foundation.NSURL.URLWithString_("http://twitter.com")
req = Foundation.NSURLRequest.requestWithURL_(pageurl)
webview.mainFrame().loadRequest_(req)
win.setContentView_(webview)
app.run()
if __name__ == '__main__':
main()
It worked fine. But I noticed that this browser is sharing cookies with safari. I want it to be independent from my Safari.app.
So I googled again and I learned that I can override cookie-handling-methods by using NSMutableURLRequest.
Below is the second code I tested:
#coding: utf-8
import Foundation
import WebKit
import AppKit
import objc
def main():
app = AppKit.NSApplication.sharedApplication()
rect = Foundation.NSMakeRect(100,350,600,800)
win = AppKit.NSWindow.alloc()
win.initWithContentRect_styleMask_backing_defer_(
rect,
AppKit.NSTitledWindowMask |
AppKit.NSClosableWindowMask |
AppKit.NSResizableWindowMask |
AppKit.NSMiniaturizableWindowMask,
AppKit.NSBackingStoreBuffered,
False)
win.display()
win.orderFrontRegardless()
webview = WebKit.WebView.alloc()
webview.initWithFrame_(rect)
pageurl = Foundation.NSURL.URLWithString_("http://twitter.com")
req = Foundation.NSMutableURLRequest.requestWithURL_(pageurl)
Foundation.NSMutableURLRequest.setHTTPShouldHandleCookies_(req, False)
webview.mainFrame().loadRequest_(req)
win.setContentView_(webview)
app.run()
if __name__ == '__main__':
main()
This code show me a login screen of twitter :-)
But I couldn't login to twitter by this browser.
I input account name, password and pushed enter key. Then the browser displays the timeline of the account which I always use in Safari.app.
Yes, I know that it's proper result.
I didn't write anything about handling cookies.
And my question is on this point.
I want to know that:
How can I implement and use something like NSHTTPCookieStorage?
Can I write it in python?
Thank you.
To start with the easy part: if it is possible to do this in Objective-C it should also be possible with PyObjC.
That said, it is unclear to me if this is possible at all. How can I have multiple instances of webkit without sharing cookies? seems to indicate that it isn't although you might be able to do something through the webkit delegate.
An other alternative is to use NSURLProtocol, register a custom NSURLProtocol class for handling http/https requests and implement that using Python's urllib or urllib2. The PyDocURL example shows how to do this (that example registers a subclass for pydoc:// URLs).
More information on NSURLConnection is on Apple's website.
Updated with an implemention hint:
An alternate method might be to disable cookie storaga by NSHTTPCookieStorage (NSHTTPCookieStorage.sharedHTTPCookieStorage.setCookieAcceptPolicy_(NSHTTPCookieAcceptPolicyNever)). Then use the webkit resource loading delegate to handle cookies yourself:
Maintain your own cookie store (possibly using a class in urllib2)
In webView:resource:willSendRequest:redirectResponse:fromDataSource: add cookie headers based on information in that store
In webView:resource:didReceiveResponse:fromDataSource: check for "set-cookie" headers and update your own cookie store.
It shouldn't be too hard to do this, and I'd love to have this functionality as an example on the PyObjC website (or even as a utility class in the WebKit bindings for PyObjC).

Show Explorer's properties dialog for a file in Windows

Is there an easy way to show the properties dialog for a file in Windows using Python?
I'm trying to show the same window that pops up when you right click a file in Explorer and choose Properties.
The way to do this is to call the Windows ShellExecuteEx() API passing the properties verb. There are various high-level Python wrappers of this but I have not succeeded in getting any of them to work with the properties verb. Instead I would use good old ctypes.
import time
import ctypes
import ctypes.wintypes
SEE_MASK_NOCLOSEPROCESS = 0x00000040
SEE_MASK_INVOKEIDLIST = 0x0000000C
class SHELLEXECUTEINFO(ctypes.Structure):
_fields_ = (
("cbSize",ctypes.wintypes.DWORD),
("fMask",ctypes.c_ulong),
("hwnd",ctypes.wintypes.HANDLE),
("lpVerb",ctypes.c_char_p),
("lpFile",ctypes.c_char_p),
("lpParameters",ctypes.c_char_p),
("lpDirectory",ctypes.c_char_p),
("nShow",ctypes.c_int),
("hInstApp",ctypes.wintypes.HINSTANCE),
("lpIDList",ctypes.c_void_p),
("lpClass",ctypes.c_char_p),
("hKeyClass",ctypes.wintypes.HKEY),
("dwHotKey",ctypes.wintypes.DWORD),
("hIconOrMonitor",ctypes.wintypes.HANDLE),
("hProcess",ctypes.wintypes.HANDLE),
)
ShellExecuteEx = ctypes.windll.shell32.ShellExecuteEx
ShellExecuteEx.restype = ctypes.wintypes.BOOL
sei = SHELLEXECUTEINFO()
sei.cbSize = ctypes.sizeof(sei)
sei.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_INVOKEIDLIST
sei.lpVerb = "properties"
sei.lpFile = "C:\\Desktop\\test.txt"
sei.nShow = 1
ShellExecuteEx(ctypes.byref(sei))
time.sleep(5)
The reason I put in the call to sleep is that the properties dialog is shown as a window in the calling process. If the Python executable terminates immediately following the call to ShellExecuteEx, then there is nothing there to service the dialog and it does not show.

Categories