What can you do with COM/ActiveX in Python? [closed] - python

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I've read that it is possible to automate monthly reports in Crystal Reports with COM/ActiveX. I'm not that advanced to understand what this is or what you can even do with it.
I also do a lot of work with Excel and it looks like you also use COM/ActiveX to interface with it.
Can someone explain how this works and maybe provide a brief example?

First you have to install the wonderful pywin32 module.
It provides COM support. You need to run the makepy utility. It is located at C:\...\Python26\Lib\site-packages\win32com\client. On Vista, it must be ran with admin rights.
This utility will show all available COM objects. You can find yours and it will generate a python wrapper for this object.
The wrapper is a python module generated in the C:\...\Python26\Lib\site-packages\win32com\gen_py folder. The module contains the interface of the COM objects. The name of the file is the COM unique id. If you have many files, it is sometimes difficult to find the right one.
After that you just have to call the right interface. It is magical :)
A short example with excel
import win32com.client
xlApp = win32com.client.Dispatch("Excel.Application")
xlApp.Visible=1
workBook = xlApp.Workbooks.Open(r"C:\MyTest.xls")
print str(workBook.ActiveSheet.Cells(i,1))
workBook.ActiveSheet.Cells(1, 1).Value = "hello"
workBook.Close(SaveChanges=0)
xlApp.Quit()

You can basically do the equivalent of late binding. So whatever is exposed through IDispatch is able to be consumed.
Here's some code I wrote this weekend to get an image from a twain device via Windows Image Acquisition 2.0 and put the data into something I can shove in a gtk based UI.
WIA_COM = "WIA.CommonDialog"
WIA_DEVICE_UNSPECIFIED = 0
WIA_INTENT_UNSPECIFIED = 0
WIA_BIAS_MIN_SIZE = 65536
WIA_IMG_FORMAT_PNG = "{B96B3CAF-0728-11D3-9D7B-0000F81EF32E}"
def acquire_image_wia():
wia = win32com.client.Dispatch(WIA_COM)
img = wia.ShowAcquireImage(WIA_DEVICE_UNSPECIFIED,
WIA_INTENT_UNSPECIFIED,
WIA_BIAS_MIN_SIZE,
WIA_IMG_FORMAT_PNG,
False,
True)
fname = str(time.time())
img.SaveFile(fname)
buff = gtk.gdk.pixbuf_new_from_file(fname)
os.remove(fname)
return buff
It's not pretty but it works. I would assert it's equivalent to what you would have to write in VB.

Here is a working solution that creates a file and adds value to a cell:
import win32com.client
import xlsxwriter
import os
cwd = os.getcwd()
file_path = cwd + "\\test.xlsx"
#Create an excel file
workbook = xlsxwriter.Workbook(file_path)
worksheet = workbook.add_worksheet()
workbook.close()
#Open an excel application
xlApp = win32com.client.Dispatch("Excel.Application")
xlApp.Visible=1
workBook = xlApp.Workbooks.Open(file_path)
print str(workBook.ActiveSheet.Cells(1,1))
workBook.ActiveSheet.Cells(1, 1).Value = "hello55"
workBook.Close(SaveChanges=1)
xlApp.Quit()

How to receive ActiveX events in python 3
# coding=utf8
from PyQt5.QAxContainer import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import QObject
import sys
TITLE = "CallX Python Example: accept any calls"
TrueConfCallX_Class = '{27EF4BA2-4500-4839-B88A-F2F4744FE56A}'
SERVER = '' # empty - connect to TrueConf Online cloud
USER = '<trueconf id>'
PASSWORD = '<password>'
class CallXWindow(QWidget):
def __init__(self):
QAxWidget.__init__(self)
self.setWindowTitle(TITLE)
self.move(400, 30)
# end of class CallXWindow(QWidget)
class ActiveXExtend(QObject):
def __init__(self, view):
super().__init__()
self.view = view
self.ocx = QAxWidget(TrueConfCallX_Class)
self.ocx.move(0, 0)
self.ocx.setFixedSize(640, 375)
self.ocx.setParent(self.view)
self.ocx.show()
# receive some ActiveX events
self.ocx.OnXAfterStart.connect(self._OnXAfterStart)
self.ocx.OnServerConnected[str].connect(self._OnServerConnected)
self.ocx.OnLogin[str].connect(self._OnLogin)
self.ocx.OnInviteReceived[str].connect(self._OnInviteReceived)
self.ocx.OnXError[int, str].connect(self._OnXError)
self.ocx.OnXLoginError[int].connect(self._OnXLoginError)
# Events
def _OnXAfterStart(self):
print("**OnXAfterStart")
# select devices
self.ocx.XSetCameraByIndex(0)
self.ocx.XSelectMicByIndex(0)
self.ocx.XSelectSpeakerByIndex(0)
# connect to server
self.ocx.connectToServer(SERVER)
def _OnServerConnected(self, eventDetails):
print("**OnServerConnected")
print(eventDetails)
# login
self.ocx.login(USER, PASSWORD)
def _OnLogin(self, eventDetails):
print("**OnLogin")
def _OnInviteReceived(self, eventDetails):
print("**OnInviteReceived")
print(eventDetails)
# accept any calls
self.ocx.accept()
def _OnXError(self, errorCode, errorMsg):
print("**OnXError")
print('{}. Code: {}'.format(errorMsg, errorCode))
def _OnXLoginError(self, errorCode):
print("**OnXLoginError")
if errorCode == 8:
print('Support for SDK Applications is not enabled on this server')
else:
print('Login error. Code: {}'.format(errorCode))
# end of class ActiveXExtend(QObject)
if __name__ == '__main__':
app = QApplication(sys.argv)
MainWindow = CallXWindow()
axwin = ActiveXExtend(MainWindow)
MainWindow.show()
sys.exit(app.exec_())

Related

Save audio file KIVY, PYTHON

What I am trying to do is, save each recorded file with a different filename(Myaudio1,2,3). Currently this code saves the audio as MYAUDIO.3gp, replacing the old file.
class MyRecorder:
def __init__(self):
'''Recorder object To access Android Hardware'''
self.MediaRecorder = autoclass('android.media.MediaRecorder')
self.AudioSource = autoclass('android.media.MediaRecorder$AudioSource')
self.OutputFormat = autoclass('android.media.MediaRecorder$OutputFormat')
self.AudioEncoder = autoclass('android.media.MediaRecorder$AudioEncoder')
# create out recorder
self.mRecorder = self.MediaRecorder()
self.mRecorder.setAudioSource(self.AudioSource.MIC)
self.mRecorder.setOutputFormat(self.OutputFormat.THREE_GPP)
self.mRecorder.setOutputFile('/sdcard/MYAUDIO.3gp')
self.mRecorder.setAudioEncoder(self.AudioEncoder.AMR_NB)
self.mRecorder.prepare()
I don't remember where I found the full code but if you need it, let me know. Thank you
You can use datetime for this.
from datetime import datetime
d = datetime.now()
d = d.strftime("%d_%m_%Y_%H%M%S")
self.mRecorder.setOutputFile('/sdcard/MYAUDIO_{}.3gp'.format(d))

Pulling QGIS plugin logic into stand alone Application

I'm new to QT, Python, and QGIS. I installed the "Plugin Builder" plugin and generated a Dockwidget. I am able to change the widget using qtcreator and am learning how to implement the signals and slots to work with my own plugin.
Now, to my question. Is there and easy way I can remove the QGIS iface and use my plugin's logic outside of QGIS? I'm not actually using any of the PyQGIS libraries at the moment, but I want to keep my QT interface and Python code/structure generated by the "Plugin Builder". Is there a way to do that?
Thanks.
Yes, there is a way to do it. But so far what I have found is that we need to copy entire Qgis library to the final software package. It is very important to set the correct path for qgis application inside the code as follows:
QgsApplication.setPrefixPath(r"C:\OSGeo4W\apps\qgis", True)
QgsApplication.initQgis()
QgsProject.instance().setFileName(strProjectName)
Also we need to write the file and close it at the end
QgsProject.instance().write()
QgsApplication.exitQgis()
Here's snapshot of the stand alone package I have created. The code needs some modification for some variables to work.
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from qgis.core import *
from qgis.gui import *
import os, datetime
class CreateQgs():
def initQgsFile(self, outputFolder, stopRadius):
strProjectName = str(outputFolder) + "\\" + "PhotoLocationMap.qgs"
QgsApplication.setPrefixPath(r"C:\OSGeo4W\apps\qgis", True)
QgsApplication.initQgis()
QgsProject.instance().setFileName(strProjectName)
highwayShapeFilePath = "C:/Shapefiles/Highway.shp"
arterialShapeFilePath = "C:/Shapefiles/StreetsMajor.shp"
highwayLayer = QgsVectorLayer(self.highwayShapeFilePath, 'HighwayDB' , 'ogr')
arterialLayer = QgsVectorLayer(self.arterialShapeFilePath, 'ArterialDB', 'ogr')
symbols = highwayLayer.rendererV2().symbols()
sym = symbols[0]
sym.setColor(QColor.fromRgb(255,94,94))
highwayLayer.triggerRepaint()
symbols = arterialLayer.rendererV2().symbols()
sym = symbols[0]
sym.setColor(QColor.fromRgb(76,138,245))
arterialLayer.triggerRepaint()
mapInstance = QgsMapLayerRegistry.instance()
mapInstance.instance().addMapLayer(arterialLayer)
mapInstance.instance().addMapLayer(highwayLayer)
QgsProject.instance().write()
QgsApplication.exitQgis()
def unitTest():
app = QgsApplication(sys.argv, True)
photoFolderPath = 'C:\Test\QGis\TestPics'
CreateQgsFile = CreateQgs()
CreateQgsFile.initQgsFile(photoFolderPath, 128)
if __name__ == "__main__":
unitTest()

Python, returning data collected in npyscreen

So I'm creating a basic TUI for a script I created. The goal is to collect several variables that include paths to directories and files. What I'm not sure about is once I've created the visual aspect of it, how to get those pieces of information to interact with other parts of the code.
Below is what I have so far in terms of the visual portion (the other part is about 500 lines), and honestly I'm at a loss on how to even print any of the variables set under the class and any pointers would be greatly appreciated.
#!/usr/bin/env python
# encoding: utf-8
import npyscreen
class PlistCreator(npyscreen.NPSApp):
def main(self):
screen = npyscreen.Form(name="Welcome to Nicks Playlist Creator!")
plistName = screen.add(npyscreen.TitleText, name="Playlist Name:" )
csvPath = screen.add(npyscreen.TitleFilenameCombo, name="CSV Schedule:")
toaPath = screen.add(npyscreen.TitleFilenameCombo, name="Path to ToA Video Folder:", use_two_lines=True)
outputPath = screen.add(npyscreen.TitleFilenameCombo, name = "Output Folder:", use_two_lines=True)
dateOfAir = screen.add(npyscreen.TitleDateCombo, name="Date of Air:")
timeOfStart = screen.add(npyscreen.TitleText, name="Time of Air (TC):")
screen.edit()
if __name__ == "__main__":
App = PlistCreator()
App.run()
You can get the value of any form object using the dit notation.
plistName = screen.add(npyscreen.TitleText, name="Playlist Name:" )
playlist_name = self.screen.plistName.value
etc. Note there are no parentheses after value. Once you have it in a variable, you can build another method in the class to handle the information.

error msg in VBA when calling a COM server created in Python using Win32

I'm reading Mark Hammond's book on Python and win32 using the pieces of code below (creation of a mini COM server mimicking Python's <variable.split> function, as well of a tiny client on VBA sending a string to be split.
My problem is that although everything seems to be peachy (the COM server is registered and does exist on regedit), I get the French version of the VBA error:
Code 438 : "property or method not managed by this object".
Needless to say that I did create a specific reg_clsid using pythoncom.CreateGuid() !
Environment : Windows 10, Python 3.5.2 under Anaconda 4.1.1, ASUS 8GB 64bits
Many thanks in advance.
Python part :
class PythonUtilities:
_public_methods_ = ['SplitString']
_reg_progid_ = "PythonDemos.Utilities"
_reg_clsid_ = "{C44B2DFA-3E19-478C-9599-3DFE7A0D619A}"
def SplitString(self, val, item=None):
import string
if item != None: item = str(item)
return string.split(str(val), item)
if __name__=='__main__':
print("Registering COM server…")
import win32com.server.register
win32com.server.register.UseCommandLine(PythonUtilities)
Messages on the console :
Registering COM server…
Requesting elevation and retrying...
Registering COM server…
Registered: PythonDemos.Utilities
VBA part :
Sub TestPython()
Set PythonUtils = CreateObject("PythonDemos.Utilities")
myResp = PythonUtils.SplitString("Hello from VB")
For Each Item In myResp
MsgBox (Item)
Next
End Sub
In your code SplitString is not a member of PythonUtilities (regard indentation). Therefore, the function you want to call is not part of the object you have created.
Also, you do not need the import string within your function.
Try the following:
import pythoncom
import win32com.client
class PythonUtilities:
_public_methods_ = ['SplitString']
_reg_progid_ = "PythonDemos.Utilities"
_reg_clsid_ = "{C44B2DFA-3E19-478C-9599-3DFE7A0D619A}"
def SplitString(self, val, item=None):
if item != None: item = str(item)
return str(val).split(item)
def run_testclient():
obj = win32com.client.Dispatch("PythonDemos.Utilities")
print(obj.SplitString("Hello from VB"))
if __name__=='__main__':
print ("Registering COM server...")
import win32com.server.register
win32com.server.register.UseCommandLine(PythonUtilities)
run_testclient()
A little bit late. But maybe it still can help...

Get Application Name from .exe file in python

I am getting both the currently active window title and exe filepath with the code below
hwnd = win32gui.GetForegroundWindow()
_, pid = win32process.GetWindowThreadProcessId(hwnd)
if hwnd != 0 or pid != 0:
try:
hndl = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION | win32con.PROCESS_VM_READ, 0, pid)
self.newExe = win32process.GetModuleFileNameEx(hndl, 0)
self.newWindowTitle = win32gui.GetWindowText(hwnd)
except:
self.newExe = ''
self.newWindowTitle = ''
the issue is that although it often is, the window title is not always the application name (the name the users understand as the main part of an application) and this is what I need. for example from calc.exe get Calculator withiout relying on the window title.
the purpose is to create a script that will log in an xml comparative use of any software on a computer
Is this possible?
Most Windows applications store information such as this inside their resource tables. There are API calls that can be used to extract this.
The following extracts the file description from a given application:
import win32api
def getFileDescription(windows_exe):
try:
language, codepage = win32api.GetFileVersionInfo(windows_exe, '\\VarFileInfo\\Translation')[0]
stringFileInfo = u'\\StringFileInfo\\%04X%04X\\%s' % (language, codepage, "FileDescription")
description = win32api.GetFileVersionInfo(windows_exe, stringFileInfo)
except:
description = "unknown"
return description
print(getFileDescription(r"C:\Program Files\Internet Explorer\iexplore.exe"))
The output is:
Internet Explorer
You could therefore pass the result of your call to win32process.GetModuleFileNameEx() to this function.

Categories