Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ As of build 305, installation .exe files have been deprecated; see
Coming in build 312, as yet unreleased
--------------------------------------

* Implement COM Records as [out] method parameters (mhammond#2708, [@geppi][geppi], [@the-snork][the-snork])
* Implement multidimensional SAFEARRAY(COM Record) and SAFEARRAY(double) (mhammond#2655, [@geppi][geppi])
* Added many missing license and copyright notice files (mhammond#2590, [@Avasam][Avasam])
* Fixed missing version stamp on built `.dll` and `.exe` files (mhammond#2647, [@Avasam][Avasam])
Expand Down
10 changes: 10 additions & 0 deletions com/TestSources/PyCOMTest/PyCOMImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,16 @@ HRESULT CPyCOMTest::GetStruct(TestStruct1 *ret)
return S_OK;
}

HRESULT CPyCOMTest::GetOutStruct(TestStruct1 *pRecord)
{
if (pRecord == NULL) {
return E_POINTER;
}
pRecord->int_value = 99;
pRecord->str_value = SysAllocString(L"Luftballons");
return S_OK;
}

HRESULT CPyCOMTest::ModifyStruct(TestStruct1 *prec)
{
prec->int_value = 100;
Expand Down
1 change: 1 addition & 0 deletions com/TestSources/PyCOMTest/PyCOMImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ class CPyCOMTest : public IDispatchImpl<IPyCOMTest, &IID_IPyCOMTest, &LIBID_PyCO
STDMETHOD(TestOptionals2)(double dval, BSTR strval, short sval, SAFEARRAY **pRet);
STDMETHOD(TestOptionals3)(double dval, short sval, IPyCOMTest **outinterface2);
STDMETHOD(GetStruct)(TestStruct1 *ret);
STDMETHOD(GetOutStruct)(TestStruct1 *pRecord);
STDMETHOD(DoubleString)(BSTR inStr, BSTR *outStr);
STDMETHOD(DoubleInOutString)(BSTR *str);
STDMETHOD(TestMyInterface)(IUnknown *t);
Expand Down
1 change: 1 addition & 0 deletions com/TestSources/PyCOMTest/PyCOMTest.idl
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ library PyCOMTestLib
[in, defaultvalue(1)] short sval,
[out, retval] IPyCOMTest **ppout );
HRESULT GetStruct([out, retval]TestStruct1 *ret);
HRESULT GetOutStruct([out]TestStruct1 *pRecord);
HRESULT DoubleString([in] BSTR inStr, [out, retval] BSTR *outStr);
HRESULT DoubleInOutString([in,out] BSTR *str);
[restricted] HRESULT NotScriptable([in,out] int *val);
Expand Down
18 changes: 17 additions & 1 deletion com/win32com/client/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,22 @@ def MakeDispatchFuncMethod(self, entry, name, bMakeClass=1):
if doc and doc[1]:
ret.append(linePrefix + "\t" + _makeDocString(doc[1]))

for i, desc in enumerate(fdesc[2]):
if (
desc[0] & pythoncom.VT_RECORD
and desc[1] & (pythoncom.PARAMFLAG_FOUT | pythoncom.PARAMFLAG_FIN)
== pythoncom.PARAMFLAG_FOUT
and desc[3]
and desc[3].__class__.__name__ == "PyIID"
):
outVal = f"pythoncom.GetRecordFromGuids(CLSID, MajorVersion, MinorVersion, LCID, {desc[3]!r})"
ret.extend(
(
f"{linePrefix}\tif {names[i + 1]} == {defOutArg}:",
f"{linePrefix}\t\t{names[i + 1]} = {outVal}",
)
)

resclsid = entry.GetResultCLSID()
if resclsid:
resclsid = "'%s'" % resclsid
Expand Down Expand Up @@ -592,7 +608,7 @@ def _ResolveType(typerepr, itypeinfo):
return pythoncom.VT_UNKNOWN, clsid, retdoc

elif typeKind == pythoncom.TKIND_RECORD:
return pythoncom.VT_RECORD, None, None
return pythoncom.VT_RECORD, resultAttr.iid, None
raise NotSupportedException("Can not resolve alias or user-defined type")
return typeSubstMap.get(typerepr, typerepr), None, None

Expand Down
13 changes: 13 additions & 0 deletions com/win32com/test/testPyComTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -657,8 +657,14 @@ def TestGenerated():

# Test plain pythoncom.com_record structs.
progress("Testing baseclass pythoncom.com_record structs.")
# Test pythoncom.com_record as an [out] parameter.
r = o.GetOutStruct()
assert type(r) is pythoncom.com_record
assert r.int_value == 99 and str(r.str_value) == "Luftballons"
# Test pythoncom.com_record as a retval:
r = o.GetStruct()
assert type(r) is pythoncom.com_record
assert r.int_value == 99 and str(r.str_value) == "Hello from C++"
TestStructByref(o, r)
test_rec = Record("TestStruct2", o)
assert type(test_rec) is pythoncom.com_record
Expand Down Expand Up @@ -701,6 +707,13 @@ def TestGenerated():
retrieved_struct = parent_struct.a_struct_field
assert retrieved_struct == member_struct

# Test a pythoncom.com_record subclass as an [out] parameter.
r = o.GetOutStruct()
# After 'TestStruct1' was registered as an instantiable subclass
# of pythoncom.com_record, the return value should have this type.
assert type(r) is TestStruct1
assert r.int_value == 99 and str(r.str_value) == "Luftballons"

# Perform the 'Byref' and 'ArrayOfStruct tests using the registered subclasses.
r = o.GetStruct()
# After 'TestStruct1' was registered as an instantiable subclass
Expand Down
Loading