Type Mismatch using win32com in Python - python

I am trying to use Python to run an external program using its COM interface. In general, everything works as expected. The only problem I’m having is that any time I try to retrieve a value from the program using their GetValue method, I get the following error (code included).
This method is supposed to overwrite the value of my Value variable. The function takes 3 arguments, and I have verified that the error is related to the first argument (Value) by using separate functions successfully that only take the last 2 arguments. The documentation for the COM interface mentions this issue for C#, and their recommended solution was to define Value as an Object type variable and set the value to null. I have it set to None below, but I’ve also tried setting it to different int/float/string with no success.
I receive this error whether or not I use the EnsureModule command before dispatch.
See the code below
Object = win32.Dispatch(“COMObject”)
Object.OpenFile(“Filename”)
Value = None
Object.GetValue(Value,0,1)
Exception has occurred:com_error
(-2147352571,’type mismatch’,None,1)

Related

Python OverflowError : in method 'get_GDSII_prisms', argument 3 of type 'int'

I'm a new user of a Python module called meep. I followed this tutorial and everything works fine. However, I tried to change something and I keep having the same error : OverflowError : in method 'get_GDSII_prisms', argument 3 of type 'int'
Here is the part of the code that causes trouble :
gdsII_file = 'coupler.gds'
UPPER_BRANCH_LAYER = 31
si_zmax = 10
si_zmin = -10
def test(p):
return mp.Medium(index=15)
upper_branch = mp.get_GDSII_prisms(test, gdsII_file, UPPER_BRANCH_LAYER, si_zmin, si_zmax)
The only change I made is that I put a function as first argument of get_GDSII_prisms instead of a mp.Medium instance (calling mp.get_GDSII_prisms(mp.Medium(index=15), gdsII_file, UPPER_BRANCH_LAYER, si_zmin, si_zmax doesn't create any trouble.) But this should work since every function of this module that takes a mp.Medium instance can also take a user-defined function. Moreover, I found it strange that Python finds an error on argument 3 whereas I only changed argument 1.
I looked on the internet in order to understand why I have this error and how to resolve it but I didn't found anything.
I'm using Python 3.8.5.
Thank you for your help!

GRPC Error: Parameter to MergeFrom() must be instance of same class

I have seen all previous questions about this, but nothing seems to be working on my end. I am trying to run a test that uses a protobuf generated file, called 'resource_pb2'. I am using Python 3.8 with grpc 1.33.2 and protobuf version 3.14.
When using a class from this protobuf generated file, my test fails with the following error:
Parameter to MergeFrom() must be instance of same class: expected RecognitionResource got RecognitionResource
I've checked the type and id's of all the "recognition resource" classes being called in that particular test, and I get the following:
<class 'resource_pb2.RecognitionResource'> 2069160783760
<class 'resource_pb2.RecognitionResource'> 2069160783760
<class 'resource_pb2.RecognitionResource'> 2069160783760
They are clearly all being called from the same source, so why is this issue occuring?
I had a similar issue and the reason was that I had made a mistake when passing parameters to the function.
The problem was solved when I realized about my bug and I invoked the function in the right way, with all required parameters properly set.
Hope it helps.

python get members of COM ole object

In python 3.6 I'm using an COM interface to communicate with Excel and Word, in this case Word for automated reporting as the data processing is done in python.
I don't know how python can get the members of such a COM object similar to the use of the dir() function.
(Previously using Matlab, i would use the .get or .invoke methods to get this)
So the code would be:
def wordOpen(wordfile):
pythoncom.CoInitializeEx(pythoncom.COINIT_APARTMENTTHREADED)
wApp = win32com.client.DispatchEx('Word.Application')
wDoc = wApp.Documents.Open(wordfile)
wApp.Visible = 1
wApp.Activate
wRange = wDoc.Content
return wApp, wDoc, wRange
wApp, wDoc, wRange = wordOpen(wordfile)
dir(wDoc)
.. which does not provide me the list of methods and properties of the Word document object (similar for wApp and wRange).
Similarly I've tried inspect.getmembers(wDoc) but this also does not provide the list of methods/properties that I'm looking for.
For the same thing when communicating with Excel, I used to go into the VBA editor and get a list there, but is there any method to do this from the IPython
console directly?
Did some more searching and figured it out myself. The above example uses 'dynamic dispatching' and we want to use 'static dispatching' instead. That does not change the code, it only entails a one-off action.
Dynamic is a quick-and-dirty way to create these objects, and then python knows nothing about the type of object.
Static means that you have to run makepy.py from the command line to create a type library (in this case for Word objects), and after that has been done once, python knows all the info about the object every next time it launches the COM object.
The procedure is very simple and comparable to the VBA action of adding References to your project.

Namespacing issue in Python

I am using a program where Python is the native scripting language. Unfortunately, they have a native function that uses the name bytes. This causes a problem when I am trying to use the actual bytes built-in function, and it thinks I am referencing that built-in variable. I will show you what I mean, one object as the following built-in code:
def receive(row, table, message, bytes):
#This is defined in the GUI
So, row, table, message, and bytes are all passed in as arguments, effectively overwriting the name bytes. So if I were to say bytes(something).decode() I get a TypeError: 'bytes' object is not callable
Is there any way to get out of this jam?
Use a different name for the fourth parameter (if you can change the signature of the function)
def receive(row, table, message, bytes_):
#This is defined in the GUI
Your problem is similar to this one. Just from builtins import bytes as _bytes; this will let you do _bytes(something).decode().
Although renaming the fourth argument is a better solution.

Python wmi parameters reversed

Using python's wmi module to create a vss snapshot, I've found that the parameters don't work unless I reverse them:
import wmi
def vss_create():
shadow_copy_service = wmi.WMI(moniker='winmgmts:\\\\.\\root\\cimv2:Win32_ShadowCopy')
res = shadow_copy_service.Create('ClientAccessible', 'C:\\')
In the msdn docs, the function is instead supposed to be used this way:
Win32_ShadowCopy.Create("C:\\", "ClientAccessible");
Why is this the case, and is there a way to use the intended order?
Summary
It looks like the parameter ordering for wmi object's methods is reversed from normal by the PyWin32 layer, and this behaviour has been present for at least five years. The relevant wmi spec says that a wmi client can pass the parameters in any order, so PyWin32 is not 'wrong' to do this, although I can't tell if it's deliberate or accident. I speculate that it's unlikely to change, for backwards compatibility reasons, but you can work around this and put the parameters in the order you want by specifying them as keyword parameters: Create(Volume=, Context=).
Details
NB. In the below details, I'm trying to go down in layers from the Python WMI module code to WMI objects accessed by COM in PyWin32 code, to WMI objects as documented and used in other languages, to WMI object specification by MOF files, to specification documents. There's several layers and I write "WMI" a lot, meaning different things at different layers.
When you say "Python's wmi module" do you mean Tim Golden's Python WMI module (link to source code) that builds on PyWin32?
When you get a Python WMI object from the wmi module, the initialization steps it goes through are inside the class _wmi_object, and include querying the underlying wmi object for its available methods:
for m in ole_object.Methods_:
self.methods[m.Name] = None
I'm going to skip beneath Python's wmi module, and use PyWin32 directly to look at what you get when querying a WMI COM object for its available methods:
>>> from win32com.client import GetObject
>>> vss = GetObject('winmgmts:\\\\.\\root\\cimv2:Win32_ShadowCopy')
>>> [method.Name for method in list(vss.Methods_)]
[u'Create', u'Revert']
And we see the Win32_ShadowCopy object has the methods Create and Revert. So that's where the Python wmi wrapper first learns about the Create method you are using.
From there, the Python WMI wrapper class does some setup work which I haven't traced through fully, but it seems to initialize class _wmi_method once for each available method of the COM object. This class includes these initialization steps:
self.method = ole_object.Methods_ (method_name)
self.in_parameter_names = [(i.Name, i.IsArray) for i in self.in_parameters.Properties_]
A list comprehension to get the available parameters for each method. Going back to my testing to explore that without the Python WMI layer, it gives output like this:
>>> CreateMethod = vss.Methods_('Create')
>>> [n.Name for n in list(CreateMethod.InParameters.Properties_)]
[u'Context', u'Volume']
This example test shows the PyWin32 later, the COM object for Win32_ShadowCopy, the Create method - lists its available parameters in the order you are seeing - the "wrong" order. The Python WMI layer is picking up that ordering.
When you call the Win32_ShadowCopy object's Create() method through Python WMI's wrapper, the _wmi_method does this:
def __call__ (self, *args, **kwargs):
for n_arg in range (len (args)):
arg = args[n_arg]
parameter = parameters.Properties_[n_arg]
parameter.Value = arg
In other words; it pairs up the parameters you pass in (*args) with the stored parameter list, one by one, taking the parameters in the order you pass them, and pairing them with the method parameters in the order WMI returned them - i.e. it's not intelligent, it just links the first parameter you enter with 'Context' and the second with 'Volume' and gets them backwards, and your code crashes.
The call method also includes Python's **kwargs parameter which takes all given keywords, suggesting you can do
Create(Volume='C:\\', Context="ClientAccessible")
and put them in the order you want by using them as keyword arguments. (I haven't tried).
I have tried tracing the .Properties_ lookup through PyWin32com to try and identify where the ordering comes from at the lower layers, and it goes through a long chain of dynamic and cached lookups. I can't see what happens and I don't understand enough COM or PyWin32 to know what kinds of things to be looking for, so that's a dead end for me.
Taking a different approach and trying to find out from the WMI object setup files where the ordering comes from: run mofcomp.exe which ships with Windows and processes Managed Object Format (MOF) files... click Connect, Create Class "Win32_ShadowCopy"; Click the "Create" method in the methods list, then click the "Edit Method" button; then click "Edit Input Arguments" then click "Show MOF", and get this result:
[abstract]
class __PARAMETERS
{
[in, ID(0): DisableOverride ToInstance] string Volume;
[in, ID(1): DisableOverride ToInstance] string Context = "ClientAccessible";
};
That's the "correct" order of the parameters coming out of the Windows MOF files, with numeric IDs for the parameters - implying they have a correct ordering 0, 1, etc.
c:\windows\system32\wbem\vss.mof, the MOF file which appears to cover the Volume Shadow Copy objects contains this:
[static,implemented,constructor] uint32 Create([in] string Volume,[in] string Context = "ClientAccessible",[out] string ShadowID);
and the PowerShell example in the comments at this MSDN link includes $class.create("C:\", "ClientAccessible").
So those three things all tie up with the same ordering and implies there is a correct or standard ordering.
That leaves me thinking of these possibilities:
There is ordering information coming out of PythonCOM and the wmi module should look at it, but doesn't. - I have looked around quickly, and can't find ID / ordering data with the parameters list, so that seems unlikely.
There is ordering information somewhere unknown to me which the PyWin32 COM layer should be looking at but doesn't. - Not sure here.
There is no official ordering. Trying to confirm this point, we get a fun chain:
What is WMI? Microsoft's implementation of standard management frameworks WBEM and CIM, specified by the DTMF. (DTMF = Distributed Management Task Force, WBEM is Web Based Enterprise Management and CIM is the Common Information Model).
MOF is the Managed Object Format, a text representation of CIM
This document: http://www.dmtf.org/sites/default/files/standards/documents/DSP0221_3.0.0.pdf appears to be the MOF specification. Check section 7.3.3 Class Declaration, from page 18:
line 570:
"A method can have zero or more parameters".
lines 626 through 628:
Method parameters are identified by name and not by position and
clients invoking a method can pass the corresponding arguments in
any order. Therefore parameters with default values can be added to
the method signature at any position.
I don't know for sure if that's an authoritative and current specification, nor have I read all of it looking for exceptions, but it sounds like you should use named parameters.
The WMI objects and methods have a MOF definition, and the MOF specification says you shouldn't rely on the parameter ordering; however, accessing the WMI objects via COM via PyWin32 is showing a different ordering to (MSDN docs, the MOF file and the PowerShell examples). I still don't know why.
And Googling that leads me to this mailing list post by Tim Golden, author of the Python wmi module, saying basically the same thing as I've just found, except five years ago:
the method definition picks up the parameters in the order in which WMI returns them [..]
I've got no idea if there is any guarantee about the order of parameters [..]
Glancing at a few other method definitions, it does seem as though WMI is consistently returning params in the reverse order of their definition in the MOF.
At this point, it looks like PyWin32 is returning a reversed list to the typical Windows parameter order, but is that a bug if the CIM managed object method parameter list specification document explicitly says don't rely on the parameter ordering?

Categories