Add test for marshalling ArgIterators on Windows (#20888)
authorJeremy Koritzinsky <jkoritzinsky@gmail.com>
Wed, 14 Nov 2018 23:18:23 +0000 (15:18 -0800)
committerGitHub <noreply@github.com>
Wed, 14 Nov 2018 23:18:23 +0000 (15:18 -0800)
* Add (windows-only) tests for __arglist and ArgIterator marshalling.

* Add explicit calling convention notation to pinvokes.

* Add license header

* Update VarargsTest.cs

* Fix calling conventions.

* PR Feedback

* Add explicit calling convention.

* Update VarargsNative.cpp

* Don't reference System.Private.Corelib directly

tests/src/Interop/CMakeLists.txt
tests/src/Interop/PInvoke/Varargs/CMakeLists.txt [new file with mode: 0644]
tests/src/Interop/PInvoke/Varargs/VarargsNative.cpp [new file with mode: 0644]
tests/src/Interop/PInvoke/Varargs/VarargsTest.cs [new file with mode: 0644]
tests/src/Interop/PInvoke/Varargs/VarargsTest.csproj [new file with mode: 0644]

index dfae466..fdddcde 100644 (file)
@@ -46,6 +46,7 @@ add_subdirectory(DllImportAttribute/Simple)
 add_subdirectory(ExecInDefAppDom)
 
 if(WIN32)
+    add_subdirectory(PInvoke/Varargs)
     add_subdirectory(PInvoke/NativeCallManagedComVisible)
     # This test doesn't necessarily need to be Windows-only, but the implementation is very tied to Windows APIs
     add_subdirectory(PInvoke/DateTime)
diff --git a/tests/src/Interop/PInvoke/Varargs/CMakeLists.txt b/tests/src/Interop/PInvoke/Varargs/CMakeLists.txt
new file mode 100644 (file)
index 0000000..aa5a676
--- /dev/null
@@ -0,0 +1,11 @@
+cmake_minimum_required (VERSION 2.6)
+project (VarargsNative)
+include_directories(${INC_PLATFORM_DIR})
+set(SOURCES VarargsNative.cpp )
+
+# add the executable
+add_library (VarargsNative SHARED ${SOURCES})
+target_link_libraries(VarargsNative ${LINK_LIBRARIES_ADDITIONAL}) 
+
+# add the install targets
+install (TARGETS VarargsNative DESTINATION bin)
diff --git a/tests/src/Interop/PInvoke/Varargs/VarargsNative.cpp b/tests/src/Interop/PInvoke/Varargs/VarargsNative.cpp
new file mode 100644 (file)
index 0000000..e2034a9
--- /dev/null
@@ -0,0 +1,19 @@
+// 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 <stdarg.h>
+
+extern "C" DLL_EXPORT void __cdecl TestVarArgs(LPWSTR formattedString, SIZE_T bufferSize, LPCWSTR format, ...)
+{
+    va_list args;
+    va_start(args, format);
+
+    vswprintf_s(formattedString, bufferSize, format, args);
+}
+
+extern "C" DLL_EXPORT void STDMETHODCALLTYPE TestArgIterator(LPWSTR formattedString, SIZE_T bufferSize, LPCWSTR format, va_list args)
+{
+    vswprintf_s(formattedString, bufferSize, format, args);
+}
diff --git a/tests/src/Interop/PInvoke/Varargs/VarargsTest.cs b/tests/src/Interop/PInvoke/Varargs/VarargsTest.cs
new file mode 100644 (file)
index 0000000..cffecd9
--- /dev/null
@@ -0,0 +1,59 @@
+// 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.Security;
+using System.Collections.Generic;
+using System.Text;
+using System.Runtime.InteropServices;
+using TestLibrary;
+
+namespace PInvokeTests
+{
+    class VarargsTest
+    {
+        [DllImport("VarargsNative", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
+        private static extern void TestVarArgs(StringBuilder builder, IntPtr bufferSize, string formatString, __arglist);
+
+        [DllImport("VarargsNative", CharSet = CharSet.Unicode)]
+        private static extern void TestArgIterator(StringBuilder builder, IntPtr bufferSize, string formatString, ArgIterator arguments);
+
+        private static void TestArgIteratorWrapper(StringBuilder builder, IntPtr bufferSize, string formatString, __arglist)
+        {
+            TestArgIterator(builder, bufferSize, formatString, new ArgIterator(__arglist));
+        }
+
+        private static bool AssertEqual(string lhs, string rhs)
+        {
+            if (lhs != rhs)
+            {
+                Console.WriteLine($"FAIL! \"{lhs}\" != \"{rhs}\"");
+                return false;
+            }
+            return true;
+        }
+
+        public static int Main()
+        {
+            var passed = true;
+            int arg1 = 10;
+            int arg2 = 20;
+            double arg3 = 12.5;
+
+            string expected = $"{arg1}, {arg2}, {arg3:F1}";
+
+            StringBuilder builder;
+
+            builder = new StringBuilder(30);
+            TestVarArgs(builder, (IntPtr)30, "%i, %i, %.1f", __arglist(arg1, arg2, arg3));
+            passed &= AssertEqual(builder.ToString(), expected);
+
+            builder = new StringBuilder(30);
+            TestArgIteratorWrapper(builder, (IntPtr)30, "%i, %i, %.1f", __arglist(arg1, arg2, arg3));
+            passed &= AssertEqual(builder.ToString(), expected);
+
+            return passed ? 100 : 101;
+        }
+    }
+}
diff --git a/tests/src/Interop/PInvoke/Varargs/VarargsTest.csproj b/tests/src/Interop/PInvoke/Varargs/VarargsTest.csproj
new file mode 100644 (file)
index 0000000..4873ceb
--- /dev/null
@@ -0,0 +1,42 @@
+<?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" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <AssemblyName>VarargsTest</AssemblyName>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0}</ProjectGuid>
+    <OutputType>exe</OutputType>
+    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <DefineConstants>$(DefineConstants);STATIC</DefineConstants>
+
+    <!-- Varargs/ArgIterator marshalling 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>
+    <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+      <Visible>False</Visible>
+    </CodeAnalysisDependentAssemblyPaths>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="*.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\Common\CoreCLRTestLibrary\CoreCLRTestLibrary.csproj">
+      <Project>{c8c0dc74-fac4-45b1-81fe-70c4808366e0}</Project>
+      <Name>CoreCLRTestLibrary</Name>
+    </ProjectReference>
+    <ProjectReference Include="CMakeLists.txt"></ProjectReference>
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>