diff --git a/Winforms.sln b/Winforms.sln index 5c8f72858c..0182c7e40a 100644 --- a/Winforms.sln +++ b/Winforms.sln @@ -135,6 +135,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Windows.Forms.TestUt EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MauiToolStripTests", "src\System.Windows.Forms\tests\IntegrationTests\MauiTests\MauiToolStripTests\MauiToolStripTests.csproj", "{83634671-CF3A-43B0-B729-42CCBA62DF2C}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Windows.Forms.Interop.Tests", "src\System.Windows.Forms\tests\InteropTests\System.Windows.Forms.Interop.Tests.csproj", "{C272DA06-B98D-4BB7-B1C4-ECF58F54B224}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -277,6 +279,18 @@ Global {83634671-CF3A-43B0-B729-42CCBA62DF2C}.Debug|Any CPU.Build.0 = Debug|Any CPU {83634671-CF3A-43B0-B729-42CCBA62DF2C}.Release|Any CPU.ActiveCfg = Release|Any CPU {83634671-CF3A-43B0-B729-42CCBA62DF2C}.Release|Any CPU.Build.0 = Release|Any CPU + {C272DA06-B98D-4BB7-B1C4-ECF58F54B224}.Debug|Any CPU.ActiveCfg = Debug|x86 + {C272DA06-B98D-4BB7-B1C4-ECF58F54B224}.Debug|Any CPU.Build.0 = Debug|x86 + {C272DA06-B98D-4BB7-B1C4-ECF58F54B224}.Release|Any CPU.ActiveCfg = Release|x86 + {C272DA06-B98D-4BB7-B1C4-ECF58F54B224}.Release|Any CPU.Build.0 = Release|x86 + {C272DA06-B98D-4BB7-B1C4-ECF58F54B224}.Debug|x86.ActiveCfg = Debug|x86 + {C272DA06-B98D-4BB7-B1C4-ECF58F54B224}.Debug|x86.Build.0 = Debug|x86 + {C272DA06-B98D-4BB7-B1C4-ECF58F54B224}.Release|x86.ActiveCfg = Release|x86 + {C272DA06-B98D-4BB7-B1C4-ECF58F54B224}.Release|x86.Build.0 = Release|x86 + {C272DA06-B98D-4BB7-B1C4-ECF58F54B224}.Debug|x64.ActiveCfg = Debug|x64 + {C272DA06-B98D-4BB7-B1C4-ECF58F54B224}.Debug|x64.Build.0 = Debug|x64 + {C272DA06-B98D-4BB7-B1C4-ECF58F54B224}.Release|x64.ActiveCfg = Release|x64 + {C272DA06-B98D-4BB7-B1C4-ECF58F54B224}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -321,6 +335,7 @@ Global {73B0857A-966B-4E7D-8A83-FECFE0281AB9} = {DF68A171-D27B-4E6A-8A7E-63A651622355} {86418F0B-39DC-4B5A-8145-6D607E6150AC} = {DF68A171-D27B-4E6A-8A7E-63A651622355} {83634671-CF3A-43B0-B729-42CCBA62DF2C} = {8F20A905-BD37-4D80-B8DF-FA45276FC23F} + {C272DA06-B98D-4BB7-B1C4-ECF58F54B224} = {583F1292-AE8D-4511-B8D8-A81FE4642DDC} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {7B1B0433-F612-4E5A-BE7E-FCF5B9F6E136} diff --git a/eng/configure-toolset.ps1 b/eng/configure-toolset.ps1 index b22416ff0f..a6048f7e63 100644 --- a/eng/configure-toolset.ps1 +++ b/eng/configure-toolset.ps1 @@ -1,2 +1,5 @@ $script:DoNotAbortNativeToolsInstallationOnFailure = $true $script:DoNotDisplayNativeToolsInstallationWarnings = $true + +# Add CMake to path. +$env:PATH = "$PSScriptRoot\..\.tools\bin;$env:PATH" diff --git a/global.json b/global.json index 5543137369..7ad9e7c39b 100644 --- a/global.json +++ b/global.json @@ -21,7 +21,7 @@ "Microsoft.NET.Sdk.IL": "5.0.0-rc.1.20371.13" }, "native-tools": { - "cmake": "3.14.2", + "cmake": "3.17.3", "dotnet-api-docs_netcoreapp3.0": "0.0.0.1" } } diff --git a/src/System.Windows.Forms.Primitives/src/Interop/Ole32/Interop.IOleClientSite.cs b/src/System.Windows.Forms.Primitives/src/Interop/Ole32/Interop.IOleClientSite.cs index 8c6c18a5a7..140a7ccc1d 100644 --- a/src/System.Windows.Forms.Primitives/src/Interop/Ole32/Interop.IOleClientSite.cs +++ b/src/System.Windows.Forms.Primitives/src/Interop/Ole32/Interop.IOleClientSite.cs @@ -23,9 +23,7 @@ internal partial class Interop Ole32.OLEWHICHMK dwWhichMoniker, IntPtr* ppmk); - [PreserveSig] - HRESULT GetContainer( - out IOleContainer container); + IOleContainer GetContainer(); [PreserveSig] HRESULT ShowObject(); diff --git a/src/System.Windows.Forms.Primitives/src/Interop/Ole32/Interop.IOleControlSite.cs b/src/System.Windows.Forms.Primitives/src/Interop/Ole32/Interop.IOleControlSite.cs index f8a8666738..6a1ee61894 100644 --- a/src/System.Windows.Forms.Primitives/src/Interop/Ole32/Interop.IOleControlSite.cs +++ b/src/System.Windows.Forms.Primitives/src/Interop/Ole32/Interop.IOleControlSite.cs @@ -24,7 +24,7 @@ internal partial class Interop [PreserveSig] HRESULT GetExtendedControl( - [MarshalAs(UnmanagedType.IDispatch)] out object ppDisp); + IntPtr* ppDisp); [PreserveSig] HRESULT TransformCoords( diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/AxHost.OleInterfaces.cs b/src/System.Windows.Forms/src/System/Windows/Forms/AxHost.OleInterfaces.cs index 1fed41be82..08e442f508 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/AxHost.OleInterfaces.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/AxHost.OleInterfaces.cs @@ -250,15 +250,21 @@ namespace System.Windows.Forms return HRESULT.E_NOTIMPL; } - HRESULT IOleControlSite.GetExtendedControl(out object ppDisp) + unsafe HRESULT IOleControlSite.GetExtendedControl(IntPtr* ppDisp) { Debug.WriteLineIf(AxHTraceSwitch.TraceVerbose, "in GetExtendedControl " + host.ToString()); - ppDisp = host.GetParentContainer().GetProxyForControl(host); if (ppDisp == null) + { + return HRESULT.E_POINTER; + } + + object proxy = host.GetParentContainer().GetProxyForControl(host); + if (proxy == null) { return HRESULT.E_NOTIMPL; } + *ppDisp = Marshal.GetIDispatchForObject(proxy); return HRESULT.S_OK; } @@ -374,11 +380,10 @@ namespace System.Windows.Forms return HRESULT.E_NOTIMPL; } - HRESULT IOleClientSite.GetContainer(out IOleContainer container) + IOleContainer IOleClientSite.GetContainer() { Debug.WriteLineIf(AxHTraceSwitch.TraceVerbose, "in getContainer"); - container = host.GetParentContainer(); - return HRESULT.S_OK; + return host.GetParentContainer(); } unsafe HRESULT IOleClientSite.ShowObject() diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Control.AxSourcingSite.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Control.AxSourcingSite.cs index ca19341f3b..9cca9f0490 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Control.AxSourcingSite.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Control.AxSourcingSite.cs @@ -38,11 +38,10 @@ namespace System.Windows.Forms { if (service == typeof(HtmlDocument)) { - HRESULT hr = _clientSite.GetContainer(out Ole32.IOleContainer iOlecontainer); - if (hr.Succeeded() && iOlecontainer is Mshtml.IHTMLDocument) + if (_clientSite.GetContainer() is Mshtml.IHTMLDocument document) { _shimManager ??= new HtmlShimManager(); - return new HtmlDocument(_shimManager, iOlecontainer as Mshtml.IHTMLDocument); + return new HtmlDocument(_shimManager, document); } } else if (_clientSite.GetType().IsAssignableFrom(service)) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/WebBrowserSiteBase.cs b/src/System.Windows.Forms/src/System/Windows/Forms/WebBrowserSiteBase.cs index 3e1fae164f..2548229e4d 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/WebBrowserSiteBase.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/WebBrowserSiteBase.cs @@ -88,9 +88,14 @@ namespace System.Windows.Forms return HRESULT.E_NOTIMPL; } - HRESULT IOleControlSite.GetExtendedControl(out object ppDisp) + unsafe HRESULT IOleControlSite.GetExtendedControl(IntPtr* ppDisp) { - ppDisp = null; + if (ppDisp == null) + { + return HRESULT.E_POINTER; + } + + *ppDisp = IntPtr.Zero; return HRESULT.E_NOTIMPL; } @@ -98,7 +103,7 @@ namespace System.Windows.Forms { if (pPtlHimetric == null || pPtfContainer == null) { - return HRESULT.E_INVALIDARG; + return HRESULT.E_POINTER; } if ((dwFlags & XFORMCOORDS.HIMETRICTOCONTAINER) != 0) @@ -183,10 +188,9 @@ namespace System.Windows.Forms return HRESULT.E_NOTIMPL; } - HRESULT IOleClientSite.GetContainer(out IOleContainer container) + IOleContainer IOleClientSite.GetContainer() { - container = Host.GetParentContainer(); - return HRESULT.S_OK; + return Host.GetParentContainer(); } unsafe HRESULT IOleClientSite.ShowObject() diff --git a/src/System.Windows.Forms/tests/InteropTests/InteropTestBase.cs b/src/System.Windows.Forms/tests/InteropTests/InteropTestBase.cs new file mode 100644 index 0000000000..34d58ed984 --- /dev/null +++ b/src/System.Windows.Forms/tests/InteropTests/InteropTestBase.cs @@ -0,0 +1,22 @@ +// 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 Xunit.Sdk; + +namespace System.Windows.Forms.InteropTests +{ + public abstract class InteropTestBase + { + public const string NativeTests = "NativeTests"; + public const string Success = "Success"; + + protected static void AssertSuccess(string result) + { + if (result != Success) + { + throw new XunitException(result); + } + } + } +} diff --git a/src/System.Windows.Forms/tests/InteropTests/NativeTests/CMakeLists.txt b/src/System.Windows.Forms/tests/InteropTests/NativeTests/CMakeLists.txt new file mode 100644 index 0000000000..314823d606 --- /dev/null +++ b/src/System.Windows.Forms/tests/InteropTests/NativeTests/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required (VERSION 2.6) +project (NativeTests) +set(CMAKE_MACOSX_RPATH 1) +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +add_library(NativeTests SHARED + WebBrowserSiteBaseInteropTests.cpp +) +install(TARGETS NativeTests) diff --git a/src/System.Windows.Forms/tests/InteropTests/NativeTests/NativeTests.proj b/src/System.Windows.Forms/tests/InteropTests/NativeTests/NativeTests.proj new file mode 100644 index 0000000000..fe624ca578 --- /dev/null +++ b/src/System.Windows.Forms/tests/InteropTests/NativeTests/NativeTests.proj @@ -0,0 +1,5 @@ + + + CMakeLists.txt + + diff --git a/src/System.Windows.Forms/tests/InteropTests/NativeTests/WebBrowserSiteBaseInteropTests.cpp b/src/System.Windows.Forms/tests/InteropTests/NativeTests/WebBrowserSiteBaseInteropTests.cpp new file mode 100644 index 0000000000..194f6d134f --- /dev/null +++ b/src/System.Windows.Forms/tests/InteropTests/NativeTests/WebBrowserSiteBaseInteropTests.cpp @@ -0,0 +1,635 @@ +// 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 "ocidl.h" +#include "testhelpers.h" +#include +#include +using namespace ATL; + +static HRESULT Test_IOleControlSite_OnControlInfoChanged(IOleControlSite* pControlSite, std::wstringstream& output) +{ + HRESULT hr; + + hr = pControlSite->OnControlInfoChanged(); + assertEqualHr(S_OK, hr); + + return S_OK; +} + +static HRESULT Test_IOleControlSite_LockInPlaceActive(IOleControlSite* pControlSite, std::wstringstream& output) +{ + HRESULT hr; + + // Negative tests. + hr = pControlSite->LockInPlaceActive(TRUE); + assertEqualHr(E_NOTIMPL, hr); + + hr = pControlSite->LockInPlaceActive(TRUE); + assertEqualHr(E_NOTIMPL, hr); + + return S_OK; +} + +static HRESULT Test_IOleControlSite_GetExtendedControl(IOleControlSite* pControlSite, std::wstringstream& output) +{ + HRESULT hr; + IDispatch* pDisp; + + pDisp = (IDispatch*)(long)0xdeadbeef; + hr = pControlSite->GetExtendedControl(&pDisp); + assertEqualHr(E_NOTIMPL, hr); + assertNull(pDisp); + + // Negative tests. + hr = pControlSite->GetExtendedControl(NULL); + assertEqualHr(E_POINTER, hr); + + return S_OK; +} + +static HRESULT Test_IOleControlSite_TransformCoords(IOleControlSite* pControlSite, std::wstringstream& output) +{ + HRESULT hr; + POINTL ptlHimetric; + POINTF ptfContainer; + + // HIMETRICTOCONTAINER, SIZE + ptlHimetric.x = 1000; + ptlHimetric.y = 2000; + ptfContainer.x = 0; + ptfContainer.y = 0; + hr = pControlSite->TransformCoords(&ptlHimetric, &ptfContainer, XFORMCOORDS_HIMETRICTOCONTAINER | XFORMCOORDS_SIZE); + assertEqualHr(S_OK, hr); + assertEqualInt(1000, ptlHimetric.x); + assertEqualInt(2000, ptlHimetric.y); + assertEqualFloat(38, ptfContainer.x); + assertEqualFloat(76, ptfContainer.y); + + ptlHimetric.x = 0; + ptlHimetric.y = 0; + ptfContainer.x = -1; + ptfContainer.y = -2; + hr = pControlSite->TransformCoords(&ptlHimetric, &ptfContainer, XFORMCOORDS_HIMETRICTOCONTAINER | XFORMCOORDS_SIZE); + assertEqualHr(S_OK, hr); + assertEqualInt(0, ptlHimetric.x); + assertEqualInt(0, ptlHimetric.y); + assertEqualFloat(0, ptfContainer.x); + assertEqualFloat(0, ptfContainer.y); + + // HIMETRICTOCONTAINER, POSITION + ptlHimetric.x = 1000; + ptlHimetric.y = 2000; + ptfContainer.x = 0; + ptfContainer.y = 0; + hr = pControlSite->TransformCoords(&ptlHimetric, &ptfContainer, XFORMCOORDS_HIMETRICTOCONTAINER | XFORMCOORDS_POSITION); + assertEqualHr(S_OK, hr); + assertEqualInt(1000, ptlHimetric.x); + assertEqualInt(2000, ptlHimetric.y); + assertEqualFloat(38, ptfContainer.x); + assertEqualFloat(76, ptfContainer.y); + + ptlHimetric.x = 0; + ptlHimetric.y = 0; + ptfContainer.x = 1; + ptfContainer.y = 2; + hr = pControlSite->TransformCoords(&ptlHimetric, &ptfContainer, XFORMCOORDS_HIMETRICTOCONTAINER | XFORMCOORDS_POSITION); + assertEqualHr(S_OK, hr); + assertEqualInt(0, ptlHimetric.x); + assertEqualInt(0, ptlHimetric.y); + assertEqualFloat(0, ptfContainer.x); + assertEqualFloat(0, ptfContainer.y); + + // CONTAINERTOHIMETRIC, SIZE + ptlHimetric.x = 0; + ptlHimetric.y = 0; + ptfContainer.x = 38; + ptfContainer.y = 76; + hr = pControlSite->TransformCoords(&ptlHimetric, &ptfContainer, XFORMCOORDS_CONTAINERTOHIMETRIC | XFORMCOORDS_SIZE); + assertEqualHr(S_OK, hr); + assertEqualInt(1005, ptlHimetric.x); + assertEqualInt(2011, ptlHimetric.y); + assertEqualFloat(38, ptfContainer.x); + assertEqualFloat(76, ptfContainer.y); + + ptlHimetric.x = 1; + ptlHimetric.y = 2; + ptfContainer.x = 0; + ptfContainer.y = 0; + hr = pControlSite->TransformCoords(&ptlHimetric, &ptfContainer, XFORMCOORDS_CONTAINERTOHIMETRIC | XFORMCOORDS_SIZE); + assertEqualHr(S_OK, hr); + assertEqualInt(0, ptlHimetric.x); + assertEqualInt(0, ptlHimetric.y); + assertEqualFloat(0, ptfContainer.x); + assertEqualFloat(0, ptfContainer.y); + + // CONTAINERTOHIMETRIC, POSITION + ptlHimetric.x = 0; + ptlHimetric.y = 0; + ptfContainer.x = 38; + ptfContainer.y = 76; + hr = pControlSite->TransformCoords(&ptlHimetric, &ptfContainer, XFORMCOORDS_CONTAINERTOHIMETRIC | XFORMCOORDS_POSITION); + assertEqualHr(S_OK, hr); + assertEqualInt(1005, ptlHimetric.x); + assertEqualInt(2011, ptlHimetric.y); + assertEqualFloat(38, ptfContainer.x); + assertEqualFloat(76, ptfContainer.y); + + ptlHimetric.x = 1; + ptlHimetric.y = 2; + ptfContainer.x = 0; + ptfContainer.y = 0; + hr = pControlSite->TransformCoords(&ptlHimetric, &ptfContainer, XFORMCOORDS_CONTAINERTOHIMETRIC | XFORMCOORDS_POSITION); + assertEqualHr(S_OK, hr); + assertEqualInt(0, ptlHimetric.x); + assertEqualInt(0, ptlHimetric.y); + assertEqualFloat(0, ptfContainer.x); + assertEqualFloat(0, ptfContainer.y); + + // Negative tests. + hr = pControlSite->TransformCoords(NULL, &ptfContainer, XFORMCOORDS_HIMETRICTOCONTAINER | XFORMCOORDS_SIZE); + assertEqualHr(E_POINTER, hr); + + hr = pControlSite->TransformCoords(&ptlHimetric, NULL, XFORMCOORDS_HIMETRICTOCONTAINER | XFORMCOORDS_SIZE); + assertEqualHr(E_POINTER, hr); + + hr = pControlSite->TransformCoords(&ptlHimetric, &ptfContainer, XFORMCOORDS_HIMETRICTOCONTAINER); + assertEqualHr(E_INVALIDARG, hr); + + hr = pControlSite->TransformCoords(&ptlHimetric, &ptfContainer, XFORMCOORDS_CONTAINERTOHIMETRIC); + assertEqualHr(E_INVALIDARG, hr); + + return S_OK; +} + +static HRESULT Test_IOleControlSite_TranslateAccelerator(IOleControlSite* pControlSite, std::wstringstream& output) +{ + HRESULT hr; + MSG msg = { 0 }; + + hr = pControlSite->TranslateAccelerator(&msg, 0); + assertEqualHr(S_FALSE, hr); + + // Negative tests. + hr = pControlSite->TranslateAccelerator(NULL, 0); + assertEqualHr(E_POINTER, hr); + + return S_OK; +} + +static HRESULT Test_IOleControlSite_OnFocus(IOleControlSite* pControlSite, std::wstringstream& output) +{ + HRESULT hr; + + hr = pControlSite->OnFocus(TRUE); + assertEqualHr(S_OK, hr); + + hr = pControlSite->OnFocus(TRUE); + assertEqualHr(S_OK, hr); + + return S_OK; +} + +static HRESULT Test_IOleControlSite_ShowPropertyFrame(IOleControlSite* pControlSite, std::wstringstream& output) +{ + HRESULT hr; + + // Negative tests. + hr = pControlSite->ShowPropertyFrame(); + assertEqualHr(E_NOTIMPL, hr); + + return S_OK; +} + +static HRESULT Test_IOleControlSite(IOleControlSite* pControlSite, std::wstringstream& output) +{ + HRESULT hr; + + hr = Test_IOleControlSite_OnControlInfoChanged(pControlSite, output); + if (hr != S_OK) + { + return hr; + } + + hr = Test_IOleControlSite_GetExtendedControl(pControlSite, output); + if (hr != S_OK) + { + return hr; + } + + hr = Test_IOleControlSite_LockInPlaceActive(pControlSite, output); + if (hr != S_OK) + { + return hr; + } + + hr = Test_IOleControlSite_TransformCoords(pControlSite, output); + if (hr != S_OK) + { + return hr; + } + + hr = Test_IOleControlSite_TranslateAccelerator(pControlSite, output); + if (hr != S_OK) + { + return hr; + } + + hr = Test_IOleControlSite_OnFocus(pControlSite, output); + if (hr != S_OK) + { + return hr; + } + + hr = Test_IOleControlSite_ShowPropertyFrame(pControlSite, output); + if (hr != S_OK) + { + return hr; + } + + return S_OK; +} + +static HRESULT Test_ISimpleFrameSite_PreMessageFilter(ISimpleFrameSite* pSimpleFrameSite, std::wstringstream& output) +{ + HRESULT hr; + + hr = pSimpleFrameSite->PreMessageFilter(NULL, 0, NULL, NULL, NULL, NULL); + assertEqualHr(S_OK, hr); + + hr = pSimpleFrameSite->PreMessageFilter((HWND)1, 1, (WPARAM)1, (LPARAM)1, (LRESULT*)1, (DWORD*)1); + assertEqualHr(S_OK, hr); + + return S_OK; +} + +static HRESULT Test_ISimpleFrameSite_PostMessageFilter(ISimpleFrameSite* pSimpleFrameSite, std::wstringstream& output) +{ + HRESULT hr; + + hr = pSimpleFrameSite->PostMessageFilter(NULL, 0, NULL, NULL, NULL, 0); + assertEqualHr(S_FALSE, hr); + + hr = pSimpleFrameSite->PostMessageFilter((HWND)1, 1, (WPARAM)1, (LPARAM)1, (LRESULT*)1, 1); + assertEqualHr(S_FALSE, hr); + + return S_OK; +} + +static HRESULT Test_ISimpleFrameSite(ISimpleFrameSite* pSimpleFrameSite, std::wstringstream& output) +{ + HRESULT hr; + + hr = Test_ISimpleFrameSite_PreMessageFilter(pSimpleFrameSite, output); + if (hr != S_OK) + { + return hr; + } + + hr = Test_ISimpleFrameSite_PostMessageFilter(pSimpleFrameSite, output); + if (hr != S_OK) + { + return hr; + } + + return S_OK; +} + +static HRESULT Test_IOleClientSite_SaveObject(IOleClientSite* pClientSite, std::wstringstream& output) +{ + HRESULT hr; + + // Negative tests. + hr = pClientSite->SaveObject(); + assertEqualHr(E_NOTIMPL, hr); + + return S_OK; +} + +static HRESULT Test_IOleClientSite_GetMoniker(IOleClientSite* pClientSite, std::wstringstream& output) +{ + HRESULT hr; + IMoniker* pmk; + + // Negative tests. + pmk = (IMoniker*)(long)0xdeadbeef; + hr = pClientSite->GetMoniker(0, 0, &pmk); + assertEqualHr(E_NOTIMPL, hr); + assertNull(pmk); + + hr = pClientSite->GetMoniker(0, 0, NULL); + assertEqualHr(E_POINTER, hr); + + return S_OK; +} + +static HRESULT Test_IOleClientSite_GetContainer(IOleClientSite* pClientSite, std::wstringstream& output) +{ + HRESULT hr; + IOleContainer* pContainer; + + pContainer = (IOleContainer*)(long)0xdeadbeef; + hr = pClientSite->GetContainer(&pContainer); + assertEqualHr(S_OK, hr); + assertNotNull(pContainer); + +#if false + // Negative tests. + hr = pClientSite->GetContainer(NULL); + assertEqualHr(E_POINTER, hr); +#endif + + return S_OK; +} + +static HRESULT Test_IOleClientSite_ShowObject(IOleClientSite* pClientSite, std::wstringstream& output) +{ + HRESULT hr; + + hr = pClientSite->ShowObject(); + assertEqualHr(S_OK, hr); + + return S_OK; +} + +static HRESULT Test_IOleClientSite_OnShowWindow(IOleClientSite* pClientSite, std::wstringstream& output) +{ + HRESULT hr; + + hr = pClientSite->OnShowWindow(TRUE); + assertEqualHr(S_OK, hr); + + hr = pClientSite->OnShowWindow(FALSE); + assertEqualHr(S_OK, hr); + + return S_OK; +} + +static HRESULT Test_IOleClientSite_RequestNewObjectLayout(IOleClientSite* pClientSite, std::wstringstream& output) +{ + HRESULT hr; + + // Negative tests. + hr = pClientSite->RequestNewObjectLayout(); + assertEqualHr(E_NOTIMPL, hr); + + return S_OK; +} + +static HRESULT Test_IOleClientSite(IOleClientSite* pClientSite, std::wstringstream& output) +{ + HRESULT hr; + + hr = Test_IOleClientSite_SaveObject(pClientSite, output); + if (hr != S_OK) + { + return hr; + } + + hr = Test_IOleClientSite_GetMoniker(pClientSite, output); + if (hr != S_OK) + { + return hr; + } + + hr = Test_IOleClientSite_GetContainer(pClientSite, output); + if (hr != S_OK) + { + return hr; + } + + hr = Test_IOleClientSite_ShowObject(pClientSite, output); + if (hr != S_OK) + { + return hr; + } + + hr = Test_IOleClientSite_OnShowWindow(pClientSite, output); + if (hr != S_OK) + { + return hr; + } + + hr = Test_IOleClientSite_RequestNewObjectLayout(pClientSite, output); + if (hr != S_OK) + { + return hr; + } + + return S_OK; +} + +static HRESULT Test_IOleInPlaceSite_GetWindow(IOleInPlaceSite* pInPlaceSite, std::wstringstream& output) +{ + HRESULT hr; + HWND hwnd; + + hwnd = NULL; + hr = pInPlaceSite->GetWindow(&hwnd); + assertEqualHr(S_OK, hr); + assertNotNull(hwnd); + + // Negative tests. + hr = pInPlaceSite->GetWindow(NULL); + assertEqualHr(E_POINTER, hr); + + return S_OK; +} + +static HRESULT Test_IOleInPlaceSite_ContextSensitiveHelp(IOleInPlaceSite* pInPlaceSite, std::wstringstream& output) +{ + HRESULT hr; + + // Negative tests. + hr = pInPlaceSite->ContextSensitiveHelp(TRUE); + assertEqualHr(E_NOTIMPL, hr); + + hr = pInPlaceSite->ContextSensitiveHelp(FALSE); + assertEqualHr(E_NOTIMPL, hr); + + return S_OK; +} + +static HRESULT Test_IOleInPlaceSite_CanInPlaceActivate(IOleInPlaceSite* pInPlaceSite, std::wstringstream& output) +{ + HRESULT hr; + + hr = pInPlaceSite->CanInPlaceActivate(); + assertEqualHr(S_OK, hr); + + return S_OK; +} + +static HRESULT Test_IOleInPlaceSite_OnInPlaceActivate(IOleInPlaceSite* pInPlaceSite, std::wstringstream& output) +{ + HRESULT hr; + + hr = pInPlaceSite->OnInPlaceActivate(); + assertEqualHr(S_OK, hr); + + return S_OK; +} + +static HRESULT Test_IOleInPlaceSite_OnUIActivate(IOleInPlaceSite* pInPlaceSite, std::wstringstream& output) +{ + HRESULT hr; + + hr = pInPlaceSite->OnUIActivate(); + assertEqualHr(S_OK, hr); + + return S_OK; +} + +static HRESULT Test_IOleInPlaceSite_GetWindowContext(IOleInPlaceSite* pInPlaceSite, std::wstringstream& output) +{ + HRESULT hr; + IOleInPlaceFrame* pFrame; + IOleInPlaceUIWindow* pDoc; + RECT posRect; + RECT clipRect; + OLEINPLACEFRAMEINFO frameInfo; + + pFrame = NULL; + pDoc = NULL; + posRect = { 0 }; + clipRect = { 0 }; + frameInfo = { 0 }; + hr = pInPlaceSite->GetWindowContext(&pFrame, &pDoc, &posRect, &clipRect, NULL); + assertEqualHr(S_OK, hr); + assertNotNull(pFrame); + assertNull(pDoc); + assertEqualInt(0, posRect.left); + assertEqualInt(0, posRect.top); + assertEqualInt(250, posRect.right); + assertEqualInt(250, posRect.bottom); + assertEqualInt(0, clipRect.left); + assertEqualInt(0, clipRect.top); + assertEqualInt(32000, clipRect.right); + assertEqualInt(32000, clipRect.bottom); + + pFrame = NULL; + pDoc = NULL; + posRect = { 0 }; + clipRect = { 0 }; + frameInfo = { 0 }; + hr = pInPlaceSite->GetWindowContext(&pFrame, &pDoc, &posRect, &clipRect, &frameInfo); + assertEqualHr(S_OK, hr); + assertNotNull(pFrame); + assertNull(pDoc); + assertEqualInt(0, posRect.left); + assertEqualInt(0, posRect.top); + assertEqualInt(250, posRect.right); + assertEqualInt(250, posRect.bottom); + assertEqualInt(0, clipRect.left); + assertEqualInt(0, clipRect.top); + assertEqualInt(32000, clipRect.right); + assertEqualInt(32000, clipRect.bottom); + assertEqualInt(sizeof(OLEINPLACEFRAMEINFO), frameInfo.cb); + assertEqualBool(FALSE, frameInfo.fMDIApp); + assertEqualInt(0, frameInfo.cAccelEntries); + assertNull(frameInfo.haccel); + assertNull(frameInfo.hwndFrame); + + // Negative tests. +#if false + hr = pInPlaceSite->GetWindowContext(NULL, &pDoc, &posRect, &clipRect, &frameInfo); + assertEqualHr(E_POINTER, hr); + + hr = pInPlaceSite->GetWindowContext(&pFrame, NULL, &posRect, &clipRect, &frameInfo); + assertEqualHr(E_POINTER, hr); +#endif + + hr = pInPlaceSite->GetWindowContext(&pFrame, &pDoc, NULL, &clipRect, &frameInfo); + assertEqualHr(E_POINTER, hr); + + hr = pInPlaceSite->GetWindowContext(&pFrame, &pDoc, &posRect, NULL, &frameInfo); + assertEqualHr(E_POINTER, hr); + + return S_OK; +} + +static HRESULT Test_IOleInPlaceSite(IOleInPlaceSite* pInPlaceSite, std::wstringstream& output) +{ + HRESULT hr; + + hr = Test_IOleInPlaceSite_GetWindow(pInPlaceSite, output); + if (hr != S_OK) + { + return hr; + } + + hr = Test_IOleInPlaceSite_ContextSensitiveHelp(pInPlaceSite, output); + if (hr != S_OK) + { + return hr; + } + + hr = Test_IOleInPlaceSite_CanInPlaceActivate(pInPlaceSite, output); + if (hr != S_OK) + { + return hr; + } + + hr = Test_IOleInPlaceSite_OnInPlaceActivate(pInPlaceSite, output); + if (hr != S_OK) + { + return hr; + } + + hr = Test_IOleInPlaceSite_OnUIActivate(pInPlaceSite, output); + if (hr != S_OK) + { + return hr; + } + + hr = Test_IOleInPlaceSite_GetWindowContext(pInPlaceSite, output); + if (hr != S_OK) + { + return hr; + } + + return S_OK; +} + +TEST const WCHAR* WINAPI Test_WebBrowserSiteBase(IUnknown* pUnknown) +{ + return RunTest([&](std::wstringstream& output) + { + HRESULT hr; + CComPtr pControlSite; + CComPtr pSimpleFrameSite; + CComPtr pClientSite; + CComPtr pInPlaceSite; + + hr = pUnknown->QueryInterface(IID_IOleControlSite, (void**)&pControlSite); + hr = Test_IOleControlSite(pControlSite, output); + if (hr != S_OK) + { + return hr; + } + + hr = pUnknown->QueryInterface(IID_ISimpleFrameSite, (void**)&pSimpleFrameSite); + hr = Test_ISimpleFrameSite(pSimpleFrameSite, output); + if (hr != S_OK) + { + return hr; + } + + hr = pUnknown->QueryInterface(IID_IOleClientSite, (void**)&pClientSite); + hr = Test_IOleClientSite(pClientSite, output); + if (hr != S_OK) + { + return hr; + } + + hr = pUnknown->QueryInterface(IID_IOleInPlaceSite, (void**)&pInPlaceSite); + hr = Test_IOleInPlaceSite(pInPlaceSite, output); + if (hr != S_OK) + { + return hr; + } + + return S_OK; + }); +} diff --git a/src/System.Windows.Forms/tests/InteropTests/NativeTests/testhelpers.h b/src/System.Windows.Forms/tests/InteropTests/NativeTests/testhelpers.h new file mode 100644 index 0000000000..b96348d57c --- /dev/null +++ b/src/System.Windows.Forms/tests/InteropTests/NativeTests/testhelpers.h @@ -0,0 +1,158 @@ +// 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. + +#pragma once + +#include +#include +#include +#include +#include + +#define TEST extern "C" __declspec(dllexport) + +template::value>> +static inline bool is_essentially_equal_to(const T& a, const T& b) +{ + if (std::isnan(a)) + { + return std::isnan(b); + } + else if (std::isnan(b)) + { + return false; + } + + return std::abs(a - b) <= std::numeric_limits::epsilon() * std::fmin(std::abs(a), std::abs(b)); +} + +template< typename... Args > +std::wstring format(const wchar_t* format, Args... args) +{ + int length = std::swprintf(nullptr, 0, format, args...); + // If this fails, let the program crash. + wchar_t* buf = new wchar_t[length + 1]; + std::swprintf(buf, length + 1, format, args...); + + std::wstring str(buf); + delete[] buf; + return str; +} + +static void printAssertionFailure(std::wstringstream& output, const char* file, const char* function, int line = __LINE__) +{ + output << format(L"Assertion failure: file %hs in %hs, line %d", file, function, line) << std::endl; +} + +#define printLine() printAssertionFailure(output, __FILE__, __FUNCTION__, __LINE__); + +#define assertEqualInt(expected, actual) \ +if ((expected) != (actual)) \ +{ \ + printLine(); \ + output << format(L"Expected: %d\n", (int)((expected))); \ + output << format(L"Actual: %d\n", (int)((actual))); \ + return E_FAIL; \ +} + +#define assertEqualBool(expected, actual) \ +if ((expected) != (actual)) \ +{ \ + printLine(); \ + if ((expected)) \ + { \ + output << format(L"Expected: TRUE\n"); \ + output << format(L"Actual: FALSE\n"); \ + } \ + else \ + { \ + output << format(L"Expected: FALSE\n"); \ + output << format(L"Actual: TRUE\n"); \ + } \ + return E_FAIL; \ +} + +#define assertEqualFloat(expected, actual) \ +if (!is_essentially_equal_to((float)((expected)), (float)((actual)))) \ +{ \ + printLine(); \ + output << format(L"Expected: %f\n", (float)((expected))); \ + output << format(L"Actual: %f\n", (float)((actual))); \ + return E_FAIL; \ +} + +#define assertEqualDouble(expected, actual) \ +if (!is_essentially_equal_to((double)((expected)), (double)((actual)))) \ +{ \ + printLine(); \ + output << format(L"Expected: %f\n", (double)((expected))); \ + output << format(L"Actual: %f\n", (double)((actual))); \ + return E_FAIL; \ +} + +#define assertEqualHr(expected, actual) \ +if ((int)((expected)) != (int)((actual))) \ +{ \ + printLine(); \ + output << format(L"Expected: 0x%08X\n", (int)((expected))); \ + output << format(L"Actual: 0x%08X\n", (int)((actual))); \ + return E_FAIL; \ +} + +#define assertEqualWString(expected, actual) \ +if (!(expected) && (actual)) \ +{ \ + output << format(L"Expected: NULL\n"); \ + output << format(L"Actual: %s\n", (const wchar_t*)((actual))); \ +} \ +else if ((expected) && !(actual)) \ +{ \ + output << format(L"Expected: %s\n", (const wchar_t*)((expected))); \ + output << format(L"Actual: NULL\n"); \ +} \ +else if (wcscmp((const wchar_t*)(expected), (const wchar_t*)(actual)) != 0) \ +{ \ + printLine(); \ + output << format(L"Expected: %s\n", (const wchar_t*)((expected))); \ + output << format(L"Actual: %s\n", (const wchar_t*)((actual))); \ + return E_FAIL; \ +} + +#define assertNull(actual) \ +if ((actual)) \ +{ \ + printLine(); \ + output << format(L"Actual: %p\n", ((actual))); \ + return E_FAIL; \ +} + +#define assertNotNull(actual) \ +if (!(actual) || (void*)((actual)) == (void*)(long)0xdeadbeef) \ +{ \ + printLine(); \ + output << format(L"Actual: %p\n", ((actual))); \ + return E_FAIL; \ +} + +template +static const WCHAR* RunTest(T method) +{ + std::wstringstream output; + HRESULT hr = method(output); + + if (hr == S_OK) + { + output << L"Success"; + } + return Duplicate(output.str().c_str()); +} + +// Need to allocate this as CoTaskMemAlloc to be interpreted by interop marshallers. +static const WCHAR* Duplicate(const WCHAR* source) +{ + size_t length = wcslen(source) + 1; + WCHAR* clone = (WCHAR*)CoTaskMemAlloc(length * sizeof(WCHAR)); + wcscpy_s(clone, length, source); + return clone; +} diff --git a/src/System.Windows.Forms/tests/InteropTests/System.Windows.Forms.Interop.Tests.csproj b/src/System.Windows.Forms/tests/InteropTests/System.Windows.Forms.Interop.Tests.csproj new file mode 100644 index 0000000000..7444bb6e09 --- /dev/null +++ b/src/System.Windows.Forms/tests/InteropTests/System.Windows.Forms.Interop.Tests.csproj @@ -0,0 +1,24 @@ + + + + System.Windows.Forms.Interop.Tests + x86;x64 + + + + + + + + + + + + + + + + + + + diff --git a/src/System.Windows.Forms/tests/InteropTests/WebBrowserSiteBaseInteropTests.cs b/src/System.Windows.Forms/tests/InteropTests/WebBrowserSiteBaseInteropTests.cs new file mode 100644 index 0000000000..52d61601c4 --- /dev/null +++ b/src/System.Windows.Forms/tests/InteropTests/WebBrowserSiteBaseInteropTests.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.Runtime.InteropServices; +using Xunit; + +namespace System.Windows.Forms.InteropTests +{ + public class WebBrowserSiteBaseInteropTests : InteropTestBase + { + [WinFormsFact] + public void WebBrowserSiteBase_RunInteropTests() + { + var browser = new SubWebBrowser(); + WebBrowserSiteBase site = browser.CreateWebBrowserSiteBase(); + AssertSuccess(Test_WebBrowserSiteBase(site)); + } + + [DllImport(NativeTests, CharSet = CharSet.Unicode, ExactSpelling = true)] + private static extern string Test_WebBrowserSiteBase([MarshalAs(UnmanagedType.IUnknown)] object pUnk); + + private class SubWebBrowser : WebBrowser + { + public new WebBrowserSiteBase CreateWebBrowserSiteBase() => base.CreateWebBrowserSiteBase(); + } + } +}