summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Robinson <arobins@microsoft.com>2018-09-10 17:24:49 -0700
committerGitHub <noreply@github.com>2018-09-10 17:24:49 -0700
commitfc3378095f04946815e627a5ab70b528a898abe6 (patch)
tree44a1e2cd85c2a5c369bf6f754a0379a0751ccb66
parentefd7220234aacef4af25a747797984d43ba5b961 (diff)
downloadcoreclr-fc3378095f04946815e627a5ab70b528a898abe6.tar.gz
coreclr-fc3378095f04946815e627a5ab70b528a898abe6.tar.bz2
coreclr-fc3378095f04946815e627a5ab70b528a898abe6.zip
Basic implementation for testing of COM activation of a .NET class (#19760)
* Rough outline of managed implementation for COM activation in SPCL * Add property for finding interop common Add property to exclude default assertion file Display exe ExeLaunchProgram class is going to launch * Add a native client for the NETServer Consume the ExeLauncherProgram.cs file as a wrapper for the native test * Update COM Server contracts to use 'int' instead of 'long' * Complete symmetric testing coverage for .NET server and native client. * Block EXE launch from running on non-Windows machines * Disable COM testing in helix since it has issues on Windows Nano and there is no way to determine that is the platform. * Update tests based on CLSID mapping manifest approach.
-rw-r--r--build-test.cmd6
-rw-r--r--src/System.Private.CoreLib/System.Private.CoreLib.csproj1
-rw-r--r--src/System.Private.CoreLib/src/System/Runtime/InteropServices/ComActivator.cs261
-rw-r--r--src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs7
-rw-r--r--src/coreclr/hosts/CMakeLists.txt1
-rw-r--r--src/coreclr/hosts/coreshim/CMakeLists.txt25
-rw-r--r--src/coreclr/hosts/coreshim/ComActivation.cpp91
-rw-r--r--src/coreclr/hosts/coreshim/CoreShim.cpp293
-rw-r--r--src/coreclr/hosts/coreshim/CoreShim.h179
-rw-r--r--src/coreclr/hosts/coreshim/Exports.def3
-rw-r--r--tests/issues.targets14
-rw-r--r--tests/src/CLRTest.Execute.Batch.targets6
-rw-r--r--tests/src/Interop/CMakeLists.txt1
-rw-r--r--tests/src/Interop/COM/Activator/Activator.csproj29
-rw-r--r--tests/src/Interop/COM/Activator/Program.cs67
-rw-r--r--tests/src/Interop/COM/NETServer/ArrayTesting.cs241
-rw-r--r--tests/src/Interop/COM/NETServer/ErrorMarshalTesting.cs28
-rw-r--r--tests/src/Interop/COM/NETServer/NETServer.csproj16
-rw-r--r--tests/src/Interop/COM/NETServer/NumericTesting.cs193
-rw-r--r--tests/src/Interop/COM/NETServer/StringTesting.cs191
-rw-r--r--tests/src/Interop/COM/NativeClients/Primitives.csproj17
-rw-r--r--tests/src/Interop/COM/NativeClients/Primitives/App.manifest17
-rw-r--r--tests/src/Interop/COM/NativeClients/Primitives/ArrayTests.cpp318
-rw-r--r--tests/src/Interop/COM/NativeClients/Primitives/CMakeLists.txt23
-rw-r--r--tests/src/Interop/COM/NativeClients/Primitives/Client.cpp45
-rw-r--r--tests/src/Interop/COM/NativeClients/Primitives/ClientTests.h70
-rw-r--r--tests/src/Interop/COM/NativeClients/Primitives/CoreShim.X.manifest28
-rw-r--r--tests/src/Interop/COM/NativeClients/Primitives/ErrorTests.cpp68
-rw-r--r--tests/src/Interop/COM/NativeClients/Primitives/NumericTests.cpp227
-rw-r--r--tests/src/Interop/COM/NativeClients/Primitives/StringTests.cpp422
-rw-r--r--tests/src/Interop/COM/NativeServer/ArrayTesting.h64
-rw-r--r--tests/src/Interop/COM/NativeServer/ErrorMarshalTesting.h7
-rw-r--r--tests/src/Interop/COM/NativeServer/NumericTesting.h36
-rw-r--r--tests/src/Interop/COM/NativeServer/Servers.h24
-rw-r--r--tests/src/Interop/COM/ServerContracts/Primitives.cs38
-rw-r--r--tests/src/Interop/COM/ServerContracts/Server.Contracts.tlh204
-rw-r--r--tests/src/Interop/COM/ServerContracts/Server.Contracts.tli72
-rw-r--r--tests/src/Interop/Interop.settings.targets3
-rw-r--r--tests/src/Interop/common/ExeLauncherProgram.cs69
-rw-r--r--tests/src/Interop/common/xplatform.h23
40 files changed, 3196 insertions, 232 deletions
diff --git a/build-test.cmd b/build-test.cmd
index 361a3f8c31..c0f45b10cc 100644
--- a/build-test.cmd
+++ b/build-test.cmd
@@ -324,7 +324,8 @@ for /l %%G in (1, 1, %__BuildLoopCount%) do (
set __MsbuildErr=/flp2:ErrorsOnly;LogFile="%__BuildErr%";Append=!__AppendToLog!
set TestBuildSlice=%%G
- call %__DotnetHost% msbuild %__ProjectDir%\tests\build.proj !__MsbuildLog! !__MsbuildWrn! !__MsbuildErr! %__msbuildArgs% %__BuildAgainstPackagesMsbuildArg% !__PriorityMsbuildArg! %__UnprocessedBuildArgs%
+ echo Running: msbuild %__ProjectDir%\tests\build.proj !__MsbuildLog! !__MsbuildWrn! !__MsbuildErr! %__msbuildArgs% %__BuildAgainstPackagesMsbuildArg% !__PriorityMsbuildArg! %__UnprocessedBuildArgs%
+ call msbuild %__ProjectDir%\tests\build.proj !__MsbuildLog! !__MsbuildWrn! !__MsbuildErr! %__msbuildArgs% %__BuildAgainstPackagesMsbuildArg% !__PriorityMsbuildArg! %__UnprocessedBuildArgs%
if errorlevel 1 (
echo %__MsgPrefix%Error: build failed. Refer to the build log files for details:
@@ -342,7 +343,8 @@ for /l %%G in (1, 1, %__BuildLoopCount%) do (
REM Check that we've built about as many tests as we expect. This is primarily intended to prevent accidental changes that cause us to build
REM drastically fewer Pri-1 tests than expected.
echo %__MsgPrefix%Check the managed tests build
-call %__DotnetHost% msbuild %__ProjectDir%\tests\runtest.proj /t:CheckTestBuild /p:CLRTestPriorityToBuild=%__Priority% %__msbuildArgs% %__unprocessedBuildArgs%
+echo Running: msbuild %__ProjectDir%\tests\runtest.proj /t:CheckTestBuild /p:CLRTestPriorityToBuild=%__Priority% %__msbuildArgs% %__unprocessedBuildArgs%
+call msbuild %__ProjectDir%\tests\runtest.proj /t:CheckTestBuild /p:CLRTestPriorityToBuild=%__Priority% %__msbuildArgs% %__unprocessedBuildArgs%
if errorlevel 1 (
echo %__MsgPrefix%Error: build failed.
exit /b 1
diff --git a/src/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/System.Private.CoreLib/System.Private.CoreLib.csproj
index 30b5b2bead..74f04d80d5 100644
--- a/src/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -158,6 +158,7 @@
<Compile Condition="'$(FeatureCominterop)' != 'true'" Include="$(BclSourcesRoot)\System\Runtime\InteropServices\NonPortable.cs" />
<Compile Condition="'$(FeatureCominterop)' == 'true'" Include="$(BclSourcesRoot)\System\Runtime\InteropServices\DispatchWrapper.cs" />
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\ICustomFactory.cs" />
+ <Compile Condition="'$(FeatureCominteropUnmanagedActivation)' == 'true'" Include="$(BclSourcesRoot)\System\Runtime\InteropServices\ComActivator.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\Expando\IExpando.cs" />
diff --git a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/ComActivator.cs b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/ComActivator.cs
new file mode 100644
index 0000000000..785e9ace62
--- /dev/null
+++ b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/ComActivator.cs
@@ -0,0 +1,261 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Reflection;
+
+namespace System.Runtime.InteropServices
+{
+ [ComImport]
+ [ComVisible(false)]
+ [Guid("00000001-0000-0000-C000-000000000046")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IClassFactory
+ {
+ void CreateInstance(
+ [MarshalAs(UnmanagedType.Interface)] object pUnkOuter,
+ ref Guid riid,
+ [MarshalAs(UnmanagedType.Interface)] out object ppvObject);
+
+ void LockServer([MarshalAs(UnmanagedType.Bool)] bool fLock);
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct LICINFO
+ {
+ public int cbLicInfo;
+
+ [MarshalAs(UnmanagedType.Bool)]
+ public bool fRuntimeKeyAvail;
+
+ [MarshalAs(UnmanagedType.Bool)]
+ public bool fLicVerified;
+ }
+
+ [ComImport]
+ [ComVisible(false)]
+ [Guid("B196B28F-BAB4-101A-B69C-00AA00341D07")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ internal interface IClassFactory2 : IClassFactory
+ {
+ new void CreateInstance(
+ [MarshalAs(UnmanagedType.Interface)] object pUnkOuter,
+ ref Guid riid,
+ [MarshalAs(UnmanagedType.Interface)] out object ppvObject);
+
+ new void LockServer([MarshalAs(UnmanagedType.Bool)] bool fLock);
+
+ void GetLicInfo(ref LICINFO pLicInfo);
+
+ void RequestLicKey(
+ int dwReserved,
+ [MarshalAs(UnmanagedType.BStr)] out string pBstrKey);
+
+ void CreateInstanceLic(
+ [MarshalAs(UnmanagedType.Interface)] object pUnkOuter,
+ [MarshalAs(UnmanagedType.Interface)] object pUnkReserved,
+ ref Guid riid,
+ [MarshalAs(UnmanagedType.BStr)] string bstrKey,
+ [MarshalAs(UnmanagedType.Interface)] out object ppvObject);
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct ComActivationContext
+ {
+ public Guid ClassId;
+ public Guid InterfaceId;
+ public string AssemblyName;
+ public string TypeName;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct ComActivationContextInternal
+ {
+ public Guid ClassId;
+ public Guid InterfaceId;
+ public IntPtr AssemblyNameBuffer;
+ public IntPtr TypeNameBuffer;
+ public IntPtr ClassFactoryDest;
+ }
+
+ public static class ComActivator
+ {
+ /// <summary>
+ /// Entry point for unmanaged COM activation API from managed code
+ /// </summary>
+ /// <param name="cxt">Reference to a <see cref="ComActivationContext"/> instance</param>
+ public static object GetClassFactoryForType(ComActivationContext cxt)
+ {
+ if (cxt.InterfaceId != typeof(IClassFactory).GUID
+ && cxt.InterfaceId != typeof(IClassFactory2).GUID)
+ {
+ throw new NotSupportedException();
+ }
+
+ Type classType = FindClassType(cxt.ClassId, cxt.AssemblyName, cxt.TypeName);
+ return new BasicClassFactory(cxt.ClassId, classType);
+ }
+
+ /// <summary>
+ /// Internal entry point for unmanaged COM activation API from native code
+ /// </summary>
+ /// <param name="cxtInt">Reference to a <see cref="ComActivationContextInternal"/> instance</param>
+ public static int GetClassFactoryForTypeInternal(ref ComActivationContextInternal cxtInt)
+ {
+ if (IsLoggingEnabled())
+ {
+ Log(
+$@"{nameof(GetClassFactoryForTypeInternal)} arguments:
+ {cxtInt.ClassId}
+ {cxtInt.InterfaceId}
+ 0x{cxtInt.AssemblyNameBuffer.ToInt64():x}
+ 0x{cxtInt.TypeNameBuffer.ToInt64():x}
+ 0x{cxtInt.ClassFactoryDest.ToInt64():x}");
+ }
+
+ try
+ {
+ var cxt = new ComActivationContext()
+ {
+ ClassId = cxtInt.ClassId,
+ InterfaceId = cxtInt.InterfaceId,
+ AssemblyName = Marshal.PtrToStringUTF8(cxtInt.AssemblyNameBuffer),
+ TypeName = Marshal.PtrToStringUTF8(cxtInt.TypeNameBuffer)
+ };
+
+ object cf = GetClassFactoryForType(cxt);
+ IntPtr nativeIUnknown = Marshal.GetIUnknownForObject(cf);
+ Marshal.WriteIntPtr(cxtInt.ClassFactoryDest, nativeIUnknown);
+ }
+ catch (Exception e)
+ {
+ return e.HResult;
+ }
+
+ return 0;
+ }
+
+ private static bool IsLoggingEnabled()
+ {
+#if COM_ACTIVATOR_DEBUG
+ return true;
+#else
+ return false;
+#endif
+ }
+
+ private static void Log(string fmt, params object[] args)
+ {
+ // [TODO] Use FrameworkEventSource in release builds
+
+ Debug.WriteLine(fmt, args);
+ }
+
+ private static Type FindClassType(Guid clsid, string assemblyName, string typeName)
+ {
+ try
+ {
+ Assembly assem = Assembly.LoadFrom(assemblyName);
+ Type t = assem.GetType(typeName);
+ if (t != null)
+ {
+ return t;
+ }
+ }
+ catch (Exception e)
+ {
+ if (IsLoggingEnabled())
+ {
+ Log($"COM Activation of {clsid} failed. {e}");
+ }
+ }
+
+ const int CLASS_E_CLASSNOTAVAILABLE = unchecked((int)0x80040111);
+ throw new COMException(string.Empty, CLASS_E_CLASSNOTAVAILABLE);
+ }
+
+ [ComVisible(true)]
+ internal class BasicClassFactory : IClassFactory2
+ {
+ private readonly Guid classId;
+ private readonly Type classType;
+
+ public BasicClassFactory(Guid clsid, Type classType)
+ {
+ this.classId = clsid;
+ this.classType = classType;
+ }
+
+ public void CreateInstance(
+ [MarshalAs(UnmanagedType.Interface)] object pUnkOuter,
+ ref Guid riid,
+ [MarshalAs(UnmanagedType.Interface)] out object ppvObject)
+ {
+ if (riid != Marshal.IID_IUnknown)
+ {
+ bool found = false;
+
+ // Verify the class implements the desired interface
+ foreach (Type i in this.classType.GetInterfaces())
+ {
+ if (i.GUID == riid)
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ // E_NOINTERFACE
+ throw new InvalidCastException();
+ }
+ }
+
+ ppvObject = Activator.CreateInstance(this.classType);
+ if (pUnkOuter != null)
+ {
+ try
+ {
+ IntPtr outerPtr = Marshal.GetIUnknownForObject(pUnkOuter);
+ IntPtr innerPtr = Marshal.CreateAggregatedObject(outerPtr, ppvObject);
+ ppvObject = Marshal.GetObjectForIUnknown(innerPtr);
+ }
+ finally
+ {
+ // Decrement the above 'Marshal.GetIUnknownForObject()'
+ Marshal.ReleaseComObject(pUnkOuter);
+ }
+ }
+ }
+
+ public void LockServer([MarshalAs(UnmanagedType.Bool)] bool fLock)
+ {
+ // nop
+ }
+
+ public void GetLicInfo(ref LICINFO pLicInfo)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void RequestLicKey(int dwReserved, [MarshalAs(UnmanagedType.BStr)] out string pBstrKey)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void CreateInstanceLic(
+ [MarshalAs(UnmanagedType.Interface)] object pUnkOuter,
+ [MarshalAs(UnmanagedType.Interface)] object pUnkReserved,
+ ref Guid riid,
+ [MarshalAs(UnmanagedType.BStr)] string bstrKey,
+ [MarshalAs(UnmanagedType.Interface)] out object ppvObject)
+ {
+ throw new NotImplementedException();
+ }
+ }
+ }
+}
diff --git a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs
index e214f1e731..c4c65da540 100644
--- a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs
+++ b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs
@@ -28,14 +28,15 @@ namespace System.Runtime.InteropServices
/// </summary>
public static partial class Marshal
{
+#if FEATURE_COMINTEROP
+ internal static Guid IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046");
+#endif //FEATURE_COMINTEROP
+
private const int LMEM_FIXED = 0;
private const int LMEM_MOVEABLE = 2;
#if !FEATURE_PAL
private const long HiWordMask = unchecked((long)0xffffffffffff0000L);
#endif //!FEATURE_PAL
-#if FEATURE_COMINTEROP
- private static Guid IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046");
-#endif //FEATURE_COMINTEROP
// Win32 has the concept of Atoms, where a pointer can either be a pointer
// or an int. If it's less than 64K, this is guaranteed to NOT be a
diff --git a/src/coreclr/hosts/CMakeLists.txt b/src/coreclr/hosts/CMakeLists.txt
index bb425b908a..c27ba16c56 100644
--- a/src/coreclr/hosts/CMakeLists.txt
+++ b/src/coreclr/hosts/CMakeLists.txt
@@ -3,6 +3,7 @@ include_directories(inc)
if(WIN32)
add_subdirectory(corerun)
add_subdirectory(coreconsole)
+ add_subdirectory(coreshim)
else(WIN32)
add_subdirectory(unixcoreruncommon)
add_subdirectory(unixcorerun)
diff --git a/src/coreclr/hosts/coreshim/CMakeLists.txt b/src/coreclr/hosts/coreshim/CMakeLists.txt
new file mode 100644
index 0000000000..828b91ce5b
--- /dev/null
+++ b/src/coreclr/hosts/coreshim/CMakeLists.txt
@@ -0,0 +1,25 @@
+project (CoreShim)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CoreShim_SOURCES
+ CoreShim.cpp
+ ComActivation.cpp
+ Exports.def)
+
+add_library_clr(CoreShim
+ SHARED
+ ${CoreShim_SOURCES}
+)
+
+target_link_libraries(CoreShim
+ utilcodestaticnohost
+ advapi32.lib
+ oleaut32.lib
+ uuid.lib
+ user32.lib
+ ${STATIC_MT_CRT_LIB}
+ ${STATIC_MT_VCRT_LIB}
+)
+
+install_clr(CoreShim) \ No newline at end of file
diff --git a/src/coreclr/hosts/coreshim/ComActivation.cpp b/src/coreclr/hosts/coreshim/ComActivation.cpp
new file mode 100644
index 0000000000..5df1d000c1
--- /dev/null
+++ b/src/coreclr/hosts/coreshim/ComActivation.cpp
@@ -0,0 +1,91 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "CoreShim.h"
+
+#include <vector>
+
+namespace
+{
+ HRESULT InitializeCoreClr(_In_ coreclr* inst)
+ {
+ assert(inst != nullptr);
+
+ HRESULT hr;
+
+ std::string tpaList;
+ RETURN_IF_FAILED(coreclr::CreateTpaList(tpaList));
+
+ const char *keys[] =
+ {
+ "APP_PATHS",
+ "TRUSTED_PLATFORM_ASSEMBLIES",
+ };
+
+ // [TODO] Support UNICODE app path
+ char wd[MAX_PATH];
+ (void)::GetCurrentDirectoryA(ARRAYSIZE(wd), wd);
+
+ const char *values[] =
+ {
+ wd,
+ tpaList.c_str(),
+ };
+
+ static_assert(ARRAYSIZE(keys) == ARRAYSIZE(values), "key/values pairs should match in length");
+
+ return inst->Initialize(ARRAYSIZE(keys), keys, values, "COMAct");
+ }
+}
+
+STDAPI DllGetClassObject(
+ _In_ REFCLSID rclsid,
+ _In_ REFIID riid,
+ _Outptr_ LPVOID FAR* ppv)
+{
+ HRESULT hr;
+
+ coreclr *inst;
+ RETURN_IF_FAILED(coreclr::GetCoreClrInstance(&inst));
+
+ if (hr == S_OK)
+ RETURN_IF_FAILED(InitializeCoreClr(inst));
+
+ using GetClassFactoryForTypeInternal_ptr = HRESULT(*)(void *);
+ GetClassFactoryForTypeInternal_ptr GetClassFactoryForTypeInternal;
+ RETURN_IF_FAILED(inst->CreateDelegate(
+ "System.Private.CoreLib",
+ "System.Runtime.InteropServices.ComActivator",
+ "GetClassFactoryForTypeInternal", (void**)&GetClassFactoryForTypeInternal));
+
+ // Get assembly and type for activation
+ std::string assemblyName;
+ RETURN_IF_FAILED(Utility::TryGetEnvVar(COMACT_ASSEMBLYNAME_ENVVAR, assemblyName));
+
+ std::string typeName;
+ RETURN_IF_FAILED(Utility::TryGetEnvVar(COMACT_TYPENAME_ENVVAR, typeName));
+
+ IUnknown *ccw = nullptr;
+
+ struct ComActivationContext
+ {
+ GUID ClassId;
+ GUID InterfaceId;
+ const void *AssemblyName;
+ const void *TypeName;
+ void **ClassFactoryDest;
+ } comCxt{ rclsid, riid, assemblyName.data(), typeName.data(), (void**)&ccw };
+
+ RETURN_IF_FAILED(GetClassFactoryForTypeInternal(&comCxt));
+ assert(ccw != nullptr);
+
+ hr = ccw->QueryInterface(riid, ppv);
+ ccw->Release();
+ return hr;
+}
+
+STDAPI DllCanUnloadNow(void)
+{
+ return S_FALSE;
+}
diff --git a/src/coreclr/hosts/coreshim/CoreShim.cpp b/src/coreclr/hosts/coreshim/CoreShim.cpp
new file mode 100644
index 0000000000..497c10e5d2
--- /dev/null
+++ b/src/coreclr/hosts/coreshim/CoreShim.cpp
@@ -0,0 +1,293 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "CoreShim.h"
+
+#include <set>
+#include <sstream>
+#include <vector>
+#include <mutex>
+
+namespace
+{
+ struct PathBuffer
+ {
+ PathBuffer()
+ : DefBuffer{}
+ , Buf{ DefBuffer }
+ , Len{ ARRAYSIZE(DefBuffer) }
+ { }
+
+ void SetLength(_In_ DWORD len)
+ {
+ if (len > Len)
+ {
+ Buf = BigBuffer.data();
+ Len = static_cast<DWORD>(BigBuffer.size());
+ }
+ }
+
+ void ExpandBuffer(_In_ DWORD factor = 2)
+ {
+ SetLength(Len * factor);
+ }
+
+ operator DWORD()
+ {
+ return Len;
+ }
+
+ operator WCHAR *()
+ {
+ return Buf;
+ }
+
+ WCHAR DefBuffer[MAX_PATH];
+ std::vector<WCHAR> BigBuffer;
+
+ WCHAR *Buf;
+ DWORD Len;
+ };
+
+ std::string GetExePath()
+ {
+ PathBuffer buffer;
+ DWORD len = ::GetModuleFileNameW(nullptr, buffer, buffer);
+ while (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+ {
+ buffer.ExpandBuffer();
+ len = ::GetModuleFileNameW(nullptr, buffer, buffer);
+ }
+
+ return std::string{ buffer.Buf, buffer.Buf + len };
+ }
+
+ std::wstring GetEnvVar(_In_z_ const WCHAR *env)
+ {
+ DWORD len = ::GetEnvironmentVariableW(env, nullptr, 0);
+ if (len == 0)
+ throw __HRESULT_FROM_WIN32(ERROR_ENVVAR_NOT_FOUND);
+
+ PathBuffer buffer;
+ buffer.SetLength(len);
+ (void)::GetEnvironmentVariableW(env, buffer, buffer);
+
+ return static_cast<WCHAR *>(buffer.Buf);
+ }
+
+ coreclr *s_CoreClrInstance;
+}
+
+namespace Utility
+{
+ HRESULT TryGetEnvVar(_In_z_ const WCHAR *env, _Inout_ std::string &envVar)
+ {
+ try
+ {
+ std::wstring envVarLocal = GetEnvVar(env);
+ envVar = { std::begin(envVarLocal), std::end(envVarLocal) };
+ }
+ catch (HRESULT hr)
+ {
+ return hr;
+ }
+
+ return S_OK;
+ }
+}
+
+HRESULT coreclr::GetCoreClrInstance(_Outptr_ coreclr **instance, _In_opt_z_ const WCHAR *path)
+{
+ if (s_CoreClrInstance != nullptr)
+ {
+ *instance = s_CoreClrInstance;
+ return S_FALSE;
+ }
+
+ try
+ {
+ std::wstring pathLocal;
+ if (path == nullptr)
+ {
+ pathLocal = GetEnvVar(W("CORE_ROOT"));
+ }
+ else
+ {
+ pathLocal = { path };
+ }
+
+ pathLocal.append(W("\\coreclr.dll"));
+
+ AutoModule hmod = ::LoadLibraryExW(pathLocal.c_str() , nullptr, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
+ if (hmod == nullptr)
+ return HRESULT_FROM_WIN32(::GetLastError());
+
+ s_CoreClrInstance = new coreclr{ std::move(hmod) };
+ }
+ catch (HRESULT hr)
+ {
+ return hr;
+ }
+ catch (const std::bad_alloc&)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ *instance = s_CoreClrInstance;
+ return S_OK;
+}
+
+HRESULT coreclr::CreateTpaList(_Inout_ std::string &tpaList, _In_opt_z_ const WCHAR *dir)
+{
+ assert(tpaList.empty());
+
+ // Represents priority order
+ static const WCHAR * const tpaExtensions[] =
+ {
+ W(".ni.dll"),
+ W(".dll"),
+ W(".ni.exe"),
+ W(".exe"),
+ };
+
+ try
+ {
+ std::wstring w_dirLocal;
+ if (dir == nullptr)
+ {
+ w_dirLocal = GetEnvVar(W("CORE_ROOT"));
+ }
+ else
+ {
+ w_dirLocal = { dir };
+ }
+
+ std::string dirLocal{ std::begin(w_dirLocal), std::end(w_dirLocal) };
+ w_dirLocal.append(W("\\*"));
+
+ std::set<std::wstring> addedAssemblies;
+ std::stringstream tpaStream;
+
+ // Walk the directory for each extension separately so assembly types
+ // are discovered in priority order - see above.
+ for (int extIndex = 0; extIndex < ARRAYSIZE(tpaExtensions); extIndex++)
+ {
+ const WCHAR* ext = tpaExtensions[extIndex];
+ size_t extLength = ::wcslen(ext);
+
+ WIN32_FIND_DATAW ffd;
+ AutoFindFile sh = ::FindFirstFileW(w_dirLocal.c_str(), &ffd);
+ if (sh == nullptr)
+ break;
+
+ // For all entries in the directory
+ do
+ {
+ // Only examine non-directory entries
+ if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ std::wstring filename{ ffd.cFileName };
+
+ // Check if the extension matches
+ int extPos = static_cast<int>(filename.length() - extLength);
+ if ((extPos <= 0) || (filename.compare(extPos, extLength, ext) != 0))
+ {
+ continue;
+ }
+
+ std::wstring filenameWithoutExt{ filename.substr(0, extPos) };
+
+ // Only one type of a particular assembly instance should be inserted
+ // See extension list above.
+ if (addedAssemblies.find(filenameWithoutExt) == std::end(addedAssemblies))
+ {
+ addedAssemblies.insert(std::move(filenameWithoutExt));
+
+ // [TODO] Properly convert to UTF-8
+ std::string filename_utf8{ std::begin(filename), std::end(filename) };
+ tpaStream << dirLocal << "\\" << filename_utf8 << ";";
+ }
+ }
+ } while (::FindNextFileW(sh, &ffd) != FALSE);
+ }
+
+ tpaList = tpaStream.str();
+ }
+ catch (HRESULT hr)
+ {
+ return hr;
+ }
+ catch (const std::bad_alloc&)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ return S_OK;
+}
+
+coreclr::coreclr(_Inout_ AutoModule hmod)
+ : _hmod{ std::move(hmod) }
+ , _clrInst{ nullptr }
+ , _appDomainId{ std::numeric_limits<uint32_t>::max() }
+{
+ _initialize = (decltype(_initialize))::GetProcAddress(_hmod, "coreclr_initialize");
+ assert(_initialize != nullptr);
+
+ _create_delegate = (decltype(_create_delegate))::GetProcAddress(_hmod, "coreclr_create_delegate");
+ assert(_create_delegate != nullptr);
+
+ _shutdown = (decltype(_shutdown))::GetProcAddress(_hmod, "coreclr_shutdown");
+ assert(_shutdown != nullptr);
+}
+
+coreclr::~coreclr()
+{
+ if (_clrInst != nullptr)
+ {
+ HRESULT hr = _shutdown(_clrInst, _appDomainId);
+ assert(SUCCEEDED(hr));
+ (void)hr;
+ }
+}
+
+HRESULT coreclr::Initialize(
+ _In_ int propertyCount,
+ _In_reads_(propertCount) const char **keys,
+ _In_reads_(propertCount) const char **values,
+ _In_opt_z_ const char *appDomainName)
+{
+ if (_clrInst != nullptr)
+ return __HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
+
+ if (appDomainName == nullptr)
+ appDomainName = "CoreShim";
+
+ HRESULT hr;
+ try
+ {
+ const std::string exePath = GetExePath();
+ RETURN_IF_FAILED(_initialize(exePath.c_str(), appDomainName, propertyCount, keys, values, &_clrInst, &_appDomainId));
+ }
+ catch (const std::bad_alloc&)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ return S_OK;
+}
+
+HRESULT coreclr::CreateDelegate(
+ _In_z_ const char *assembly,
+ _In_z_ const char *type,
+ _In_z_ const char *method,
+ _Out_ void **del)
+{
+ if (_clrInst == nullptr)
+ return E_NOT_VALID_STATE;
+
+ HRESULT hr;
+ RETURN_IF_FAILED(_create_delegate(_clrInst, _appDomainId, assembly, type, method, del));
+
+ return S_OK;
+}
diff --git a/src/coreclr/hosts/coreshim/CoreShim.h b/src/coreclr/hosts/coreshim/CoreShim.h
new file mode 100644
index 0000000000..dd5e9d1297
--- /dev/null
+++ b/src/coreclr/hosts/coreshim/CoreShim.h
@@ -0,0 +1,179 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef _CORESHIM_H_
+#define _CORESHIM_H_
+
+// Platform
+#define NOMINMAX
+#include <Windows.h>
+#include <combaseapi.h>
+
+// Standard library
+#include <utility>
+#include <string>
+#include <cstdint>
+#include <cassert>
+
+// CoreCLR
+#include <palclr.h>
+#include <coreclrhost.h>
+
+#define WCHAR wchar_t
+
+#define RETURN_IF_FAILED(exp) { hr = (exp); if (FAILED(hr)) { assert(false && #exp); return hr; } }
+
+template
+<
+ typename T,
+ T DEFAULT,
+ void(*RELEASE)(T)
+>
+struct AutoClass
+{
+ T c;
+
+ AutoClass() : c{ DEFAULT }
+ { }
+
+ AutoClass(_Inout_ T t) : c{ t }
+ { }
+
+ AutoClass(_In_ const AutoClass&) = delete;
+ AutoClass& operator=(_In_ const AutoClass&) = delete;
+
+ AutoClass(_Inout_ AutoClass &&other)
+ : c{ other.Detach() }
+ { }
+
+ AutoClass& operator=(_Inout_ AutoClass &&other)
+ {
+ Attach(other.Detach());
+ }
+
+ ~AutoClass()
+ {
+ Attach(DEFAULT);
+ }
+
+ operator T()
+ {
+ return c;
+ }
+
+ T* operator &()
+ {
+ return &c;
+ }
+
+ void Attach(_In_opt_ T cm)
+ {
+ RELEASE(c);
+ c = cm;
+ }
+
+ T Detach()
+ {
+ T tmp = c;
+ c = DEFAULT;
+ return tmp;
+ }
+};
+
+inline void ReleaseHandle(_In_ HANDLE h)
+{
+ if (h != nullptr && h != INVALID_HANDLE_VALUE)
+ ::CloseHandle(h);
+}
+
+using AutoHandle = AutoClass<HANDLE, nullptr, &ReleaseHandle>;
+
+inline void ReleaseFindFile(_In_ HANDLE h)
+{
+ if (h != nullptr)
+ ::FindClose(h);
+}
+
+using AutoFindFile = AutoClass<HANDLE, nullptr, &ReleaseFindFile>;
+
+inline void ReleaseModule(_In_ HMODULE m)
+{
+ if (m != nullptr)
+ ::FreeLibrary(m);
+}
+
+using AutoModule = AutoClass<HMODULE, nullptr, &ReleaseModule>;
+
+namespace Utility
+{
+ /// <summary>
+ /// Get the supplied environment variable.
+ /// </summary>
+ HRESULT TryGetEnvVar(_In_z_ const WCHAR *env, _Inout_ std::string &envVar);
+}
+
+// CoreShim environment variables used to indicate what assembly/type tuple
+// to load during COM activation.
+#define COMACT_ASSEMBLYNAME_ENVVAR W("CORESHIM_COMACT_ASSEMBLYNAME")
+#define COMACT_TYPENAME_ENVVAR W("CORESHIM_COMACT_TYPENAME")
+
+// CoreCLR class to handle lifetime and provide a simpler API surface
+class coreclr
+{
+public: // static
+ /// <summary>
+ /// Get a CoreCLR instance
+ /// </summary>
+ /// <returns>S_OK if newly created and needs initialization, S_FALSE if already exists and no initialization needed, otherwise an error code</returns>
+ /// <remarks>
+ /// If a CoreCLR instance has already been created, the existing instance is returned.
+ /// If the <paramref name="path"/> is not supplied, the 'CORE_ROOT' environment variable is used.
+ /// </remarks>
+ static HRESULT GetCoreClrInstance(_Outptr_ coreclr **instance, _In_opt_z_ const WCHAR *path = nullptr);
+
+ /// <summary>
+ /// Populate the supplied string with a delimited string of TPA assemblies in from the supplied directory path.
+ /// </summary>
+ /// <remarks>
+ /// If <paramref name="dir"/> is not supplied, the 'CORE_ROOT' environment variable is used.
+ /// </remarks>
+ static HRESULT CreateTpaList(_Inout_ std::string &tpaList, _In_opt_z_ const WCHAR *dir = nullptr);
+
+public:
+ coreclr(_Inout_ AutoModule hmod);
+
+ coreclr(_In_ const coreclr &) = delete;
+ coreclr& operator=(_In_ const coreclr &) = delete;
+
+ coreclr(_Inout_ coreclr &&) = delete;
+ coreclr& operator=(_Inout_ coreclr &&) = delete;
+
+ ~coreclr();
+
+ // See exported function 'coreclr_initialize' from coreclr library
+ HRESULT Initialize(
+ _In_ int propertyCount,
+ _In_reads_(propertyCount) const char **keys,
+ _In_reads_(propertyCount) const char **values,
+ _In_opt_z_ const char *appDomainName = nullptr);
+
+ // See exported function 'coreclr_create_delegate' from coreclr library
+ HRESULT CreateDelegate(
+ _In_z_ const char *assembly,
+ _In_z_ const char *type,
+ _In_z_ const char *method,
+ _Out_ void **del);
+
+private:
+ AutoModule _hmod;
+
+ void *_clrInst;
+ uint32_t _appDomainId;
+
+ coreclr_initialize_ptr _initialize;
+ coreclr_create_delegate_ptr _create_delegate;
+ coreclr_shutdown_ptr _shutdown;
+};
+
+#endif /* _CORESHIM_H_ */
diff --git a/src/coreclr/hosts/coreshim/Exports.def b/src/coreclr/hosts/coreshim/Exports.def
new file mode 100644
index 0000000000..fbdded0f69
--- /dev/null
+++ b/src/coreclr/hosts/coreshim/Exports.def
@@ -0,0 +1,3 @@
+EXPORTS
+ DllGetClassObject PRIVATE
+ DllCanUnloadNow PRIVATE \ No newline at end of file
diff --git a/tests/issues.targets b/tests/issues.targets
index 2a3464237b..68f7472fe1 100644
--- a/tests/issues.targets
+++ b/tests/issues.targets
@@ -47,7 +47,11 @@
<ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/JitBlue/GitHub_11408/GitHub_11408/*">
<Issue>11408</Issue>
</ExcludeList>
- <ExcludeList Include="$(XunitTestBinBase)\Interop\COM\NETClients\Primitives\NETClientPrimitives\NETClientPrimitives.cmd">
+ <!-- Disable COM tests since they don't properly run on Windows.Nano and at present there is no way to special case that OS flavor. -->
+ <ExcludeList Include="$(XunitTestBinBase)/Interop/COM/NETClients/Primitives/NETClientPrimitives/NETClientPrimitives.cmd">
+ <Issue>19164</Issue>
+ </ExcludeList>
+ <ExcludeList Include="$(XunitTestBinBase)/Interop/COM/NativeClients/Primitives/Primitives.cmd">
<Issue>19164</Issue>
</ExcludeList>
</ItemGroup>
@@ -671,11 +675,6 @@
<ExcludeList Include="$(XunitTestBinBase)/baseservices/varargs/varargsupport_r/*">
<Issue>Varargs supported on this platform</Issue>
</ExcludeList>
-
- <!-- Disable COM tests since they don't properly run on Windows.Nano and at present there is no way to special case that OS flavor. -->
- <ExcludeList Include="$(XunitTestBinBase)/Interop/COM/NETClients/Primitives/NETClientPrimitives/*">
- <Issue>Fails on Windows.Nano</Issue>
- </ExcludeList>
</ItemGroup>
<!-- The following are tests that fail on non-Windows, which we must not run when building against packages -->
@@ -786,6 +785,9 @@
<ExcludeList Include="$(XunitTestBinBase)/Interop/COM/NETClients/Primitives/NETClientPrimitives/NETClientPrimitives.*">
<Issue>by design Windows only</Issue>
</ExcludeList>
+ <ExcludeList Include="$(XunitTestBinBase)/Interop/COM/NativeClients/Primitives/Primitives.*">
+ <Issue>by design Windows only</Issue>
+ </ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)/JIT/Directed/IL/PInvokeTail/PInvokeTail/*">
<Issue>needs triage</Issue>
</ExcludeList>
diff --git a/tests/src/CLRTest.Execute.Batch.targets b/tests/src/CLRTest.Execute.Batch.targets
index 4407010de4..1b1d36eb74 100644
--- a/tests/src/CLRTest.Execute.Batch.targets
+++ b/tests/src/CLRTest.Execute.Batch.targets
@@ -253,6 +253,11 @@ if defined DoLink (
</PropertyGroup>
<PropertyGroup>
<_CLRTestRunFile Condition="'$(CLRTestIsHosted)'=='true'">"%CORE_ROOT%\corerun.exe"</_CLRTestRunFile>
+ <BatchCopyCoreShimLocalCmds Condition="'$(CLRTestScriptLocalCoreShim)' == 'true'"><![CDATA[
+REM Local CoreShim requested - see MSBuild property 'CLRTestScriptLocalCoreShim'
+ECHO Copying '%CORE_ROOT%\CoreShim.dll'...
+COPY /y %CORE_ROOT%\CoreShim.dll .
+ ]]></BatchCopyCoreShimLocalCmds>
<BatchCLRTestLaunchCmds><![CDATA[
IF NOT "%CLRCustomTestLauncher%"=="" (
set LAUNCHER=call %CLRCustomTestLauncher% %~dp0
@@ -260,6 +265,7 @@ IF NOT "%CLRCustomTestLauncher%"=="" (
set LAUNCHER=%_DebuggerFullPath% $(_CLRTestRunFile)
)
$(BatchIlrtTestLaunchCmds)
+$(BatchCopyCoreShimLocalCmds)
]]></BatchCLRTestLaunchCmds>
<BatchCLRTestLaunchCmds Condition="'$(CLRTestKind)' == 'BuildAndRun'">
<![CDATA[
diff --git a/tests/src/Interop/CMakeLists.txt b/tests/src/Interop/CMakeLists.txt
index 0107958aa5..76384b488d 100644
--- a/tests/src/Interop/CMakeLists.txt
+++ b/tests/src/Interop/CMakeLists.txt
@@ -33,6 +33,7 @@ add_subdirectory(DllImportAttribute/Simple)
if(WIN32)
add_subdirectory(COM/NativeServer)
+ add_subdirectory(COM/NativeClients/Primitives)
add_subdirectory(IJW/FakeMscoree)
# IJW isn't supported on ARM64
diff --git a/tests/src/Interop/COM/Activator/Activator.csproj b/tests/src/Interop/COM/Activator/Activator.csproj
new file mode 100644
index 0000000000..51b89ebd40
--- /dev/null
+++ b/tests/src/Interop/COM/Activator/Activator.csproj
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), Interop.settings.targets))\Interop.settings.targets" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <AssemblyName>Activator</AssemblyName>
+ <SchemaVersion>2.0</SchemaVersion>
+ <OutputType>Exe</OutputType>
+ <ReferenceSystemPrivateCoreLib>true</ReferenceSystemPrivateCoreLib>
+
+ <!-- Test unsupported outside of windows -->
+ <TestUnsupportedOutsideWindows>true</TestUnsupportedOutsideWindows>
+ <DisableProjectBuild Condition="'$(TargetsUnix)' == 'true'">true</DisableProjectBuild>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="Program.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\NetServer\NetServer.csproj" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/tests/src/Interop/COM/Activator/Program.cs b/tests/src/Interop/COM/Activator/Program.cs
new file mode 100644
index 0000000000..117d55fa70
--- /dev/null
+++ b/tests/src/Interop/COM/Activator/Program.cs
@@ -0,0 +1,67 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Activator
+{
+ using System;
+ using System.Runtime.InteropServices;
+
+ using CoreFXTestLibrary;
+
+ using Console = Internal.Console;
+
+ class Program
+ {
+ static void InvalidInterfaceRequest()
+ {
+ Assert.Throws<NotSupportedException>(
+ () =>
+ {
+ var notIClassFactory = new Guid("ED53F949-63E4-43B5-A13D-5655478AADD5");
+ var cxt = new ComActivationContext()
+ {
+ InterfaceId = notIClassFactory
+ };
+ ComActivator.GetClassFactoryForType(cxt);
+ },
+ "Non-IClassFactory request should fail");
+ }
+
+ static void ClassNotRegistered()
+ {
+ COMException e = Assert.Throws<COMException>(
+ () =>
+ {
+ var CLSID_NotRegistered = new Guid("328FF83E-3F6C-4BE9-A742-752562032925"); // Random GUID
+ var IID_IClassFactory = new Guid("00000001-0000-0000-C000-000000000046");
+ var cxt = new ComActivationContext()
+ {
+ ClassId = CLSID_NotRegistered,
+ InterfaceId = IID_IClassFactory
+ };
+ ComActivator.GetClassFactoryForType(cxt);
+ },
+ "Class should not be found");
+
+ const int CLASS_E_CLASSNOTAVAILABLE = unchecked((int)0x80040111);
+ Assert.AreEqual(CLASS_E_CLASSNOTAVAILABLE, e.HResult, "Unexpected HRESULT");
+ }
+
+ static int Main(string[] doNotUse)
+ {
+ try
+ {
+ InvalidInterfaceRequest();
+ ClassNotRegistered();
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine($"Test Failure: {e}");
+ return 101;
+ }
+
+ return 100;
+ }
+ }
+}
diff --git a/tests/src/Interop/COM/NETServer/ArrayTesting.cs b/tests/src/Interop/COM/NETServer/ArrayTesting.cs
new file mode 100644
index 0000000000..3cdd5d100b
--- /dev/null
+++ b/tests/src/Interop/COM/NETServer/ArrayTesting.cs
@@ -0,0 +1,241 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+#pragma warning disable 618 // Must test deprecated features
+
+[ComVisible(true)]
+[Guid(Server.Contract.Guids.ArrayTesting)]
+public class ArrayTesting : Server.Contract.IArrayTesting
+{
+ private static double Mean(byte[] d)
+ {
+ double t = 0.0;
+ foreach (var b in d)
+ {
+ t += b;
+ }
+ return (t / d.Length);
+ }
+ private static double Mean(short[] d)
+ {
+ double t = 0.0;
+ foreach (var b in d)
+ {
+ t += b;
+ }
+ return (t / d.Length);
+ }
+ private static double Mean(ushort[] d)
+ {
+ double t = 0.0;
+ foreach (var b in d)
+ {
+ t += b;
+ }
+ return (t / d.Length);
+ }
+ private static double Mean(int[] d)
+ {
+ double t = 0.0;
+ foreach (var b in d)
+ {
+ t += b;
+ }
+ return (t / d.Length);
+ }
+ private static double Mean(uint[] d)
+ {
+ double t = 0.0;
+ foreach (var b in d)
+ {
+ t += b;
+ }
+ return (t / d.Length);
+ }
+ private static double Mean(long[] d)
+ {
+ double t = 0.0;
+ foreach (var b in d)
+ {
+ t += b;
+ }
+ return (t / d.Length);
+ }
+ private static double Mean(ulong[] d)
+ {
+ double t = 0.0;
+ foreach (var b in d)
+ {
+ t += b;
+ }
+ return (t / d.Length);
+ }
+ private static double Mean(float[] d)
+ {
+ double t = 0.0;
+ foreach (var b in d)
+ {
+ t += b;
+ }
+ return (t / d.Length);
+ }
+ private static double Mean(double[] d)
+ {
+ double t = 0.0;
+ foreach (var b in d)
+ {
+ t += b;
+ }
+ return (t / d.Length);
+ }
+
+ public double Mean_Byte_LP_PreLen(int len, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] byte[] d)
+ {
+ return Mean(d);
+ }
+
+ public double Mean_Short_LP_PreLen(int len, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] short[] d)
+ {
+ return Mean(d);
+ }
+
+ public double Mean_UShort_LP_PreLen(int len, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] ushort[] d)
+ {
+ return Mean(d);
+ }
+
+ public double Mean_Int_LP_PreLen(int len, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] int[] d)
+ {
+ return Mean(d);
+ }
+
+ public double Mean_UInt_LP_PreLen(int len, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] uint[] d)
+ {
+ return Mean(d);
+ }
+
+ public double Mean_Long_LP_PreLen(int len, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] long[] d)
+ {
+ return Mean(d);
+ }
+
+ public double Mean_ULong_LP_PreLen(int len, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] ulong[] d)
+ {
+ return Mean(d);
+ }
+
+ public double Mean_Float_LP_PreLen(int len, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] float[] d)
+ {
+ return Mean(d);
+ }
+
+ public double Mean_Double_LP_PreLen(int len, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] double[] d)
+ {
+ return Mean(d);
+ }
+
+ public double Mean_Byte_LP_PostLen([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] byte[] d, int len)
+ {
+ return Mean(d);
+ }
+
+ public double Mean_Short_LP_PostLen([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] short[] d, int len)
+ {
+ return Mean(d);
+ }
+
+ public double Mean_UShort_LP_PostLen([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] ushort[] d, int len)
+ {
+ return Mean(d);
+ }
+
+ public double Mean_Int_LP_PostLen([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] int[] d, int len)
+ {
+ return Mean(d);
+ }
+
+ public double Mean_UInt_LP_PostLen([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] uint[] d, int len)
+ {
+ return Mean(d);
+ }
+
+ public double Mean_Long_LP_PostLen([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] long[] d, int len)
+ {
+ return Mean(d);
+ }
+
+ public double Mean_ULong_LP_PostLen([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] ulong[] d, int len)
+ {
+ return Mean(d);
+ }
+
+ public double Mean_Float_LP_PostLen([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] float[] d, int len)
+ {
+ return Mean(d);
+ }
+
+ public double Mean_Double_LP_PostLen([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] double[] d, int len)
+ {
+ return Mean(d);
+ }
+
+ public double Mean_Byte_SafeArray_OutLen([MarshalAs(UnmanagedType.SafeArray)] byte[] d, out int len)
+ {
+ len = d.Length;
+ return Mean(d);
+ }
+
+ public double Mean_Short_SafeArray_OutLen([MarshalAs(UnmanagedType.SafeArray)] short[] d, out int len)
+ {
+ len = d.Length;
+ return Mean(d);
+ }
+
+ public double Mean_UShort_SafeArray_OutLen([MarshalAs(UnmanagedType.SafeArray)] ushort[] d, out int len)
+ {
+ len = d.Length;
+ return Mean(d);
+ }
+
+ public double Mean_Int_SafeArray_OutLen([MarshalAs(UnmanagedType.SafeArray)] int[] d, out int len)
+ {
+ len = d.Length;
+ return Mean(d);
+ }
+
+ public double Mean_UInt_SafeArray_OutLen([MarshalAs(UnmanagedType.SafeArray)] uint[] d, out int len)
+ {
+ len = d.Length;
+ return Mean(d);
+ }
+
+ public double Mean_Long_SafeArray_OutLen([MarshalAs(UnmanagedType.SafeArray)] long[] d, out int len)
+ {
+ len = d.Length;
+ return Mean(d);
+ }
+
+ public double Mean_ULong_SafeArray_OutLen([MarshalAs(UnmanagedType.SafeArray)] ulong[] d, out int len)
+ {
+ len = d.Length;
+ return Mean(d);
+ }
+
+ public double Mean_Float_SafeArray_OutLen([MarshalAs(UnmanagedType.SafeArray)] float[] d, out int len)
+ {
+ len = d.Length;
+ return Mean(d);
+ }
+
+ public double Mean_Double_SafeArray_OutLen([MarshalAs(UnmanagedType.SafeArray)] double[] d, out int len)
+ {
+ len = d.Length;
+ return Mean(d);
+ }
+}
+
+#pragma warning restore 618 // Must test deprecated features \ No newline at end of file
diff --git a/tests/src/Interop/COM/NETServer/ErrorMarshalTesting.cs b/tests/src/Interop/COM/NETServer/ErrorMarshalTesting.cs
new file mode 100644
index 0000000000..6bd104f5d4
--- /dev/null
+++ b/tests/src/Interop/COM/NETServer/ErrorMarshalTesting.cs
@@ -0,0 +1,28 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+[ComVisible(true)]
+[Guid(Server.Contract.Guids.ErrorMarshalTesting)]
+public class ErrorMarshalTesting : Server.Contract.IErrorMarshalTesting
+{
+ public void Throw_HResult(int hresultToReturn)
+ {
+ // This GetExceptionForHR call is needed to 'eat' the IErrorInfo put to TLS by
+ // any previous exception on this thread. If this isn't done, calls can return
+ // previous exception objects that have occurred.
+ Marshal.GetExceptionForHR(hresultToReturn);
+
+ Exception e = Marshal.GetExceptionForHR(hresultToReturn);
+ throw e;
+ }
+
+ [PreserveSig]
+ public int Return_As_HResult(int hresultToReturn)
+ {
+ return hresultToReturn;
+ }
+} \ No newline at end of file
diff --git a/tests/src/Interop/COM/NETServer/NETServer.csproj b/tests/src/Interop/COM/NETServer/NETServer.csproj
index 214bb25c5a..0610fca6ae 100644
--- a/tests/src/Interop/COM/NETServer/NETServer.csproj
+++ b/tests/src/Interop/COM/NETServer/NETServer.csproj
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), Interop.settings.targets))\Interop.settings.targets" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@@ -9,8 +10,6 @@
<ProjectGuid>{C04AB564-CC61-499D-9F4C-AA1A9FDE42C9}</ProjectGuid>
<OutputType>library</OutputType>
<ProjectTypeGuids>{4948E98A-ECFC-4988-851E-68E1ADD2DD5A};{B850CC46-E8FB-4569-A28D-423F81E8A861}</ProjectTypeGuids>
- <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
- <DefineConstants>$(DefineConstants);STATIC</DefineConstants>
</PropertyGroup>
<!-- Default configurations to help VS understand the configurations -->
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
@@ -18,16 +17,13 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
</PropertyGroup>
<ItemGroup>
- <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
- <Visible>False</Visible>
- </CodeAnalysisDependentAssemblyPaths>
- </ItemGroup>
- <ItemGroup>
<Compile Include="ImportedTypes.cs" />
+ <Compile Include="NumericTesting.cs" />
+ <Compile Include="ArrayTesting.cs" />
+ <Compile Include="StringTesting.cs" />
+ <Compile Include="ErrorMarshalTesting.cs" />
+ <Compile Include="../ServerContracts/Primitives.cs" />
<Compile Include="../ServerContracts/ServerGuids.cs" />
</ItemGroup>
- <ItemGroup>
- <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
- </ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/tests/src/Interop/COM/NETServer/NumericTesting.cs b/tests/src/Interop/COM/NETServer/NumericTesting.cs
new file mode 100644
index 0000000000..c6b11630ef
--- /dev/null
+++ b/tests/src/Interop/COM/NETServer/NumericTesting.cs
@@ -0,0 +1,193 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+#pragma warning disable 618 // Must test deprecated features
+
+[ComVisible(true)]
+[Guid(Server.Contract.Guids.NumericTesting)]
+public class NumericTesting : Server.Contract.INumericTesting
+{
+ public byte Add_Byte(byte a, byte b)
+ {
+ return (byte)(a + b);
+ }
+
+ public short Add_Short(short a, short b)
+ {
+ return (short)(a + b);
+ }
+
+ public ushort Add_UShort(ushort a, ushort b)
+ {
+ return (ushort)(a + b);
+ }
+
+ public int Add_Int(int a, int b)
+ {
+ return a + b;
+ }
+
+ public uint Add_UInt(uint a, uint b)
+ {
+ return a + b;
+ }
+
+ public long Add_Long(long a, long b)
+ {
+ return a + b;
+ }
+
+ public ulong Add_ULong(ulong a, ulong b)
+ {
+ return a + b;
+ }
+
+ public float Add_Float(float a, float b)
+ {
+ return a + b;
+ }
+
+ public double Add_Double(double a, double b)
+ {
+ return a + b;
+ }
+
+ public void Add_Byte_Ref(byte a, byte b, ref byte c)
+ {
+ if (c != byte.MaxValue)
+ {
+ throw new Exception();
+ }
+
+ c = (byte)(a + b);
+ }
+
+ public void Add_Short_Ref(short a, short b, ref short c)
+ {
+ if (c != short.MaxValue)
+ {
+ throw new Exception();
+ }
+
+ c = (short)(a + b);
+ }
+
+ public void Add_UShort_Ref(ushort a, ushort b, ref ushort c)
+ {
+ if (c != ushort.MaxValue)
+ {
+ throw new Exception();
+ }
+
+ c = (ushort)(a + b);
+ }
+
+ public void Add_Int_Ref(int a, int b, ref int c)
+ {
+ if (c != int.MaxValue)
+ {
+ throw new Exception();
+ }
+
+ c = a + b;
+ }
+
+ public void Add_UInt_Ref(uint a, uint b, ref uint c)
+ {
+ if (c != uint.MaxValue)
+ {
+ throw new Exception();
+ }
+
+ c = a + b;
+ }
+
+ public void Add_Long_Ref(long a, long b, ref long c)
+ {
+ if (c != long.MaxValue)
+ {
+ throw new Exception();
+ }
+
+ c = a + b;
+ }
+
+ public void Add_ULong_Ref(ulong a, ulong b, ref ulong c)
+ {
+ if (c != ulong.MaxValue)
+ {
+ throw new Exception();
+ }
+
+ c = a + b;
+ }
+
+ public void Add_Float_Ref(float a, float b, ref float c)
+ {
+ if (c != float.MaxValue)
+ {
+ throw new Exception();
+ }
+
+ c = a + b;
+ }
+
+ public void Add_Double_Ref(double a, double b, ref double c)
+ {
+ if (c != double.MaxValue)
+ {
+ throw new Exception();
+ }
+
+ c = a + b;
+ }
+
+ public void Add_Byte_Out(byte a, byte b, out byte c)
+ {
+ c = (byte)(a + b);
+ }
+
+ public void Add_Short_Out(short a, short b, out short c)
+ {
+ c = (short)(a + b);
+ }
+
+ public void Add_UShort_Out(ushort a, ushort b, out ushort c)
+ {
+ c = (ushort)(a + b);
+ }
+
+ public void Add_Int_Out(int a, int b, out int c)
+ {
+ c = a + b;
+ }
+
+ public void Add_UInt_Out(uint a, uint b, out uint c)
+ {
+ c = a + b;
+ }
+
+ public void Add_Long_Out(long a, long b, out long c)
+ {
+ c = a + b;
+ }
+
+ public void Add_ULong_Out(ulong a, ulong b, out ulong c)
+ {
+ c = a + b;
+ }
+
+ public void Add_Float_Out(float a, float b, out float c)
+ {
+ c = a + b;
+ }
+
+ public void Add_Double_Out(double a, double b, out double c)
+ {
+ c = a + b;
+ }
+} \ No newline at end of file
diff --git a/tests/src/Interop/COM/NETServer/StringTesting.cs b/tests/src/Interop/COM/NETServer/StringTesting.cs
new file mode 100644
index 0000000000..3a510f5e9b
--- /dev/null
+++ b/tests/src/Interop/COM/NETServer/StringTesting.cs
@@ -0,0 +1,191 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Text;
+using System.Runtime.InteropServices;
+
+#pragma warning disable 618 // Must test deprecated features
+
+[ComVisible(true)]
+[Guid(Server.Contract.Guids.StringTesting)]
+public class StringTesting : Server.Contract.IStringTesting
+{
+ private static string Reverse(string s)
+ {
+ var chars = s.ToCharArray();
+ Array.Reverse(chars);
+ return new string(chars);
+ }
+
+ [return: MarshalAs(UnmanagedType.LPStr)]
+ public string Add_LPStr(
+ [MarshalAs(UnmanagedType.LPStr)] string a,
+ [MarshalAs(UnmanagedType.LPStr)] string b)
+ {
+ return a + b;
+ }
+
+ [return: MarshalAs(UnmanagedType.LPWStr)]
+ public string Add_LPWStr(
+ [MarshalAs(UnmanagedType.LPWStr)] string a,
+ [MarshalAs(UnmanagedType.LPWStr)] string b)
+ {
+ return a + b;
+ }
+
+ [return: MarshalAs(UnmanagedType.BStr)]
+ public string Add_BStr(
+ [MarshalAs(UnmanagedType.BStr)] string a,
+ [MarshalAs(UnmanagedType.BStr)] string b)
+ {
+ return a + b;
+ }
+
+ // LPStr
+
+ [return: MarshalAs(UnmanagedType.LPStr)]
+ public string Reverse_LPStr([MarshalAs(UnmanagedType.LPStr)] string a)
+ {
+ return Reverse(a);
+ }
+
+ [return: MarshalAs(UnmanagedType.LPStr)]
+ public string Reverse_LPStr_Ref([MarshalAs(UnmanagedType.LPStr)] ref string a)
+ {
+ return Reverse(a);
+ }
+
+ [return: MarshalAs(UnmanagedType.LPStr)]
+ public string Reverse_LPStr_InRef([In][MarshalAs(UnmanagedType.LPStr)] ref string a)
+ {
+ return Reverse(a);
+ }
+
+ public void Reverse_LPStr_Out([MarshalAs(UnmanagedType.LPStr)] string a, [MarshalAs(UnmanagedType.LPStr)] out string b)
+ {
+ b = Reverse(a);
+ }
+
+ public void Reverse_LPStr_OutAttr([MarshalAs(UnmanagedType.LPStr)] string a, [Out][MarshalAs(UnmanagedType.LPStr)] string b)
+ {
+ b = Reverse(a);
+ }
+
+ [return: MarshalAs(UnmanagedType.LPStr)]
+ public StringBuilder Reverse_SB_LPStr([MarshalAs(UnmanagedType.LPStr)] StringBuilder a)
+ {
+ return new StringBuilder(Reverse(a.ToString()));
+ }
+
+ [return: MarshalAs(UnmanagedType.LPStr)]
+ public StringBuilder Reverse_SB_LPStr_Ref([MarshalAs(UnmanagedType.LPStr)] ref StringBuilder a)
+ {
+ return new StringBuilder(Reverse(a.ToString()));
+ }
+
+ [return: MarshalAs(UnmanagedType.LPStr)]
+ public StringBuilder Reverse_SB_LPStr_InRef([In][MarshalAs(UnmanagedType.LPStr)] ref StringBuilder a)
+ {
+ return new StringBuilder(Reverse(a.ToString()));
+ }
+
+ public void Reverse_SB_LPStr_Out([MarshalAs(UnmanagedType.LPStr)] StringBuilder a, [MarshalAs(UnmanagedType.LPStr)] out StringBuilder b)
+ {
+ b = new StringBuilder(Reverse(a.ToString()));
+ }
+
+ public void Reverse_SB_LPStr_OutAttr([MarshalAs(UnmanagedType.LPStr)] StringBuilder a, [Out][MarshalAs(UnmanagedType.LPStr)] StringBuilder b)
+ {
+ b.Append(Reverse(a.ToString()));
+ }
+
+ // LPWStr
+
+ [return: MarshalAs(UnmanagedType.LPWStr)]
+ public string Reverse_LPWStr([MarshalAs(UnmanagedType.LPWStr)] string a)
+ {
+ return Reverse(a);
+ }
+
+ [return: MarshalAs(UnmanagedType.LPWStr)]
+ public string Reverse_LPWStr_Ref([MarshalAs(UnmanagedType.LPWStr)] ref string a)
+ {
+ return Reverse(a);
+ }
+
+ [return: MarshalAs(UnmanagedType.LPWStr)]
+ public string Reverse_LPWStr_InRef([In][MarshalAs(UnmanagedType.LPWStr)] ref string a)
+ {
+ return Reverse(a);
+ }
+
+ public void Reverse_LPWStr_Out([MarshalAs(UnmanagedType.LPWStr)] string a, [MarshalAs(UnmanagedType.LPWStr)] out string b)
+ {
+ b = Reverse(a);
+ }
+
+ public void Reverse_LPWStr_OutAttr([MarshalAs(UnmanagedType.LPWStr)] string a, [Out][MarshalAs(UnmanagedType.LPWStr)] string b)
+ {
+ b = Reverse(a);
+ }
+
+ [return: MarshalAs(UnmanagedType.LPWStr)]
+ public StringBuilder Reverse_SB_LPWStr([MarshalAs(UnmanagedType.LPWStr)] StringBuilder a)
+ {
+ return new StringBuilder(Reverse(a.ToString()));
+ }
+
+ [return: MarshalAs(UnmanagedType.LPWStr)]
+ public StringBuilder Reverse_SB_LPWStr_Ref([MarshalAs(UnmanagedType.LPWStr)] ref StringBuilder a)
+ {
+ return new StringBuilder(Reverse(a.ToString()));
+ }
+
+ [return: MarshalAs(UnmanagedType.LPWStr)]
+ public StringBuilder Reverse_SB_LPWStr_InRef([In][MarshalAs(UnmanagedType.LPWStr)] ref StringBuilder a)
+ {
+ return new StringBuilder(Reverse(a.ToString()));
+ }
+
+ public void Reverse_SB_LPWStr_Out([MarshalAs(UnmanagedType.LPWStr)] StringBuilder a, [MarshalAs(UnmanagedType.LPWStr)] out StringBuilder b)
+ {
+ b = new StringBuilder(Reverse(a.ToString()));
+ }
+
+ public void Reverse_SB_LPWStr_OutAttr([MarshalAs(UnmanagedType.LPWStr)] StringBuilder a, [Out][MarshalAs(UnmanagedType.LPWStr)] StringBuilder b)
+ {
+ b.Append(Reverse(a.ToString()));
+ }
+
+ // BSTR
+
+ [return: MarshalAs(UnmanagedType.BStr)]
+ public string Reverse_BStr([MarshalAs(UnmanagedType.BStr)] string a)
+ {
+ return Reverse(a);
+ }
+
+ [return: MarshalAs(UnmanagedType.BStr)]
+ public string Reverse_BStr_Ref([MarshalAs(UnmanagedType.BStr)] ref string a)
+ {
+ return Reverse(a);
+ }
+
+ [return: MarshalAs(UnmanagedType.BStr)]
+ public string Reverse_BStr_InRef([In][MarshalAs(UnmanagedType.BStr)] ref string a)
+ {
+ return Reverse(a);
+ }
+
+ public void Reverse_BStr_Out([MarshalAs(UnmanagedType.BStr)] string a, [MarshalAs(UnmanagedType.BStr)] out string b)
+ {
+ b = Reverse(a);
+ }
+
+ public void Reverse_BStr_OutAttr([MarshalAs(UnmanagedType.BStr)] string a, [Out][MarshalAs(UnmanagedType.BStr)] string b)
+ {
+ b = Reverse(a);
+ }
+} \ No newline at end of file
diff --git a/tests/src/Interop/COM/NativeClients/Primitives.csproj b/tests/src/Interop/COM/NativeClients/Primitives.csproj
new file mode 100644
index 0000000000..b1bc0e656c
--- /dev/null
+++ b/tests/src/Interop/COM/NativeClients/Primitives.csproj
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), Interop.settings.targets))\Interop.settings.targets" />
+ <PropertyGroup>
+ <IgnoreInteropAssertionFile>true</IgnoreInteropAssertionFile>
+ <CLRTestScriptLocalCoreShim>true</CLRTestScriptLocalCoreShim>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="$(InteropCommonDir)ExeLauncherProgram.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="Primitives/CMakeLists.txt"/>
+ <ProjectReference Include="../NetServer/NetServer.csproj" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project> \ No newline at end of file
diff --git a/tests/src/Interop/COM/NativeClients/Primitives/App.manifest b/tests/src/Interop/COM/NativeClients/Primitives/App.manifest
new file mode 100644
index 0000000000..ed665080a7
--- /dev/null
+++ b/tests/src/Interop/COM/NativeClients/Primitives/App.manifest
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <assemblyIdentity
+ type="win32"
+ name="COMClientPrimitives"
+ version="1.0.0.0"/>
+
+ <dependency>
+ <dependentAssembly>
+ <!-- RegFree COM - CoreCLR Shim -->
+ <assemblyIdentity
+ type="win32"
+ name="CoreShim.X"
+ version="1.0.0.0"/>
+ </dependentAssembly>
+ </dependency>
+</assembly> \ No newline at end of file
diff --git a/tests/src/Interop/COM/NativeClients/Primitives/ArrayTests.cpp b/tests/src/Interop/COM/NativeClients/Primitives/ArrayTests.cpp
new file mode 100644
index 0000000000..5b54a1445b
--- /dev/null
+++ b/tests/src/Interop/COM/NativeClients/Primitives/ArrayTests.cpp
@@ -0,0 +1,318 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "ClientTests.h"
+#include <numeric>
+#include <vector>
+
+namespace
+{
+ bool EqualByBound(double expected, double actual)
+ {
+ double low = expected - 0.00001;
+ double high = expected + 0.00001;
+ double eps = std::fabs(expected - actual);
+ bool isEqual = eps < std::numeric_limits<double>::epsilon() || (low < actual && actual < high);
+ return isEqual;
+ }
+
+ template<typename T>
+ std::vector<T> Convert(_In_ const std::vector<int> &in)
+ {
+ std::vector<T> out;
+ for (auto i : in)
+ out.push_back((T)i);
+ return out;
+ }
+
+ template<typename T>
+ VARTYPE ToSafeArrayType();
+ template<>
+ VARTYPE ToSafeArrayType<byte>() { return VT_UI1; }
+ template<>
+ VARTYPE ToSafeArrayType<int16_t>() { return VT_I2; }
+ template<>
+ VARTYPE ToSafeArrayType<uint16_t>() { return VT_UI2; }
+ template<>
+ VARTYPE ToSafeArrayType<int32_t>() { return VT_I4; }
+ template<>
+ VARTYPE ToSafeArrayType<uint32_t>() { return VT_UI4; }
+ template<>
+ VARTYPE ToSafeArrayType<int64_t>() { return VT_I8; }
+ template<>
+ VARTYPE ToSafeArrayType<uint64_t>() { return VT_UI8; }
+ template<>
+ VARTYPE ToSafeArrayType<float>() { return VT_R4; }
+ template<>
+ VARTYPE ToSafeArrayType<double>() { return VT_R8; }
+
+ template<typename T>
+ class SafeArraySmartPtr
+ {
+ public:
+ SafeArraySmartPtr(_In_ const std::vector<T> &in)
+ : _safeArray{}
+ , _elementCount{ static_cast<int>(in.size()) }
+ {
+ SAFEARRAYBOUND saBound;
+ saBound.lLbound = 0;
+ saBound.cElements = static_cast<ULONG>(in.size());
+
+ _safeArray = ::SafeArrayCreate(ToSafeArrayType<T>(), 1, &saBound);
+ assert(_safeArray != nullptr);
+
+ std::memcpy(static_cast<T*>(_safeArray->pvData), in.data(), sizeof(T) * in.size());
+ }
+
+ ~SafeArraySmartPtr()
+ {
+ ::SafeArrayDestroy(_safeArray);
+ }
+
+ int Length() const
+ {
+ return _elementCount;
+ }
+
+ operator SAFEARRAY *()
+ {
+ return _safeArray;
+ }
+
+ private:
+ int _elementCount;
+ SAFEARRAY *_safeArray;
+ };
+
+ void ByteArray(_In_ IArrayTesting *arrayTesting, _In_ const std::vector<int> &baseData, _In_ double expectedMean)
+ {
+ HRESULT hr;
+ auto data = Convert<byte>(baseData);
+
+ ::printf("Byte[] marshalling\n");
+
+ double actual;
+ THROW_IF_FAILED(arrayTesting->raw_Mean_Byte_LP_PreLen(static_cast<int>(baseData.size()), data.data(), &actual));
+ THROW_FAIL_IF_FALSE(EqualByBound(expectedMean, actual));
+
+ actual = 0.0;
+ THROW_IF_FAILED(arrayTesting->raw_Mean_Byte_LP_PostLen(data.data(), static_cast<int>(baseData.size()), &actual));
+ THROW_FAIL_IF_FALSE(EqualByBound(expectedMean, actual));
+
+ actual = 0.0;
+ int len;
+ SafeArraySmartPtr<byte> saData{ data };
+ THROW_IF_FAILED(arrayTesting->raw_Mean_Byte_SafeArray_OutLen(saData, &len, &actual));
+ THROW_FAIL_IF_FALSE(EqualByBound(expectedMean, actual));
+ THROW_FAIL_IF_FALSE(len == saData.Length());
+ }
+
+ void ShortArray(_In_ IArrayTesting *arrayTesting, _In_ const std::vector<int> &baseData, _In_ double expectedMean)
+ {
+ HRESULT hr;
+ auto data = Convert<int16_t>(baseData);
+
+ ::printf("Short[] marshalling\n");
+
+ double actual;
+ THROW_IF_FAILED(arrayTesting->raw_Mean_Short_LP_PreLen(static_cast<int>(baseData.size()), data.data(), &actual));
+ THROW_FAIL_IF_FALSE(EqualByBound(expectedMean, actual));
+
+ actual = 0.0;
+ THROW_IF_FAILED(arrayTesting->raw_Mean_Short_LP_PostLen(data.data(), static_cast<int>(baseData.size()), &actual));
+ THROW_FAIL_IF_FALSE(EqualByBound(expectedMean, actual));
+
+ actual = 0.0;
+ int len;
+ SafeArraySmartPtr<int16_t> saData{ data };
+ THROW_IF_FAILED(arrayTesting->raw_Mean_Short_SafeArray_OutLen(saData, &len, &actual));
+ THROW_FAIL_IF_FALSE(EqualByBound(expectedMean, actual));
+ THROW_FAIL_IF_FALSE(len == saData.Length());
+ }
+
+ void UShortArray(_In_ IArrayTesting *arrayTesting, _In_ const std::vector<int> &baseData, _In_ double expectedMean)
+ {
+ HRESULT hr;
+ auto data = Convert<uint16_t>(baseData);
+
+ ::printf("UShort[] marshalling\n");
+
+ double actual;
+ THROW_IF_FAILED(arrayTesting->raw_Mean_UShort_LP_PreLen(static_cast<int>(baseData.size()), data.data(), &actual));
+ THROW_FAIL_IF_FALSE(EqualByBound(expectedMean, actual));
+
+ actual = 0.0;
+ THROW_IF_FAILED(arrayTesting->raw_Mean_UShort_LP_PostLen(data.data(), static_cast<int>(baseData.size()), &actual));
+ THROW_FAIL_IF_FALSE(EqualByBound(expectedMean, actual));
+
+ actual = 0.0;
+ int len;
+ SafeArraySmartPtr<uint16_t> saData{ data };
+ THROW_IF_FAILED(arrayTesting->raw_Mean_UShort_SafeArray_OutLen(saData, &len, &actual));
+ THROW_FAIL_IF_FALSE(EqualByBound(expectedMean, actual));
+ THROW_FAIL_IF_FALSE(len == saData.Length());
+ }
+
+ void IntArray(_In_ IArrayTesting *arrayTesting, _In_ const std::vector<int> &baseData, _In_ double expectedMean)
+ {
+ HRESULT hr;
+ auto data = Convert<int32_t>(baseData);
+
+ ::printf("Int[] marshalling\n");
+
+ double actual;
+ THROW_IF_FAILED(arrayTesting->raw_Mean_Int_LP_PreLen(static_cast<int>(baseData.size()), data.data(), &actual));
+ THROW_FAIL_IF_FALSE(EqualByBound(expectedMean, actual));
+
+ actual = 0.0;
+ THROW_IF_FAILED(arrayTesting->raw_Mean_Int_LP_PostLen(data.data(), static_cast<int>(baseData.size()), &actual));
+ THROW_FAIL_IF_FALSE(EqualByBound(expectedMean, actual));
+
+ actual = 0.0;
+ int len;
+ SafeArraySmartPtr<int32_t> saData{ data };
+ THROW_IF_FAILED(arrayTesting->raw_Mean_Int_SafeArray_OutLen(saData, &len, &actual));
+ THROW_FAIL_IF_FALSE(EqualByBound(expectedMean, actual));
+ THROW_FAIL_IF_FALSE(len == saData.Length());
+ }
+
+ void UIntArray(_In_ IArrayTesting *arrayTesting, _In_ const std::vector<int> &baseData, _In_ double expectedMean)
+ {
+ HRESULT hr;
+ auto data = Convert<uint32_t>(baseData);
+
+ ::printf("UInt[] marshalling\n");
+
+ double actual;
+ THROW_IF_FAILED(arrayTesting->raw_Mean_UInt_LP_PreLen(static_cast<int>(baseData.size()), data.data(), &actual));
+ THROW_FAIL_IF_FALSE(EqualByBound(expectedMean, actual));
+
+ actual = 0.0;
+ THROW_IF_FAILED(arrayTesting->raw_Mean_UInt_LP_PostLen(data.data(), static_cast<int>(baseData.size()), &actual));
+ THROW_FAIL_IF_FALSE(EqualByBound(expectedMean, actual));
+
+ actual = 0.0;
+ int len;
+ SafeArraySmartPtr<uint32_t> saData{ data };
+ THROW_IF_FAILED(arrayTesting->raw_Mean_UInt_SafeArray_OutLen(saData, &len, &actual));
+ THROW_FAIL_IF_FALSE(EqualByBound(expectedMean, actual));
+ THROW_FAIL_IF_FALSE(len == saData.Length());
+ }
+
+ void LongArray(_In_ IArrayTesting *arrayTesting, _In_ const std::vector<int> &baseData, _In_ double expectedMean)
+ {
+ HRESULT hr;
+ auto data = Convert<int64_t>(baseData);
+
+ ::printf("Long[] marshalling\n");
+
+ double actual;
+ THROW_IF_FAILED(arrayTesting->raw_Mean_Long_LP_PreLen(static_cast<int>(baseData.size()), data.data(), &actual));
+ THROW_FAIL_IF_FALSE(EqualByBound(expectedMean, actual));
+
+ actual = 0.0;
+ THROW_IF_FAILED(arrayTesting->raw_Mean_Long_LP_PostLen(data.data(), static_cast<int>(baseData.size()), &actual));
+ THROW_FAIL_IF_FALSE(EqualByBound(expectedMean, actual));
+
+ actual = 0.0;
+ int len;
+ SafeArraySmartPtr<int64_t> saData{ data };
+ THROW_IF_FAILED(arrayTesting->raw_Mean_Long_SafeArray_OutLen(saData, &len, &actual));
+ THROW_FAIL_IF_FALSE(EqualByBound(expectedMean, actual));
+ THROW_FAIL_IF_FALSE(len == saData.Length());
+ }
+
+ void ULongArray(_In_ IArrayTesting *arrayTesting, _In_ const std::vector<int> &baseData, _In_ double expectedMean)
+ {
+ HRESULT hr;
+ auto data = Convert<uint64_t>(baseData);
+
+ ::printf("ULong[] marshalling\n");
+
+ double actual;
+ THROW_IF_FAILED(arrayTesting->raw_Mean_ULong_LP_PreLen(static_cast<int>(baseData.size()), data.data(), &actual));
+ THROW_FAIL_IF_FALSE(EqualByBound(expectedMean, actual));
+
+ actual = 0.0;
+ THROW_IF_FAILED(arrayTesting->raw_Mean_ULong_LP_PostLen(data.data(), static_cast<int>(baseData.size()), &actual));
+ THROW_FAIL_IF_FALSE(EqualByBound(expectedMean, actual));
+
+ actual = 0.0;
+ int len;
+ SafeArraySmartPtr<uint64_t> saData{ data };
+ THROW_IF_FAILED(arrayTesting->raw_Mean_ULong_SafeArray_OutLen(saData, &len, &actual));
+ THROW_FAIL_IF_FALSE(EqualByBound(expectedMean, actual));
+ THROW_FAIL_IF_FALSE(len == saData.Length());
+ }
+
+ void FloatArray(_In_ IArrayTesting *arrayTesting, _In_ const std::vector<int> &baseData, _In_ double expectedMean)
+ {
+ HRESULT hr;
+ auto data = Convert<float>(baseData);
+
+ ::printf("Float[] marshalling\n");
+
+ double actual;
+ THROW_IF_FAILED(arrayTesting->raw_Mean_Float_LP_PreLen(static_cast<int>(baseData.size()), data.data(), &actual));
+ THROW_FAIL_IF_FALSE(EqualByBound(expectedMean, actual));
+
+ actual = 0.0;
+ THROW_IF_FAILED(arrayTesting->raw_Mean_Float_LP_PostLen(data.data(), static_cast<int>(baseData.size()), &actual));
+ THROW_FAIL_IF_FALSE(EqualByBound(expectedMean, actual));
+
+ actual = 0.0;
+ int len;
+ SafeArraySmartPtr<float> saData{ data };
+ THROW_IF_FAILED(arrayTesting->raw_Mean_Float_SafeArray_OutLen(saData, &len, &actual));
+ THROW_FAIL_IF_FALSE(EqualByBound(expectedMean, actual));
+ THROW_FAIL_IF_FALSE(len == saData.Length());
+ }
+
+ void DoubleArray(_In_ IArrayTesting *arrayTesting, _In_ const std::vector<int> &baseData, _In_ double expectedMean)
+ {
+ HRESULT hr;
+ auto data = Convert<double>(baseData);
+
+ ::printf("Double[] marshalling\n");
+
+ double actual;
+ THROW_IF_FAILED(arrayTesting->raw_Mean_Double_LP_PreLen(static_cast<int>(baseData.size()), data.data(), &actual));
+ THROW_FAIL_IF_FALSE(EqualByBound(expectedMean, actual));
+
+ actual = 0.0;
+ THROW_IF_FAILED(arrayTesting->raw_Mean_Double_LP_PostLen(data.data(), static_cast<int>(baseData.size()), &actual));
+ THROW_FAIL_IF_FALSE(EqualByBound(expectedMean, actual));
+
+ actual = 0.0;
+ int len;
+ SafeArraySmartPtr<double> saData{ data };
+ THROW_IF_FAILED(arrayTesting->raw_Mean_Double_SafeArray_OutLen(saData, &len, &actual));
+ THROW_FAIL_IF_FALSE(EqualByBound(expectedMean, actual));
+ THROW_FAIL_IF_FALSE(len == saData.Length());
+ }
+}
+
+void Run_ArrayTests()
+{
+ HRESULT hr;
+
+ CoreShimComActivation csact{ W("NETServer.dll"), W("ArrayTesting") };
+
+ ComSmartPtr<IArrayTesting> arrayTesting;
+ THROW_IF_FAILED(::CoCreateInstance(CLSID_ArrayTesting, nullptr, CLSCTX_INPROC, IID_IArrayTesting, (void**)&arrayTesting));
+
+ std::vector<int> baseData(10);
+ std::iota(std::begin(baseData), std::end(baseData), 0);
+ double mean = std::accumulate(std::begin(baseData), std::end(baseData), 0.0) / baseData.size();
+
+ ByteArray(arrayTesting, baseData, mean);
+ ShortArray(arrayTesting, baseData, mean);
+ UShortArray(arrayTesting, baseData, mean);
+ IntArray(arrayTesting, baseData, mean);
+ UIntArray(arrayTesting, baseData, mean);
+ LongArray(arrayTesting, baseData, mean);
+ ULongArray(arrayTesting, baseData, mean);
+ FloatArray(arrayTesting, baseData, mean);
+ DoubleArray(arrayTesting, baseData, mean);
+}
diff --git a/tests/src/Interop/COM/NativeClients/Primitives/CMakeLists.txt b/tests/src/Interop/COM/NativeClients/Primitives/CMakeLists.txt
new file mode 100644
index 0000000000..b2b2fb00db
--- /dev/null
+++ b/tests/src/Interop/COM/NativeClients/Primitives/CMakeLists.txt
@@ -0,0 +1,23 @@
+cmake_minimum_required (VERSION 2.6)
+
+project (COMClientPrimitives)
+include_directories( ${INC_PLATFORM_DIR} )
+include_directories( "../../ServerContracts" )
+include_directories( "../../NativeServer" )
+set(SOURCES
+ Client.cpp
+ NumericTests.cpp
+ ArrayTests.cpp
+ StringTests.cpp
+ ErrorTests.cpp
+ App.manifest)
+
+# add the executable
+add_executable (COMClientPrimitives ${SOURCES})
+target_link_libraries(COMClientPrimitives ${LINK_LIBRARIES_ADDITIONAL})
+
+# Copy CoreShim manifest to project output
+file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/CoreShim.X.manifest INPUT ${CMAKE_CURRENT_SOURCE_DIR}/CoreShim.X.manifest)
+
+# add the install targets
+install (TARGETS COMClientPrimitives DESTINATION bin)
diff --git a/tests/src/Interop/COM/NativeClients/Primitives/Client.cpp b/tests/src/Interop/COM/NativeClients/Primitives/Client.cpp
new file mode 100644
index 0000000000..bfb32c5b9a
--- /dev/null
+++ b/tests/src/Interop/COM/NativeClients/Primitives/Client.cpp
@@ -0,0 +1,45 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "ClientTests.h"
+
+template<COINIT TM>
+struct ComInit
+{
+ const HRESULT Result;
+
+ ComInit()
+ : Result{ ::CoInitializeEx(nullptr, TM) }
+ { }
+
+ ~ComInit()
+ {
+ if (SUCCEEDED(Result))
+ ::CoUninitialize();
+ }
+};
+
+using ComMTA = ComInit<COINIT_MULTITHREADED>;
+
+int __cdecl main()
+{
+ ComMTA init;
+ if (FAILED(init.Result))
+ return -1;
+
+ try
+ {
+ Run_NumericTests();
+ Run_ArrayTests();
+ Run_StringTests();
+ Run_ErrorTests();
+ }
+ catch (HRESULT hr)
+ {
+ ::printf("Test Failure: 0x%08x\n", hr);
+ return 101;
+ }
+
+ return 100;
+}
diff --git a/tests/src/Interop/COM/NativeClients/Primitives/ClientTests.h b/tests/src/Interop/COM/NativeClients/Primitives/ClientTests.h
new file mode 100644
index 0000000000..029ed028ce
--- /dev/null
+++ b/tests/src/Interop/COM/NativeClients/Primitives/ClientTests.h
@@ -0,0 +1,70 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include <xplatform.h>
+#include <cassert>
+#include <Server.Contracts.tlh>
+
+#define COM_CLIENT
+#include <Servers.h>
+
+#define THROW_IF_FAILED(exp) { hr = exp; if (FAILED(hr)) { ::printf("FAILURE: 0x%08x = %s\n", hr, #exp); throw hr; } }
+#define THROW_FAIL_IF_FALSE(exp) { if (!(exp)) { ::printf("FALSE: %s\n", #exp); throw E_FAIL; } }
+
+template<typename T>
+struct ComSmartPtr
+{
+ ComSmartPtr()
+ : p{}
+ { }
+
+ ComSmartPtr(_In_ const ComSmartPtr &) = delete;
+ ComSmartPtr(_Inout_ ComSmartPtr &&) = delete;
+
+ ComSmartPtr& operator=(_In_ const ComSmartPtr &) = delete;
+ ComSmartPtr& operator=(_Inout_ ComSmartPtr &&) = delete;
+
+ ~ComSmartPtr()
+ {
+ if (p != nullptr)
+ p->Release();
+ }
+
+ operator T*()
+ {
+ return p;
+ }
+
+ T** operator&()
+ {
+ return &p;
+ }
+
+ T* operator->()
+ {
+ return p;
+ }
+
+ void Attach(_In_opt_ T *t)
+ {
+ if (p != nullptr)
+ p->Release();
+
+ p = t;
+ }
+
+ T *Detach()
+ {
+ T *tmp = p;
+ p = nullptr;
+ return tmp;
+ }
+
+ T *p;
+};
+
+void Run_NumericTests();
+void Run_ArrayTests();
+void Run_StringTests();
+void Run_ErrorTests();
diff --git a/tests/src/Interop/COM/NativeClients/Primitives/CoreShim.X.manifest b/tests/src/Interop/COM/NativeClients/Primitives/CoreShim.X.manifest
new file mode 100644
index 0000000000..1dba8e03b3
--- /dev/null
+++ b/tests/src/Interop/COM/NativeClients/Primitives/CoreShim.X.manifest
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+
+<assemblyIdentity
+ type="win32"
+ name="CoreShim.X"
+ version="1.0.0.0" />
+
+<file name="CoreShim.dll">
+ <!-- NumericTesting -->
+ <comClass
+ clsid="{53169A33-E85D-4E3C-B668-24E438D0929B}"
+ threadingModel="Both" />
+ <!-- ArrayTesting -->
+ <comClass
+ clsid="{B99ABE6A-DFF6-440F-BFB6-55179B8FE18E}"
+ threadingModel="Both" />
+ <!-- StringTesting -->
+ <comClass
+ clsid="{C73C83E8-51A2-47F8-9B5C-4284458E47A6}"
+ threadingModel="Both" />
+ <!-- ErrorMarshalTesting -->
+ <comClass
+ clsid="{71CF5C45-106C-4B32-B418-43A463C6041F}"
+ threadingModel="Both" />
+</file>
+
+</assembly>
diff --git a/tests/src/Interop/COM/NativeClients/Primitives/ErrorTests.cpp b/tests/src/Interop/COM/NativeClients/Primitives/ErrorTests.cpp
new file mode 100644
index 0000000000..9f0af224bd
--- /dev/null
+++ b/tests/src/Interop/COM/NativeClients/Primitives/ErrorTests.cpp
@@ -0,0 +1,68 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "ClientTests.h"
+
+namespace
+{
+ void VerifyExpectedException(_In_ IErrorMarshalTesting *et)
+ {
+ ::printf("Verify expected exception from HRESULT\n");
+
+ HRESULT hrs[] =
+ {
+ E_NOTIMPL,
+ E_POINTER,
+ E_ACCESSDENIED,
+ E_OUTOFMEMORY,
+ E_INVALIDARG,
+ E_UNEXPECTED,
+ HRESULT{-1}
+ };
+
+ for (int i = 0; i < ARRAYSIZE(hrs); ++i)
+ {
+ HRESULT hr = hrs[i];
+ HRESULT hrMaybe = et->raw_Throw_HResult(hr);
+ THROW_FAIL_IF_FALSE(hr == hrMaybe);
+ }
+ }
+
+ void VerifyReturnHResult(_In_ IErrorMarshalTesting *et)
+ {
+ ::printf("Verify preserved function signature\n");
+
+ HRESULT hrs[] =
+ {
+ E_NOTIMPL,
+ E_POINTER,
+ E_ACCESSDENIED,
+ E_INVALIDARG,
+ E_UNEXPECTED,
+ HRESULT{-1},
+ S_FALSE,
+ HRESULT{2}
+ };
+
+ for (int i = 0; i < ARRAYSIZE(hrs); ++i)
+ {
+ HRESULT hr = hrs[i];
+ HRESULT hrMaybe = et->Return_As_HResult(hr);
+ THROW_FAIL_IF_FALSE(hr == hrMaybe);
+ }
+ }
+}
+
+void Run_ErrorTests()
+{
+ HRESULT hr;
+
+ CoreShimComActivation csact{ W("NETServer.dll"), W("ErrorMarshalTesting") };
+
+ ComSmartPtr<IErrorMarshalTesting> errorMarshal;
+ THROW_IF_FAILED(::CoCreateInstance(CLSID_ErrorMarshalTesting, nullptr, CLSCTX_INPROC, IID_IErrorMarshalTesting, (void**)&errorMarshal));
+
+ VerifyExpectedException(errorMarshal);
+ VerifyReturnHResult(errorMarshal);
+}
diff --git a/tests/src/Interop/COM/NativeClients/Primitives/NumericTests.cpp b/tests/src/Interop/COM/NativeClients/Primitives/NumericTests.cpp
new file mode 100644
index 0000000000..68ae4f4560
--- /dev/null
+++ b/tests/src/Interop/COM/NativeClients/Primitives/NumericTests.cpp
@@ -0,0 +1,227 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "ClientTests.h"
+#include <cstdint>
+#include <limits>
+
+namespace
+{
+ void MarshalByte(_In_ INumericTesting *numericTesting, _In_ byte a, _In_ byte b)
+ {
+ HRESULT hr;
+
+ byte expected = a + b;
+ ::printf("Byte test invariant: %d + %d = %d\n", a, b, expected);
+
+ byte c;
+ THROW_IF_FAILED(numericTesting->raw_Add_Byte(a, b, &c));
+ THROW_FAIL_IF_FALSE(expected == c);
+
+ c = std::numeric_limits<decltype(c)>::max();
+ THROW_IF_FAILED(numericTesting->raw_Add_Byte_Ref(a, b, &c));
+ THROW_FAIL_IF_FALSE(expected == c);
+
+ c = 0;
+ THROW_IF_FAILED(numericTesting->raw_Add_Byte_Out(a, b, &c));
+ THROW_FAIL_IF_FALSE(expected == c);
+ }
+
+ void MarshalShort(_In_ INumericTesting *numericTesting, _In_ int16_t a, _In_ int16_t b)
+ {
+ HRESULT hr;
+
+ int16_t expected = a + b;
+ ::printf("Short test invariant: %d + %d = %d\n", a, b, expected);
+
+ int16_t c;
+ THROW_IF_FAILED(numericTesting->raw_Add_Short(a, b, &c));
+ THROW_FAIL_IF_FALSE(expected == c);
+
+ c = std::numeric_limits<decltype(c)>::max();
+ THROW_IF_FAILED(numericTesting->raw_Add_Short_Ref(a, b, &c));
+ THROW_FAIL_IF_FALSE(expected == c);
+
+ c = 0;
+ THROW_IF_FAILED(numericTesting->raw_Add_Short_Out(a, b, &c));
+ THROW_FAIL_IF_FALSE(expected == c);
+ }
+
+ void MarshalUShort(_In_ INumericTesting *numericTesting, _In_ uint16_t a, _In_ uint16_t b)
+ {
+ HRESULT hr;
+
+ uint16_t expected = a + b;
+ ::printf("UShort test invariant: %u + %u = %u\n", a, b, expected);
+
+ uint16_t c;
+ THROW_IF_FAILED(numericTesting->raw_Add_UShort(a, b, &c));
+ THROW_FAIL_IF_FALSE(expected == c);
+
+ c = std::numeric_limits<decltype(c)>::max();
+ THROW_IF_FAILED(numericTesting->raw_Add_UShort_Ref(a, b, &c));
+ THROW_FAIL_IF_FALSE(expected == c);
+
+ c = 0;
+ THROW_IF_FAILED(numericTesting->raw_Add_UShort_Out(a, b, &c));
+ THROW_FAIL_IF_FALSE(expected == c);
+ }
+
+ void MarshalInt(_In_ INumericTesting *numericTesting, _In_ int32_t a, _In_ int32_t b)
+ {
+ HRESULT hr;
+
+ int32_t expected = a + b;
+ ::printf("Int test invariant: %d + %d = %d\n", a, b, expected);
+
+ int32_t c;
+ THROW_IF_FAILED(numericTesting->raw_Add_Int(a, b, &c));
+ THROW_FAIL_IF_FALSE(expected == c);
+
+ c = std::numeric_limits<decltype(c)>::max();
+ THROW_IF_FAILED(numericTesting->raw_Add_Int_Ref(a, b, &c));
+ THROW_FAIL_IF_FALSE(expected == c);
+
+ c = 0;
+ THROW_IF_FAILED(numericTesting->raw_Add_Int_Out(a, b, &c));
+ THROW_FAIL_IF_FALSE(expected == c);
+ }
+
+ void MarshalUInt(_In_ INumericTesting *numericTesting, _In_ uint32_t a, _In_ uint32_t b)
+ {
+ HRESULT hr;
+
+ uint32_t expected = a + b;
+ ::printf("UInt test invariant: %u + %u = %u\n", a, b, expected);
+
+ uint32_t c;
+ THROW_IF_FAILED(numericTesting->raw_Add_UInt(a, b, &c));
+ THROW_FAIL_IF_FALSE(expected == c);
+
+ c = std::numeric_limits<decltype(c)>::max();
+ THROW_IF_FAILED(numericTesting->raw_Add_UInt_Ref(a, b, &c));
+ THROW_FAIL_IF_FALSE(expected == c);
+
+ c = 0;
+ THROW_IF_FAILED(numericTesting->raw_Add_UInt_Out(a, b, &c));
+ THROW_FAIL_IF_FALSE(expected == c);
+ }
+
+ void MarshalLong(_In_ INumericTesting *numericTesting, _In_ int64_t a, _In_ int64_t b)
+ {
+ HRESULT hr;
+
+ int64_t expected = a + b;
+ ::printf("Long test invariant: %lld + %lld = %lld\n", a, b, expected);
+
+ int64_t c;
+ THROW_IF_FAILED(numericTesting->raw_Add_Long(a, b, &c));
+ THROW_FAIL_IF_FALSE(expected == c);
+
+ c = std::numeric_limits<decltype(c)>::max();
+ THROW_IF_FAILED(numericTesting->raw_Add_Long_Ref(a, b, &c));
+ THROW_FAIL_IF_FALSE(expected == c);
+
+ c = 0;
+ THROW_IF_FAILED(numericTesting->raw_Add_Long_Out(a, b, &c));
+ THROW_FAIL_IF_FALSE(expected == c);
+ }
+
+ void MarshalULong(_In_ INumericTesting *numericTesting, _In_ uint64_t a, _In_ uint64_t b)
+ {
+ HRESULT hr;
+
+ uint64_t expected = a + b;
+ ::printf("ULong test invariant: %llu + %llu = %llu\n", a, b, expected);
+
+ uint64_t c;
+ THROW_IF_FAILED(numericTesting->raw_Add_ULong(a, b, &c));
+ THROW_FAIL_IF_FALSE(expected == c);
+
+ c = std::numeric_limits<decltype(c)>::max();
+ THROW_IF_FAILED(numericTesting->raw_Add_ULong_Ref(a, b, &c));
+ THROW_FAIL_IF_FALSE(expected == c);
+
+ c = 0;
+ THROW_IF_FAILED(numericTesting->raw_Add_ULong_Out(a, b, &c));
+ THROW_FAIL_IF_FALSE(expected == c);
+ }
+
+ template<typename T>
+ bool EqualByBound(_In_ T expected, _In_ T actual)
+ {
+ T low = expected - (T)0.0001;
+ T high = expected + (T)0.0001;
+ T eps = std::abs(expected - actual);
+ return (eps < std::numeric_limits<T>::epsilon() || (low < actual && actual < high));
+ }
+
+ void MarshalFloat(_In_ INumericTesting *numericTesting, _In_ float a, _In_ float b)
+ {
+ HRESULT hr;
+
+ float expected = a + b;
+ ::printf("Float test invariant: %f + %f = %f\n", a, b, expected);
+
+ float c;
+ THROW_IF_FAILED(numericTesting->raw_Add_Float(a, b, &c));
+ THROW_FAIL_IF_FALSE(EqualByBound(expected, c));
+
+ c = std::numeric_limits<decltype(c)>::max();
+ THROW_IF_FAILED(numericTesting->raw_Add_Float_Ref(a, b, &c));
+ THROW_FAIL_IF_FALSE(EqualByBound(expected, c));
+
+ c = 0;
+ THROW_IF_FAILED(numericTesting->raw_Add_Float_Out(a, b, &c));
+ THROW_FAIL_IF_FALSE(EqualByBound(expected, c));
+ }
+
+ void MarshalDouble(_In_ INumericTesting *numericTesting, _In_ double a, _In_ double b)
+ {
+ HRESULT hr;
+
+ double expected = a + b;
+ ::printf("Double test invariant: %f + %f = %f\n", a, b, expected);
+
+ double c;
+ THROW_IF_FAILED(numericTesting->raw_Add_Double(a, b, &c));
+ THROW_FAIL_IF_FALSE(EqualByBound(expected, c));
+
+ c = std::numeric_limits<decltype(c)>::max();
+ THROW_IF_FAILED(numericTesting->raw_Add_Double_Ref(a, b, &c));
+ THROW_FAIL_IF_FALSE(EqualByBound(expected, c));
+
+ c = 0;
+ THROW_IF_FAILED(numericTesting->raw_Add_Double_Out(a, b, &c));
+ THROW_FAIL_IF_FALSE(EqualByBound(expected, c));
+ }
+}
+
+void Run_NumericTests()
+{
+ HRESULT hr;
+
+ CoreShimComActivation csact{ W("NETServer.dll"), W("NumericTesting") };
+
+ ComSmartPtr<INumericTesting> numericTesting;
+ THROW_IF_FAILED(::CoCreateInstance(CLSID_NumericTesting, nullptr, CLSCTX_INPROC, IID_INumericTesting, (void**)&numericTesting));
+
+ int seed = 37;
+ ::srand(seed);
+
+ ::printf("Numeric RNG seed: %d\n", seed);
+
+ int a = ::rand();
+ int b = ::rand();
+
+ MarshalByte(numericTesting, (byte)a, (byte)b);
+ MarshalShort(numericTesting, (int16_t)a, (int16_t)b);
+ MarshalUShort(numericTesting, (uint16_t)a, (uint16_t)b);
+ MarshalInt(numericTesting, a, b);
+ MarshalUInt(numericTesting, (uint32_t)a, (uint32_t)b);
+ MarshalLong(numericTesting, (int64_t)a, (int64_t)b);
+ MarshalULong(numericTesting, (uint64_t)a, (uint64_t)b);
+ MarshalFloat(numericTesting, (float)a / 100.f, (float)b / 100.f);
+ MarshalDouble(numericTesting, (double)a / 100.0, (double)b / 100.0);
+}
diff --git a/tests/src/Interop/COM/NativeClients/Primitives/StringTests.cpp b/tests/src/Interop/COM/NativeClients/Primitives/StringTests.cpp
new file mode 100644
index 0000000000..a9dad99668
--- /dev/null
+++ b/tests/src/Interop/COM/NativeClients/Primitives/StringTests.cpp
@@ -0,0 +1,422 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "ClientTests.h"
+#include <vector>
+#include <sstream>
+
+namespace
+{
+ template
+ <
+ typename CT,
+ void*(*STR_ALLOC)(size_t),
+ void(*STR_FREE)(void*)
+ >
+ class AnyStr
+ {
+ public:
+ AnyStr() : _lenBytes{ 0 } , _str{ nullptr }
+ { }
+
+ explicit AnyStr(_In_z_ const char *str)
+ : _lenBytes{ (::strlen(str) + 1) * sizeof(CT) }
+ {
+ _str = (CT *)STR_ALLOC(_lenBytes);
+ CT *strLocal = _str;
+
+ while (*str)
+ {
+ // [TODO] handle UTF8
+ *strLocal = static_cast<CT>(*str++);
+ strLocal++;
+ }
+ *strLocal = CT{ '\0' };
+ }
+
+ // Concat strings
+ AnyStr(_In_ const AnyStr &l, _In_ const AnyStr &r)
+ : _lenBytes{ l._lenBytes + r._lenBytes - sizeof(CT) } // Remove duplicate null
+ {
+ _str = (CT *)STR_ALLOC(_lenBytes);
+ CT *strLocal = _str;
+ std::memcpy(strLocal, l._str, l._lenBytes - sizeof(CT)); // Ignore null
+
+ size_t l_len = l.Length();
+ std::memcpy(strLocal + l_len, r._str, r._lenBytes);
+ }
+
+ AnyStr(_In_ const AnyStr &other)
+ : _lenBytes{ other._lenBytes }
+ , _str{ (CT *)STR_ALLOC(other._lenBytes) }
+ {
+ std::memcpy(_str, other._str, _lenBytes);
+ }
+
+ AnyStr& operator=(_In_ const AnyStr &other)
+ {
+ AnyStr old{ std::move(*this) };
+ AnyStr otherCopy{ other };
+ (*this) = std::move(otherCopy);
+ return (*this);
+ }
+
+ AnyStr(_Inout_ AnyStr &&other)
+ : _lenBytes{ other._lenBytes }
+ , _str{ other._str }
+ {
+ other._str = nullptr;
+ }
+
+ AnyStr& operator=(_Inout_ AnyStr &&other)
+ {
+ AnyStr tmp{ std::move(*this) };
+ _lenBytes = other._lenBytes;
+ _str = other._str;
+ other._str = nullptr;
+ return (*this);
+ }
+
+ ~AnyStr()
+ {
+ if (_str != nullptr)
+ STR_FREE(_str);
+ }
+
+ operator CT*()
+ {
+ return _str;
+ }
+
+ operator const CT*() const
+ {
+ return _str;
+ }
+
+ CT** operator &()
+ {
+ return &_str;
+ }
+
+ bool operator==(_In_ const AnyStr &other) const
+ {
+ return EqualTo(other._str);
+ }
+
+ bool operator!=(_In_ const AnyStr &other) const
+ {
+ return !(*this == other);
+ }
+
+ void Attach(_In_z_ CT *data)
+ {
+ AnyStr tmp{ std::move(*this) };
+
+ CT *dataIter = data;
+ int len = 1; // Include 1 for null
+ while (*dataIter++)
+ ++len;
+
+ _str = data;
+ _lenBytes = len * sizeof(CT);
+ }
+
+ // String length _not_ including null
+ size_t Length() const
+ {
+ if (_lenBytes == 0)
+ return 0;
+
+ return (_lenBytes - sizeof(CT)) / sizeof(CT);
+ }
+
+ // String length including null in bytes
+ size_t LengthByte() const
+ {
+ return _lenBytes;
+ }
+
+ bool AllAscii() const
+ {
+ const CT *c = _str;
+ const CT MaxAscii = (CT)0x7f;
+ while (*c)
+ {
+ if ((*c++) > MaxAscii)
+ return false;
+ }
+
+ return true;
+ }
+
+ bool EqualTo(_In_z_ const CT *str) const
+ {
+ const CT *tmp = str;
+ int len = 1; // Include 1 for null
+ while (*tmp++)
+ ++len;
+
+ if (_lenBytes != (sizeof(CT) * len))
+ return false;
+
+ return (0 == std::memcmp(_str, str, _lenBytes));
+ }
+
+ HRESULT Reverse(_Inout_ AnyStr &res) const
+ {
+ AnyStr tmp{};
+
+ if (_lenBytes > 0)
+ {
+ tmp._lenBytes = _lenBytes;
+ tmp._str = (CT *)STR_ALLOC(_lenBytes);
+ if (tmp._str == nullptr)
+ return E_OUTOFMEMORY;
+
+ ::memcpy(tmp._str, _str, _lenBytes);
+ std::reverse(tmp._str, tmp._str + Length());
+ }
+
+ res = std::move(tmp);
+ return S_OK;
+ }
+
+ private:
+ size_t _lenBytes;
+ CT *_str;
+ };
+
+ // BSTR string
+ using BStr = AnyStr<OLECHAR, &CoreClrBstrAlloc, &CoreClrBstrFree>;
+
+ // Wide string
+ using WStr = AnyStr<WCHAR, &CoreClrAlloc, &CoreClrFree>;
+
+ // Narrow string
+ using NStr = AnyStr<CHAR, &CoreClrAlloc, &CoreClrFree>;
+
+ template <typename STR>
+ std::vector<std::pair<STR, STR>> GetAddPairs()
+ {
+ std::vector<std::pair<STR, STR>> pairs;
+
+ pairs.push_back({ STR{ "" }, STR{ "" } });
+ pairs.push_back({ STR{ "" }, STR{ "def" } });
+ pairs.push_back({ STR{ "abc" }, STR{ "" } });
+ pairs.push_back({ STR{ "abc" }, STR{ "def" } });
+
+ // String marshalling is optimized where strings shorter than MAX_PATH are
+ // allocated on the stack. Longer strings have memory allocated for them.
+ pairs.push_back({
+ STR{ "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901" },
+ STR{ "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901" }
+ });
+
+ return pairs;
+ }
+
+ template <typename STR>
+ std::vector<STR> GetReversableStrings()
+ {
+ std::vector<STR> rev;
+
+ rev.push_back(STR{ "" });
+ rev.push_back(STR{ "a" });
+ rev.push_back(STR{ "abc" });
+ rev.push_back(STR{ "reversable string" });
+
+ // Long string optimization validation
+ rev.push_back(STR{ "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901" });
+
+ return rev;
+ }
+
+ void Marshal_LPString(_In_ IStringTesting* stringTesting)
+ {
+ ::printf("Marshal strings as LPStr\n");
+
+ HRESULT hr;
+
+ auto pairs = GetAddPairs<NStr>();
+ for (auto &p : pairs)
+ {
+ if (!p.first.AllAscii() || !p.second.AllAscii())
+ {
+ // LPStr doesn't support non-ascii characters
+ continue;
+ }
+
+ LPSTR tmp;
+ NStr expected{ p.first, p.second };
+ THROW_IF_FAILED(stringTesting->raw_Add_LPStr(p.first, p.second, &tmp));
+
+ NStr actual;
+ actual.Attach(tmp);
+ THROW_FAIL_IF_FALSE(expected.EqualTo(actual));
+ }
+
+ auto reversable = GetReversableStrings<NStr>();
+ for (const auto &r : reversable)
+ {
+ if (!r.AllAscii())
+ {
+ // LPStr doesn't support non-ascii characters
+ continue;
+ }
+
+ LPSTR tmp;
+ NStr local{ r };
+
+ NStr actual;
+ NStr expected;
+ THROW_IF_FAILED(r.Reverse(expected));
+
+ THROW_IF_FAILED(stringTesting->raw_Reverse_LPStr(local, &tmp));
+ actual.Attach(tmp);
+ THROW_FAIL_IF_FALSE(expected == actual);
+
+ THROW_IF_FAILED(stringTesting->raw_Reverse_LPStr_Ref(&local, &tmp));
+ actual.Attach(tmp);
+ THROW_FAIL_IF_FALSE(expected == actual);
+ THROW_FAIL_IF_FALSE(r == local); // Local should not be changed
+
+ local = r;
+ THROW_IF_FAILED(stringTesting->raw_Reverse_LPStr_InRef(&local, &tmp));
+ actual.Attach(tmp);
+ THROW_FAIL_IF_FALSE(expected == actual);
+ THROW_FAIL_IF_FALSE(r == local); // Local should not be changed
+
+ THROW_IF_FAILED(stringTesting->raw_Reverse_LPStr_Out(local, &tmp));
+ actual.Attach(tmp);
+ THROW_FAIL_IF_FALSE(expected == actual);
+
+ actual = local;
+ tmp = actual;
+ THROW_IF_FAILED(stringTesting->raw_Reverse_LPStr_OutAttr(local, tmp)); // No-op for strings
+ THROW_FAIL_IF_FALSE(local == actual);
+ }
+ }
+
+ void Marshal_LPWString(_In_ IStringTesting* stringTesting)
+ {
+ ::printf("Marshal strings as LPWStr\n");
+
+ HRESULT hr;
+
+ auto pairs = GetAddPairs<WStr>();
+ for (auto &p : pairs)
+ {
+ LPWSTR tmp;
+ WStr expected{ p.first, p.second };
+ THROW_IF_FAILED(stringTesting->raw_Add_LPWStr(p.first, p.second, &tmp));
+
+ WStr actual;
+ actual.Attach(tmp);
+ THROW_FAIL_IF_FALSE(expected.EqualTo(actual));
+ }
+
+ auto reversable = GetReversableStrings<WStr>();
+ for (const auto &r : reversable)
+ {
+ LPWSTR tmp;
+ WStr local{ r };
+
+ WStr actual;
+ WStr expected;
+ THROW_IF_FAILED(r.Reverse(expected));
+
+ THROW_IF_FAILED(stringTesting->raw_Reverse_LPWStr(local, &tmp));
+ actual.Attach(tmp);
+ THROW_FAIL_IF_FALSE(expected == actual);
+
+ THROW_IF_FAILED(stringTesting->raw_Reverse_LPWStr_Ref(&local, &tmp));
+ actual.Attach(tmp);
+ THROW_FAIL_IF_FALSE(expected == actual);
+ THROW_FAIL_IF_FALSE(r == local); // Local should not be changed
+
+ local = r;
+ THROW_IF_FAILED(stringTesting->raw_Reverse_LPWStr_InRef(&local, &tmp));
+ actual.Attach(tmp);
+ THROW_FAIL_IF_FALSE(expected == actual);
+ THROW_FAIL_IF_FALSE(r == local); // Local should not be changed
+
+ THROW_IF_FAILED(stringTesting->raw_Reverse_LPWStr_Out(local, &tmp));
+ actual.Attach(tmp);
+ THROW_FAIL_IF_FALSE(expected == actual);
+
+ actual = local;
+ tmp = actual;
+ THROW_IF_FAILED(stringTesting->raw_Reverse_LPWStr_OutAttr(local, tmp)); // No-op for strings
+ THROW_FAIL_IF_FALSE(local == actual);
+ }
+ }
+
+ void Marshal_BStrString(_In_ IStringTesting* stringTesting)
+ {
+ ::printf("Marshal strings as BStr\n");
+
+ HRESULT hr;
+
+ auto pairs = GetAddPairs<BStr>();
+ for (auto &p : pairs)
+ {
+ BSTR tmp;
+ BStr expected{ p.first, p.second };
+ THROW_IF_FAILED(stringTesting->raw_Add_BStr(p.first, p.second, &tmp));
+
+ BStr actual;
+ actual.Attach(tmp);
+ THROW_FAIL_IF_FALSE(expected.EqualTo(actual));
+ }
+
+ auto reversable = GetReversableStrings<BStr>();
+ for (const auto &r : reversable)
+ {
+ BSTR tmp;
+ BStr local{ r };
+
+ BStr actual;
+ BStr expected;
+ THROW_IF_FAILED(r.Reverse(expected));
+
+ THROW_IF_FAILED(stringTesting->raw_Reverse_BStr(local, &tmp));
+ actual.Attach(tmp);
+ THROW_FAIL_IF_FALSE(expected == actual);
+
+ THROW_IF_FAILED(stringTesting->raw_Reverse_BStr_Ref(&local, &tmp));
+ actual.Attach(tmp);
+ THROW_FAIL_IF_FALSE(expected == actual);
+ THROW_FAIL_IF_FALSE(r == local); // Local should not be changed
+
+ local = r;
+ THROW_IF_FAILED(stringTesting->raw_Reverse_BStr_InRef(&local, &tmp));
+ actual.Attach(tmp);
+ THROW_FAIL_IF_FALSE(expected == actual);
+ THROW_FAIL_IF_FALSE(r == local); // Local should not be changed
+
+ THROW_IF_FAILED(stringTesting->raw_Reverse_BStr_Out(local, &tmp));
+ actual.Attach(tmp);
+ THROW_FAIL_IF_FALSE(expected == actual);
+
+ actual = local;
+ tmp = actual;
+ THROW_IF_FAILED(stringTesting->raw_Reverse_BStr_OutAttr(local, tmp)); // No-op for strings
+ THROW_FAIL_IF_FALSE(local == actual);
+ }
+ }
+}
+
+void Run_StringTests()
+{
+ HRESULT hr;
+
+ CoreShimComActivation csact{ W("NETServer.dll"), W("StringTesting") };
+
+ ComSmartPtr<IStringTesting> stringTesting;
+ THROW_IF_FAILED(::CoCreateInstance(CLSID_StringTesting, nullptr, CLSCTX_INPROC, IID_IStringTesting, (void**)&stringTesting));
+
+ Marshal_LPString(stringTesting);
+ Marshal_LPWString(stringTesting);
+ Marshal_BStrString(stringTesting);
+}
diff --git a/tests/src/Interop/COM/NativeServer/ArrayTesting.h b/tests/src/Interop/COM/NativeServer/ArrayTesting.h
index 6939762a8b..27d02396a2 100644
--- a/tests/src/Interop/COM/NativeServer/ArrayTesting.h
+++ b/tests/src/Interop/COM/NativeServer/ArrayTesting.h
@@ -20,7 +20,7 @@ private:
return (t / l);
}
template<VARTYPE E>
- HRESULT Mean(SAFEARRAY *d, long *l, double *r)
+ HRESULT Mean(SAFEARRAY *d, int *l, double *r)
{
HRESULT hr;
@@ -74,7 +74,7 @@ private:
public: // IArrayTesting
DEF_RAWFUNC(Mean_Byte_LP_PreLen)(
- /*[in]*/ long len,
+ /*[in]*/ int len,
/*[in]*/ unsigned char * d,
/*[out,retval]*/ double * pRetVal)
{
@@ -84,7 +84,7 @@ public: // IArrayTesting
return S_OK;
}
DEF_RAWFUNC(Mean_Short_LP_PreLen)(
- /*[in]*/ long len,
+ /*[in]*/ int len,
/*[in]*/ short * d,
/*[out,retval]*/ double * pRetVal)
{
@@ -94,7 +94,7 @@ public: // IArrayTesting
return S_OK;
}
DEF_RAWFUNC(Mean_UShort_LP_PreLen)(
- /*[in]*/ long len,
+ /*[in]*/ int len,
/*[in]*/ unsigned short * d,
/*[out,retval]*/ double * pRetVal)
{
@@ -104,8 +104,8 @@ public: // IArrayTesting
return S_OK;
}
DEF_RAWFUNC(Mean_Int_LP_PreLen)(
- /*[in]*/ long len,
- /*[in]*/ long * d,
+ /*[in]*/ int len,
+ /*[in]*/ int * d,
/*[out,retval]*/ double * pRetVal)
{
if (pRetVal == nullptr)
@@ -114,8 +114,8 @@ public: // IArrayTesting
return S_OK;
}
DEF_RAWFUNC(Mean_UInt_LP_PreLen)(
- /*[in]*/ long len,
- /*[in]*/ unsigned long * d,
+ /*[in]*/ int len,
+ /*[in]*/ unsigned int * d,
/*[out,retval]*/ double * pRetVal)
{
if (pRetVal == nullptr)
@@ -124,7 +124,7 @@ public: // IArrayTesting
return S_OK;
}
DEF_RAWFUNC(Mean_Long_LP_PreLen)(
- /*[in]*/ long len,
+ /*[in]*/ int len,
/*[in]*/ __int64 * d,
/*[out,retval]*/ double * pRetVal)
{
@@ -134,7 +134,7 @@ public: // IArrayTesting
return S_OK;
}
DEF_RAWFUNC(Mean_ULong_LP_PreLen)(
- /*[in]*/ long len,
+ /*[in]*/ int len,
/*[in]*/ unsigned __int64 * d,
/*[out,retval]*/ double * pRetVal)
{
@@ -144,7 +144,7 @@ public: // IArrayTesting
return S_OK;
}
DEF_RAWFUNC(Mean_Float_LP_PreLen)(
- /*[in]*/ long len,
+ /*[in]*/ int len,
/*[in]*/ float * d,
/*[out,retval]*/ double * pRetVal)
{
@@ -154,7 +154,7 @@ public: // IArrayTesting
return S_OK;
}
DEF_RAWFUNC(Mean_Double_LP_PreLen)(
- /*[in]*/ long len,
+ /*[in]*/ int len,
/*[in]*/ double * d,
/*[out,retval]*/ double * pRetVal)
{
@@ -165,7 +165,7 @@ public: // IArrayTesting
}
DEF_RAWFUNC(Mean_Byte_LP_PostLen)(
/*[in]*/ unsigned char * d,
- /*[in]*/ long len,
+ /*[in]*/ int len,
/*[out,retval]*/ double * pRetVal)
{
if (pRetVal == nullptr)
@@ -175,7 +175,7 @@ public: // IArrayTesting
}
DEF_RAWFUNC(Mean_Short_LP_PostLen)(
/*[in]*/ short * d,
- /*[in]*/ long len,
+ /*[in]*/ int len,
/*[out,retval]*/ double * pRetVal)
{
if (pRetVal == nullptr)
@@ -185,7 +185,7 @@ public: // IArrayTesting
}
DEF_RAWFUNC(Mean_UShort_LP_PostLen)(
/*[in]*/ unsigned short * d,
- /*[in]*/ long len,
+ /*[in]*/ int len,
/*[out,retval]*/ double * pRetVal)
{
if (pRetVal == nullptr)
@@ -194,8 +194,8 @@ public: // IArrayTesting
return S_OK;
}
DEF_RAWFUNC(Mean_Int_LP_PostLen)(
- /*[in]*/ long * d,
- /*[in]*/ long len,
+ /*[in]*/ int * d,
+ /*[in]*/ int len,
/*[out,retval]*/ double * pRetVal)
{
if (pRetVal == nullptr)
@@ -204,8 +204,8 @@ public: // IArrayTesting
return S_OK;
}
DEF_RAWFUNC(Mean_UInt_LP_PostLen)(
- /*[in]*/ unsigned long * d,
- /*[in]*/ long len,
+ /*[in]*/ unsigned int * d,
+ /*[in]*/ int len,
/*[out,retval]*/ double * pRetVal)
{
if (pRetVal == nullptr)
@@ -215,7 +215,7 @@ public: // IArrayTesting
}
DEF_RAWFUNC(Mean_Long_LP_PostLen)(
/*[in]*/ __int64 * d,
- /*[in]*/ long len,
+ /*[in]*/ int len,
/*[out,retval]*/ double * pRetVal)
{
if (pRetVal == nullptr)
@@ -225,7 +225,7 @@ public: // IArrayTesting
}
DEF_RAWFUNC(Mean_ULong_LP_PostLen)(
/*[in]*/ unsigned __int64 * d,
- /*[in]*/ long len,
+ /*[in]*/ int len,
/*[out,retval]*/ double * pRetVal)
{
if (pRetVal == nullptr)
@@ -235,7 +235,7 @@ public: // IArrayTesting
}
DEF_RAWFUNC(Mean_Float_LP_PostLen)(
/*[in]*/ float * d,
- /*[in]*/ long len,
+ /*[in]*/ int len,
/*[out,retval]*/ double * pRetVal)
{
if (pRetVal == nullptr)
@@ -245,7 +245,7 @@ public: // IArrayTesting
}
DEF_RAWFUNC(Mean_Double_LP_PostLen)(
/*[in]*/ double * d,
- /*[in]*/ long len,
+ /*[in]*/ int len,
/*[out,retval]*/ double * pRetVal)
{
if (pRetVal == nullptr)
@@ -255,7 +255,7 @@ public: // IArrayTesting
}
DEF_RAWFUNC(Mean_Byte_SafeArray_OutLen)(
/*[in]*/ SAFEARRAY * d,
- /*[out]*/ long * len,
+ /*[out]*/ int * len,
/*[out,retval]*/ double * pRetVal)
{
if (pRetVal == nullptr)
@@ -264,7 +264,7 @@ public: // IArrayTesting
}
DEF_RAWFUNC(Mean_Short_SafeArray_OutLen)(
/*[in]*/ SAFEARRAY * d,
- /*[out]*/ long * len,
+ /*[out]*/ int * len,
/*[out,retval]*/ double * pRetVal)
{
if (pRetVal == nullptr)
@@ -273,7 +273,7 @@ public: // IArrayTesting
}
DEF_RAWFUNC(Mean_UShort_SafeArray_OutLen)(
/*[in]*/ SAFEARRAY * d,
- /*[out]*/ long * len,
+ /*[out]*/ int * len,
/*[out,retval]*/ double * pRetVal)
{
if (pRetVal == nullptr)
@@ -282,7 +282,7 @@ public: // IArrayTesting
}
DEF_RAWFUNC(Mean_Int_SafeArray_OutLen)(
/*[in]*/ SAFEARRAY * d,
- /*[out]*/ long * len,
+ /*[out]*/ int * len,
/*[out,retval]*/ double * pRetVal)
{
if (pRetVal == nullptr)
@@ -291,7 +291,7 @@ public: // IArrayTesting
}
DEF_RAWFUNC(Mean_UInt_SafeArray_OutLen)(
/*[in]*/ SAFEARRAY * d,
- /*[out]*/ long * len,
+ /*[out]*/ int * len,
/*[out,retval]*/ double * pRetVal)
{
if (pRetVal == nullptr)
@@ -300,7 +300,7 @@ public: // IArrayTesting
}
DEF_RAWFUNC(Mean_Long_SafeArray_OutLen)(
/*[in]*/ SAFEARRAY * d,
- /*[out]*/ long * len,
+ /*[out]*/ int * len,
/*[out,retval]*/ double * pRetVal)
{
if (pRetVal == nullptr)
@@ -309,7 +309,7 @@ public: // IArrayTesting
}
DEF_RAWFUNC(Mean_ULong_SafeArray_OutLen)(
/*[in]*/ SAFEARRAY * d,
- /*[out]*/ long * len,
+ /*[out]*/ int * len,
/*[out,retval]*/ double * pRetVal)
{
if (pRetVal == nullptr)
@@ -318,7 +318,7 @@ public: // IArrayTesting
}
DEF_RAWFUNC(Mean_Float_SafeArray_OutLen)(
/*[in]*/ SAFEARRAY * d,
- /*[out]*/ long * len,
+ /*[out]*/ int * len,
/*[out,retval]*/ double * pRetVal)
{
if (pRetVal == nullptr)
@@ -327,7 +327,7 @@ public: // IArrayTesting
}
DEF_RAWFUNC(Mean_Double_SafeArray_OutLen)(
/*[in]*/ SAFEARRAY * d,
- /*[out]*/ long * len,
+ /*[out]*/ int * len,
/*[out,retval]*/ double * pRetVal)
{
if (pRetVal == nullptr)
diff --git a/tests/src/Interop/COM/NativeServer/ErrorMarshalTesting.h b/tests/src/Interop/COM/NativeServer/ErrorMarshalTesting.h
index 6dd76490c7..2b1276c989 100644
--- a/tests/src/Interop/COM/NativeServer/ErrorMarshalTesting.h
+++ b/tests/src/Interop/COM/NativeServer/ErrorMarshalTesting.h
@@ -10,12 +10,13 @@ class ErrorMarshalTesting : public UnknownImpl, public IErrorMarshalTesting
{
public: // IErrorMarshalTesting
DEF_RAWFUNC(Throw_HResult)(
- /*[in]*/ long hresultToReturn)
+ /*[in]*/ int hresultToReturn)
{
return HRESULT{ hresultToReturn };
}
- long STDMETHODCALLTYPE Return_As_HResult(
- /*[in]*/ long hresultToReturn)
+
+ int STDMETHODCALLTYPE Return_As_HResult(
+ /*[in]*/ int hresultToReturn)
{
return hresultToReturn;
}
diff --git a/tests/src/Interop/COM/NativeServer/NumericTesting.h b/tests/src/Interop/COM/NativeServer/NumericTesting.h
index 555a38d0c4..1f4acf9b0f 100644
--- a/tests/src/Interop/COM/NativeServer/NumericTesting.h
+++ b/tests/src/Interop/COM/NativeServer/NumericTesting.h
@@ -36,17 +36,17 @@ public:
return S_OK;
}
DEF_RAWFUNC(Add_Int)(
- /*[in]*/ long a,
- /*[in]*/ long b,
- /*[out,retval]*/ long * pRetVal)
+ /*[in]*/ int a,
+ /*[in]*/ int b,
+ /*[out,retval]*/ int * pRetVal)
{
*pRetVal = a + b;
return S_OK;
}
DEF_RAWFUNC(Add_UInt)(
- /*[in]*/ unsigned long a,
- /*[in]*/ unsigned long b,
- /*[out,retval]*/ unsigned long * pRetVal)
+ /*[in]*/ unsigned int a,
+ /*[in]*/ unsigned int b,
+ /*[out,retval]*/ unsigned int * pRetVal)
{
*pRetVal = a + b;
return S_OK;
@@ -114,9 +114,9 @@ public:
return S_OK;
}
DEF_RAWFUNC(Add_Int_Ref)(
- /*[in]*/ long a,
- /*[in]*/ long b,
- /*[in,out]*/ long * c)
+ /*[in]*/ int a,
+ /*[in]*/ int b,
+ /*[in,out]*/ int * c)
{
if (*c != std::numeric_limits<std::remove_reference<decltype(*c)>::type>::max())
return E_UNEXPECTED;
@@ -124,9 +124,9 @@ public:
return S_OK;
}
DEF_RAWFUNC(Add_UInt_Ref)(
- /*[in]*/ unsigned long a,
- /*[in]*/ unsigned long b,
- /*[in,out]*/ unsigned long * c)
+ /*[in]*/ unsigned int a,
+ /*[in]*/ unsigned int b,
+ /*[in,out]*/ unsigned int * c)
{
if (*c != std::numeric_limits<std::remove_reference<decltype(*c)>::type>::max())
return E_UNEXPECTED;
@@ -198,17 +198,17 @@ public:
return S_OK;
}
DEF_RAWFUNC(Add_Int_Out)(
- /*[in]*/ long a,
- /*[in]*/ long b,
- /*[out]*/ long * c)
+ /*[in]*/ int a,
+ /*[in]*/ int b,
+ /*[out]*/ int * c)
{
*c = a + b;
return S_OK;
}
DEF_RAWFUNC(Add_UInt_Out)(
- /*[in]*/ unsigned long a,
- /*[in]*/ unsigned long b,
- /*[out]*/ unsigned long * c)
+ /*[in]*/ unsigned int a,
+ /*[in]*/ unsigned int b,
+ /*[out]*/ unsigned int * c)
{
*c = a + b;
return S_OK;
diff --git a/tests/src/Interop/COM/NativeServer/Servers.h b/tests/src/Interop/COM/NativeServer/Servers.h
index bcfdbe2c5f..4f279e0a14 100644
--- a/tests/src/Interop/COM/NativeServer/Servers.h
+++ b/tests/src/Interop/COM/NativeServer/Servers.h
@@ -5,6 +5,7 @@
#pragma once
#include <xplatform.h>
+#include <cassert>
//#import "Server.Contract.tlb" no_namespace
#include <Server.Contracts.tlh>
@@ -25,6 +26,29 @@ class DECLSPEC_UUID("71CF5C45-106C-4B32-B418-43A463C6041F") ErrorMarshalTesting;
#define IID_IStringTesting __uuidof(IStringTesting)
#define IID_IErrorMarshalTesting __uuidof(IErrorMarshalTesting)
+// Class used for COM activation when using CoreShim
+struct CoreShimComActivation
+{
+ CoreShimComActivation(_In_z_ const WCHAR *assemblyName, _In_z_ const WCHAR *typeName)
+ {
+ assert(assemblyName && typeName);
+ Set(assemblyName, typeName);
+ }
+
+ ~CoreShimComActivation()
+ {
+ Set(nullptr, nullptr);
+ }
+
+private:
+ void Set(_In_opt_z_ const WCHAR *assemblyName, _In_opt_z_ const WCHAR *typeName)
+ {
+ // See CoreShim.h for usage of environment variables
+ ::SetEnvironmentVariableW(W("CORESHIM_COMACT_ASSEMBLYNAME"), assemblyName);
+ ::SetEnvironmentVariableW(W("CORESHIM_COMACT_TYPENAME"), typeName);
+ }
+};
+
#ifndef COM_CLIENT
#include "ComHelpers.h"
diff --git a/tests/src/Interop/COM/ServerContracts/Primitives.cs b/tests/src/Interop/COM/ServerContracts/Primitives.cs
index cc6a30344b..0714047003 100644
--- a/tests/src/Interop/COM/ServerContracts/Primitives.cs
+++ b/tests/src/Interop/COM/ServerContracts/Primitives.cs
@@ -51,25 +51,25 @@ namespace Server.Contract
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IArrayTesting
{
- double Mean_Byte_LP_PreLen(int len, [MarshalAs(UnmanagedType.LPArray)] byte[] d);
- double Mean_Short_LP_PreLen(int len, [MarshalAs(UnmanagedType.LPArray)] short[] d);
- double Mean_UShort_LP_PreLen(int len, [MarshalAs(UnmanagedType.LPArray)] ushort[] d);
- double Mean_Int_LP_PreLen(int len, [MarshalAs(UnmanagedType.LPArray)] int[] d);
- double Mean_UInt_LP_PreLen(int len, [MarshalAs(UnmanagedType.LPArray)] uint[] d);
- double Mean_Long_LP_PreLen(int len, [MarshalAs(UnmanagedType.LPArray)] long[] d);
- double Mean_ULong_LP_PreLen(int len, [MarshalAs(UnmanagedType.LPArray)] ulong[] d);
- double Mean_Float_LP_PreLen(int len, [MarshalAs(UnmanagedType.LPArray)] float[] d);
- double Mean_Double_LP_PreLen(int len, [MarshalAs(UnmanagedType.LPArray)] double[] d);
-
- double Mean_Byte_LP_PostLen([MarshalAs(UnmanagedType.LPArray)] byte[] d, int len);
- double Mean_Short_LP_PostLen([MarshalAs(UnmanagedType.LPArray)] short[] d, int len);
- double Mean_UShort_LP_PostLen([MarshalAs(UnmanagedType.LPArray)] ushort[] d, int len);
- double Mean_Int_LP_PostLen([MarshalAs(UnmanagedType.LPArray)] int[] d, int len);
- double Mean_UInt_LP_PostLen([MarshalAs(UnmanagedType.LPArray)] uint[] d, int len);
- double Mean_Long_LP_PostLen([MarshalAs(UnmanagedType.LPArray)] long[] d, int len);
- double Mean_ULong_LP_PostLen([MarshalAs(UnmanagedType.LPArray)] ulong[] d, int len);
- double Mean_Float_LP_PostLen([MarshalAs(UnmanagedType.LPArray)] float[] d, int len);
- double Mean_Double_LP_PostLen([MarshalAs(UnmanagedType.LPArray)] double[] d, int len);
+ double Mean_Byte_LP_PreLen(int len, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] byte[] d);
+ double Mean_Short_LP_PreLen(int len, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] short[] d);
+ double Mean_UShort_LP_PreLen(int len, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] ushort[] d);
+ double Mean_Int_LP_PreLen(int len, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] int[] d);
+ double Mean_UInt_LP_PreLen(int len, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] uint[] d);
+ double Mean_Long_LP_PreLen(int len, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] long[] d);
+ double Mean_ULong_LP_PreLen(int len, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] ulong[] d);
+ double Mean_Float_LP_PreLen(int len, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] float[] d);
+ double Mean_Double_LP_PreLen(int len, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] double[] d);
+
+ double Mean_Byte_LP_PostLen([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] byte[] d, int len);
+ double Mean_Short_LP_PostLen([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] short[] d, int len);
+ double Mean_UShort_LP_PostLen([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] ushort[] d, int len);
+ double Mean_Int_LP_PostLen([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] int[] d, int len);
+ double Mean_UInt_LP_PostLen([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] uint[] d, int len);
+ double Mean_Long_LP_PostLen([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] long[] d, int len);
+ double Mean_ULong_LP_PostLen([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] ulong[] d, int len);
+ double Mean_Float_LP_PostLen([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] float[] d, int len);
+ double Mean_Double_LP_PostLen([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] double[] d, int len);
double Mean_Byte_SafeArray_OutLen([MarshalAs(UnmanagedType.SafeArray)] byte[] d, out int len);
double Mean_Short_SafeArray_OutLen([MarshalAs(UnmanagedType.SafeArray)] short[] d, out int len);
diff --git a/tests/src/Interop/COM/ServerContracts/Server.Contracts.tlh b/tests/src/Interop/COM/ServerContracts/Server.Contracts.tlh
index 9bc826d766..412d352156 100644
--- a/tests/src/Interop/COM/ServerContracts/Server.Contracts.tlh
+++ b/tests/src/Interop/COM/ServerContracts/Server.Contracts.tlh
@@ -49,12 +49,12 @@ INumericTesting : IUnknown
unsigned short Add_UShort (
unsigned short a,
unsigned short b );
- long Add_Int (
- long a,
- long b );
- unsigned long Add_UInt (
- unsigned long a,
- unsigned long b );
+ int Add_Int (
+ int a,
+ int b );
+ unsigned int Add_UInt (
+ unsigned int a,
+ unsigned int b );
__int64 Add_Long (
__int64 a,
__int64 b );
@@ -80,13 +80,13 @@ INumericTesting : IUnknown
unsigned short b,
unsigned short * c );
HRESULT Add_Int_Ref (
- long a,
- long b,
- long * c );
+ int a,
+ int b,
+ int * c );
HRESULT Add_UInt_Ref (
- unsigned long a,
- unsigned long b,
- unsigned long * c );
+ unsigned int a,
+ unsigned int b,
+ unsigned int * c );
HRESULT Add_Long_Ref (
__int64 a,
__int64 b,
@@ -116,13 +116,13 @@ INumericTesting : IUnknown
unsigned short b,
unsigned short * c );
HRESULT Add_Int_Out (
- long a,
- long b,
- long * c );
+ int a,
+ int b,
+ int * c );
HRESULT Add_UInt_Out (
- unsigned long a,
- unsigned long b,
- unsigned long * c );
+ unsigned int a,
+ unsigned int b,
+ unsigned int * c );
HRESULT Add_Long_Out (
__int64 a,
__int64 b,
@@ -157,13 +157,13 @@ INumericTesting : IUnknown
/*[in]*/ unsigned short b,
/*[out,retval]*/ unsigned short * pRetVal ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Add_Int (
- /*[in]*/ long a,
- /*[in]*/ long b,
- /*[out,retval]*/ long * pRetVal ) = 0;
+ /*[in]*/ int a,
+ /*[in]*/ int b,
+ /*[out,retval]*/ int * pRetVal ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Add_UInt (
- /*[in]*/ unsigned long a,
- /*[in]*/ unsigned long b,
- /*[out,retval]*/ unsigned long * pRetVal ) = 0;
+ /*[in]*/ unsigned int a,
+ /*[in]*/ unsigned int b,
+ /*[out,retval]*/ unsigned int * pRetVal ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Add_Long (
/*[in]*/ __int64 a,
/*[in]*/ __int64 b,
@@ -193,13 +193,13 @@ INumericTesting : IUnknown
/*[in]*/ unsigned short b,
/*[in,out]*/ unsigned short * c ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Add_Int_Ref (
- /*[in]*/ long a,
- /*[in]*/ long b,
- /*[in,out]*/ long * c ) = 0;
+ /*[in]*/ int a,
+ /*[in]*/ int b,
+ /*[in,out]*/ int * c ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Add_UInt_Ref (
- /*[in]*/ unsigned long a,
- /*[in]*/ unsigned long b,
- /*[in,out]*/ unsigned long * c ) = 0;
+ /*[in]*/ unsigned int a,
+ /*[in]*/ unsigned int b,
+ /*[in,out]*/ unsigned int * c ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Add_Long_Ref (
/*[in]*/ __int64 a,
/*[in]*/ __int64 b,
@@ -229,13 +229,13 @@ INumericTesting : IUnknown
/*[in]*/ unsigned short b,
/*[out]*/ unsigned short * c ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Add_Int_Out (
- /*[in]*/ long a,
- /*[in]*/ long b,
- /*[out]*/ long * c ) = 0;
+ /*[in]*/ int a,
+ /*[in]*/ int b,
+ /*[out]*/ int * c ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Add_UInt_Out (
- /*[in]*/ unsigned long a,
- /*[in]*/ unsigned long b,
- /*[out]*/ unsigned long * c ) = 0;
+ /*[in]*/ unsigned int a,
+ /*[in]*/ unsigned int b,
+ /*[out]*/ unsigned int * c ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Add_Long_Out (
/*[in]*/ __int64 a,
/*[in]*/ __int64 b,
@@ -262,198 +262,198 @@ IArrayTesting : IUnknown
//
double Mean_Byte_LP_PreLen (
- long len,
+ int len,
unsigned char * d );
double Mean_Short_LP_PreLen (
- long len,
+ int len,
short * d );
double Mean_UShort_LP_PreLen (
- long len,
+ int len,
unsigned short * d );
double Mean_Int_LP_PreLen (
- long len,
- long * d );
+ int len,
+ int * d );
double Mean_UInt_LP_PreLen (
- long len,
- unsigned long * d );
+ int len,
+ unsigned int * d );
double Mean_Long_LP_PreLen (
- long len,
+ int len,
__int64 * d );
double Mean_ULong_LP_PreLen (
- long len,
+ int len,
unsigned __int64 * d );
double Mean_Float_LP_PreLen (
- long len,
+ int len,
float * d );
double Mean_Double_LP_PreLen (
- long len,
+ int len,
double * d );
double Mean_Byte_LP_PostLen (
unsigned char * d,
- long len );
+ int len );
double Mean_Short_LP_PostLen (
short * d,
- long len );
+ int len );
double Mean_UShort_LP_PostLen (
unsigned short * d,
- long len );
+ int len );
double Mean_Int_LP_PostLen (
- long * d,
- long len );
+ int * d,
+ int len );
double Mean_UInt_LP_PostLen (
- unsigned long * d,
- long len );
+ unsigned int * d,
+ int len );
double Mean_Long_LP_PostLen (
__int64 * d,
- long len );
+ int len );
double Mean_ULong_LP_PostLen (
unsigned __int64 * d,
- long len );
+ int len );
double Mean_Float_LP_PostLen (
float * d,
- long len );
+ int len );
double Mean_Double_LP_PostLen (
double * d,
- long len );
+ int len );
double Mean_Byte_SafeArray_OutLen (
SAFEARRAY * d,
- long * len );
+ int * len );
double Mean_Short_SafeArray_OutLen (
SAFEARRAY * d,
- long * len );
+ int * len );
double Mean_UShort_SafeArray_OutLen (
SAFEARRAY * d,
- long * len );
+ int * len );
double Mean_Int_SafeArray_OutLen (
SAFEARRAY * d,
- long * len );
+ int * len );
double Mean_UInt_SafeArray_OutLen (
SAFEARRAY * d,
- long * len );
+ int * len );
double Mean_Long_SafeArray_OutLen (
SAFEARRAY * d,
- long * len );
+ int * len );
double Mean_ULong_SafeArray_OutLen (
SAFEARRAY * d,
- long * len );
+ int * len );
double Mean_Float_SafeArray_OutLen (
SAFEARRAY * d,
- long * len );
+ int * len );
double Mean_Double_SafeArray_OutLen (
SAFEARRAY * d,
- long * len );
+ int * len );
//
// Raw methods provided by interface
//
virtual HRESULT STDMETHODCALLTYPE raw_Mean_Byte_LP_PreLen (
- /*[in]*/ long len,
+ /*[in]*/ int len,
/*[in]*/ unsigned char * d,
/*[out,retval]*/ double * pRetVal ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Mean_Short_LP_PreLen (
- /*[in]*/ long len,
+ /*[in]*/ int len,
/*[in]*/ short * d,
/*[out,retval]*/ double * pRetVal ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Mean_UShort_LP_PreLen (
- /*[in]*/ long len,
+ /*[in]*/ int len,
/*[in]*/ unsigned short * d,
/*[out,retval]*/ double * pRetVal ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Mean_Int_LP_PreLen (
- /*[in]*/ long len,
- /*[in]*/ long * d,
+ /*[in]*/ int len,
+ /*[in]*/ int * d,
/*[out,retval]*/ double * pRetVal ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Mean_UInt_LP_PreLen (
- /*[in]*/ long len,
- /*[in]*/ unsigned long * d,
+ /*[in]*/ int len,
+ /*[in]*/ unsigned int * d,
/*[out,retval]*/ double * pRetVal ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Mean_Long_LP_PreLen (
- /*[in]*/ long len,
+ /*[in]*/ int len,
/*[in]*/ __int64 * d,
/*[out,retval]*/ double * pRetVal ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Mean_ULong_LP_PreLen (
- /*[in]*/ long len,
+ /*[in]*/ int len,
/*[in]*/ unsigned __int64 * d,
/*[out,retval]*/ double * pRetVal ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Mean_Float_LP_PreLen (
- /*[in]*/ long len,
+ /*[in]*/ int len,
/*[in]*/ float * d,
/*[out,retval]*/ double * pRetVal ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Mean_Double_LP_PreLen (
- /*[in]*/ long len,
+ /*[in]*/ int len,
/*[in]*/ double * d,
/*[out,retval]*/ double * pRetVal ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Mean_Byte_LP_PostLen (
/*[in]*/ unsigned char * d,
- /*[in]*/ long len,
+ /*[in]*/ int len,
/*[out,retval]*/ double * pRetVal ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Mean_Short_LP_PostLen (
/*[in]*/ short * d,
- /*[in]*/ long len,
+ /*[in]*/ int len,
/*[out,retval]*/ double * pRetVal ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Mean_UShort_LP_PostLen (
/*[in]*/ unsigned short * d,
- /*[in]*/ long len,
+ /*[in]*/ int len,
/*[out,retval]*/ double * pRetVal ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Mean_Int_LP_PostLen (
- /*[in]*/ long * d,
- /*[in]*/ long len,
+ /*[in]*/ int * d,
+ /*[in]*/ int len,
/*[out,retval]*/ double * pRetVal ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Mean_UInt_LP_PostLen (
- /*[in]*/ unsigned long * d,
- /*[in]*/ long len,
+ /*[in]*/ unsigned int * d,
+ /*[in]*/ int len,
/*[out,retval]*/ double * pRetVal ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Mean_Long_LP_PostLen (
/*[in]*/ __int64 * d,
- /*[in]*/ long len,
+ /*[in]*/ int len,
/*[out,retval]*/ double * pRetVal ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Mean_ULong_LP_PostLen (
/*[in]*/ unsigned __int64 * d,
- /*[in]*/ long len,
+ /*[in]*/ int len,
/*[out,retval]*/ double * pRetVal ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Mean_Float_LP_PostLen (
/*[in]*/ float * d,
- /*[in]*/ long len,
+ /*[in]*/ int len,
/*[out,retval]*/ double * pRetVal ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Mean_Double_LP_PostLen (
/*[in]*/ double * d,
- /*[in]*/ long len,
+ /*[in]*/ int len,
/*[out,retval]*/ double * pRetVal ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Mean_Byte_SafeArray_OutLen (
/*[in]*/ SAFEARRAY * d,
- /*[out]*/ long * len,
+ /*[out]*/ int * len,
/*[out,retval]*/ double * pRetVal ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Mean_Short_SafeArray_OutLen (
/*[in]*/ SAFEARRAY * d,
- /*[out]*/ long * len,
+ /*[out]*/ int * len,
/*[out,retval]*/ double * pRetVal ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Mean_UShort_SafeArray_OutLen (
/*[in]*/ SAFEARRAY * d,
- /*[out]*/ long * len,
+ /*[out]*/ int * len,
/*[out,retval]*/ double * pRetVal ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Mean_Int_SafeArray_OutLen (
/*[in]*/ SAFEARRAY * d,
- /*[out]*/ long * len,
+ /*[out]*/ int * len,
/*[out,retval]*/ double * pRetVal ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Mean_UInt_SafeArray_OutLen (
/*[in]*/ SAFEARRAY * d,
- /*[out]*/ long * len,
+ /*[out]*/ int * len,
/*[out,retval]*/ double * pRetVal ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Mean_Long_SafeArray_OutLen (
/*[in]*/ SAFEARRAY * d,
- /*[out]*/ long * len,
+ /*[out]*/ int * len,
/*[out,retval]*/ double * pRetVal ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Mean_ULong_SafeArray_OutLen (
/*[in]*/ SAFEARRAY * d,
- /*[out]*/ long * len,
+ /*[out]*/ int * len,
/*[out,retval]*/ double * pRetVal ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Mean_Float_SafeArray_OutLen (
/*[in]*/ SAFEARRAY * d,
- /*[out]*/ long * len,
+ /*[out]*/ int * len,
/*[out,retval]*/ double * pRetVal ) = 0;
virtual HRESULT STDMETHODCALLTYPE raw_Mean_Double_SafeArray_OutLen (
/*[in]*/ SAFEARRAY * d,
- /*[out]*/ long * len,
+ /*[out]*/ int * len,
/*[out,retval]*/ double * pRetVal ) = 0;
};
@@ -635,16 +635,16 @@ IErrorMarshalTesting : IUnknown
//
HRESULT Throw_HResult (
- long hresultToReturn );
+ int hresultToReturn );
//
// Raw methods provided by interface
//
virtual HRESULT STDMETHODCALLTYPE raw_Throw_HResult (
- /*[in]*/ long hresultToReturn ) = 0;
- virtual long STDMETHODCALLTYPE Return_As_HResult (
- /*[in]*/ long hresultToReturn ) = 0;
+ /*[in]*/ int hresultToReturn ) = 0;
+ virtual int STDMETHODCALLTYPE Return_As_HResult (
+ /*[in]*/ int hresultToReturn ) = 0;
};
//
diff --git a/tests/src/Interop/COM/ServerContracts/Server.Contracts.tli b/tests/src/Interop/COM/ServerContracts/Server.Contracts.tli
index a419c654e6..94046af919 100644
--- a/tests/src/Interop/COM/ServerContracts/Server.Contracts.tli
+++ b/tests/src/Interop/COM/ServerContracts/Server.Contracts.tli
@@ -27,15 +27,15 @@ inline unsigned short INumericTesting::Add_UShort ( unsigned short a, unsigned s
return _result;
}
-inline long INumericTesting::Add_Int ( long a, long b ) {
- long _result = 0;
+inline int INumericTesting::Add_Int ( int a, int b ) {
+ int _result = 0;
HRESULT _hr = raw_Add_Int(a, b, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
-inline unsigned long INumericTesting::Add_UInt ( unsigned long a, unsigned long b ) {
- unsigned long _result = 0;
+inline unsigned int INumericTesting::Add_UInt ( unsigned int a, unsigned int b ) {
+ unsigned int _result = 0;
HRESULT _hr = raw_Add_UInt(a, b, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
@@ -87,13 +87,13 @@ inline HRESULT INumericTesting::Add_UShort_Ref ( unsigned short a, unsigned shor
return _hr;
}
-inline HRESULT INumericTesting::Add_Int_Ref ( long a, long b, long * c ) {
+inline HRESULT INumericTesting::Add_Int_Ref ( int a, int b, int * c ) {
HRESULT _hr = raw_Add_Int_Ref(a, b, c);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _hr;
}
-inline HRESULT INumericTesting::Add_UInt_Ref ( unsigned long a, unsigned long b, unsigned long * c ) {
+inline HRESULT INumericTesting::Add_UInt_Ref ( unsigned int a, unsigned int b, unsigned int * c ) {
HRESULT _hr = raw_Add_UInt_Ref(a, b, c);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _hr;
@@ -141,13 +141,13 @@ inline HRESULT INumericTesting::Add_UShort_Out ( unsigned short a, unsigned shor
return _hr;
}
-inline HRESULT INumericTesting::Add_Int_Out ( long a, long b, long * c ) {
+inline HRESULT INumericTesting::Add_Int_Out ( int a, int b, int * c ) {
HRESULT _hr = raw_Add_Int_Out(a, b, c);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _hr;
}
-inline HRESULT INumericTesting::Add_UInt_Out ( unsigned long a, unsigned long b, unsigned long * c ) {
+inline HRESULT INumericTesting::Add_UInt_Out ( unsigned int a, unsigned int b, unsigned int * c ) {
HRESULT _hr = raw_Add_UInt_Out(a, b, c);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _hr;
@@ -181,189 +181,189 @@ inline HRESULT INumericTesting::Add_Double_Out ( double a, double b, double * c
// interface IArrayTesting wrapper method implementations
//
-inline double IArrayTesting::Mean_Byte_LP_PreLen ( long len, unsigned char * d ) {
+inline double IArrayTesting::Mean_Byte_LP_PreLen ( int len, unsigned char * d ) {
double _result = 0;
HRESULT _hr = raw_Mean_Byte_LP_PreLen(len, d, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
-inline double IArrayTesting::Mean_Short_LP_PreLen ( long len, short * d ) {
+inline double IArrayTesting::Mean_Short_LP_PreLen ( int len, short * d ) {
double _result = 0;
HRESULT _hr = raw_Mean_Short_LP_PreLen(len, d, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
-inline double IArrayTesting::Mean_UShort_LP_PreLen ( long len, unsigned short * d ) {
+inline double IArrayTesting::Mean_UShort_LP_PreLen ( int len, unsigned short * d ) {
double _result = 0;
HRESULT _hr = raw_Mean_UShort_LP_PreLen(len, d, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
-inline double IArrayTesting::Mean_Int_LP_PreLen ( long len, long * d ) {
+inline double IArrayTesting::Mean_Int_LP_PreLen ( int len, int * d ) {
double _result = 0;
HRESULT _hr = raw_Mean_Int_LP_PreLen(len, d, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
-inline double IArrayTesting::Mean_UInt_LP_PreLen ( long len, unsigned long * d ) {
+inline double IArrayTesting::Mean_UInt_LP_PreLen ( int len, unsigned int * d ) {
double _result = 0;
HRESULT _hr = raw_Mean_UInt_LP_PreLen(len, d, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
-inline double IArrayTesting::Mean_Long_LP_PreLen ( long len, __int64 * d ) {
+inline double IArrayTesting::Mean_Long_LP_PreLen ( int len, __int64 * d ) {
double _result = 0;
HRESULT _hr = raw_Mean_Long_LP_PreLen(len, d, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
-inline double IArrayTesting::Mean_ULong_LP_PreLen ( long len, unsigned __int64 * d ) {
+inline double IArrayTesting::Mean_ULong_LP_PreLen ( int len, unsigned __int64 * d ) {
double _result = 0;
HRESULT _hr = raw_Mean_ULong_LP_PreLen(len, d, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
-inline double IArrayTesting::Mean_Float_LP_PreLen ( long len, float * d ) {
+inline double IArrayTesting::Mean_Float_LP_PreLen ( int len, float * d ) {
double _result = 0;
HRESULT _hr = raw_Mean_Float_LP_PreLen(len, d, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
-inline double IArrayTesting::Mean_Double_LP_PreLen ( long len, double * d ) {
+inline double IArrayTesting::Mean_Double_LP_PreLen ( int len, double * d ) {
double _result = 0;
HRESULT _hr = raw_Mean_Double_LP_PreLen(len, d, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
-inline double IArrayTesting::Mean_Byte_LP_PostLen ( unsigned char * d, long len ) {
+inline double IArrayTesting::Mean_Byte_LP_PostLen ( unsigned char * d, int len ) {
double _result = 0;
HRESULT _hr = raw_Mean_Byte_LP_PostLen(d, len, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
-inline double IArrayTesting::Mean_Short_LP_PostLen ( short * d, long len ) {
+inline double IArrayTesting::Mean_Short_LP_PostLen ( short * d, int len ) {
double _result = 0;
HRESULT _hr = raw_Mean_Short_LP_PostLen(d, len, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
-inline double IArrayTesting::Mean_UShort_LP_PostLen ( unsigned short * d, long len ) {
+inline double IArrayTesting::Mean_UShort_LP_PostLen ( unsigned short * d, int len ) {
double _result = 0;
HRESULT _hr = raw_Mean_UShort_LP_PostLen(d, len, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
-inline double IArrayTesting::Mean_Int_LP_PostLen ( long * d, long len ) {
+inline double IArrayTesting::Mean_Int_LP_PostLen ( int * d, int len ) {
double _result = 0;
HRESULT _hr = raw_Mean_Int_LP_PostLen(d, len, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
-inline double IArrayTesting::Mean_UInt_LP_PostLen ( unsigned long * d, long len ) {
+inline double IArrayTesting::Mean_UInt_LP_PostLen ( unsigned int * d, int len ) {
double _result = 0;
HRESULT _hr = raw_Mean_UInt_LP_PostLen(d, len, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
-inline double IArrayTesting::Mean_Long_LP_PostLen ( __int64 * d, long len ) {
+inline double IArrayTesting::Mean_Long_LP_PostLen ( __int64 * d, int len ) {
double _result = 0;
HRESULT _hr = raw_Mean_Long_LP_PostLen(d, len, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
-inline double IArrayTesting::Mean_ULong_LP_PostLen ( unsigned __int64 * d, long len ) {
+inline double IArrayTesting::Mean_ULong_LP_PostLen ( unsigned __int64 * d, int len ) {
double _result = 0;
HRESULT _hr = raw_Mean_ULong_LP_PostLen(d, len, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
-inline double IArrayTesting::Mean_Float_LP_PostLen ( float * d, long len ) {
+inline double IArrayTesting::Mean_Float_LP_PostLen ( float * d, int len ) {
double _result = 0;
HRESULT _hr = raw_Mean_Float_LP_PostLen(d, len, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
-inline double IArrayTesting::Mean_Double_LP_PostLen ( double * d, long len ) {
+inline double IArrayTesting::Mean_Double_LP_PostLen ( double * d, int len ) {
double _result = 0;
HRESULT _hr = raw_Mean_Double_LP_PostLen(d, len, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
-inline double IArrayTesting::Mean_Byte_SafeArray_OutLen ( SAFEARRAY * d, long * len ) {
+inline double IArrayTesting::Mean_Byte_SafeArray_OutLen ( SAFEARRAY * d, int * len ) {
double _result = 0;
HRESULT _hr = raw_Mean_Byte_SafeArray_OutLen(d, len, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
-inline double IArrayTesting::Mean_Short_SafeArray_OutLen ( SAFEARRAY * d, long * len ) {
+inline double IArrayTesting::Mean_Short_SafeArray_OutLen ( SAFEARRAY * d, int * len ) {
double _result = 0;
HRESULT _hr = raw_Mean_Short_SafeArray_OutLen(d, len, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
-inline double IArrayTesting::Mean_UShort_SafeArray_OutLen ( SAFEARRAY * d, long * len ) {
+inline double IArrayTesting::Mean_UShort_SafeArray_OutLen ( SAFEARRAY * d, int * len ) {
double _result = 0;
HRESULT _hr = raw_Mean_UShort_SafeArray_OutLen(d, len, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
-inline double IArrayTesting::Mean_Int_SafeArray_OutLen ( SAFEARRAY * d, long * len ) {
+inline double IArrayTesting::Mean_Int_SafeArray_OutLen ( SAFEARRAY * d, int * len ) {
double _result = 0;
HRESULT _hr = raw_Mean_Int_SafeArray_OutLen(d, len, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
-inline double IArrayTesting::Mean_UInt_SafeArray_OutLen ( SAFEARRAY * d, long * len ) {
+inline double IArrayTesting::Mean_UInt_SafeArray_OutLen ( SAFEARRAY * d, int * len ) {
double _result = 0;
HRESULT _hr = raw_Mean_UInt_SafeArray_OutLen(d, len, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
-inline double IArrayTesting::Mean_Long_SafeArray_OutLen ( SAFEARRAY * d, long * len ) {
+inline double IArrayTesting::Mean_Long_SafeArray_OutLen ( SAFEARRAY * d, int * len ) {
double _result = 0;
HRESULT _hr = raw_Mean_Long_SafeArray_OutLen(d, len, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
-inline double IArrayTesting::Mean_ULong_SafeArray_OutLen ( SAFEARRAY * d, long * len ) {
+inline double IArrayTesting::Mean_ULong_SafeArray_OutLen ( SAFEARRAY * d, int * len ) {
double _result = 0;
HRESULT _hr = raw_Mean_ULong_SafeArray_OutLen(d, len, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
-inline double IArrayTesting::Mean_Float_SafeArray_OutLen ( SAFEARRAY * d, long * len ) {
+inline double IArrayTesting::Mean_Float_SafeArray_OutLen ( SAFEARRAY * d, int * len ) {
double _result = 0;
HRESULT _hr = raw_Mean_Float_SafeArray_OutLen(d, len, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
-inline double IArrayTesting::Mean_Double_SafeArray_OutLen ( SAFEARRAY * d, long * len ) {
+inline double IArrayTesting::Mean_Double_SafeArray_OutLen ( SAFEARRAY * d, int * len ) {
double _result = 0;
HRESULT _hr = raw_Mean_Double_SafeArray_OutLen(d, len, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
@@ -564,7 +564,7 @@ inline HRESULT IStringTesting::Reverse_BStr_OutAttr ( _bstr_t a, _bstr_t b ) {
// interface IErrorMarshalTesting wrapper method implementations
//
-inline HRESULT IErrorMarshalTesting::Throw_HResult ( long hresultToReturn ) {
+inline HRESULT IErrorMarshalTesting::Throw_HResult ( int hresultToReturn ) {
HRESULT _hr = raw_Throw_HResult(hresultToReturn);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _hr;
diff --git a/tests/src/Interop/Interop.settings.targets b/tests/src/Interop/Interop.settings.targets
index 50e37af67f..df05c154b0 100644
--- a/tests/src/Interop/Interop.settings.targets
+++ b/tests/src/Interop/Interop.settings.targets
@@ -1,6 +1,7 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Properties for all Interop managed test assets -->
<PropertyGroup>
+ <InteropCommonDir>$(MSBuildThisFileDirectory)common/</InteropCommonDir>
</PropertyGroup>
<!-- Environment properties -->
@@ -9,6 +10,6 @@
<!-- Required source files -->
<ItemGroup>
- <Compile Include="$(MSBuildThisFileDirectory)\common\Assertion.cs"/>
+ <Compile Condition="'$(IgnoreInteropAssertionFile)' != 'true'" Include="$(InteropCommonDir)Assertion.cs"/>
</ItemGroup>
</Project>
diff --git a/tests/src/Interop/common/ExeLauncherProgram.cs b/tests/src/Interop/common/ExeLauncherProgram.cs
new file mode 100644
index 0000000000..7f643f3d71
--- /dev/null
+++ b/tests/src/Interop/common/ExeLauncherProgram.cs
@@ -0,0 +1,69 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Reflection;
+
+/// <summary>
+/// This class is used for creating a test that has an entry point
+/// that is not the test itself. For example a test that starts from
+/// a native exe instead of a managed entry point.
+/// </summary>
+public class Program
+{
+ static int Main(string[] noArgs)
+ {
+ if (Environment.OSVersion.Platform != PlatformID.Win32NT)
+ {
+ Console.WriteLine($"Exe launcher only supported on Windows environments...");
+ return 100;
+ }
+
+ string workingDir = Environment.CurrentDirectory;
+ Console.WriteLine($"Searching for exe to launch in {workingDir}...");
+
+ Assembly thisAssem = Assembly.GetEntryAssembly();
+ string startExe = string.Empty;
+ foreach (string exeMaybe in Directory.EnumerateFiles(workingDir, "*.exe"))
+ {
+ // This entry point is _not_ an option
+ if (exeMaybe.Equals(thisAssem.Location, StringComparison.OrdinalIgnoreCase))
+ {
+ continue;
+ }
+
+ startExe = exeMaybe;
+ break;
+ }
+
+ if (string.IsNullOrEmpty(startExe))
+ {
+ throw new Exception("Unable to find start EXE");
+ }
+
+ var startInfo = new ProcessStartInfo()
+ {
+ FileName = startExe,
+
+ UseShellExecute = false,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true
+ };
+
+ Console.WriteLine($"Launching '{startExe}'...");
+ using (Process p = Process.Start(startInfo))
+ {
+ p.OutputDataReceived += (_, args) => Console.WriteLine(args.Data);
+ p.BeginOutputReadLine();
+
+ p.ErrorDataReceived += (_, args) => Console.Error.WriteLine(args.Data);
+ p.BeginErrorReadLine();
+
+ p.WaitForExit();
+ return p.ExitCode;
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/src/Interop/common/xplatform.h b/tests/src/Interop/common/xplatform.h
index e0b939eb60..94a693e384 100644
--- a/tests/src/Interop/common/xplatform.h
+++ b/tests/src/Interop/common/xplatform.h
@@ -36,6 +36,7 @@
// include
#ifdef _WIN32
+ #define NOMINMAX
#include <windows.h>
#include <combaseapi.h>
@@ -95,6 +96,28 @@ inline void CoreClrFree(void *p)
#endif
}
+inline void *CoreClrBstrAlloc(size_t cb)
+{
+#ifdef _WIN32
+ // A null is automatically applied in the SysAllocStringByteLen API.
+ // Remove a single OLECHAR for the implied null.
+ // https://docs.microsoft.com/en-us/previous-versions/windows/desktop/api/oleauto/nf-oleauto-sysallocstringbytelen
+ if (cb >= sizeof(OLECHAR))
+ cb -= sizeof(OLECHAR);
+
+ return ::SysAllocStringByteLen(nullptr, static_cast<UINT>(cb));
+#else
+ return nullptr;
+#endif
+}
+
+inline void CoreClrBstrFree(void *p)
+{
+#ifdef _WIN32
+ return ::SysFreeString((BSTR)p);
+#endif
+}
+
// redirected types not-windows only
#ifndef _WIN32