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
566 changes: 566 additions & 0 deletions comtypes/test/test_compatibility_tlbparser_VT_I1_assignment.py
Comment thread
junkmd marked this conversation as resolved.

Large diffs are not rendered by default.

23 changes: 22 additions & 1 deletion comtypes/test/test_cpp_safearray.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,16 +141,37 @@ def test_ndarray_values_2d(self):
self.assertEqual(method(2, 6), expected)

def test_int8_codegen_1d(self):
# VT_I1 is currently parsed as c_char (see #935), whose pointer slice
# VT_I1 is currently parsed as c_char (see issue #969), whose pointer slice
# returns bytes. Check the real COM/code-generator path and raw bytes;
# signed int8/NumPy dtype assertions await the separate c_char/c_byte fix.
result = self.server.GetInt8Array(1, 6)
self.assertEqual(result, (249, 0, 42, 249, 0, 42))
self.assertNotEqual(result, (-7, 0, 42, -7, 0, 42))

def test_int8_codegen_2d(self):
# As above, 249 is the raw byte for -7, not a signed dtype assertion.
result = self.server.GetInt8Array(2, 6)
self.assertEqual(result, ((249, 42, 0), (0, 249, 42)))
self.assertNotEqual(result, ((-7, 42, 0), (0, -7, 42)))

@unittest.skipIf(IMPORT_NUMPY_FAILED, "Requires NumPy.")
def test_int8_codegen_ndarray_1d_is_byte_string_scalar(self):
# c_char pointer slicing produces bytes, not signed numeric elements.
# This records the current problem; the mapping decision is in #969.
with safearray_as_ndarray:
result = self.server.GetInt8Array(1, 6)
self.assertIsInstance(result, numpy.ndarray)
self.assertEqual(result.shape, ())
self.assertEqual(result.dtype.kind, "S")
self.assertEqual(result.item(), b"\xf9\0*\xf9\0*")
self.assertNotEqual(result.dtype, numpy.dtype("int8"))

@unittest.skipIf(IMPORT_NUMPY_FAILED, "Requires NumPy.")
def test_int8_codegen_ndarray_2d_raises_value_error(self):
# A single byte-string scalar cannot be reshaped to the native 2x3 array.
with safearray_as_ndarray:
with self.assertRaises(ValueError):
self.server.GetInt8Array(2, 6)


if __name__ == "__main__":
Expand Down
2 changes: 2 additions & 0 deletions comtypes/tools/tlbparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ def PTR(typ):

# basic C data types, with size and alignment in bits
char_type = typedesc.FundamentalType("char", 8, 8)
schar_type = typedesc.FundamentalType("signed char", 8, 8)
uchar_type = typedesc.FundamentalType("unsigned char", 8, 8)
wchar_t_type = typedesc.FundamentalType("wchar_t", 16, 16)
short_type = typedesc.FundamentalType("short int", 16, 16)
Expand Down Expand Up @@ -81,6 +82,7 @@ def midlSAFEARRAY(typ):
automation.VT_VARIANT: VARIANT_type, # 12
automation.VT_UNKNOWN: PTR(IUNKNOWN_type), # 13
automation.VT_DECIMAL: DECIMAL_type, # 14
# Signed-byte mapping and compatibility: https://github.com/enthought/comtypes/issues/969
automation.VT_I1: char_type, # 16
automation.VT_UI1: uchar_type, # 17
automation.VT_UI2: ushort_type, # 18
Expand Down
84 changes: 84 additions & 0 deletions source/CppTestSrv/CoByteCompatibilityTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#include <objbase.h>
#include <string.h>
#include "CoByteCompatibilityTest.h"

HRESULT CByteCompatibilityTest::CreateInstance(IUnknown* pUnknownOuter, CUnknown** ppNewComponent)
{
if (pUnknownOuter != NULL)
{
return CLASS_E_NOAGGREGATION ;
}
*ppNewComponent = new CByteCompatibilityTest(pUnknownOuter) ;
return S_OK ;
}

HRESULT __stdcall CByteCompatibilityTest::NondelegatingQueryInterface(const IID& iid, void** ppv)
{
if (iid == IID_IByteCompatibilityTest)
{
return FinishQI(static_cast<IByteCompatibilityTest*>(this), ppv) ;
}
return CUnknown::NondelegatingQueryInterface(iid, ppv) ;
}

HRESULT __stdcall CByteCompatibilityTest::EchoInt8(char value, char* result)
{
if (result == NULL)
{
return E_POINTER ;
}
*result = value ;
return S_OK ;
}

HRESULT __stdcall CByteCompatibilityTest::EchoUint8(byte value, byte* result)
{
if (result == NULL)
{
return E_POINTER ;
}
*result = value ;
return S_OK ;
}

HRESULT __stdcall CByteCompatibilityTest::EchoLpStr(LPSTR value, LPSTR* result)
{
if (result == NULL)
{
return E_POINTER ;
}
*result = NULL ;
if (value == NULL)
{
return E_INVALIDARG ;
}
size_t size = strlen(value) + 1 ;
*result = static_cast<LPSTR>(CoTaskMemAlloc(size)) ;
if (*result == NULL)
{
return E_OUTOFMEMORY ;
}
memcpy(*result, value, size) ;
return S_OK ;
}

HRESULT __stdcall CByteCompatibilityTest::ReadCharPointer(unsigned char* value, byte* result)
{
if (value == NULL || result == NULL)
{
return E_POINTER ;
}
// A raw char* marshals one character, not a NUL-terminated string.
*result = static_cast<byte>(*value) ;
return S_OK ;
}

HRESULT __stdcall CByteCompatibilityTest::GetCharacterBytes(byte value, unsigned char* result)
{
if (result == NULL)
{
return E_POINTER ;
}
*result = value ;
return S_OK ;
}
20 changes: 20 additions & 0 deletions source/CppTestSrv/CoByteCompatibilityTest.h
Comment thread
junkmd marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// A separate COM component for byte and narrow-string compatibility.
#include "CUnknown.h"
#include "Iface.h"

class CByteCompatibilityTest : public CUnknown, public IByteCompatibilityTest
{
public:
static HRESULT CreateInstance(IUnknown* pUnknownOuter, CUnknown** ppNewComponent) ;

private:
DECLARE_IUNKNOWN
virtual HRESULT __stdcall NondelegatingQueryInterface(const IID& iid, void** ppv) ;
virtual HRESULT __stdcall EchoInt8(char value, char* result) ;
virtual HRESULT __stdcall EchoUint8(byte value, byte* result) ;
virtual HRESULT __stdcall EchoLpStr(LPSTR value, LPSTR* result) ;
virtual HRESULT __stdcall ReadCharPointer(unsigned char* value, byte* result) ;
virtual HRESULT __stdcall GetCharacterBytes(byte value, unsigned char* result) ;

CByteCompatibilityTest(IUnknown* pUnknownOuter) : CUnknown(pUnknownOuter) {} ;
} ;
6 changes: 5 additions & 1 deletion source/CppTestSrv/MAKEFILE
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ guids.obj : guids.c
# Component/server source files
#

server.obj : server.cpp cunknown.h cfactory.h iface.h CoNumericSafearrayTest.h CoVariantErrorTest.h
server.obj : server.cpp cunknown.h cfactory.h iface.h CoNumericSafearrayTest.h CoByteCompatibilityTest.h CoVariantErrorTest.h
cl $(CPP_FLAGS) server.cpp

CoComtypesDispRecordParamTest.obj : CoComtypesDispRecordParamTest.cpp \
Expand All @@ -56,6 +56,9 @@ CoNumericSafearrayTest.obj : CoNumericSafearrayTest.cpp \
CoNumericSafearrayTest.h iface.h CUnknown.h
cl $(CPP_FLAGS) CoNumericSafearrayTest.cpp

CoByteCompatibilityTest.obj : CoByteCompatibilityTest.cpp \
CoByteCompatibilityTest.h iface.h CUnknown.h
cl $(CPP_FLAGS) CoByteCompatibilityTest.cpp
CoStringSafearrayInsideVariantTest.obj : CoStringSafearrayInsideVariantTest.cpp \
CoStringSafearrayInsideVariantTest.h iface.h registry.h CUnknown.h
cl $(CPP_FLAGS) CoStringSafearrayInsideVariantTest.cpp
Expand Down Expand Up @@ -94,6 +97,7 @@ SERVER_OBJS = Server.obj \
CoComtypesDispRecordParamTest.obj \
CoComtypesDispSafearrayParamTest.obj \
CoNumericSafearrayTest.obj \
CoByteCompatibilityTest.obj \
CoStringSafearrayInsideVariantTest.obj \
CoVariantErrorTest.obj \
Registry.obj \
Expand Down
7 changes: 7 additions & 0 deletions source/CppTestSrv/SERVER.CPP
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "CoComtypesDispRecordParamTest.h"
#include "CoComtypesDispSafearrayParamTest.h"
#include "CoNumericSafearrayTest.h"
#include "CoByteCompatibilityTest.h"
#include "CoStringSafearrayInsideVariantTest.h"
#include "CoVariantErrorTest.h"

Expand Down Expand Up @@ -57,6 +58,12 @@ CFactoryData g_FactoryDataArray[] =
L"Comtypes.NumericSafearrayTest",
&LIBID_ComtypesCppTestSrvLib,
NULL, 0},
{&CLSID_CoByteCompatibilityTest, CByteCompatibilityTest::CreateInstance,
L"Comtypes component for byte and narrow-string compatibility tests",
L"Comtypes.ByteCompatibilityTest.1",
L"Comtypes.ByteCompatibilityTest",
&LIBID_ComtypesCppTestSrvLib,
NULL, 0},
{&CLSID_CoStringSafearrayInsideVariantTest, CStringSafearrayInsideVariantTest::CreateInstance,
L"String SAFEARRAY inside VARIANT Tester",
L"Comtypes.CoStringSafearrayInsideVariantTest.1",
Expand Down
25 changes: 25 additions & 0 deletions source/CppTestSrv/SERVER.IDL
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,22 @@ interface INumericSafearrayTest : IUnknown
HRESULT GetFloat64Array([in] short dimensions, [in] long count, [out, retval] SAFEARRAY(double)* result);
} ;

// A separate interface for scalar input/output and string compatibility.
[
object,
uuid(047E34C1-33A8-4DAA-A1E5-B941756A8319),
oleautomation
]
interface IByteCompatibilityTest : IUnknown
{
HRESULT EchoInt8([in] small value, [out, retval] small* result);
HRESULT EchoUint8([in] byte value, [out, retval] byte* result);
HRESULT EchoLpStr([in] LPSTR value, [out, retval] LPSTR* result);
HRESULT ReadCharPointer([in] char* value, [out, retval] byte* result);
// Return one character through a plain char pointer.
HRESULT GetCharacterBytes([in] byte value, [out, retval] char* result);
} ;

// Interface IDispSafearrayParamTest
[
uuid(4097A6D0-A111-40E2-BD0B-177B775A9496)
Expand Down Expand Up @@ -165,6 +181,15 @@ library ComtypesCppTestSrvLib
[default] interface INumericSafearrayTest ;
} ;

[
uuid(E07D71E8-C8A5-4B76-9A88-688DB10CF712),
helpstring("Comtypes component for byte and narrow-string compatibility tests.")
]
coclass CoByteCompatibilityTest
{
[default] interface IByteCompatibilityTest ;
} ;

// Interface IStringSafearrayInsideVariantTest
[
odl,
Expand Down
Loading