Python win32com.client function with propput - python

I'm using win32com.client to write a little plugin, but I have a problem with set a property. The definition for the property or function is this:
[id(0x00000021), propget, helpstring("property SystemChannel")]
long SystemChannel(
long lVEN,
long lDEV,
long lSVID,
long lSID);
[id(0x00000021), propput, helpstring("property SystemChannel")]
void SystemChannel(
long lVEN,
long lDEV,
long lSVID,
long lSID,
[in] long rhs);
I have not problems with get the value, the next code work greats:
app = Dispatch("CmAVConfig.AudioConfig")
self.speakerNumber = app.SystemChannel(self.glVid, self.glDid, self.glSvid, self.glsid)
But I can't set the value of the same property, I have tried using the next instructions and I get the errors below:
app = Dispatch("CmAVConfig.AudioConfig")
app.SystemChannel(self.glVid, self.glDid, self.glSvid, self.glsid, self.speakerNumber)
ERROR: SystemChannel() takes at most 5 arguments (6 given)
//this one is from a working example using javascript
app.SystemChannel(self.glVid, self.glDid, self.glSvid, self.glsid) = self.speakerNumber
ERROR: SyntaxError: ("can't assign to function call", ('ooo.py', 56, None, 'app.SystemChannel(self.glVid, self.glDid, self.glSvid, self.glsid) = self.speakerNumber\n'))

If you run makepy for the library (or use win32com.client.gencache.EnsureDispatch)
it should create a SetSystemChannel method that takes an extra arg.

Related

Reset environment/scope between multiple function calls in Python.Net

I want to execute the same Python function several times and I want each execution to be completely isolated from the previous one.
But the problem is that the first execution of the method changes a global variable and when I execute the method the second time the global variable has the value left by the first execution.
I want that from one call to another the environment is reset and is like the first time.
var1=1
def Met(n) :
global var1
if n!=1 : var1=n
print(f"Py: {var1}")
return var1
if __name__ == "__main__":
args = sys.argv
globals()[args[1]](*args[2:])
If I execute it from command line:
python .\Test1.py Met 2
python .\Test1.py Met 1
The output is (correct):
Py: 2
Py: 1
What I want, OK.
But if I run it from Pythonet I get:
Py: 2
Py: 2
Incorrect!
That is, the second call, the value of var1 is the value of first call.
The code (simplifying):
public string Met2(int n) {
dynamic txtResul="X";
using ( Py.GIL() ) {
using (var scope=gbl.NewScope() ) { //Witout this, it doesn't work too
dynamic f=Py.Import(NOM_FICH_Py);
txtResul=f.Met(n);
}
}
return txtResul.ToString();
}
I have tried initialising with and without this:
PythonEngine.Initialize();
gbl = Py.CreateScope(nombre);
pyPtr=PythonEngine.BeginAllowThreads();
I have also tried to finalize everything and run it, with and without this:
public void Fin() {
PythonEngine.EndAllowThreads(pyPtr);
PythonEngine.Shutdown();
}
I have also tried running each function call as a separate script:
using (Py.GIL()) {
dynamic sys = Py.Import("sys");
string script ="import sys\n"+ "from io import StringIO\n"+
$"from {NOM_FICH_Py} import {funcion.Split('(')[0]}\n"+
"sys.stdout=StringIO()\n"+ "sys.stdout.flush()\n"+
"sys.stderr=StringIO()\n"+ "sys.stderr.flush()\n"+
funcion;
var scope = Py.CreateScope();
var vars=scope.Variables();
scope.Exec(script, new PyDict());
salida=sys.stdout.getvalue();
scope.Dispose();
}
I use Python 3.10 and Python .Net 3.0.0-rc 4 and Python.Net 3.0.0-preview2022-03-03 (in other computer) and I cann't get the 'reset' as I executed it like command line.
Thanks in advance.
Extra question, is there any wiki/documentacion to read the detail of functions like CreateScope, NewScope, Exec...? In https://github.com/pythonnet/pythonnet/wiki I haven't found the function's detail.
The only supported way to fully reset Python environment with Python.NET is to restart the process.
At the end, the only posible solution it's to exectue like a script in cmd.
It's not the best solution (it's not posible to debug) but it's the only one I know.
public string ExecCmd(string funcion, string args) {
Process p = new Process();
p.StartInfo=new ProcessStartInfo(PYTHON_EXE, $"{NombreFichApp} {funcion} {args}") {
RedirectStandardOutput=true,
UseShellExecute=false,
CreateNoWindow=true
};
p.Start();
string salida = p.StandardOutput.ReadToEnd();
p.WaitForExit();
return salida;
}

cannot spot the Type Error reported by the Python Shell

Hi I'm realtively new to computer science and learning to code Python. Here is a section of the code that I have trouble with:
from uagame import Window
from time import sleep
window = Window('hello',300,200)
user = window.input_string('Enter string>',0,0)
x = window.get_width() - window.get_string_width(user)
y = window.get_height() - window.get_font_height(user)
window.draw_string(user_input,x,y)
sleep(2)
window.close()
It always display a Type error and I do not know the reasons. I've run similar codes with no problem
Here is the error:
builtins.TypeError: get_font_height() takes 1 positional argument but 2 were given
Any help will be appreciated
What that means, I'm guessing, is that window.get_font_height() is a method that doesn't take an argument. Since it's window.<method name>, the first argument to get_font_height is probably going to be self! So you are passing a user to that function, which is, I'm guessing, the second argument.
Look up the documentation for uagame window.get_font_height and make sure you're using it correctly.
The guesses of the other respondents are correct: get_font_height takes only the Window object as an argument, and receives that through the normal call sequence (i.e. the window is the self argument). The font height is returned as an int.
There is no dependence whatsoever on your input string; that argument is not allowed, and that's why you got that error message. Simply remove that and call as window.get_font_height().

"Unexpected" TypeError: unexpected keyword

I have written this function in a package of mine.
def partitionIntoDays(ls, number, lookupKey=None):
''' Partitions the location measurements into days.
#ls: The list of measurements you want to partition
#return: A dictionary in the format {'Number of partition':
'List of measurements'}'''
if len(ls) == 0:
return {0: []}
firstMidnight = TimeAux.localTimeToEpoch(Delorean(TimeAux.epochToLocalTime(ls[0].time, TIMEZONE)).midnight())
return splitByTimedelta(ls, delta=number*24*3600, lowerBound=firstMidnight, lookupKey=lookupKey)
But whenever I try to call the function from a script I get the following error:
TypeError: partitionIntoDays() got an unexpected keyword argument 'lookupKey'
However if I import the function somewhere manually, I can check that the function has the argument. For example, I can even do this while I am debugging the above error in pdb.
import geogps.Partition as pt
pt.partitionIntoDays.func_code.co_varnames
>>>>('ls', 'number', 'lookupKey', 'firstMidnight')
Also the above code works fine in Python 3.4.
I am in short completely flabbergasted.
So I figured it out: While there were no lingering pyc files, my package structure was messed up and I had an extraneous file in a nested folder.
Thanks #bruno-desthuilliers for pointing me the right way.

Create SAFEARRAY of Strings in Python

I'm trying to call a COM method that requires a SafeArray of Strings to be passed as reference, which is then filled up with the method results. This is the code in VBA, which works flawlessly:
dimr RC as New RAS41.HECRASController
RC.Project_Open "c:\myProj.prj"
dim numMessages as Long
dim messages() as String
RC.Compute_CurrentPlan( numMessages, messages())
Now, I'm trying to do the same from with Python 3.4, using the win32com module. However, I'm stuck at trying to create the second parameter with the correct type, which according to combrowse.py should be "Pointer SafeArray String".
This was my first attempt:
import win32com
RC = win32com.client.Dispatch("RAS41.HECRASController")
RC.Project_Open("c:\\myProj.prj")
numMessages = 0
messages = []
RC.Compute_CurrentPlan(numMessages, messages)
I also tried constructing that variable as
messages = win32com.client.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_BSTR, [])
but it didn't work either. Error messages look like this:
Traceback (most recent call last):
File "<pyshell#101>", line 1, in <module>
print(o.Compute_CurrentPlan(1,b))
File "<COMObject RAS41.HECRASController>", line 3, in Compute_CurrentPlan
File "C:\Python34\lib\site-packages\win32com\client\dynamic.py", line 282, in _ApplyTypes_
result = self._oleobj_.InvokeTypes(*(dispid, LCID, wFlags, retType, argTypes) + args)
TypeError: Objects for SAFEARRAYS must be sequences (of sequences), or a buffer object.
Make sure that you python variables are in the right format (Long and String). Try to use something like the following to get the variable types in shape:
messages = ['']
RC.Compute_CurrentPlan(long(numMessages), messages)
To be more flexible with your program you should check the variable types prior to the win32 call.
I realize this is an old question, but I ran into this issue and wanted to share the resolution. I was having issues defining the type of data for the first two arguments, but simply setting them to None works and your number of messages and compute messages are reported (I checked by assigning text = hec.Compute_CurrentPlan(None, None, True) and then print(test)). The third argument is Blocking Mode, set to True, meaning that the RAS computation will complete before moving to the next line of code. I am using Python 3.10.4 and HEC-RAS version 6.3.
import win32com.client
hec = win32com.client.Dispatch('RAS630.HECRASController')
hec.Project_Open(r"C:\myproj.prj")
hec.ShowRAS()
hec.Compute_CurrentPlan(None, None, True)
hec.QuitRAS()

Call functions in AutoIt DLL using Python ctypes

I want to call functions from an AutoIt dll, that I found at C:\Program Files (x86)\AutoIt3\AutoItX\AutoItX3.dll using Python. I know I could use win32com.client.Dispatch("AutoItX3.Control") but I can't install the application or register anything in the system.
So far, this is where I am:
from ctypes import *
path = r"C:\Program Files (x86)\AutoIt3\AutoItX\AutoItX3.dll"
autoit = windll.LoadLibrary(path)
Here are the methods that works:
autoit.AU3_WinMinimizeAll() # windows were successfully minimized.
autoit.AU3_Sleep(1000) # sleeps 1 sec.
Here is my problem, python is crashing when I call other methods like this one. I get python.exe has stopped working from windows...
autoit.AU3_WinGetHandle('Untitled - Notepad', '')
And some other methods are not crashing python but are just not working. This one doesn't close the window and return 0:
autoit.AU3_WinClose('Untitled - Notepad', '')
And this other one return 1 but the window is still minimized:
autoit.AU3_WinActivate('Untitled - Notepad', '')
I've tested the examples with with Dispatch("AutoItX3.Control") and everything is working like expected.
It seems like methods that should return something other than a string are crashing python. But still, others like WinClose are not even working...
Thank you in advance for your help!
EDIT:
These methods are now working when using unicode strings:
autoit.AU3_WinClose(u'Untitled - Notepad', u'')
autoit.AU3_WinActivate(u'Untitled - Notepad', u'')
And I found the prototype for AU3_WinGetHandle:
AU3_API void WINAPI AU3_WinGetHandle(const char szTitle,
/[in,defaultvalue("")]*/const char *szText, char *szRetText, int
nBufSize);
Now I can retrieve the return value using the following code!
from ctypes.wintypes import LPCWSTR
s = LPCWSTR(u'')
print AU3_WinGetHandle(u'Untitled - Notepad', u'', s, 100) # prints 1
print s.value # prints '000705E0'!
Thank you to those who helped me!
If you have the prototypes of the functions you're trying to call, then we can help you debug the calls without guessing. Or, more importantly, we won't have to help you debug the calls, because you can let ctypes do it for you.
See Specifying the required argument types in the docs.
For example, let's say the function looks like this (just a random guess!):
void AU3_WinClose(LPCWSTR name, LPCWSTR someotherthing);
You can do this:
autoit.AU3_WinClose.argtypes = (LPCWSTR, LPCWSTR)
autoit.AU3_WinClose.restype = None
If you do this, ctypes will try to convert your arguments to the specified types (LPWSTR, which is a pointer to wide char used for Windows UTF-16 strings) if it can, or raise an exception if it can't, and will not expect any return value.
If you don't do this, ctypes will try to guess the right things to convert your arguments to, possibly guessing wrong, and will try to interpret the non-existent return value as an int. So, it will usually crash until you managed to guess exactly what types to throw at it to make it guess the right types to pass to the function.
Will it work with unicode strings?
autoit.AU3_WinClose(u'Untitled - Notepad', u'')
autoit.AU3_WinActivate(u'Untitled - Notepad', u'')
Actually you might have to explicitly create unicode buffers, e.g.:
autoit.AU3_WinClose(create_unicode_buffer('Untitled - Notepad'), create_unicode_buffer(''))
Via some Googling, it looks like AU3_WinGetHandle takes 4 arguments, not 2. So you need to get that sorted out.

Categories