You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Support VT_ERROR variant type and optional parameters #325
Currently comtypes does not support variants with typecode 0xa (VT_ERROR). This is particularly important for servers supporting optional arguments for their methods, as an optional argument is replaced with a VT_ERROR variant with a particular error code (DISP_E_PARAMNOTFOUND).
Supporting VT_ERROR itself seems like a simple fix, as internally it is just an HRESULT, i.e. a 32-bit integer (where different parts of the bit field represent different components). As far as I can tell, the only change necessary is to modify VARIANT.__get_value() to have a VT_ERROR branch which duplicates the 32bit int pathway. comtypes currently has some support for creating HRESULTs from the individual components but does not have an actual class representing them, a more advanced fix would perhaps be to create an HRESULT/SCODE class that would allow the subfields to be examined.
However, the most important change required is to modify the machinery used in calling the Python functions on the server class so that if an argument is supplied with DISP_E_PARAMNOTFOUND then this can be removed from the argument list actually supplied to the server. I am not completely sure how to do this so would welcome some support in implementing this, and any pitfalls that might be lurking out there for the unwary. @vasily-v-ryabov , @cfarrow do you have any thoughts?
@junkmd I am not quite sure of the purpose of VARIANT.missing (that is a bit deeper into the COM internals than I have gone so far), but I note that it is defined to be simply an empty VARIANT rather than specifically an error type.
My use case is in implementing a server with optional arguments where the COM layer is providing the DISP_E_PARAMNOTFOUNDVT_ERROR and comtypes crashes on receiving it. The fix I proposed above will stop the crash from occurring but the server will receive the VARIANT object as the value which then has to be checked against the DISP_E_PARAMNOTFOUND to decide if it is a real value or not. I thought it would be nicer to get the interface layer to strip the value out of the call arguments altogether, if that were possible, but I couldn't figure out how to do it.
At that point, you wouldn't really need to worry about the .value as users wouldn't see it. Defining it as a constant would probably be sensible, but would we then need to define an equality operator for VARIANT to be able to compare to the constant?
This is not currently blocking me so is more of a "wouldn't it be nice" feature than something I am desperately pursuing. But if you can give me some hints (and some design guidance) then I am happy to dig back into this and see where we can get to.
I think that VARIANT.missing is a class attribute used by comtypes to get default values for parameters, rather than a process in the COM layer.
I will later write a summary of what I found when I improved _memberspec.py in #373 and #368.
When COMMETHOD is called, _resolve_argspec is called to derive argtypes for creating function prototypes.
In it, VARIANT.missing is used as the default value for optional arguments.
I thought that this VARIANT instance could be a module-level constant, as defined in ruby's WIN32OLE module, but it has been set as a class attribute of VARIANT ever since this package development was started.
When I was working on Excel COM operations after a long break, I encountered a situation in my use case where VARIANT with vt=VT_ERROR should be supported.
This can apply to cells that contain formulas resulting in errors, such as #DIV/0!.
Presumably, adding conditional branches like them is the correct way to handle it.
However, testing this requires Excel, which is currently skipped in the GHA CI pipeline due to licensing issues.
If you could contribute a simple COM server (acting as a test double) that receives or returns VARIANTs with vt=VT_ERROR, I believe we could release this change with greater confidence.
Any feedback is welcome.
Note:
My computer's Excel is the Japanese localized version.
While some output characters may differ from the English version of Excel, the internal processing should be the same.
The Japanese katakana "エラー" is "Error" in English.
@junkmd thanks for continuing your amazing commitment to improving comtypes. I think this is a simple fix and should not be controversial as it doesn’t break any existing behaviour, it just prevents some crashes.
I am happy to work on contributing a server that deals with VT_ERROR, but it would probably have to be a non Python server as otherwise you end up with a circular testing mechanism as we would have to implement the support to test the support. I am currently interested in exploring COM servers in Rust and so making this test server would be a convenient way to do that. However, I don’t currently have the bandwidth to get that done soon due to some urgent deadlines. So this post is basically just to acknowledge yours, say I will work on it but it won’t be soon.
Thank you as well for your continued participation and long-standing contributions to this community.
Regarding the test server, I believe that implementing a COM server in Rust should be possible, given the existence of the windows crate.
Perhaps @forderud might also have insights into this in Rust, or even know how to generate VARIANTs with vt=VT_ERROR in languages other than Python.
They have previously contributed to this project and published COM implementation examples in multiple languages.
In any case, I warmly welcome you and other community members to deepen your COM knowledge and contribute to this project.
For my part, handling error cells currently has a workaround by using Application.WorksheetFunction.IsError, so this is not an urgent issue for me personally.
However, many other COM libraries may not have such workarounds, so supporting VT_ERROR will definitely be a benefit to the project.
Please feel free to comment on this issue with any findings, questions, or suggestions you may have.
For now, I have added support for VARIANT with VT_ERROR. See #965.
Considering how it works with Excel, the .value property returns the VARIANT itself instead of the error code.
We can now also get scode, which holds the error code, but I haven't made it a public property yet.
Your use case will probably be a good reference for what works best here.
Activity
junkmd commentedon Jun 13, 2023
#372 is very close to your suggestion.
In 1.2.0,
repr(VARIANT.missing)returns"VARIANT.missing".comtypes/comtypes/automation.py
Lines 220 to 229 in d1f5cd7
When implementing #486, I noticed that the
VARIANTwithvt==VT_ERRORand_.VT_I4==DISP_E_PARAMNOTFOUNDis not onlyVARIANT.missing.Your suggestion is smarter than adding a workaround that will not cause errors when
repring suchVARIANT.But I'm not sure what type the
.valueproperty should return.I think that use cases implementing com-ffi and
VARIANTin other languages would be helpful.junkmd commentedon Jun 14, 2023
I don't know whether this will be helpful for this issue, I will share how COM support in other languages has handled
VARIANT.In PHP, There was an error that
VARIANTwithVT_ERRORcould not be created.php/php-src#8750
php/php-src@56804e3
junkmd commentedon Jun 14, 2023
In ruby, "
VARIANTwithvt==VT_ERRORand_.VT_I4==DISP_E_PARAMNOTFOUND" is defined as a constant.https://github.com/ruby/ruby/blob/813a5f4fc46a24ca1695d23c159250b9e1080ac7/ext/win32ole/win32ole_variant.c#L727-L736
bennyrowland commentedon Jun 15, 2023
@junkmd I am not quite sure of the purpose of
VARIANT.missing(that is a bit deeper into the COM internals than I have gone so far), but I note that it is defined to be simply an emptyVARIANTrather than specifically an error type.My use case is in implementing a server with optional arguments where the COM layer is providing the
DISP_E_PARAMNOTFOUNDVT_ERRORandcomtypescrashes on receiving it. The fix I proposed above will stop the crash from occurring but the server will receive theVARIANTobject as the value which then has to be checked against theDISP_E_PARAMNOTFOUNDto decide if it is a real value or not. I thought it would be nicer to get the interface layer to strip the value out of the call arguments altogether, if that were possible, but I couldn't figure out how to do it.At that point, you wouldn't really need to worry about the
.valueas users wouldn't see it. Defining it as a constant would probably be sensible, but would we then need to define an equality operator forVARIANTto be able to compare to the constant?This is not currently blocking me so is more of a "wouldn't it be nice" feature than something I am desperately pursuing. But if you can give me some hints (and some design guidance) then I am happy to dig back into this and see where we can get to.
junkmd commentedon Jun 16, 2023
I think that
VARIANT.missingis a class attribute used bycomtypesto get default values for parameters, rather than a process in the COM layer.I will later write a summary of what I found when I improved
_memberspec.pyin #373 and #368.junkmd commentedon Jun 17, 2023
When
COMMETHODis called,_resolve_argspecis called to derive argtypes for creating function prototypes.In it,
VARIANT.missingis used as the default value for optional arguments.I thought that this
VARIANTinstance could be a module-level constant, as defined in ruby'sWIN32OLEmodule, but it has been set as a class attribute ofVARIANTever since this package development was started.comtypes/comtypes/automation.py
Lines 571 to 574 in d1f5cd7
comtypes/comtypes/__init__.py
Lines 753 to 773 in d1f5cd7
comtypes/comtypes/_memberspec.py
Lines 53 to 83 in da27aaf
comtypes/comtypes/_memberspec.py
Lines 346 to 347 in da27aaf
junkmd commentedon Apr 26, 2025
@bennyrowland
When I was working on Excel COM operations after a long break, I encountered a situation in my use case where
VARIANTwithvt=VT_ERRORshould be supported.This can apply to cells that contain formulas resulting in errors, such as
#DIV/0!.In VBA, it's clear from the procedure execution result that the return value of the
.Valueproperty for error cells is aVARIANTwhereVarTypereturns10andTypeNameisError.https://learn.microsoft.com/en-us/office/vba/excel/concepts/cells-and-ranges/cell-error-values
https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/variant-data-type
https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/cverr-function
Attempting the equivalent operation with Python and
comtypesfails because theVARIANTimplementation does not supportvt=VT_ERROR.This error stops occurring if we modify
comtypes/automation.pyas shown in the diff below:Presumably, adding conditional branches like them is the correct way to handle it.
However, testing this requires Excel, which is currently skipped in the GHA CI pipeline due to licensing issues.
If you could contribute a simple COM server (acting as a test double) that receives or returns VARIANTs with
vt=VT_ERROR, I believe we could release this change with greater confidence.Any feedback is welcome.
Note:
My computer's Excel is the Japanese localized version.
While some output characters may differ from the English version of Excel, the internal processing should be the same.
The Japanese katakana "エラー" is "Error" in English.
bennyrowland commentedon Apr 27, 2025
@junkmd thanks for continuing your amazing commitment to improving comtypes. I think this is a simple fix and should not be controversial as it doesn’t break any existing behaviour, it just prevents some crashes.
I am happy to work on contributing a server that deals with VT_ERROR, but it would probably have to be a non Python server as otherwise you end up with a circular testing mechanism as we would have to implement the support to test the support. I am currently interested in exploring COM servers in Rust and so making this test server would be a convenient way to do that. However, I don’t currently have the bandwidth to get that done soon due to some urgent deadlines. So this post is basically just to acknowledge yours, say I will work on it but it won’t be soon.
junkmd commentedon Apr 29, 2025
@bennyrowland
Thank you as well for your continued participation and long-standing contributions to this community.
Regarding the test server, I believe that implementing a COM server in Rust should be possible, given the existence of the
windowscrate.Perhaps @forderud might also have insights into this in Rust, or even know how to generate
VARIANTs withvt=VT_ERRORin languages other than Python.They have previously contributed to this project and published COM implementation examples in multiple languages.
In any case, I warmly welcome you and other community members to deepen your COM knowledge and contribute to this project.
For my part, handling error cells currently has a workaround by using
Application.WorksheetFunction.IsError, so this is not an urgent issue for me personally.However, many other COM libraries may not have such workarounds, so supporting
VT_ERRORwill definitely be a benefit to the project.Please feel free to comment on this issue with any findings, questions, or suggestions you may have.
junkmd commentedon Oct 12, 2026
@bennyrowland
For now, I have added support for
VARIANTwithVT_ERROR. See #965.Considering how it works with Excel, the .value property returns the
VARIANTitself instead of the error code.We can now also get
scode, which holds the error code, but I haven't made it a public property yet.Your use case will probably be a good reference for what works best here.