Files
6098/packages/Microsoft.Web.WebView2.1.0.2592.51/tools/wv2winrt/wv2winrt.exe

5484 lines
205 KiB
Plaintext
Raw Normal View History

MZ<EFBFBD><00><><00>@<00><1F><00> <09>!<21>L<>!This program cannot be run in DOS mode.
$PEL!<21><><EFBFBD><00> 0
<00> @ `<0E>`<60>@O <00> @(@ <00>8  H.text<00><>  `.rsrc<00> @@.reloc @
@BtH<00>#<00>$<h<>07(
}}}|(+|(
*(
*0(o
(
*~rp(
o
(
o
(
*0<00>-<16>$-<16>$-<16>$ rp(
, ((
 , (
+o
,+ + <04>rp(
(
X <09>i2<69> <16>s

, o!
(

 s"
s#
(

($
*0<00>s%
s&
s'
o(
()
()
()
r#p(*
+H<06>%(+
s,
r-po-
rIp o-
ripo-
o.
X<05>i2<69>r<>po/
%r<>po0
&*0Ar<>p(*
<16>%(+
s,
s&
%s'
o(
r<EFBFBD>po/
%r<>po0
&*(
*0<00>{
,P<>(1
o2
{rp(3
o
(4
-<%
}}|(+<2B>Q{ |<04>%
}(
<0B> <1F>}| (6
<EFBFBD><1F>}|(7
*y<>6|(8
*BSJB v4.0.30319l #~xT #Strings<00><00>#US<00>#GUID<00><00>#BlobW
<00>3.
8 <00>Y<03>
<00><03>
X<02>
 <00><02><<03><03><00><03>y<03><00><03>l<02>
J<02>
<03><00><02>/<02>
k <0B><00><01><00><02>
? 3<00>
<00><01>f<01>
 <09><00>
<00><02>
<00><01><00>
<EFBFBD>V <0B><00> <0B>
A
<EFBFBD>v
<EFBFBD>Bh
"<04> <0C> <09>
C<04>A<01><00>
<EFBFBD>
`
<EFBFBD>
m
<EFBFBD><00>
<EFBFBD><08><00>Ah<01>Pr @IO<00>A<00><08> AU <02>O
<EFBFBD>/ <0B> <00>P <00><00><08><00> <00><18>
<00> <00>X<00><00> <00><00> <0B><00> <00><00><08><00>!<00><00>`"<00><00><00>"<00><18>
<00>"<00><01> <00>#<00>y / / 4 <00><00><00> <00>
 
<00> <00> <00> <00> <00><00>Y <00>
<00>
<00>
)<00>
1<00>
9<00>
A<00>
I<00>
Q<00>
Y<00>
a<00>
i<00>
q<00>
y<00>
<00><00>
<00><00> <00>y <00><00>
 <00>1 <00> : G<00><00>
<00>
^<00> m<01> r<01>x |<01>x!d <0B>!G <0C>)\<01><00><00>
<EFBFBD><00>x<00><00>
<EFBFBD><00><00>
<EFBFBD>1<01><01><00><00>
<00><00>
9<01>
<EFBFBD><00>\
<EFBFBD>I0 <0C>I<01>I6  <01>
<01> <01> "<01><00>(<01><00>.<01>.F<01><00> Ni<01>T<00>f <00>j <00> <00> <0B> y <00><00><00><00>!<00>%<00>)<00>-<00>1<00>5<00>9<00>=<00> {<00>. ..=.#F.+T.3<00>.;<00>.CF.K<00>.S .[.c;.kLCs<00><03>s<00>@<01><00>&P<00><00>5:!#+Xg<04>
3<00> <00>_<00><01><00> <00><01><00>r <00>I<00>h<00>`g{hax<><00>H<>J0<00>H>( E<00>(F<00> *x4U`<00><00>fOpk4HpzXs<00>(u
p{<00>(<28><00>ЏX H<>* ȡ<00> <00><><00> x<><00> <00><>
<00><><00><>eX<>0<><00><00><>S)Bku<Main>d__0<>u__1Task`1AsyncTaskMethodBuilder`1TaskAwaiter`1IDictionary`2<Module><Main>mscorlibSystem.Collections.GenericExecuteAssemblyAsyncAntlr4.StringTemplate.MiscAddAwaitUnsafeOnCompletedget_IsCompletedResourceKinduseFullNamespaceoutputNamespaceincludeexcludeRuntimeTypeHandleGetTypeFromHandleIConsoleSystem.CommandLineWriteLineIAsyncStateMachineSetStateMachinestateMachineValueTypeuseJavascriptCaseverboseCreateWriteTemplateAntlr4.StringTemplateApplyIdlTemplateApplyRootTemplate<>1__staterequireAllowForWebAttributeCompilerGeneratedAttributeGuidAttributeDebuggableAttributeComVisibleAttributeAssemblyTitleAttributeAsyncStateMachineAttributeTargetFrameworkAttributeDebuggerHiddenAttributeignoreWebHostHiddenAttributeAssemblyFileVersionAttributeAssemblyConfigurationAttributeAssemblyDescriptionAttributeCompilationRelaxationsAttributeAssemblyProductAttributeAssemblyCopyrightAttributeAssemblyCompanyAttributeRuntimeCompatibilityAttributewv2winrt.exeGetInstanceOfSystem.Runtime.VersioningToStringTemplateGroupStringGetResourceAsStringwv2winrt.WSPStatic.stgwv2winrt.WSPNamespace.stgwv2winrt.WSPEnum.stgwv2winrt.Main.stgwv2winrt.WSPClass.stgwv2winrt.WSPStruct.stgwv2winrt.WSPRoot.stgwv2winrt.FileResources.base.hwv2winrt.FileResources.dispatchbase.hwv2winrt.FileResources.asyncdispatch.hwv2winrt.FileResources.eventargsdispatch.hwv2winrt.FileResources.main.hwv2winrt.FileResources.dispatchcontainer.hwv2winrt.FileResources.timehelper.hwv2winrt.FileResources.converter.hwv2winrt.FileResources.returnaggregator.hwv2winrt.FileResources.globals.hwv2winrt.FileResources.dispatchcollectionhelpers.hwv2winrt.FileResources.uniquevariant.hwv2winrt.FileResources.remotedictionary.hpchoutputPathGetResourceNamesEndingWithget_Taskidlcodegen_utilwv2winrt.FileSnippetResources.Windows.Foundation.DateTime.DateTime.implwv2winrt.FileSnippetResources.Windows.Foundation.DateTime.UniversalTime.get.implwv2winrt.FileSnippetResources.Windows.Foundation.TimeSpan.Duration.get.implwv2winrt.FileSnippetResources.Windows.Foundation.DateTime.UniversalTime.put.implwv2winrt.FileSnippetResources.Windows.Foundation.TimeSpan.Duration.put.implAutoGeneratedProgramSystemwinmd_code_genMainget_FileVersionget_LocationSystem.ReflectionSetExceptionFileVersionInfoGetVersionInfowv2winrt.FileSourceResources.dispatchbase.cppwv2winrt.FileSourceResources.asyncdispatch.cppwv2winrt.FileSourceResources.eventargsdispatch.cppwv2winrt.FileSourceResources.main.cppwv2winrt.FileSourceResources.returnaggregator.cppwv2winrt.FileSourceResources.uniquevariant.cppTemplateGroup<>t__builderset_ErrorManagerITemplateErrorListenerResourceHelperTemplateHelperGetAwaiterTypeFilter.ctorSystem.DiagnosticsSystem.Runtime.InteropServicesSystem.Runtime.CompilerServicesDebuggingModesImportTemplatesargswinmdPathsSystem.Threading.TasksTHRootOptionsConcatObjectSystem.CommandLine.DragonFruitGetResultSetResultTHRootrootStartwv2winrtMoveNextGetToolInfoTexttype_hierarchyget_AssemblyGetExecutingAssemblyexplicitIncludesOnlyDefineDictionaryGetResourcesDictionaryop_Equalitywv2winrt v in: .stgfileResourcessourceResources!snippetResources Main rootMain.stg%DispatchAdapterIdloutputNamespace-B<><42>@<40>a_I<5F>E<EFBFBD>      E Yaa0
 MQM QQ <12><> <12><> imq
  mqi!y}<12><><12><><12><><12><> <12><> <12><> <12><><11><>  <12><> y i i} Q]E<11><> <12><>M<12><><12><> 
0
Q ] <08>z\V4<><34><08>Bc&<06>&1<>8V<38>6N5--WinRTAdapteraQ M iuiTWrapNonExceptionThrows wv2winrtPKTool to generate COM IDispatch wrappers for WinRT classes from winmd files. ReleaseMicrosoft Corporation=8Copyright © Microsoft Corporation. All rights reserved.)$2e9d6768-3aac-4bb0-909c-729d5978673d 1.0.2592.51I.NETFramework,Version=v4.8TFrameworkDisplayName.NET Framework 4.8$AutoGeneratedProgram+<Main>d__0_// Copyright (C) Microsoft Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// We use $ to delimit instead of <> because of the amount of C++ template
// code we have to deal with.
delimiters "$", "$"
Main(root) ::= <<
$root:WSPMain()$
>>
DispatchAdapterIdl(outputNamespace) ::= <<
// MultipartEntry.FileName = wv2winrt\DispatchAdapter.idl
namespace $outputNamespace$
{
[default_interface]
runtimeclass DispatchAdapter : Microsoft.Web.WebView2.Core.ICoreWebView2DispatchAdapter
{
DispatchAdapter();
}
// Attribute applied to properties to indicate that their value
// won't change. This can be used as a hint to wv2winrt that
// the property value can be cached.
[attributeusage(target_property)]
[attributename("cacheable")]
attribute CacheableAttribute
{
}
}
>>
<00>c// Copyright (C) Microsoft Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// We use $ to delimit instead of <> because of the amount of C++ template
// code we have to deal with.
delimiters "$", "$"
Class(class) ::= <<
$class:ClassHeader()$
$class:ClassSource()$
>>
ClassHeader(class) ::= <<
// MultipartEntry.FileName = wv2winrt/$class.TargetFileName$.g.h
namespace wv2winrt_impl
{
struct $class.TargetTypeName$ : winrt::implements<
$class.TargetTypeName$,
DispatchBase>
{
public:
$class.TargetTypeName$(::IInspectable* innerObject, const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter& dispatchAdapter);
// IDispatch methods
HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid,
LPOLESTR* names,
unsigned int namesCount,
LCID localeId,
DISPID* dispId) override;
HRESULT STDMETHODCALLTYPE Invoke(DISPID dispId,
REFIID riid,
LCID localeId,
WORD flags,
DISPPARAMS* dispParams,
VARIANT* result,
EXCEPINFO* excepInfo,
UINT* argErr) override;
// ICoreWebView2PrivateDispatchContainer methods
HRESULT STDMETHODCALLTYPE GetInnerObject(IUnknown** object) override;
$if (class.IsCollectionVector)$
HRESULT STDMETHODCALLTYPE GetScriptBehavior(DWORD* behavior)
{
*behavior = DispatchContainerScriptBehaviorVector;
return S_OK;
}
$elseif (class.IsCollectionMap)$
HRESULT STDMETHODCALLTYPE GetScriptBehavior(DWORD* behavior)
{
*behavior = DispatchContainerScriptBehaviorMap;
return S_OK;
}
$endif$
HRESULT STDMETHODCALLTYPE GetPropertyNames(wchar_t***, size_t*);
$if (class.HasCacheableProperties)$
HRESULT STDMETHODCALLTYPE IsPropertyCacheable(
DISPID propertyId,
BOOL* isCacheable) override;
$endif$
HRESULT STDMETHODCALLTYPE GetPropertiesPrecacheability(BOOL** boolsOut, size_t* propertiesLengthOut);
private:
winrt::com_ptr<::IInspectable> m_innerObject;
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
static DispatchProperties s_dispatchProperties;
static const DISPID s_dispatchIds[];
static const int s_precacheableProperties[];
$class:ClassDeclarationEvents()$
$if (class.IsCollection)$
$if (class.IsCollectionMap)$
DispatchMapHelper<winrt::Windows::Foundation::Collections::IMap$if (!class.IsCollectionReadWrite)$View$endif$<
winrt::hstring, $class.CollectionValueType.CppWinRTTypeName$>,
$endif$
$if (class.IsCollectionVector)$
DispatchVectorHelper<winrt::Windows::Foundation::Collections::IVector$if (!class.IsCollectionReadWrite)$View$endif$<
$class.CollectionValueType.CppWinRTTypeName$>,
$endif$
$class.IsCollectionReadWrite$, $class.CollectionValueType.CppWinRTTypeName$> m_dispatchCollectionHelper;
$endif$
};
}
>>
ClassDeclarationEvents(class) ::= <<
$if (class.HasEvents)$
// Event registration uses the callback's IDispatch* as the key value.
// It is a weak reference and should not be resolved.
$class.Events:ClassDeclarationEventEntry(); separator="\n"$
$endif$
>>
ClassDeclarationEventEntry(event) ::= <<
std::map<void*, $class.CppWinRTTypeName$::$event.Name$_revoker > m_eventRegistration$event.Name$;
>>
IsPrecacheableAsInt(prop) ::= <<
$if(prop.IsPrecacheable)$1$else$0$endif$
>>
ClassSource(class) ::= <<
// MultipartEntry.FileName = wv2winrt/$class.TargetFileName$.g.cpp
#include <algorithm>
#include <array>
#include <windows.h>
namespace wv2winrt_impl
{
$class.TargetTypeName$::$class.TargetTypeName$(::IInspectable* innerObject, const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter& dispatchAdapter)
: m_dispatchAdapter(dispatchAdapter)
$if (class.IsCollection)$
, m_dispatchCollectionHelper(dispatchAdapter, $class.ExtensionIdOffset$)
$endif$
{
m_innerObject.copy_from(innerObject);
}
$if (class.DispatchProperties || class.IsCollectionMap)$
const static wchar_t* const s_$class.TargetTypeName$_dispatchProperties[] =
{
$class.DispatchProperties:{prop | L"$prop.NameAsPropertyName$"}; separator=",\n"$
$if(class.IsCollectionMap)$
$if (class.DispatchProperties)$,$endif$
L"getAllKeyNames"
$endif$
};
$endif$
DispatchProperties $class.TargetTypeName$::s_dispatchProperties = $if (class.DispatchProperties || class.IsCollectionMap)$s_$class.TargetTypeName$_dispatchProperties$else$nullptr$endif$;
$if (class.DispatchProperties)$
const DISPID $class.TargetTypeName$::s_dispatchIds[$length(class.DispatchProperties)$] =
{
$class.DispatchProperties:{prop | $prop.Id$}; separator=",\n"$
};
$endif$
$if (class.PrecacheableProperties)$
const int $class.TargetTypeName$::s_precacheableProperties[$length(class.DispatchProperties)$] =
{
$class.DispatchProperties:IsPrecacheableAsInt(); separator=",\n"$
};
$endif$
HRESULT $class.TargetTypeName$::GetPropertyNames(wchar_t*** namesOut, size_t* namesLengthOut)
{
*namesLengthOut = $if (class.DispatchProperties || class.IsCollectionMap)$ARRAYSIZE(s_$class.TargetTypeName$_dispatchProperties)$else$0$endif$;
*namesOut = const_cast<wchar_t **>(s_dispatchProperties);
return S_OK;
}
$if (class.PrecacheableProperties)$
HRESULT $class.TargetTypeName$::GetPropertiesPrecacheability(BOOL** boolsOut, size_t* propertiesLengthOut)
{
*propertiesLengthOut = ARRAYSIZE(s_$class.TargetTypeName$_dispatchProperties);
const BOOL* boolArray = s_precacheableProperties;
*boolsOut = const_cast<BOOL*>(boolArray);
return S_OK;
}
$else$
HRESULT $class.TargetTypeName$::GetPropertiesPrecacheability(BOOL**, size_t*)
{
return E_NOTIMPL;
}
$endif$
HRESULT $class.TargetTypeName$::GetIDsOfNames(REFIID riid,
LPOLESTR* names,
unsigned int namesCount,
LCID localeId,
DISPID* dispId)
{
HRESULT hr = DispatchBase::GetIDsOfNames(
riid, names, namesCount, localeId, dispId);
if (SUCCEEDED(hr))
{
hr = DISP_E_MEMBERNOTFOUND;
$if (class.DispatchProperties)$
size_t idx;
if (LookupProperty(s_dispatchProperties, names[0], idx, $class.DispatchProperties.Count$))
{
*dispId = s_dispatchIds[idx];
hr = S_OK;
}
$endif$
$if (class.HasEvents)$
if (FAILED(hr) && wcscmp(names[0], L"addEventListener") == 0)
{
*dispId = $class.EventIdOffset$;
hr = S_OK;
}
else if (FAILED(hr) && wcscmp(names[0], L"removeEventListener") == 0)
{
*dispId = $class.EventIdOffset$ + 1;
hr = S_OK;
}
$endif$
$if (class.IsCollection)$
if (hr == DISP_E_MEMBERNOTFOUND)
{
hr = m_dispatchCollectionHelper.GetIDsOfNames(
names, dispId);
}
$endif$
}
return hr;
}
HRESULT $class.TargetTypeName$::GetInnerObject(IUnknown** object)
{
HRESULT hr = DISP_E_MEMBERNOTFOUND;
if (m_innerObject != nullptr)
{
hr = S_OK;
*object = m_innerObject.as<IUnknown>().detach();
}
return hr;
}
HRESULT $class.TargetTypeName$::Invoke(
DISPID dispId,
REFIID riid,
LCID localeId,
WORD flags,
DISPPARAMS* dispParams,
VARIANT* result,
EXCEPINFO* excepInfo,
UINT* argErr)
{
HRESULT hr = DispatchBase::Invoke(dispId,
riid,
localeId,
flags,
dispParams,
result,
excepInfo,
argErr);
if (SUCCEEDED(hr))
{
hr = DISP_E_MEMBERNOTFOUND;
if (flags == DISPATCH_METHOD || flags == 0)
{
#ifdef _MSC_VER
// A class may have no methods and in that case this switch statement will
// have only a default case and so will invoke warning 4065. This is fine and
// so we disable the warning.
// <https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warnings-c4000-through-c4199>
#pragma warning( push )
#pragma warning( disable: 4065 )
#endif
switch (dispId)
{
$class.MethodsGroupedByName:MethodGroupInvokeCase(); separator="\n"$
$if (class.HasEvents)$
$class:ClassAddEventListenerInvoke()$
$class:ClassRemoveEventListenerInvoke()$
$endif$
default:
hr = DISP_E_MEMBERNOTFOUND;
break;
}
#ifdef _MSC_VER
#pragma warning( pop )
#endif
}
else if (flags == DISPATCH_PROPERTYGET || flags == DISPATCH_PROPERTYPUT)
{
#pragma warning( push )
#pragma warning( disable: 4065 )
switch (dispId)
{
$class.Properties:PropertyInvokeCase(); separator="\n"$
default:
hr = DISP_E_MEMBERNOTFOUND;
break;
}
#pragma warning( pop )
}
$if (class.IsCollection)$
if (hr == DISP_E_MEMBERNOTFOUND)
{
hr = m_dispatchCollectionHelper.Invoke(
m_innerObject.as<
$if (class.IsCollectionMap)$
winrt::Windows::Foundation::Collections::IMap$if (!class.IsCollectionReadWrite)$View$endif$<winrt::hstring, $class.CollectionValueType.CppWinRTTypeName$>
$else$
winrt::Windows::Foundation::Collections::IVector$if (!class.IsCollectionReadWrite)$View$endif$<$class.CollectionValueType.CppWinRTTypeName$>
$endif$
>(),
dispId,
flags,
dispParams,
result);
}
$endif$
}
return hr;
}
$if (class.HasCacheableProperties)$
HRESULT STDMETHODCALLTYPE $class.TargetTypeName$::IsPropertyCacheable(
DISPID propertyId,
BOOL* isCacheable)
{
static const int32_t cacheableIds[] =
{
$class.CacheableProperties:{prop | $prop.Id$}; separator=", "$
};
*isCacheable = std::binary_search(
cacheableIds, cacheableIds + std::size(cacheableIds), propertyId);
return S_OK;
}
$endif$
}
>>
ClassAddEventListenerInvoke(class) ::= <<
case $class.EventIdOffset$:
// addEventListener(name, callback) Invoke method
if (2 == dispParams->cArgs)
{
// Remember that rgvarg stores parameters in reverse order.
std::wstring eventName =
Converter<VARIANT, std::wstring>(m_dispatchAdapter).Convert(dispParams->rgvarg[1]);
if (dispParams->rgvarg[0].vt == VT_DISPATCH &&
dispParams->rgvarg[0].pdispVal != nullptr)
{
$class.Events:ClassAddEventListenerInvokeEventEntry(); separator="\nelse "$
else
{
// AddEventListener silently ignores subscriptions to events that don't exist.
hr = S_OK;
}
}
else
{
hr = DISP_E_BADVARTYPE;
}
}
else
{
hr = DISP_E_BADPARAMCOUNT;
}
break;
>>
ArgAsVariant(param) ::= <<
UniqueVariant $param$AsVARIANT(
Converter<decltype($param$), VARIANT>(dispatchAdapter).
Convert($param$));
>>
ClassAddEventListenerInvokeEventEntry(event) ::= <<
if (_wcsicmp(eventName.c_str(), L"$event.NameAsJavascript$") == 0)
{
$class.CppWinRTTypeName$ innerObject = m_innerObject
.as<$class.CppWinRTTypeName$>();
winrt::com_ptr<::IDispatch> callback;
hr = dispParams->rgvarg[0].pdispVal->QueryInterface(callback.put());
if (SUCCEEDED(hr))
{
// Subsequent identical registrations are discarded.
if (m_eventRegistration$event.Name$.find(callback.get()) ==
m_eventRegistration$event.Name$.end())
{
auto dispatchAdapter = m_dispatchAdapter; // Copy for the lambda capture
// subscribe to event
auto revoker = innerObject.$event.Name$(
winrt::auto_revoke,
$if (event.HasSource)$
[callback, dispatchAdapter](const auto& $event.SourceName$$event.NonSourceInvokeParams:{param | , const auto& $param$}$) {
$ArgAsVariant(event.SourceName)$
$event.NonSourceInvokeParams:ArgAsVariant(); separator="\n"$
IDispatch* $event.SourceName$AsIDispatch = nullptr; // Weak ref. Do not release.
if ($event.SourceName$AsVARIANT.vt == VT_DISPATCH)
{
$event.SourceName$AsIDispatch = $event.SourceName$AsVARIANT.pdispVal;
}
VARIANT paramsAsVARIANTs[$event.NonSourceInvokeParams.Count$] = { $event.NonSourceInvokeParams:{param | $param$AsVARIANT}; separator=", "$ };
winrt::com_ptr<IDispatch> aggregateEventArgs;
if (SUCCEEDED(CreateAggregateEventArgs(L"$event.NameAsJavascript$", $event.SourceName$AsIDispatch, paramsAsVARIANTs, $event.NonSourceInvokeParams.Count$, aggregateEventArgs.put())))
{
$else$
[callback, dispatchAdapter]($event.NonSourceInvokeParams:{param | const auto& $param$}$) {
$event.NonSourceInvokeParams:ArgAsVariant(); separator="\n"$
$if (event.HasInvokeParams)$
VARIANT paramsAsVARIANTs[$event.NonSourceInvokeParams.Count$] = { $event.NonSourceInvokeParams:{param | $param$AsVARIANT}; separator=", "$ };
$else$
VARIANT* paramsAsVARIANTs = nullptr;
$endif$
winrt::com_ptr<IDispatch> aggregateEventArgs;
if (SUCCEEDED(CreateAggregateEventArgs(L"$event.NameAsJavascript$", nullptr, paramsAsVARIANTs, $event.NonSourceInvokeParams.Count$, aggregateEventArgs.put())))
{
$endif$
// Ownership is passed to the callback below
VARIANT aggregateEventArgsAsVARIANT{VT_DISPATCH};
aggregateEventArgsAsVARIANT.pdispVal = aggregateEventArgs.get();
DISPPARAMS callbackDispParams = {};
VARIANT callbackDispParamsVarg[1] = {};
callbackDispParams.cArgs = ARRAYSIZE(callbackDispParamsVarg);
callbackDispParams.rgvarg = &callbackDispParamsVarg[0];
callbackDispParams.rgvarg[0] = aggregateEventArgsAsVARIANT;
// We don't actually do anything with the result, but we collect it in case
// the callback doesn't check for nullptr out parameters.
UniqueVariant callbackResult;
EXCEPINFO excepInfo;
UINT argErr;
callback->Invoke(
DISPID_VALUE, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD,
&callbackDispParams, &callbackResult,
&excepInfo, &argErr);
}
});
m_eventRegistration$event.Name$[callback.get()] =
std::move(revoker);
}
}
}
>>
ClassRemoveEventListenerInvoke(class) ::= <<
case $class.EventIdOffset$ + 1:
// removeEventListener(name, callback) invoke method
if (2 == dispParams->cArgs)
{
// Remember that rgvarg stores parameters in reverse order.
std::wstring eventName =
Converter<VARIANT, std::wstring>(m_dispatchAdapter).Convert(dispParams->rgvarg[1]);
if (dispParams->rgvarg[0].vt == VT_DISPATCH &&
dispParams->rgvarg[0].pdispVal != nullptr)
{
$class.Events:ClassRemoveEventListenerInvokeEventEntry(); separator="\nelse "$
else
{
// RemoveEventListener silently ignores unregistering events that don't exist.
hr = S_OK;
}
}
else
{
hr = DISP_E_BADVARTYPE;
}
}
else
{
hr = DISP_E_BADPARAMCOUNT;
}
break;
>>
ClassRemoveEventListenerInvokeEventEntry(event) ::= <<
if (_wcsicmp(eventName.c_str(), L"$event.NameAsJavascript$") == 0)
{
// We use the callback IDispatch* as the key. Its stored only
// as a value, weakly.
// Because the value type is a winrt::event_revoker it will
// revoke in its destructor so simply erasing the value will
// fix the map and unregister the event.
// removeEventListener silently ignores requests to unregister
// event handlers that aren't registered.
m_eventRegistration$event.Name$.erase(dispParams->rgvarg[0].pdispVal);
hr = S_OK;
}
>>
MethodGroupInvokeCase(methodGroup) ::= <<
case $methodGroup.Id$:
{
$methodGroup.Methods:MethodInvokeCase(); separator="\nelse "$
else
{
hr = DISP_E_BADPARAMCOUNT;
}
break;
}
>>
MethodInvokeCase(method) ::= <<
$if (method.IsAsync)$
// Invoke for async method $methodGroup.Name$
$method:AsyncMethodInvokeCase()$
$else$
// Invoke for method $methodGroup.Name$
$method:SyncMethodInvokeCase()$
$endif$
>>
AsyncMethodInvokeCase(method) ::= <<
if ($method.ParametersNoOut.Count$ == dispParams->cArgs)
{
hr = S_OK;
try
{
$class.CppWinRTTypeName$ innerObject = m_innerObject
.as<$class.CppWinRTTypeName$>();
auto asyncResultAsWinRT = innerObject.$method.Name$(
$method.Parameters:MethodInvokeCaseParameter(); separator=",\n"$);
if (asyncResultAsWinRT)
{
winrt::com_ptr<ICoreWebView2PrivateDispatchAsyncResult> asyncResultAsCOM;
wv2winrt_impl::CreateDispatchAsyncResult(asyncResultAsCOM.put());
winrt::com_ptr<ICoreWebView2PrivateDispatchAsyncFinishedHandler> asyncCompletedHandlerAsCOM;
asyncResultAsCOM.as(asyncCompletedHandlerAsCOM);
auto dispatchAdapter = m_dispatchAdapter;
winrt::com_ptr<ICoreWebView2PrivateDispatchAsyncInfo> asyncInfoAsCOM;
asyncResultAsCOM.as(asyncInfoAsCOM);
asyncInfoAsCOM->SetAsyncInfo(asyncResultAsWinRT);
asyncResultAsWinRT.Completed(
[asyncCompletedHandlerAsCOM, dispatchAdapter](
const auto& asyncInfo,
winrt::Windows::Foundation::AsyncStatus const& asyncStatus)
{
if (asyncStatus == winrt::Windows::Foundation::AsyncStatus::Completed)
{
UniqueVariant resultAsVariant;
$if (!method.IsReturnTypeAsyncVoid)$
auto resultAsWinRT = asyncInfo.GetResults();
resultAsVariant.reset(Converter<decltype(resultAsWinRT), VARIANT>(
dispatchAdapter)
.Convert(resultAsWinRT));
$endif$
asyncCompletedHandlerAsCOM->Invoke(
asyncInfo.ErrorCode().value,
resultAsVariant.addressof());
}
else
{
asyncCompletedHandlerAsCOM->Invoke(asyncInfo.ErrorCode().value, nullptr);
}
});
UniqueVariant resultAsVariant;
resultAsVariant.vt = VT_UNKNOWN;
asyncResultAsCOM.as<IUnknown>().copy_to(&resultAsVariant.punkVal);
*result = resultAsVariant.release();
}
else
{
hr = E_UNEXPECTED;
}
}
catch (winrt::hresult_error)
{
hr = winrt::to_hresult();
}
catch (...)
{
hr = E_UNEXPECTED;
}
}
>>
SyncMethodInvokeCase(method) ::= <<
if ($method.ParametersNoOut.Count$ == dispParams->cArgs)
{
hr = S_OK;
try
{
$if (method.HasMultipleReturnValuesOrOutParameters || method.HasOutArrayParameters)$
auto returnAggregator = winrt::make_self<wv2winrt_impl::ReturnAggregator>(
$method.ParametersOut.Count$, !$method.IsReturnTypeVoid$);
$endif$
auto innerObject = m_innerObject.as<$method.ParentInterface.CppWinRTTypeName$>();
$if (!method.IsReturnTypeVoid)$auto resultAsWinRT = $endif$innerObject.$method.Name$(
$method.Parameters:MethodInvokeCaseParameter(); separator=",\n"$);
$if (method.HasOutArrayParameters)$
LPWSTR namesArr[] = { $method.GetOutArrayParameterNames: {name | L"$name$"}; separator=",\n"$ };
int indexesArr[] = { $method.GetOutArrayParameterIndexes: {index | $index$}; separator=",\n"$ };
for (int i = 0; i < $length(method.GetOutArrayParameterIndexes)$; i++) {
returnAggregator->AddOutArrayParameterInfoEntry(
namesArr[i], indexesArr[i]);
}
$endif$
$if (!method.IsReturnTypeVoid)$
$if (method.HasOutParameters)$
returnAggregator->SetReturnValue(
Converter<decltype(resultAsWinRT), VARIANT>(m_dispatchAdapter).Convert(resultAsWinRT));
$else$
*result = Converter<decltype(resultAsWinRT), VARIANT>(m_dispatchAdapter).Convert(resultAsWinRT);
$endif$
$endif$
$if (method.HasMultipleReturnValuesOrOutParameters)$
result->vt = VT_DISPATCH;
returnAggregator.as<::IDispatch>().copy_to(&result->pdispVal);
$endif$
}
catch (winrt::hresult_error)
{
hr = winrt::to_hresult();
}
catch (...)
{
hr = E_UNEXPECTED;
}
}
>>
MethodInvokeCaseParameter(methodParameter) ::= <<$if(!methodParameter.Flags.Out && !methodParameter.ByRef)$
Converter<VARIANT, $methodParameter.THType.CppWinRTTypeName$>(m_dispatchAdapter).Convert(dispParams->rgvarg[$method.ParametersNoOut.Count$ - $methodParameter.NoOutParameterIdx$ - 1])
$elseif(methodParameter.Flags.Out && methodParameter.THType.m_isArray && !methodParameter.ByRef)$
RefConverter<$methodParameter.THType.CppWinRTTypeName$, VARIANT>(m_dispatchAdapter).ConvertInOut(dispParams->rgvarg[$method.ParametersNoOut.Count$ - $methodParameter.NoOutParameterIdx$ - 1],
$if (method.HasNoReturnValueAndOneOutParameter)$
result
$else$
returnAggregator->AddParameter(L"$methodParameter.Name$")
$endif$) // Out
$elseif(methodParameter.Flags.Out && !methodParameter.ByRef)$
RefConverter<$methodParameter.THType.CppWinRTTypeName$, VARIANT>(m_dispatchAdapter).ConvertOut(
$if (method.HasNoReturnValueAndOneOutParameter)$
result
$else$
returnAggregator->AddParameter(L"$methodParameter.Name$")
$endif$) // Out
$elseif(!methodParameter.Flags.Out && methodParameter.ByRef)$
RefConverter<$methodParameter.THType.CppWinRTTypeName$, VARIANT>(m_dispatchAdapter).ConvertRef(&dispParams->rgvarg[$method.ParametersNoOut.Count$ - $methodParameter.NoOutParameterIdx$ - 1]) // Ref
$else$
RefConverter<$methodParameter.THType.CppWinRTTypeName$, VARIANT>(m_dispatchAdapter).ConvertOutRef(
$if (method.HasNoReturnValueAndOneOutParameter)$
result
$else$
returnAggregator->AddParameter(L"$methodParameter.Name$")
$endif$) // Out, Ref
$endif$>>
PropertyInvokeCase(property) ::= <<
case $property.Id$:
{
// Invoke for $property.Name$
$if(property.HasGetter)$
if (flags == DISPATCH_PROPERTYGET)
{
hr = S_OK;
try
{
auto innerObject = m_innerObject.as<$property.ParentInterface.CppWinRTTypeName$>();
auto resultAsWinRT = innerObject.$property.Name$();
*result = Converter<decltype(resultAsWinRT), VARIANT>(m_dispatchAdapter).Convert(resultAsWinRT);
}
catch (winrt::hresult_error)
{
hr = winrt::to_hresult();
}
catch (...)
{
hr = E_UNEXPECTED;
}
}
$if(property.HasSetter)$
else
$endif$
$endif$
$if(property.HasSetter)$
if (flags == DISPATCH_PROPERTYPUT)
{
hr = S_OK;
try
{
auto innerObject = m_innerObject.as<$property.ParentInterface.CppWinRTTypeName$>();
innerObject.$property.Name$(
Converter<VARIANT, $property.THType.CppWinRTTypeName$>(m_dispatchAdapter).Convert(*(dispParams->rgvarg)));
}
catch (winrt::hresult_error)
{
hr = winrt::to_hresult();
}
catch (...)
{
hr = E_UNEXPECTED;
}
}
$endif$
break;
}
>>
// Copyright (C) Microsoft Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// We use $ to delimit instead of <> because of the amount of C++ template
// code we have to deal with.
delimiters "$", "$"
Enum(enum) ::= <<
$enum:EnumHeader()$
$enum:EnumSource()$
>>
EnumHeader(enum) ::= <<
// MultipartEntry.FileName = wv2winrt/$enum.TargetFileName$.g.h
namespace wv2winrt_impl
{
struct $enum.TargetTypeName$ : winrt::implements<$enum.TargetTypeName$, DispatchBase>
{
public:
$enum.TargetTypeName$(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&);
HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid,
LPOLESTR* names,
unsigned int namesCount,
LCID localeId,
DISPID* dispId) override;
HRESULT STDMETHODCALLTYPE Invoke(DISPID dispId,
REFIID riid,
LCID localeId,
WORD flags,
DISPPARAMS* dispParams,
VARIANT* result,
EXCEPINFO* excepInfo,
UINT* argErr) override;
// ICoreWebView2PrivateDispatchContainer methods
HRESULT STDMETHODCALLTYPE GetPropertyNames(wchar_t***, size_t*);
private:
static DispatchProperties s_dispatchProperties;
static const DISPID s_dispatchIds[];
};
}
>>
EnumSource(enum) ::= <<
// MultipartEntry.FileName = wv2winrt/$enum.TargetFileName$.g.cpp
namespace wv2winrt_impl
{
// We match the namespace types which do need the DispatchAdapter in the
// constructor even though the enum types do not require the DispatchAdapter.
$enum.TargetTypeName$::$enum.TargetTypeName$(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&)
{
}
$if (enum.DispatchProperties)$
const static wchar_t* const s_$enum.TargetTypeName$_dispatchProperties[] =
{
$enum.DispatchProperties:{prop | L"$prop.NameAsPropertyName$"}; separator=",\n"$
};
$endif$
DispatchProperties $enum.TargetTypeName$::s_dispatchProperties = $if (enum.DispatchProperties)$s_$enum.TargetTypeName$_dispatchProperties$else$nullptr$endif$;
$if (enum.DispatchProperties)$
const DISPID $enum.TargetTypeName$::s_dispatchIds[$length(enum.DispatchProperties)$] =
{
$enum.DispatchProperties:{prop | $prop.Id$}; separator=",\n"$
};
$endif$
HRESULT $enum.TargetTypeName$::GetIDsOfNames(REFIID riid,
LPOLESTR* names,
unsigned int namesCount,
LCID localeId,
DISPID* dispId)
{
HRESULT hr = DispatchBase::GetIDsOfNames(riid, names, namesCount, localeId, dispId);
if (SUCCEEDED(hr))
{
hr = DISP_E_MEMBERNOTFOUND;
$if (enum.DispatchProperties)$
size_t idx;
if (LookupProperty(s_dispatchProperties, names[0], idx, $enum.DispatchProperties.Count$))
{
*dispId = s_dispatchIds[idx];
hr = S_OK;
}
$endif$
}
return hr;
}
HRESULT $enum.TargetTypeName$::Invoke(DISPID dispId,
REFIID riid,
LCID localeId,
WORD flags,
DISPPARAMS* dispParams,
VARIANT* result,
EXCEPINFO* excepInfo,
UINT* argErr)
{
HRESULT hr = DispatchBase::Invoke(dispId,
riid,
localeId,
flags,
dispParams,
result,
excepInfo,
argErr);
if (SUCCEEDED(hr))
{
hr = DISP_E_MEMBERNOTFOUND;
if (flags == DISPATCH_PROPERTYGET)
{
if (dispParams->cArgs != 0 ||
dispParams->rgvarg != nullptr)
{
hr = E_INVALIDARG;
}
else
{
struct EnumEntry
{
DISPID id;
UINT32 value;
bool isValueUnsigned;
};
static const EnumEntry enumEntries[] =
{
$enum.Entries:EnumInvokeEntryArray(); separator=",\n"$
};
static const size_t enumEntriesCount = ARRAYSIZE(enumEntries);
const size_t requestIdx = dispId - 1;
if (requestIdx < enumEntriesCount)
{
if (enumEntries[requestIdx].isValueUnsigned)
{
result->vt = VT_UI4;
result->uintVal = enumEntries[requestIdx].value;
hr = S_OK;
}
else
{
result->vt = VT_I4;
result->intVal = static_cast<INT32>(enumEntries[requestIdx].value);
hr = S_OK;
}
}
}
}
}
return hr;
}
HRESULT $enum.TargetTypeName$::GetPropertyNames(wchar_t*** namesOut, size_t* namesLengthOut)
{
*namesLengthOut = $if (enum.DispatchProperties)$ARRAYSIZE(s_$enum.TargetTypeName$_dispatchProperties)$else$0$endif$;
*namesOut = const_cast<wchar_t **>(s_dispatchProperties);
return S_OK;
}
} // namespace wv2winrt_impl
>>
EnumInvokeEntryArray(enumEntry) ::= <<
{
$enumEntry.Id$,
static_cast<UINT32>($enumEntry.ValueAsFormattedString$),
$enumEntry.IsValueUnsigned$
}
>>
'// Copyright (C) Microsoft Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// We use $ to delimit instead of <> because of the amount of C++ template
// code we have to deal with.
delimiters "$", "$"
Namespace(namespace) ::= <<
$namespace.Namespaces:Namespace()$
$namespace:NamespaceHeader()$
$namespace:NamespaceSource()$
$namespace.Enums:Enum()$
$! ImplicitStructsNamespaceInclude needs to come before Struct so native WinRT
struct type decls from this namespace can be used by
Converter<ICoreWebView2PrivateRemoteDictionary*, StructT> generated from the Struct
template !$
$namespace:ImplicitStructsNamespaceInclude()$
$namespace.Structs:Struct()$
$namespace.Classes:Class()$
$namespace.ClassesWithStaticsOrCtors:StaticClass()$
$namespace:NamespaceHeaderPost()$
>>
ImplicitStructsNamespaceInclude(namespace) ::= <<
$if (namespace.HasStructs)$
// MultipartEntry.FileName = wv2winrt/implicitstructs.g.h
$namespace:IncludeCppWinRTNamespace()$
$endif$
>>
NamespaceHeader(namespace) ::= <<
// MultipartEntry.FileName = wv2winrt/$namespace.TargetFileName$.g.h
// WARNING: Please don't edit this file. It was generated by wv2winrt v$root.Version$
#pragma once
#include "wv2winrt/dispatchbase.h"
#include "wv2winrt/dispatchcollectionhelpers.h"
#include <functional>
#include "wv2winrt/base.h"
$if (namespace.CppWinRTFileName)$
$namespace:IncludeCppWinRTNamespace()$
$endif$
$namespace.TypeReferenceNamespacesHeader:IncludeCppWinRTNamespaceRaw()$
namespace wv2winrt_impl
{
struct $namespace.TargetTypeName$ : winrt::implements<$namespace.TargetTypeName$, DispatchBase>
{
public:
$namespace.TargetTypeName$(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter& dispatchAdapter);
// IDispatch methods
HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid,
LPOLESTR* names,
unsigned int namesCount,
LCID localeId,
DISPID* dispId);
HRESULT STDMETHODCALLTYPE Invoke(DISPID dispId,
REFIID riid,
LCID localeId,
WORD flags,
DISPPARAMS* dispParams,
VARIANT* result,
EXCEPINFO* excepInfo,
UINT* argErr);
// ICoreWebView2PrivateDispatchContainer methods
HRESULT STDMETHODCALLTYPE GetPropertyNames(wchar_t***, size_t*);
private:
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
static DispatchProperties s_dispatchProperties;
static const DISPID s_dispatchIds[];
};
}
>>
NamespaceSource(namespace) ::= <<
// MultipartEntry.FileName = wv2winrt/$namespace.TargetFileName$.g.cpp
// WARNING: Please don't edit this file. It was generated by wv2winrt v$root.Version$
$ProjectPchInclude()$
#include "wv2winrt/asyncdispatch.h"
#include "wv2winrt/converter.h"
#include "wv2winrt/eventargsdispatch.h"
#include "wv2winrt/implicitstructs.g.h"
#include "wv2winrt/main.h"
#include "wv2winrt/returnaggregator.h"
#include "wv2winrt/uniquevariant.h"
$namespace:IncludeWV2WinRTTypeHeader(); separator="\n"$
$namespace.Namespaces:IncludeWV2WinRTTypeHeader(); separator="\n"$
$namespace.Enums:IncludeWV2WinRTTypeHeader(); separator="\n"$
$namespace.Structs:IncludeWV2WinRTTypeHeader(); separator="\n"$
$namespace.ClassesWithStaticsOrCtors:IncludeWV2WinRTTypeHeader(); separator="\n"$
$namespace.TypeReferenceNamespacesSource:IncludeCppWinRTNamespaceRaw()$
namespace wv2winrt_impl
{
$namespace.TargetTypeName$::$namespace.TargetTypeName$(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter& dispatchAdapter)
: m_dispatchAdapter(dispatchAdapter)
{
}
$if (namespace.DispatchProperties)$
const static wchar_t* const s_$namespace.TargetTypeName$_dispatchProperties[] =
{
$namespace.DispatchProperties:{prop | L"$prop.NameAsPropertyName$"}; separator=",\n"$
};
$endif$
DispatchProperties $namespace.TargetTypeName$::s_dispatchProperties = $if (namespace.DispatchProperties)$s_$namespace.TargetTypeName$_dispatchProperties$else$nullptr$endif$;
$if (namespace.DispatchProperties)$
const DISPID $namespace.TargetTypeName$::s_dispatchIds[$length(namespace.DispatchProperties)$] =
{
$namespace.DispatchProperties:{prop | $prop.Id$}; separator=",\n"$
};
$endif$
HRESULT $namespace.TargetTypeName$::GetPropertyNames(wchar_t*** namesOut, size_t* namesLengthOut)
{
*namesLengthOut = $if (namespace.DispatchProperties)$ARRAYSIZE(s_$namespace.TargetTypeName$_dispatchProperties)$else$0$endif$;
*namesOut = const_cast<wchar_t **>(s_dispatchProperties);
return S_OK;
}
HRESULT $namespace.TargetTypeName$::GetIDsOfNames(REFIID riid,
LPOLESTR* names,
unsigned int namesCount,
LCID localeId,
DISPID* dispId)
{
HRESULT hr = DispatchBase::GetIDsOfNames(riid, names, namesCount, localeId, dispId);
if (SUCCEEDED(hr))
{
hr = DISP_E_MEMBERNOTFOUND;
$if (namespace.DispatchProperties)$
size_t idx;
if (LookupProperty(s_dispatchProperties, names[0], idx, $namespace.DispatchProperties.Count$))
{
*dispId = s_dispatchIds[idx];
hr = S_OK;
}
$endif$
}
return hr;
}
HRESULT $namespace.TargetTypeName$::Invoke(DISPID dispId,
REFIID riid,
LCID localeId,
WORD flags,
DISPPARAMS* dispParams,
VARIANT* result,
EXCEPINFO* excepInfo,
UINT* argErr)
{
HRESULT hr = DispatchBase::Invoke(dispId,
riid,
localeId,
flags,
dispParams,
result,
excepInfo,
argErr);
if (SUCCEEDED(hr))
{
hr = DISP_E_MEMBERNOTFOUND;
if (flags == DISPATCH_PROPERTYGET)
{
if (dispParams->cArgs != 0 ||
dispParams->rgvarg != nullptr)
{
hr = E_INVALIDARG;
}
else
{
winrt::com_ptr<IDispatch> dispatch;
#pragma warning( push )
#pragma warning( disable: 4065 )
switch (dispId)
{
$namespace.Namespaces:NamespaceChildInvokeEntryCase(); separator="\n"$
$namespace.Enums:NamespaceChildInvokeEntryCase(); separator="\n"$
$namespace.ClassesWithStaticsOrCtors:NamespaceChildInvokeEntryCase(); separator="\n"$
default:
hr = DISP_E_MEMBERNOTFOUND;
break;
}
#pragma warning( pop )
if (SUCCEEDED(hr))
{
// Copy dispatch into output result
VARIANT dispatchAsVariant;
dispatchAsVariant.vt = VT_DISPATCH;
dispatchAsVariant.pdispVal = dispatch.detach();
*result = dispatchAsVariant;
}
}
}
$if (namespace.HasStructs)$
$! Invoke struct constructors as methods under this namespace as there is no static from which to make the call !$
else if (flags == DISPATCH_METHOD || flags == 0)
{
switch (dispId)
{
$namespace.Structs:NamespaceStructInvokeEntryCase(); separator="\n"$
default:
hr = DISP_E_MEMBERNOTFOUND;
break;
}
}
$endif$
}
return hr;
}
}
>>
NamespaceChildInvokeEntryCase(child) ::= <<
case $child.Id$:
{
dispatch = m_dispatchAdapter.WrapNamedObject(L"$child.Name$", m_dispatchAdapter).as<IDispatch>();
hr = S_OK;
break;
}
>>
NamespaceStructInvokeEntryCase(struct) ::= <<
case $struct.Id$:
{
// Invoke for $struct.Name$ c'tor
if ($struct.Fields.Count$ == dispParams->cArgs)
{
hr = S_OK;
try
{
$if (snippetResources.(struct.CtorSnippetKey))$
$struct.CtorSnippetKey:ResourceSnippet()$
$else$
$! Create WinRT struct !$
$! This is the projected WinRT struct type from winmd, we don't winrt::make our wrapper here !$
$struct.CppWinRTTypeName$ resultAsWinRT{ $struct.Fields:StructInvokeEntryCaseParameter(); separator=",\n"$ };
$! Make wrapper IDispatch !$
*result = Converter<decltype(resultAsWinRT), VARIANT>(m_dispatchAdapter).Convert(resultAsWinRT);
$endif$
}
catch (winrt::hresult_error)
{
hr = winrt::to_hresult();
}
catch (...)
{
hr = E_UNEXPECTED;
}
}
else
{
hr = DISP_E_BADPARAMCOUNT;
}
break;
}
>>
StructInvokeEntryCaseParameter(field) ::= <<
$! Field Ids start at 1 as they're the same as dispatch ID, which skips the reserved 0 value !$
Converter<VARIANT, $field.Type.CppWinRTTypeName$>(m_dispatchAdapter).Convert(dispParams->rgvarg[$struct.Fields.Count$ - $field.Id$])
>>
NamespaceHeaderPost(namespace) ::= <<
// MultipartEntry.FileName = wv2winrt/$namespace.TargetFileName$.g.h
>>
<EFBFBD>+// Copyright (C) Microsoft Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// We use $ to delimit instead of <> because of the amount of C++ template
// code we have to deal with.
delimiters "$", "$"
ResourceFile(filename) ::= <<
// MultipartEntry.FileName = wv2winrt\\$filename$
$fileResources.(filename)$
>>
ResourceFileSource(filename) ::= <<
// MultipartEntry.FileName = wv2winrt\\$filename$
$CopyrightHeader()$
$ProjectPchInclude()$
$sourceResources.(filename)$
>>
ResourceSnippet(key) ::= <<
$snippetResources.(key)$
>>
CopyrightHeader() ::= <<
// Copyright (C) Microsoft Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
>>
ProjectPchInclude() ::= <<
$if (root.ProjectPch)$#include "$root.ProjectPch$"$endif$
>>
WSPMain(root) ::= <<
$root.OutputNamespace:DispatchAdapterIdl()$
$root:DispatchAdapterH()$
$root:DispatchAdapterCpp()$
$root:ImplicitStructsH()$
$ResourceFile("main.h")$
$ResourceFile("globals.h")$
$ResourceFile("base.h")$
$ResourceFile("converter.h")$
$ResourceFile("timehelper.h")$
$ResourceFile("asyncdispatch.h")$
$ResourceFileSource("asyncdispatch.cpp")$
$ResourceFile("dispatchbase.h")$
$ResourceFile("dispatchcollectionhelpers.h")$
$ResourceFileSource("dispatchbase.cpp")$
$ResourceFile("dispatchcontainer.h")$
$ResourceFile("eventargsdispatch.h")$
$ResourceFileSource("eventargsdispatch.cpp")$
$ResourceFile("returnaggregator.h")$
$ResourceFileSource("returnaggregator.cpp")$
$ResourceFile("remotedictionary.h")$
$ResourceFile("uniquevariant.h")$
$ResourceFileSource("uniquevariant.cpp")$
$root.Namespaces:Namespace()$
$root:GlobalsCpp()$
$ResourceFileSource("main.cpp")$
>>
DispatchAdapterH(root) ::= <<
// MultipartEntry.FileName = wv2winrt\DispatchAdapter.h
#pragma once
$! For component types, C++/WinRT prefixes type filenames with namespace if different to project's RootNamespace !$
#include "$if (root.UseFullNamespace)$$root.OutputNamespace$.$endif$DispatchAdapter.g.h"
namespace winrt::$root.OutputNamespace$::implementation
{
struct DispatchAdapter : DispatchAdapterT<DispatchAdapter>
{
DispatchAdapter();
void Clean();
winrt::Windows::Foundation::IInspectable WrapObject(
winrt::Windows::Foundation::IInspectable unwrapped,
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter dispatchAdapter);
winrt::Windows::Foundation::IInspectable WrapNamedObject(
winrt::hstring name,
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter dispatchAdapter);
winrt::Windows::Foundation::IInspectable UnwrapObject(
winrt::Windows::Foundation::IInspectable wrapped);
private:
// Cache of wrapped objects used by WrapObject. This maps unwrapped objects (as void*)
// to wrapped IDispatch objects (as weak_ref).
std::map<void*, winrt::weak_ref<winrt::Windows::Foundation::IInspectable> > m_wrappedObjects;
// Cache of wrapped objects used by WrapNamedObject. This maps names (as hstring)
// to wrapped IDispatch objects (as weak_ref).
std::map<winrt::hstring, winrt::weak_ref<winrt::Windows::Foundation::IInspectable> > m_wrappedNamedObjects;
};
}
namespace winrt::$root.OutputNamespace$::factory_implementation
{
struct DispatchAdapter : DispatchAdapterT<DispatchAdapter, implementation::DispatchAdapter>
{
};
}
>>
DispatchAdapterCpp(root) ::= <<
// MultipartEntry.FileName = wv2winrt\DispatchAdapter.cpp
$ProjectPchInclude()$
#include "wv2winrt/DispatchAdapter.h"
#include "wv2winrt/dispatchcontainer.h"
#include "wv2winrt/main.h"
$! For component types, C++/WinRT prefixes type filenames with namespace if different to project's RootNamespace !$
#include "$if (root.UseFullNamespace)$$root.OutputNamespace$.$endif$DispatchAdapter.g.cpp"
using namespace wv2winrt_impl;
namespace winrt::$root.OutputNamespace$::implementation
{
DispatchAdapter::DispatchAdapter()
{
}
void DispatchAdapter::Clean()
{
for (auto entry = m_wrappedNamedObjects.begin(); entry != m_wrappedNamedObjects.end(); ++entry)
{
if (!entry->second.get())
{
m_wrappedNamedObjects.erase(entry);
}
}
for (auto entry = m_wrappedObjects.begin(); entry != m_wrappedObjects.end(); ++entry)
{
if (!entry->second.get())
{
m_wrappedObjects.erase(entry);
}
}
}
winrt::Windows::Foundation::IInspectable DispatchAdapter::WrapObject(
winrt::Windows::Foundation::IInspectable unwrapped,
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter dispatchAdapter)
{
winrt::com_ptr<::IInspectable> unwrappedAsABI = unwrapped.as<::IInspectable>();
IInspectable wrappedDispatch;
auto cacheEntry = m_wrappedObjects.find(unwrappedAsABI.get());
if (cacheEntry != m_wrappedObjects.end())
{
// Found entry, attempt to resolve weak pointer.
wrappedDispatch = cacheEntry->second.get();
}
if (!wrappedDispatch)
{
// Missing cache entry or couldn't resolve weak pointer. Make new wrapper.
winrt::com_ptr<::IDispatch> dispatch;
bool is_cacheable = false;
HRESULT hr = CreateDispatchFromInspectable(
unwrappedAsABI.get(), dispatchAdapter, dispatch.put(), &is_cacheable);
winrt::check_hresult(hr);
wrappedDispatch = dispatch.as<IInspectable>();
// Update cache with new wrapper.
if (is_cacheable)
{
m_wrappedObjects[unwrappedAsABI.get()] = winrt::make_weak(wrappedDispatch);
}
}
return wrappedDispatch;
}
winrt::Windows::Foundation::IInspectable DispatchAdapter::WrapNamedObject(
winrt::hstring name,
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter dispatchAdapter)
{
IInspectable wrappedDispatch;
auto cacheEntry = m_wrappedNamedObjects.find(name);
if (cacheEntry != m_wrappedNamedObjects.end())
{
// Found entry, attempt to resolve weak pointer.
wrappedDispatch = cacheEntry->second.get();
}
if (!wrappedDispatch)
{
// Missing cache entry or couldn't resolve weak pointer. Make new wrapper.
winrt::com_ptr<::IDispatch> dispatch;
HRESULT hr = CreateDispatchFromName(name.c_str(), dispatchAdapter, dispatch.put());
winrt::check_hresult(hr);
wrappedDispatch = dispatch.as<IInspectable>();
// Update cache with new wrapper.
m_wrappedNamedObjects[name] = winrt::make_weak(wrappedDispatch);
}
return wrappedDispatch;
}
winrt::Windows::Foundation::IInspectable DispatchAdapter::UnwrapObject(
winrt::Windows::Foundation::IInspectable wrapped)
{
winrt::com_ptr<IUnknown> unwrappedAsIUnknown;
winrt::com_ptr<::wv2winrt_impl::ICoreWebView2PrivateDispatchContainer> dispatchContainer;
dispatchContainer = wrapped.as<::wv2winrt_impl::ICoreWebView2PrivateDispatchContainer>();
if (dispatchContainer)
{
if (SUCCEEDED(dispatchContainer->
GetInnerObject(unwrappedAsIUnknown.put())))
{
return unwrappedAsIUnknown.as<IInspectable>();
}
}
return nullptr;
}
}
>>
ImplicitStructsH(root) ::= <<
// MultipartEntry.FileName = wv2winrt/implicitstructs.g.h
// WARNING: Please don't edit this file. It was generated by wv2winrt v$root.Version$
#pragma once
#include "wv2winrt/converter.h"
#include "wv2winrt/remotedictionary.h"
// Must be included before any cppwinrt headers
#include <wv2winrt/base.h>
#include <winrt/Microsoft.Web.WebView2.Core.h>
namespace wv2winrt_impl
{
template <typename TIn, typename TOut> struct Converter;
static void GetDispId(::IDispatch* value, LPOLESTR* names, DISPID* dispId)
{
HRESULT hr = value->GetIDsOfNames(IID_NULL, names, 1, LOCALE_USER_DEFAULT, dispId);
if (hr == DISP_E_UNKNOWNNAME)
{
std::wstring message(L"Could not convert object to struct: object missing expected property '");
message += std::wstring(*names) + L"'";
throw winrt::hresult_error(hr, {message});
}
winrt::check_hresult(hr);
}
}
>>
GlobalEntriesInitializerList(instanceEntries, staticEntries) ::= <<
$instanceEntries:GlobalEntry(); separator = ",\n"$$if (instanceEntries && staticEntries)$,
$endif$
$staticEntries:GlobalEntryStaticClasses(); separator = ",\n"$
>>
GlobalsCpp(root) ::= <<
// MultipartEntry.FileName = wv2winrt\globals.cpp
$CopyrightHeader()$
$ProjectPchInclude()$
#include "wv2winrt/globals.h"
$! All generated types are written to their namespace's file. Including all
namespace headers brings in all types. We want visibility of all types since
we need an entry for each of them. !$
$root.AllNamespaces:IncludeWV2WinRTTypeHeader(); separator="\n"$
namespace wv2winrt_impl
{
extern const GlobalEntry s_globalEntries[] =
{
$GlobalEntriesInitializerList([root.AllNamespaces, root.AllEnums], root.AllClassesWithStaticsOrCtors)$
};
extern const size_t s_globalEntriesCount = ARRAYSIZE(s_globalEntries);
extern const InstanceConstructibleEntry s_instanceConstructibleEntries[] =
{
$root.AllInstanceConstructibleEntitiesSorted:InstanceConstructibleEntry(); separator = ",\n"$
};
extern const size_t s_instanceConstructibleEntriesCount = $root.AllInstanceConstructibleEntitiesSorted.Count$;
}
>>
GlobalEntry(entry) ::= <<
{
L"$entry.Name$",
([](const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter& dispatchAdapter, IDispatch** dispatch) -> HRESULT
{
winrt::com_ptr<IDispatch> obj = winrt::make<$entry.TargetTypeName$>(dispatchAdapter);
*dispatch = obj.detach();
return S_OK;
}
)
}
>>
GlobalEntryStaticClasses(entry) ::= <<
{
L"$entry.Name$",
([](const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter& dispatchAdapter, IDispatch** dispatch) -> HRESULT
{
winrt::com_ptr<IDispatch> obj = winrt::make<Static_$entry.TargetTypeName$>(dispatchAdapter);
*dispatch = obj.detach();
return S_OK;
}
)
}
>>
InstanceConstructibleEntry(entry) ::= <<
{
L"$entry.SortName$",
$entry.IsStruct$,
([](IInspectable* abiInspectable,
const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter& dispatchAdapter) -> winrt::com_ptr<IDispatch>
{
$if (entry.IsStruct)$
winrt::Windows::Foundation::IInspectable inspectable;
winrt::copy_from_abi(inspectable, abiInspectable);
return winrt::make<$entry.THBase.TargetTypeName$>(winrt::unbox_value<$entry.THBase.CppWinRTTypeName$>(inspectable), dispatchAdapter);
$else$
return winrt::make<$entry.THBase.TargetTypeName$>(abiInspectable, dispatchAdapter);
$endif$
}
)
}
>>
IncludeWV2WinRTTypeHeader(entry) ::= <<
#include "wv2winrt/$entry.TargetFileName$.g.h"
>>
IncludeCppWinRTNamespace(namespace) ::= <<
#include "winrt/$namespace.CppWinRTFileName$.h"
>>
IncludeCppWinRTNamespaceRaw(namespace) ::= <<
#include "winrt/$namespace$.h"
>><00>J// Copyright (C) Microsoft Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// We use $ to delimit instead of <> because of the amount of C++ template
// code we have to deal with.
delimiters "$", "$"
StaticClass(class) ::= <<
$class:StaticHeader()$
$class:StaticSource()$
>>
StaticHeader(class) ::= <<
// MultipartEntry.FileName = wv2winrt/$class.TargetFileName$.g.h
namespace wv2winrt_impl
{
struct Static_$class.TargetTypeName$ : winrt::implements<Static_$class.TargetTypeName$, DispatchBase>
{
public:
Static_$class.TargetTypeName$(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter& dispatchAdapter);
HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid,
LPOLESTR* names,
unsigned int namesCount,
LCID localeId,
DISPID* dispId) override;
HRESULT STDMETHODCALLTYPE Invoke(DISPID dispId,
REFIID riid,
LCID localeId,
WORD flags,
DISPPARAMS* dispParams,
VARIANT* result,
EXCEPINFO* excepInfo,
UINT* argErr) override;
// ICoreWebView2PrivateDispatchContainer methods
HRESULT STDMETHODCALLTYPE GetPropertyNames(wchar_t***, size_t*);
private:
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
static DispatchProperties s_dispatchProperties;
static const DISPID s_dispatchIds[];
$class:StaticClassDeclarationEvents()$
};
}
>>
StaticClassDeclarationEvents(class) ::= <<
$if (class.HasStaticEvents)$
// Event registration uses the callback's IDispatch* as the key value.
// It is a weak reference and should not be resolved.
$class.StaticEvents:StaticClassDeclarationEventEntry(); separator="\n"$
$endif$
>>
StaticClassDeclarationEventEntry(event) ::= <<
std::map<void*, $class.CppWinRTTypeName$::$event.Name$_revoker > m_eventRegistration$event.Name$;
>>
StaticSource(class) ::= <<
// MultipartEntry.FileName = wv2winrt/$class.TargetFileName$.g.cpp
namespace wv2winrt_impl
{
Static_$class.TargetTypeName$::Static_$class.TargetTypeName$(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter& dispatchAdapter)
: m_dispatchAdapter(dispatchAdapter)
{
}
$if (class.StaticDispatchProperties || class.IsCollectionMap)$
const static wchar_t* const s_Static_$class.TargetTypeName$_dispatchProperties[] =
{
$class.StaticDispatchProperties:{prop | L"$prop.NameAsPropertyName$"}; separator=",\n"$
$if(class.IsCollectionMap)$
$if (class.StaticDispatchProperties)$,$endif$
L"getAllKeyNames"
$endif$
};
$endif$
DispatchProperties Static_$class.TargetTypeName$::s_dispatchProperties = $if (class.StaticDispatchProperties || class.IsCollectionMap)$s_Static_$class.TargetTypeName$_dispatchProperties$else$nullptr$endif$;
$if (class.StaticDispatchProperties)$
const DISPID Static_$class.TargetTypeName$::s_dispatchIds[$length(class.StaticDispatchProperties)$] =
{
$class.StaticDispatchProperties:{prop | $prop.Id$}; separator=",\n"$
};
$endif$
HRESULT Static_$class.TargetTypeName$::GetPropertyNames(wchar_t*** namesOut, size_t* namesLengthOut)
{
*namesLengthOut = $if (class.StaticDispatchProperties || class.IsCollectionMap)$ARRAYSIZE(s_Static_$class.TargetTypeName$_dispatchProperties)$else$0$endif$;
*namesOut = const_cast<wchar_t **>(s_dispatchProperties);
return S_OK;
}
HRESULT Static_$class.TargetTypeName$::GetIDsOfNames(
REFIID riid,
LPOLESTR* names,
unsigned int namesCount,
LCID localeId,
DISPID* dispId)
{
HRESULT hr = DispatchBase::GetIDsOfNames(
riid, names, namesCount, localeId, dispId);
if (SUCCEEDED(hr))
{
hr = DISP_E_MEMBERNOTFOUND;
$if (class.StaticDispatchProperties)$
size_t idx;
if (LookupProperty(s_dispatchProperties, names[0], idx, $class.StaticDispatchProperties.Count$))
{
*dispId = s_dispatchIds[idx];
hr = S_OK;
}
$endif$
$if (class.HasStaticEvents)$
if (FAILED(hr) && wcscmp(names[0], L"addEventListener") == 0)
{
*dispId = $class.EventIdOffset$;
hr = S_OK;
}
else if (FAILED(hr) && wcscmp(names[0], L"removeEventListener") == 0)
{
*dispId = $class.EventIdOffset$ + 1;
hr = S_OK;
}
$endif$
}
return hr;
}
HRESULT Static_$class.TargetTypeName$::Invoke(
DISPID dispId,
REFIID riid,
LCID localeId,
WORD flags,
DISPPARAMS* dispParams,
VARIANT* result,
EXCEPINFO* excepInfo,
UINT* argErr)
{
HRESULT hr = DispatchBase::Invoke(dispId,
riid,
localeId,
flags,
dispParams,
result,
excepInfo,
argErr);
if (SUCCEEDED(hr))
{
hr = DISP_E_MEMBERNOTFOUND;
if (flags == DISPATCH_METHOD || flags == 0)
{
#ifdef _MSC_VER
// A class may have no methods and in that case this switch statement will
// have only a default case and so will invoke warning 4065. This is fine and
// so we disable the warning.
// <https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warnings-c4000-through-c4199>
#pragma warning( push )
#pragma warning( disable: 4065 )
#endif
switch (dispId)
{
$if (class.HasConstructor)$
// 0 is the special dispId refering to the current object.
// We use it here to mean you are invoking a constructor.
case 0:
$class.ConstructorMethods:StaticConstructorMethodInvokeCase(); separator="\n"$
break;
$endif$
$class.StaticMethodsGroupedByName:StaticMethodGroupInvokeCase(); separator="\n"$
$if (class.HasStaticEvents)$
$class:StaticClassAddEventListenerInvoke()$
$class:StaticClassRemoveEventListenerInvoke()$
$endif$
default:
hr = DISP_E_MEMBERNOTFOUND;
break;
}
#ifdef _MSC_VER
#pragma warning( pop )
#endif
}
else if (flags == DISPATCH_PROPERTYGET || flags == DISPATCH_PROPERTYPUT)
{
#pragma warning( push )
#pragma warning( disable: 4065 )
switch (dispId)
{
$class.StaticProperties:StaticPropertyInvokeCase(); separator="\n"$
default:
hr = DISP_E_MEMBERNOTFOUND;
break;
}
#pragma warning( pop )
}
}
return hr;
}
}
>>
StaticClassAddEventListenerInvoke(class) ::= <<
case $class.EventIdOffset$:
// addEventListener(name, callback) Invoke method
if (2 == dispParams->cArgs)
{
// Remember that rgvarg stores parameters in reverse order.
std::wstring eventName =
Converter<VARIANT, std::wstring>(m_dispatchAdapter).Convert(dispParams->rgvarg[1]);
if (dispParams->rgvarg[0].vt == VT_DISPATCH &&
dispParams->rgvarg[0].pdispVal != nullptr)
{
$class.StaticEvents:StaticClassAddEventListenerInvokeEventEntry(); separator="\nelse "$
else
{
// AddEventListener silently ignores subscriptions to events that don't exist.
hr = S_OK;
}
}
else
{
hr = DISP_E_BADVARTYPE;
}
}
else
{
hr = DISP_E_BADPARAMCOUNT;
}
break;
>>
ArgAsVariant(arg) ::= <<
UniqueVariant $arg$AsVARIANT(
Converter<decltype($arg$), VARIANT>(dispatchAdapter).
Convert($arg$));
>>
StaticClassAddEventListenerInvokeEventEntry(event) ::= <<
if (_wcsicmp(eventName.c_str(), L"$event.Name$") == 0)
{
winrt::com_ptr<::IDispatch> callback;
hr = dispParams->rgvarg[0].pdispVal->QueryInterface(callback.put());
if (SUCCEEDED(hr))
{
// Subsequent identical registrations are discarded.
if (m_eventRegistration$event.Name$.find(callback.get()) ==
m_eventRegistration$event.Name$.end())
{
auto dispatchAdapter = m_dispatchAdapter; // Copy for the lambda capture
// subscribe to event
auto revoker = $class.CppWinRTTypeName$::$event.Name$(
winrt::auto_revoke,
$if (event.HasSource)$
[callback, dispatchAdapter](const auto& $event.SourceName$$event.NonSourceInvokeParams:{param | , const auto& $param$}$) {
$ArgAsVariant(event.SourceName)$
$event.NonSourceInvokeParams:ArgAsVariant(); separator="\n"$
IDispatch* $event.SourceName$AsIDispatch = nullptr; // Weak ref. Do not release.
if ($event.SourceName$AsVARIANT.vt == VT_DISPATCH)
{
$event.SourceName$AsIDispatch = $event.SourceName$AsVARIANT.pdispVal;
}
VARIANT paramsAsVARIANTs[$event.NonSourceInvokeParams.Count$] = { $event.NonSourceInvokeParams:{param | $param$AsVARIANT}; separator=", "$ };
winrt::com_ptr<IDispatch> aggregateEventArgs;
if (SUCCEEDED(CreateAggregateEventArgs(L"$event.NameAsJavascript$", $event.SourceName$AsIDispatch, paramsAsVARIANTs, $event.NonSourceInvokeParams.Count$, aggregateEventArgs.put())))
{
$else$
[callback, dispatchAdapter]($event.NonSourceInvokeParams:{param | const auto& $param$}$) {
$event.NonSourceInvokeParams:ArgAsVariant(); separator="\n"$
$if (event.HasInvokeParams)$
VARIANT paramsAsVARIANTs[$event.NonSourceInvokeParams.Count$] = { $event.NonSourceInvokeParams:{param | $param$AsVARIANT}; separator=", "$ };
$else$
VARIANT* paramsAsVARIANTs = nullptr;
$endif$
winrt::com_ptr<IDispatch> aggregateEventArgs;
if (SUCCEEDED(CreateAggregateEventArgs(L"$event.NameAsJavascript$", nullptr, paramsAsVARIANTs, $event.NonSourceInvokeParams.Count$, aggregateEventArgs.put())))
{
$endif$
// Ownership is passed to the callback below
VARIANT aggregateEventArgsAsVARIANT{VT_DISPATCH};
aggregateEventArgsAsVARIANT.pdispVal = aggregateEventArgs.get();
DISPPARAMS callbackDispParams = {};
VARIANT callbackDispParamsVarg[1] = {};
callbackDispParams.cArgs = ARRAYSIZE(callbackDispParamsVarg);
callbackDispParams.rgvarg = &callbackDispParamsVarg[0];
callbackDispParams.rgvarg[0] = aggregateEventArgsAsVARIANT;
// We don't actually do anything with the result, but we collect it in case
// the callback doesn't check for nullptr out parameters.
UniqueVariant callbackResult;
EXCEPINFO excepInfo;
UINT argErr;
callback->Invoke(
DISPID_VALUE, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD,
&callbackDispParams, &callbackResult,
&excepInfo, &argErr);
}
});
m_eventRegistration$event.Name$[callback.get()] =
std::move(revoker);
}
}
}
>>
StaticClassRemoveEventListenerInvoke(class) ::= <<
case $class.EventIdOffset$ + 1:
// removeEventListener(name, callback) invoke method
if (2 == dispParams->cArgs)
{
// Remember that rgvarg stores parameters in reverse order.
std::wstring eventName =
Converter<VARIANT, std::wstring>(m_dispatchAdapter).Convert(dispParams->rgvarg[1]);
if (dispParams->rgvarg[0].vt == VT_DISPATCH &&
dispParams->rgvarg[0].pdispVal != nullptr)
{
$class.StaticEvents:StaticClassRemoveEventListenerInvokeEventEntry(); separator="\nelse "$
else
{
// RemoveEventListener silently ignores unregistering events that don't exist.
hr = S_OK;
}
}
else
{
hr = DISP_E_BADVARTYPE;
}
}
else
{
hr = DISP_E_BADPARAMCOUNT;
}
break;
>>
StaticClassRemoveEventListenerInvokeEventEntry(event) ::= <<
if (_wcsicmp(eventName.c_str(), L"$event.Name$") == 0)
{
// We use the callback IDispatch* as the key. Its stored only
// as a value, weakly.
// Because the value type is a winrt::event_revoker it will
// revoke in its destructor so simply erasing the value will
// fix the map and unregister the event.
// removeEventListener silently ignores requests to unregister
// event handlers that aren't registered.
m_eventRegistration$event.Name$.erase(dispParams->rgvarg[0].pdispVal);
hr = S_OK;
}
>>
StaticConstructorMethodInvokeCase(method) ::= <<
if ($method.Parameters.Count$ == dispParams->cArgs)
{
hr = S_OK;
try
{
$class.CppWinRTTypeName$ resultAsWinRT {
$method.Parameters:MethodInvokeCaseParameter(); separator=",\n"$
};
*result = Converter<decltype(resultAsWinRT), VARIANT>(m_dispatchAdapter).Convert(resultAsWinRT);
}
catch (winrt::hresult_error)
{
hr = winrt::to_hresult();
}
catch (...)
{
hr = E_UNEXPECTED;
}
}
>>
StaticMethodGroupInvokeCase(methodGroup) ::= <<
case $methodGroup.Id$:
{
// Invoke for $methodGroup.Name$
$methodGroup.Methods:StaticMethodInvokeCase(); separator="\nelse "$
else
{
hr = DISP_E_BADPARAMCOUNT;
}
break;
}
>>
StaticMethodInvokeCase(method) ::= <<
$if (method.IsAsync)$
$method:StaticAsyncMethodInvokeCase()$
$else$
$method:StaticSyncMethodInvokeCase()$
$endif$
>>
StaticAsyncMethodInvokeCase(method) ::= <<
if ($method.ParametersNoOut.Count$ == dispParams->cArgs)
{
hr = S_OK;
try
{
auto asyncResultAsWinRT = $class.CppWinRTTypeName$::$method.Name$(
$method.Parameters:MethodInvokeCaseParameter(); separator=",\n"$);
if (asyncResultAsWinRT)
{
winrt::com_ptr<ICoreWebView2PrivateDispatchAsyncResult> asyncResultAsCOM;
wv2winrt_impl::CreateDispatchAsyncResult(asyncResultAsCOM.put());
winrt::com_ptr<ICoreWebView2PrivateDispatchAsyncFinishedHandler> asyncCompletedHandlerAsCOM;
asyncResultAsCOM.as(asyncCompletedHandlerAsCOM);
auto dispatchAdapter = m_dispatchAdapter;
winrt::com_ptr<ICoreWebView2PrivateDispatchAsyncInfo> asyncInfoAsCOM;
asyncResultAsCOM.as(asyncInfoAsCOM);
asyncInfoAsCOM->SetAsyncInfo(asyncResultAsWinRT);
asyncResultAsWinRT.Completed(
[asyncCompletedHandlerAsCOM, dispatchAdapter](
const auto& asyncInfo,
winrt::Windows::Foundation::AsyncStatus const& asyncStatus)
{
if (asyncStatus == winrt::Windows::Foundation::AsyncStatus::Completed)
{
UniqueVariant resultAsVariant;
$if (!method.IsReturnTypeAsyncVoid)$
auto resultAsWinRT = asyncInfo.GetResults();
resultAsVariant.reset(Converter<decltype(resultAsWinRT), VARIANT>(
dispatchAdapter)
.Convert(resultAsWinRT));
$endif$
asyncCompletedHandlerAsCOM->Invoke(
asyncInfo.ErrorCode().value,
resultAsVariant.addressof());
}
else
{
asyncCompletedHandlerAsCOM->Invoke(asyncInfo.ErrorCode().value, nullptr);
}
});
UniqueVariant resultAsVariant;
resultAsVariant.vt = VT_UNKNOWN;
asyncResultAsCOM.as<IUnknown>().copy_to(&resultAsVariant.punkVal);
*result = resultAsVariant.release();
}
else
{
hr = E_UNEXPECTED;
}
}
catch (winrt::hresult_error)
{
hr = winrt::to_hresult();
}
catch (...)
{
hr = E_UNEXPECTED;
}
}
>>
StaticSyncMethodInvokeCase(method) ::= <<
if ($method.ParametersNoOut.Count$ == dispParams->cArgs)
{
hr = S_OK;
try
{
$if (method.HasMultipleReturnValuesOrOutParameters)$
auto returnAggregator = winrt::make_self<wv2winrt_impl::ReturnAggregator>(
$method.ParametersOut.Count$, !$method.IsReturnTypeVoid$);
$endif$
$if (!method.IsReturnTypeVoid)$auto resultAsWinRT = $endif$$class.CppWinRTTypeName$::$method.Name$(
$method.Parameters:MethodInvokeCaseParameter(); separator=",\n"$);
$if (!method.IsReturnTypeVoid)$
$if (method.HasOutParameters)$
returnAggregator->SetReturnValue(
Converter<decltype(resultAsWinRT), VARIANT>(m_dispatchAdapter).Convert(resultAsWinRT));
$else$
*result = Converter<decltype(resultAsWinRT), VARIANT>(m_dispatchAdapter).Convert(resultAsWinRT);
$endif$
$endif$
$if (method.HasMultipleReturnValuesOrOutParameters)$
result->vt = VT_DISPATCH;
returnAggregator.as<::IDispatch>().copy_to(&result->pdispVal);
$endif$
}
catch (winrt::hresult_error)
{
hr = winrt::to_hresult();
}
catch (...)
{
hr = E_UNEXPECTED;
}
}
>>
StaticPropertyInvokeCase(property) ::= <<
case $property.Id$:
{
// Invoke for $property.Name$
if (flags == DISPATCH_PROPERTYGET)
{
hr = S_OK;
try
{
auto resultAsWinRT = $class.CppWinRTTypeName$::$property.Name$();
*result = Converter<decltype(resultAsWinRT), VARIANT>(m_dispatchAdapter).Convert(resultAsWinRT);
}
catch (winrt::hresult_error)
{
hr = winrt::to_hresult();
}
catch (...)
{
hr = E_UNEXPECTED;
}
}
$if(property.HasSetter)$
else if (flags == DISPATCH_PROPERTYPUT)
{
hr = S_OK;
try
{
$class.CppWinRTTypeName$::$property.Name$(
Converter<VARIANT, $property.THType.CppWinRTTypeName$>(m_dispatchAdapter).Convert(*(dispParams->rgvarg)));
}
catch (winrt::hresult_error)
{
hr = winrt::to_hresult();
}
catch (...)
{
hr = E_UNEXPECTED;
}
}
$endif$
break;
}
>>
!// Copyright (C) Microsoft Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// We use $ to delimit instead of <> because of the amount of C++ template
// code we have to deal with.
delimiters "$", "$"
Struct(struct) ::= <<
$struct:StructHeader()$
$struct:StructSource()$
$struct:StructImplicitConverter()$
>>
StructHeader(struct) ::= <<
// MultipartEntry.FileName = wv2winrt/$struct.TargetFileName$.g.h
namespace wv2winrt_impl
{
struct $struct.TargetTypeName$ : winrt::implements<
$struct.TargetTypeName$,
DispatchBase>
{
public:
$struct.TargetTypeName$($struct.CppWinRTTypeName$ innerObject, const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter& dispatchAdapter);
// IDispatch methods
HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid,
LPOLESTR* names,
unsigned int namesCount,
LCID localeId,
DISPID* dispId) override;
HRESULT STDMETHODCALLTYPE Invoke(DISPID dispId,
REFIID riid,
LCID localeId,
WORD flags,
DISPPARAMS* dispParams,
VARIANT* result,
EXCEPINFO* excepInfo,
UINT* argErr) override;
// ICoreWebView2PrivateDispatchContainer methods
HRESULT STDMETHODCALLTYPE GetInnerObject(IUnknown** object) override;
HRESULT STDMETHODCALLTYPE GetPropertyNames(wchar_t***, size_t*);
private:
$struct.CppWinRTTypeName$ m_innerObject;
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
static DispatchProperties s_dispatchProperties;
static const DISPID s_dispatchIds[];
};
}
>>
StructSource(struct) ::= <<
// MultipartEntry.FileName = wv2winrt/$struct.TargetFileName$.g.cpp
namespace wv2winrt_impl
{
$struct.TargetTypeName$::$struct.TargetTypeName$($struct.CppWinRTTypeName$ innerObject, const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter& dispatchAdapter)
: m_innerObject(innerObject), m_dispatchAdapter(dispatchAdapter)
{
}
$if (struct.DispatchProperties)$
const static wchar_t* const s_$struct.TargetTypeName$_dispatchProperties[] =
{
$struct.DispatchProperties:{prop | L"$prop.NameAsPropertyName$"}; separator=",\n"$
};
$endif$
DispatchProperties $struct.TargetTypeName$::s_dispatchProperties = $if (struct.DispatchProperties)$s_$struct.TargetTypeName$_dispatchProperties$else$nullptr$endif$;
$if (struct.DispatchProperties)$
const DISPID $struct.TargetTypeName$::s_dispatchIds[$length(struct.DispatchProperties)$] =
{
$struct.DispatchProperties:{prop | $prop.Id$}; separator=",\n"$
};
$endif$
HRESULT $struct.TargetTypeName$::GetIDsOfNames(REFIID riid,
LPOLESTR* names,
unsigned int namesCount,
LCID localeId,
DISPID* dispId)
{
HRESULT hr = DispatchBase::GetIDsOfNames(
riid, names, namesCount, localeId, dispId);
if (SUCCEEDED(hr))
{
hr = DISP_E_MEMBERNOTFOUND;
$if (struct.DispatchProperties)$
size_t idx;
if (LookupProperty(s_dispatchProperties, names[0], idx, $struct.DispatchProperties.Count$))
{
*dispId = s_dispatchIds[idx];
hr = S_OK;
}
$endif$
}
return hr;
}
HRESULT $struct.TargetTypeName$::Invoke(
DISPID dispId,
REFIID riid,
LCID localeId,
WORD flags,
DISPPARAMS* dispParams,
VARIANT* result,
EXCEPINFO* excepInfo,
UINT* argErr)
{
HRESULT hr = DispatchBase::Invoke(dispId,
riid,
localeId,
flags,
dispParams,
result,
excepInfo,
argErr);
if (SUCCEEDED(hr))
{
hr = DISP_E_MEMBERNOTFOUND;
if (flags == DISPATCH_PROPERTYGET || flags == DISPATCH_PROPERTYPUT)
{
#pragma warning( push )
#pragma warning( disable: 4065 )
switch (dispId)
{
$struct.Fields:FieldInvokeCase(); separator="\n"$
default:
hr = DISP_E_MEMBERNOTFOUND;
break;
}
#pragma warning( pop )
}
}
return hr;
}
HRESULT $struct.TargetTypeName$::GetInnerObject(IUnknown** object)
{
$! Return boxed winrt struct as IUnknown !$
auto boxed = winrt::box_value(m_innerObject);
*object = boxed.as<IUnknown>().detach();
return S_OK;
}
HRESULT $struct.TargetTypeName$::GetPropertyNames(wchar_t*** namesOut, size_t* namesLengthOut)
{
*namesLengthOut = $if (struct.DispatchProperties)$ARRAYSIZE(s_$struct.TargetTypeName$_dispatchProperties)$else$0$endif$;
*namesOut = const_cast<wchar_t **>(s_dispatchProperties);
return S_OK;
}
} // namespace wv2winrt_impl
>>
FieldInvokeCase(field) ::= <<
case $field.Id$:
// Invoke for $field.Name$
if (flags == DISPATCH_PROPERTYGET)
{
hr = S_OK;
try
{
$if (snippetResources.(field.GetSnippetKey))$
$field.GetSnippetKey:ResourceSnippet()$
$else$
auto resultAsWinRT = m_innerObject.$field.CppWinRTName$;
*result = Converter<decltype(resultAsWinRT), VARIANT>(m_dispatchAdapter).Convert(resultAsWinRT);
$endif$
}
catch (winrt::hresult_error)
{
hr = winrt::to_hresult();
}
catch (...)
{
hr = E_UNEXPECTED;
}
}
else if (flags == DISPATCH_PROPERTYPUT)
{
hr = S_OK;
try
{
$if (snippetResources.(field.PutSnippetKey))$
$field.PutSnippetKey:ResourceSnippet()$
$else$
m_innerObject.$field.CppWinRTName$ = Converter<VARIANT, $field.Type.CppWinRTTypeName$>(m_dispatchAdapter).Convert(*(dispParams->rgvarg));
$endif$
}
catch (winrt::hresult_error)
{
hr = winrt::to_hresult();
}
catch (...)
{
hr = E_UNEXPECTED;
}
}
break;
>>
StructImplicitConverter(struct) ::= <<
$if (struct.NeedsImplicitConverter)$
// MultipartEntry.FileName = wv2winrt/implicitstructs.g.h
namespace wv2winrt_impl
{
template<>
struct Converter<ICoreWebView2PrivateRemoteDictionary*, $struct.CppWinRTTypeName$>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&
dispatchAdapter)
: m_dispatchAdapter(dispatchAdapter)
{
}
$struct.CppWinRTTypeName$ Convert(ICoreWebView2PrivateRemoteDictionary* value)
{
winrt::com_ptr<::IDispatch> valueAsIDispatch;
winrt::check_hresult(value->QueryInterface(IID_PPV_ARGS(valueAsIDispatch.put())));
$struct.Fields:RemoteDictionaryFieldInvoke(); separator="\n"$
return {
$struct.Fields:{field | Converter<VARIANT, $field.Type.CppWinRTTypeName$>(m_dispatchAdapter).Convert(result$field.Id$)}; separator=",\n"$
};
}
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
};
}
$endif$
>>
RemoteDictionaryFieldInvoke(field) ::= <<
LPOLESTR names$field.Id$ = const_cast<LPOLESTR>(L"$field.Name$");
DISPID dispid$field.Id$ = 0;
GetDispId(valueAsIDispatch.get(), &names$field.Id$, &dispid$field.Id$);
VARIANT result$field.Id$;
EXCEPINFO excepInfo$field.Id$;
winrt::check_hresult(valueAsIDispatch->Invoke(dispid$field.Id$, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, NULL, &result$field.Id$, &excepInfo$field.Id$, NULL));
>>
<00>// Copyright (C) Microsoft Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <windows.h>
#include <winrt/Windows.Foundation.h>
namespace wv2winrt_impl
{
struct __declspec(uuid("32A1E429-C362-48B3-832D-4A895810C573"))
ICoreWebView2PrivateDispatchAsyncFinishedHandler : ::IUnknown
{
virtual HRESULT STDMETHODCALLTYPE Invoke(HRESULT errorCode, VARIANT* result) = 0;
};
struct __declspec(uuid("79EDD0B3-1E40-4A58-B771-FE8B4F380DF9"))
ICoreWebView2PrivateDispatchAsyncResult : ::IUnknown
{
// Add an IDispatch that will be invoked after async completion. If provided before
// async completion it will be invoked later after async completion. If provided after
// async completion it will be invoked immediately.
virtual HRESULT STDMETHODCALLTYPE SetCompletedHandler(
ICoreWebView2PrivateDispatchAsyncFinishedHandler* completedCallback) = 0;
};
// Creates an object that implements ICoreWebView2PrivateDispatchAsyncResult to allow callers to
// observe async completion. It also implements IDispatch and can be Invoked to set the result
// of async completion.
HRESULT CreateDispatchAsyncResult(ICoreWebView2PrivateDispatchAsyncResult** asyncResult);
struct __declspec(uuid("82fe62e1-a009-427c-8d1c-59b0a377b73d"))
ICoreWebView2PrivateDispatchAsyncResult2 : ::IUnknown
{
virtual HRESULT STDMETHODCALLTYPE Cancel() = 0;
};
struct __declspec(uuid("8df7da06-d243-4ef8-b927-fe346d2e7ff6"))
ICoreWebView2PrivateDispatchAsyncInfo : ::IUnknown
{
virtual HRESULT STDMETHODCALLTYPE
SetAsyncInfo(winrt::Windows::Foundation::IAsyncInfo asyncInfo) = 0;
};
} // namespace wv2winrt_impl
<00>// Copyright (C) Microsoft Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <unknwn.h>
#include <windows.foundation.h>
#include <winrt/base.h>
<00><>// Copyright (C) Microsoft Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include "wv2winrt/remotedictionary.h"
#include "wv2winrt/timehelper.h"
#include <ios>
#include <sstream>
// Must be included before any cppwinrt headers
#include <wv2winrt/base.h>
#include <winrt/Microsoft.Web.WebView2.Core.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Foundation.h>
namespace wv2winrt_impl
{
#define DEFINE_IS_TEMPLATIZED_TYPE_CHECK(WinRTType, Name) \
template <typename T> struct TIs##Name : public std::false_type \
{ \
}; \
template <typename T> struct TIs##Name<WinRTType<T>> : public std::true_type \
{ \
}; \
template <typename T> constexpr bool TIs##Name##_v = TIs##Name<T>::value;
DEFINE_IS_TEMPLATIZED_TYPE_CHECK(
winrt::Windows::Foundation::Collections::IVectorView, VectorView);
DEFINE_IS_TEMPLATIZED_TYPE_CHECK(winrt::Windows::Foundation::Collections::IVector, Vector);
DEFINE_IS_TEMPLATIZED_TYPE_CHECK(winrt::array_view, ArrayView);
DEFINE_IS_TEMPLATIZED_TYPE_CHECK(winrt::com_array, ComArray);
#undef DEFINE_IS_TEMPLATIZED_TYPE_CHECK
template <typename T> T GetDefaultValue()
{
if constexpr (std::is_integral_v<T> || std::is_floating_point_v<T>)
{
return 0;
}
else if constexpr (std::is_same_v<T, bool>)
{
return false;
}
else if constexpr (std::is_constructible_v<T>)
{
return {};
}
else
{
return {nullptr};
}
}
// Some helpers to make it easier to read and write the below Converter specializations.
// normalize_t<T> will turn const T& into T, is_similar_v<T1, T2> is true when T1 and T2
// are the same after normalize_t. We have many Converter specializations that do the same
// thing for and need to be defined for both T and const T&.
template <typename T> using normalize_t = std::remove_const_t<std::remove_reference_t<T>>;
template <typename T1, typename T2>
using is_similar = std::is_same<normalize_t<T1>, normalize_t<T2>>;
template <typename T1, typename T2> constexpr bool is_similar_v = is_similar<T1, T2>::value;
template <typename T1, typename T2>
using variant_if_similar_t = std::enable_if_t<is_similar_v<T1, T2>, VARIANT>;
// MemberContainer just contains a member of a certain type. But not all types have
// default constructors. So we use the is_constructible to figure out if it does and
// if so pick the template specialization that uses default construction or otherwise
// uses nullptr_t initialization. Most smart types allow for default construction
// but the winrt types do not and require explicit {nullptr} init.
template <typename TMember, bool HasDefaultCtor = std::is_constructible<TMember>::value>
struct MemberContainer;
template <typename TMember> struct MemberContainer<TMember, true>
{
TMember value;
};
template <typename TMember> struct MemberContainer<TMember, false>
{
TMember value{nullptr};
};
// MemberContainerArray is similar to MemberContainer but for arrays. Unlike
// MemberContainerOutArray, it does not require a size to be passed in the constructor
// and initializes an empty array.
template <typename TMember, bool HasDefaultCtor = std::is_constructible<TMember>::value>
struct MemberContainerArray;
template <typename TMember> struct MemberContainerArray<TMember, true>
{
winrt::com_array<TMember> value;
};
template <typename TMember> struct MemberContainerArray<TMember, false>
{
winrt::com_array<TMember> value{nullptr};
};
// MemberContainerOutArray is similar to MemberContainerArray but requires a size to be
// passed in the constructor and initializes an com_array of that size.
template <typename TMember, bool HasDefaultCtor = std::is_constructible<TMember>::value>
struct MemberContainerOutArray;
template <typename TMember> struct MemberContainerOutArray<TMember, true>
{
MemberContainerOutArray(uint32_t size) : value(size)
{
}
winrt::com_array<TMember> value;
};
template <typename TMember> struct MemberContainerOutArray<TMember, false>
{
MemberContainerOutArray(uint32_t size) : value{size, nullptr}
{
}
winrt::com_array<TMember> value{size, nullptr};
};
template <typename TIn, typename TOut> struct Converter;
// RefConverter just does the normal Converter functionality but obtaining the in value is
// separate from and requires storage before later converting to the out value. Call
// ConvertRef with where to store the result of the conversion and ConvertRef will return a
// pointer to where the input should be stored. When the object destructs it will perform
// the conversion. This is intended to be used in a method call as a temporary object like:
// VARIANT indexAsVariant;
// Uri.GetIndex("find", RefConverter<uint32_t,
// VARIANT>(dispatchAdapter).ConvertRef(&indexAsVariant));
// In the above GetIndex has a uint32_t out parameter for its second parameter. We receive
// the value from the out param via the return value of ConvertRef. When the RefConverter
// destructs (which occurs after the statement completes) the conversion happens and is
// stored into indexAsVariant.
//
template <typename TIn, typename TOut> struct RefConverter
{
RefConverter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&
dispatchAdapter)
: m_dispatchAdapter(dispatchAdapter)
{
}
~RefConverter()
{
*m_out = Converter<TIn, TOut>(m_dispatchAdapter).Convert(m_in.value);
}
TIn& ConvertRef(TOut* out)
{
m_out = out;
m_in.value = Converter<TOut, TIn>(m_dispatchAdapter).Convert(*out);
return m_in.value;
}
TIn& ConvertOut(TOut* out)
{
m_out = out;
return m_in.value;
}
TIn& ConvertOutRef(TOut* out)
{
m_out = out;
return m_in.value;
}
private:
MemberContainer<TIn> m_in;
TOut* m_out;
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
};
template <typename TInChild> struct RefConverter<winrt::array_view<TInChild>, VARIANT>
{
using TIn = winrt::com_array<TInChild>;
using TInArrayView = winrt::array_view<TInChild>;
using TOut = VARIANT;
RefConverter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&
dispatchAdapter)
: m_dispatchAdapter(dispatchAdapter)
{
}
~RefConverter()
{
if (!m_isInOutArray)
{
*m_out = Converter<TIn, TOut>(m_dispatchAdapter).Convert(m_in.value);
}
else
{
*m_out = Converter<TIn, TOut>(m_dispatchAdapter).Convert(m_arrayPointer->value);
delete m_arrayPointer;
}
}
TIn& ConvertRef(TOut* out)
{
m_out = out;
return m_in.value;
}
TInArrayView ConvertOut(TOut* out)
{
m_out = out;
return m_in.value;
}
TInArrayView ConvertInOut(VARIANT arr, TOut* out)
{
// Used for In Out Array parameters in order to get the size of the passed
// in array and allocate the new out winrt::com_array.
m_out = out;
if (arr.vt & VT_ARRAY)
{
SAFEARRAY* pArray = arr.parray;
long lBound, uBound;
SafeArrayGetLBound(pArray, 1, &lBound);
SafeArrayGetUBound(pArray, 1, &uBound);
long d = uBound - lBound + 1;
uint32_t size = static_cast<uint32_t>(d);
m_arrayPointer = new MemberContainerOutArray<TInChild>(size);
m_isInOutArray = true;
return m_arrayPointer->value;
}
return m_in.value;
}
TIn& ConvertOutRef(TOut* out)
{
m_out = out;
return m_in.value;
}
private:
// m_in is used to store the initialized com_array if no array is passed in.
// m_arrayPointer is used to store the initialized com_array if an array is
// passed in, it handles in out arrays.
// m_out is used to store the result array after the method completes.
MemberContainerArray<TInChild> m_in;
MemberContainerOutArray<TInChild>* m_arrayPointer = nullptr;
TOut* m_out;
bool m_isInOutArray = false;
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
};
// The Converter template converts values of type TIn to corresponding value of TOut.
// We use template specialization to customize the conversion behavior for particular types.
// The default non-specialized case just tries to cast.
template <typename TIn, typename TOut> struct Converter
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&
dispatchAdapter)
{
}
TOut Convert(const TIn& value)
{
return static_cast<const TOut>(value);
}
};
// A bunch of VARIANT types can be implemented the same via this macro
#define CONVERTER_VARIANT_TO_FROM_TYPE(winrtType, vtType, variantProperty) \
static_assert(sizeof(winrtType) == sizeof(decltype(VARIANT().variantProperty))); \
static_assert( \
std::is_signed_v<winrtType> == std::is_signed_v<decltype(VARIANT().variantProperty)>); \
\
template <typename TIn> struct Converter<TIn, variant_if_similar_t<TIn, winrtType>> \
{ \
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&) \
{ \
} \
VARIANT Convert(winrtType value) \
{ \
VARIANT result{vtType}; \
result.variantProperty = value; \
return result; \
} \
};
CONVERTER_VARIANT_TO_FROM_TYPE(uint8_t, VT_UI1, bVal)
CONVERTER_VARIANT_TO_FROM_TYPE(int16_t, VT_I2, iVal)
CONVERTER_VARIANT_TO_FROM_TYPE(uint16_t, VT_UI2, uiVal)
CONVERTER_VARIANT_TO_FROM_TYPE(int32_t, VT_I4, lVal)
CONVERTER_VARIANT_TO_FROM_TYPE(uint32_t, VT_UI4, ulVal)
CONVERTER_VARIANT_TO_FROM_TYPE(int64_t, VT_I8, llVal)
CONVERTER_VARIANT_TO_FROM_TYPE(uint64_t, VT_UI8, ullVal)
CONVERTER_VARIANT_TO_FROM_TYPE(float, VT_R4, fltVal)
CONVERTER_VARIANT_TO_FROM_TYPE(double, VT_R8, dblVal)
#undef CONVERTER_VARIANT_TO_FROM_TYPE
// Convert variant to integers
template <typename TInt>
struct Converter<
std::enable_if_t<
std::is_integral_v<std::remove_reference_t<TInt>> ||
std::is_floating_point_v<std::remove_reference_t<TInt>>,
VARIANT>,
TInt>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&
dispatchAdapter)
: m_dispatchAdapter(dispatchAdapter)
{
}
TInt Convert(VARIANT value)
{
if (value.vt & VT_ARRAY)
{
winrt::com_array<TInt> array =
Converter<VARIANT, winrt::com_array<TInt>>(m_dispatchAdapter).Convert(value);
return (array.size() == 1) ? array[0] : 0;
}
#define CONVERTER_INTEGRAL_CASE(vtType, variantProperty) \
case vtType: \
/* For integral types, we need to cast to uint64_t first */ \
/* to ensure we get the correct conversion for large values */ \
if (std::is_integral_v<TInt>) \
return static_cast<TInt>(static_cast<uint64_t>(value.variantProperty)); \
return static_cast<TInt>(value.variantProperty);
switch (value.vt)
{
CONVERTER_INTEGRAL_CASE(VT_I1, cVal)
CONVERTER_INTEGRAL_CASE(VT_UI1, bVal)
CONVERTER_INTEGRAL_CASE(VT_I2, iVal)
CONVERTER_INTEGRAL_CASE(VT_UI2, uiVal)
CONVERTER_INTEGRAL_CASE(VT_I4, lVal)
CONVERTER_INTEGRAL_CASE(VT_UI4, ulVal)
CONVERTER_INTEGRAL_CASE(VT_I8, llVal)
CONVERTER_INTEGRAL_CASE(VT_UI8, ullVal)
CONVERTER_INTEGRAL_CASE(VT_R4, fltVal)
CONVERTER_INTEGRAL_CASE(VT_R8, dblVal)
#undef CONVERTER_INTEGRAL_CASE
case VT_BOOL:
return static_cast<TInt>((value.boolVal == VARIANT_TRUE) ? 1 : 0);
case VT_DATE:
// This will be in JS Date format - milliseconds from UNIX epoch
return static_cast<TInt>(VariantTimeToJsTime(value.date));
case VT_DISPATCH:
case VT_BSTR:
{
try
{
std::wstring stringValue =
Converter<VARIANT, std::wstring>(m_dispatchAdapter).Convert(value);
TInt result = 0;
size_t index = 0;
if (stringValue.find('.') != std::string::npos)
{
// If the string contains a decimal, try converting the string to a double.
result = static_cast<decltype(result)>(std::stod(stringValue, &index));
}
else
{
// Otherwise, try converting the string to an integer.
result = static_cast<decltype(result)>(std::stoi(stringValue, &index));
if (result == 0 && index == 1)
{
// If stoi got zero, check to see if stringValue had a prefix for bin,
// oct, or hex.
std::wstring prefix = stringValue.substr(0, 2);
if (prefix.compare(L"0x") == 0 || prefix.compare(L"0X") == 0)
{
result = static_cast<decltype(result)>(
std::stoi(stringValue.substr(2), &index, 16));
}
else if (prefix.compare(L"0b") == 0 || prefix.compare(L"0B") == 0)
{
result = static_cast<decltype(result)>(
std::stoi(stringValue.substr(2), &index, 2));
}
else if (prefix.compare(L"0o") == 0 || prefix.compare(L"0O") == 0)
{
result = static_cast<decltype(result)>(
std::stoi(stringValue.substr(2), &index, 8));
}
// Increment index for offset of the substring above. If none of the
// above conditions were met, then result is already 0.
index += 2;
}
}
// If index is not the length of the string, then there are characters in the
// string that couldn't be converted to an int. This makes the string an invalid
// int and should return 0.
return (index == stringValue.length()) ? result : 0;
}
catch (...)
{
return 0;
}
}
default:
return 0;
}
}
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
};
// Converting any cpp/winrt IUnknown/IInspectable object to an IDispatch VARIANT
// enable_if_t takes a bool as the first template param and resolves to the second template
// param type. In our case it resolves to a VARIANT and the bool is if our TIn type is
// derived from IUnknown. The conditional bool isn't really related to the VARIANT type and
// it more belongs on the TIn, but C++ doesn't want us to use TIn as the type that
// enable_if_t resolves to. The is_base_of_v template will check if the second template
// param is derived from the first. We use it here to determine if TIn is derived from the
// c++/winrt IUnknown type or if TIn is a reference to a c++/winrt IUnknown derived type. We
// do this using the remove_reference_t template which given a T& type will give out T type.
template <typename TIn>
struct Converter<
TIn,
std::enable_if_t<
(std::is_base_of_v<winrt::Windows::Foundation::IUnknown, TIn> ||
std::is_base_of_v<winrt::Windows::Foundation::IUnknown, std::remove_reference_t<TIn>>),
VARIANT>>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&
dispatchAdapter)
: m_dispatchAdapter(dispatchAdapter)
{
}
VARIANT Convert(const TIn& value)
{
if (!value)
{
VARIANT resultAsVariant{VT_EMPTY};
return resultAsVariant;
}
if (auto valueAsIPropertyValue =
value.try_as<winrt::Windows::Foundation::IPropertyValue>())
{
auto resultAsValueVariant =
Converter<decltype(valueAsIPropertyValue), VARIANT>(m_dispatchAdapter)
.Convert(valueAsIPropertyValue);
// Boxed WinRT structs implement IPropertyValue but can't get arbitrary types out of
// it, the Converter will return VT_NULL for them, and we'll let dispatch adapter
// unbox the struct.
if (resultAsValueVariant.vt != VT_NULL)
{
return resultAsValueVariant;
}
}
winrt::Windows::Foundation::IInspectable valueAsInspectable;
winrt::Windows::Foundation::IInspectable resultAsInspectable;
winrt::com_ptr<IDispatch> resultAsDispatch;
VARIANT resultAsVariant{VT_DISPATCH};
valueAsInspectable = value.as<decltype(valueAsInspectable)>();
resultAsInspectable =
m_dispatchAdapter.WrapObject(valueAsInspectable, m_dispatchAdapter);
resultAsDispatch = resultAsInspectable.as<::IDispatch>();
resultAsVariant.pdispVal = resultAsDispatch.detach();
return resultAsVariant;
}
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
};
template <typename> struct is_ireference : std::false_type
{
};
template <typename TRef>
struct is_ireference<winrt::Windows::Foundation::IReference<TRef>> : std::true_type
{
};
template <typename TOut>
struct Converter<
std::enable_if_t<
(std::is_base_of_v<winrt::Windows::Foundation::IUnknown, TOut> ||
std::is_base_of_v<
winrt::Windows::Foundation::IUnknown,
std::remove_reference_t<TOut>>)&&!TIsVectorView_v<TOut> &&
!TIsVector_v<TOut> && !is_ireference<TOut>::value,
VARIANT>,
TOut>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&
dispatchAdapter)
: m_dispatchAdapter(dispatchAdapter)
{
}
TOut Convert(const VARIANT& valueAsVariant)
{
if (valueAsVariant.vt == VT_NULL || valueAsVariant.vt == VT_EMPTY)
{
return {nullptr};
}
else if (valueAsVariant.vt == VT_DISPATCH || valueAsVariant.vt == VT_UNKNOWN)
{
winrt::com_ptr<IInspectable> valueAsComInspectable;
winrt::Windows::Foundation::IInspectable resultAsInspectable;
winrt::check_hresult(valueAsVariant.pdispVal->QueryInterface(
IID_PPV_ARGS(valueAsComInspectable.put())));
winrt::Windows::Foundation::IInspectable valueAsInspectable = {
valueAsComInspectable.as<winrt::Windows::Foundation::IInspectable>()};
resultAsInspectable = m_dispatchAdapter.UnwrapObject(valueAsInspectable);
return resultAsInspectable.as<TOut>();
}
else
{
if constexpr (
std::is_same_v<TOut, winrt::Windows::Foundation::IPropertyValue> ||
std::is_same_v<TOut, winrt::Windows::Foundation::IInspectable>)
{
return Converter<VARIANT, winrt::Windows::Foundation::IPropertyValue>(
m_dispatchAdapter)
.Convert(valueAsVariant);
}
else
{
winrt::throw_hresult(DISP_E_BADVARTYPE);
}
}
}
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
};
// Convert from VARIANT to cpp/winrt type
template <typename TIn> struct Converter<TIn, variant_if_similar_t<TIn, std::wstring>>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&)
{
}
VARIANT Convert(const std::wstring in)
{
VARIANT out{VT_BSTR};
out.bstrVal = SysAllocString(in.c_str());
return out;
};
};
// Convert to/from arrays
// Vector/VectorView -> VARIANT is covered by normal IUnknown -> VARIANT dispatch wrapper above.
template <typename TInChild> struct Converter<winrt::com_array<TInChild>, VARIANT>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&
dispatchAdapter)
: m_dispatchAdapter(dispatchAdapter)
{
}
VARIANT Convert(const winrt::com_array<TInChild>& value)
{
return Converter<winrt::array_view<TInChild>, VARIANT>(m_dispatchAdapter)
.Convert(value);
}
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
};
template <typename TInChild> struct Converter<winrt::array_view<TInChild>, VARIANT>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&
dispatchAdapter)
: m_dispatchAdapter(dispatchAdapter)
{
}
VARIANT Convert(const winrt::array_view<TInChild>& value)
{
const uint32_t size = value.size();
SAFEARRAY* array = SafeArrayCreateVector(VT_VARIANT, 0, size);
winrt::check_pointer(array);
for (uint32_t index = 0; index < size; ++index)
{
VARIANT entryAsVariant =
Converter<TInChild, VARIANT>(m_dispatchAdapter).Convert(value.at(index));
LONG indexAsLong = index;
HRESULT hr = SafeArrayPutElement(array, &indexAsLong, &entryAsVariant);
winrt::check_hresult(hr);
}
VARIANT arrayAsVariant;
arrayAsVariant.vt = VT_ARRAY | VT_VARIANT;
arrayAsVariant.parray = array;
return arrayAsVariant;
}
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
};
template <typename TOutChild> struct Converter<VARIANT, winrt::array_view<TOutChild>>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&
dispatchAdapter)
: m_dispatchAdapter(dispatchAdapter)
{
}
winrt::array_view<TOutChild> Convert(VARIANT value)
{
m_result =
Converter<VARIANT, winrt::com_array<TOutChild>>(m_dispatchAdapter).Convert(value);
return m_result;
}
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
// We must store the com_array here. A com_array owns its memory (CoTaskMemAlloc) and
// deletes it when the com_array goes out of scope. The array_view doesn't own memory
// and is more like a view into something else. Accordingly we must keep the com_array
// here so that the array_view has something to reference. Otherwise it goes out of
// scope and the contents are deleted. This is further confusing because com_array is
// derived from array_view but they don't have a virtual destructor.
winrt::com_array<TOutChild> m_result;
};
template <typename TOutChild> struct Converter<VARIANT, winrt::com_array<TOutChild>>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&
dispatchAdapter)
: m_dispatchAdapter(dispatchAdapter)
{
}
winrt::com_array<TOutChild> Convert(VARIANT value)
{
auto vector =
Converter<VARIANT, winrt::Windows::Foundation::Collections::IVector<TOutChild>>(
m_dispatchAdapter)
.Convert(value);
return {vector.begin(), vector.end()};
}
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
};
struct BoolWidener
{
BoolWidener(bool value) : m_data(value)
{
}
operator bool() const
{
return m_data;
}
operator bool*()
{
return &m_data;
}
operator const bool*() const
{
return &m_data;
}
BoolWidener& operator=(const bool value)
{
m_data = value;
return *this;
}
union
{
bool m_data;
BYTE m_singleByte;
};
};
struct BoolVector : winrt::implements<
BoolVector, winrt::Windows::Foundation::Collections::IVector<bool>,
winrt::Windows::Foundation::Collections::IVectorView<bool>,
winrt::Windows::Foundation::Collections::IIterable<bool>>,
winrt::vector_base<BoolVector, bool>
{
auto& get_container() const noexcept
{
return m_values;
}
auto& get_container() noexcept
{
return m_values;
}
private:
std::vector<BoolWidener> m_values;
};
template <typename TOut, typename TOutChild> struct ConverterToVectorHelper
{
ConverterToVectorHelper(
const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&
dispatchAdapter)
: m_dispatchAdapter(dispatchAdapter)
{
}
TOut Convert(VARIANT value)
{
if ((value.vt & VT_ARRAY) != 0)
{
SAFEARRAY* safeArray =
(value.vt == (VT_BYREF | VT_ARRAY)) ? *value.pparray : value.parray;
DWORD dimension = SafeArrayGetDim(safeArray);
if (dimension != 1)
{
winrt::throw_hresult(E_INVALIDARG);
}
LONG lowerBound = 0; // lower bound of array
LONG upperBound = 0; // upper bound of array
SafeArrayGetLBound(safeArray, dimension, &lowerBound);
SafeArrayGetUBound(safeArray, dimension, &upperBound);
VARTYPE childVarType;
HRESULT hr = SafeArrayGetVartype(safeArray, &childVarType);
winrt::check_hresult(hr);
if (childVarType != VT_VARIANT)
{
winrt::throw_hresult(E_INVALIDARG);
}
const UINT elementSize = SafeArrayGetElemsize(safeArray);
if (elementSize != sizeof(VARIANT))
{
winrt::throw_hresult(E_ABORT);
}
winrt::Windows::Foundation::Collections::IVector<TOutChild> collection;
if constexpr (!std::is_same_v<TOutChild, bool>)
{
if constexpr (std::is_same_v<
winrt::Windows::Foundation::Collections::IObservableVector<
TOutChild>,
TOut>)
{
collection = winrt::single_threaded_observable_vector<TOutChild>();
}
else
{
collection = winrt::single_threaded_vector<TOutChild>();
}
}
else
{
collection = winrt::make<BoolVector>();
}
for (LONG index = lowerBound; index <= upperBound; ++index)
{
VARIANT entryAsVariant;
hr = SafeArrayGetElement(
safeArray, &index, reinterpret_cast<void*>(&entryAsVariant));
winrt::check_hresult(hr);
auto entryAsOutType =
Converter<VARIANT, TOutChild>(m_dispatchAdapter).Convert(entryAsVariant);
collection.Append(entryAsOutType);
VariantClear(&entryAsVariant);
}
return collection.as<TOut>();
}
else if (value.vt == VT_DISPATCH || value.vt == VT_UNKNOWN)
{
// If the VARIANT represents a wrapped IDispatch object, then we need to extract
// the inner object, but it must implement the specified IVector interface.
winrt::com_ptr<IInspectable> valueAsComInspectable;
winrt::Windows::Foundation::IInspectable resultAsInspectable;
winrt::check_hresult(
value.pdispVal->QueryInterface(IID_PPV_ARGS(valueAsComInspectable.put())));
winrt::Windows::Foundation::IInspectable valueAsInspectable = {
valueAsComInspectable.as<winrt::Windows::Foundation::IInspectable>()};
resultAsInspectable = m_dispatchAdapter.UnwrapObject(valueAsInspectable);
return resultAsInspectable.as<TOut>();
}
winrt::throw_hresult(E_INVALIDARG);
}
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
};
#define VARIANT_TO_VECTOR_TYPE_HELPER(VectorType) \
template <typename TOutChild> \
struct Converter<VARIANT, winrt::Windows::Foundation::Collections::VectorType<TOutChild>> \
{ \
using TOut = winrt::Windows::Foundation::Collections::VectorType<TOutChild>; \
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter& \
dispatchAdapter) \
: m_converterHelper(dispatchAdapter) \
{ \
} \
TOut Convert(VARIANT value) \
{ \
return m_converterHelper.Convert(value); \
} \
ConverterToVectorHelper<TOut, TOutChild> m_converterHelper; \
};
VARIANT_TO_VECTOR_TYPE_HELPER(IVector);
VARIANT_TO_VECTOR_TYPE_HELPER(IVectorView);
VARIANT_TO_VECTOR_TYPE_HELPER(IObservableVector);
#undef VARIANT_TO_VECTOR_TYPE_HELPER
// Convert from VARIANT to cppwinrt type
template <> struct Converter<VARIANT, std::wstring>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&
dispatchAdapter)
: m_dispatchAdapter(dispatchAdapter)
{
}
std::wstring Convert(const VARIANT& value)
{
if (value.vt & VT_ARRAY)
{
winrt::com_array<winrt::hstring> array =
Converter<VARIANT, winrt::com_array<winrt::hstring>>(m_dispatchAdapter)
.Convert(value);
std::wstring result;
for (auto it = array.begin(); it != array.end(); ++it)
{
if (it != array.begin())
result.append(L",");
result.append(*it);
}
return result;
}
#define CONVERTER_INTEGRAL_CASE(vtType, variantProperty) \
case vtType: \
return std::to_wstring(value.variantProperty);
switch (value.vt)
{
CONVERTER_INTEGRAL_CASE(VT_I1, cVal)
CONVERTER_INTEGRAL_CASE(VT_UI1, bVal)
CONVERTER_INTEGRAL_CASE(VT_I2, iVal)
CONVERTER_INTEGRAL_CASE(VT_UI2, uiVal)
CONVERTER_INTEGRAL_CASE(VT_I4, lVal)
CONVERTER_INTEGRAL_CASE(VT_UI4, ulVal)
CONVERTER_INTEGRAL_CASE(VT_I8, llVal)
CONVERTER_INTEGRAL_CASE(VT_UI8, ullVal)
#undef CONVERTER_INTEGRAL_CASE
case VT_R4:
case VT_R8:
{
// Floats and doubles need to use ostringstream instead of to_string
// to get formatting correctly. Using to_string for floats and doubles
// can cause trailing zeroes (i.e. 1.875 becomes 1.875000)
std::wostringstream oss;
oss << std::noshowpoint << ((value.vt == VT_R8) ? value.dblVal : value.fltVal);
return oss.str();
}
case VT_LPWSTR:
case VT_BSTR:
return value.bstrVal;
case VT_EMPTY:
case VT_NULL:
return L"null";
case VT_BOOL:
return (value.boolVal == VARIANT_TRUE) ? L"true" : L"false";
case VT_DISPATCH:
{
wchar_t kToStringProperty[] = L"toString";
LPOLESTR names = kToStringProperty;
DISPID dispid = 0;
HRESULT hr = value.pdispVal->GetIDsOfNames(
IID_NULL, &names, 1, LOCALE_USER_DEFAULT, &dispid);
if (SUCCEEDED(hr))
{
VARIANTARG vararg{VT_BSTR};
vararg.bstrVal = kToStringProperty;
DISPPARAMS dispParams;
dispParams.rgvarg = &vararg;
dispParams.cArgs = 1;
EXCEPINFO excepInfo;
VARIANT result;
hr = value.pdispVal->Invoke(
dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispParams,
&result, &excepInfo, NULL);
if (SUCCEEDED(hr))
{
return Converter<VARIANT, std::wstring>(m_dispatchAdapter).Convert(result);
}
else
{
// The object does not support toString as a method.
winrt::throw_hresult(E_INVALIDARG);
}
}
// If we aren't able to query the object for a toString property, then return
// the object string.
return L"[object Object]";
}
default:
winrt::throw_hresult(E_INVALIDARG);
}
}
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
};
template <> struct Converter<VARIANT, winrt::hstring>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&
dispatchAdapter)
: m_dispatchAdapter(dispatchAdapter)
{
}
winrt::hstring Convert(const VARIANT& value)
{
return Converter<VARIANT, std::wstring>(m_dispatchAdapter).Convert(value).c_str();
}
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
};
template <typename TIn> struct Converter<TIn, variant_if_similar_t<TIn, winrt::hstring>>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&)
{
}
VARIANT Convert(const winrt::hstring& value)
{
VARIANT result{VT_BSTR};
result.bstrVal = SysAllocString(value.data());
return result;
}
};
template <> struct Converter<VARIANT, bool>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&)
{
}
bool Convert(const VARIANT& value)
{
if (value.vt & VT_ARRAY)
{
return true;
}
else
{
bool result = false;
#define CONVERTER_INTEGRAL_CASE(vtType, variantProperty) \
case vtType: \
result = !(value.variantProperty == 0 || value.variantProperty == -0); \
break;
switch (value.vt)
{
CONVERTER_INTEGRAL_CASE(VT_I1, cVal)
CONVERTER_INTEGRAL_CASE(VT_UI1, bVal)
CONVERTER_INTEGRAL_CASE(VT_I2, iVal)
CONVERTER_INTEGRAL_CASE(VT_UI2, uiVal)
CONVERTER_INTEGRAL_CASE(VT_I4, lVal)
CONVERTER_INTEGRAL_CASE(VT_UI4, ulVal)
CONVERTER_INTEGRAL_CASE(VT_I8, llVal)
CONVERTER_INTEGRAL_CASE(VT_UI8, ullVal)
#undef CONVERTER_INTEGRAL_CASE
case VT_BOOL:
// VARIANT_FALSE == 0 and FALSE == 0
// VARIANT_TRUE == -1 and TRUE == 1
// Because true values don't match we just compare against false
result = value.boolVal != VARIANT_FALSE;
break;
case VT_R4:
result = !(std::isnan(value.fltVal) || value.fltVal == 0 || value.fltVal == -0);
break;
case VT_R8:
result = !(std::isnan(value.dblVal) || value.dblVal == 0 || value.dblVal == -0);
break;
case VT_BSTR:
case VT_LPWSTR:
result = !(value.bstrVal[0] == L'\0' || value.bstrVal == nullptr);
break;
case VT_EMPTY:
case VT_NULL:
result = false;
break;
case VT_DISPATCH:
case VT_DATE:
result = true;
break;
default:
winrt::throw_hresult(E_INVALIDARG);
}
return result;
}
}
};
template <typename TIn> struct Converter<TIn, variant_if_similar_t<bool, TIn>>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&)
{
}
VARIANT Convert(const bool& value)
{
VARIANT result{VT_BOOL};
// Note we must use VARIANT_TRUE and VARIANT_FALSE not TRUE, FALSE since
// the true values don't match (see above)
result.boolVal = value ? VARIANT_TRUE : VARIANT_FALSE;
return result;
}
};
template <> struct Converter<VARIANT, char16_t>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&
dispatchAdapter)
: m_dispatchAdapter(dispatchAdapter)
{
}
char16_t Convert(const VARIANT& value)
{
std::wstring result =
Converter<VARIANT, std::wstring>(m_dispatchAdapter).Convert(value);
if (result.length() != 1)
{
winrt::throw_hresult(E_INVALIDARG);
}
return result.at(0);
}
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
};
template <typename TIn> struct Converter<TIn, variant_if_similar_t<char16_t, TIn>>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&)
{
}
VARIANT Convert(const char16_t& value)
{
VARIANT result{VT_BSTR};
result.bstrVal = SysAllocString(std::wstring(1, value).c_str());
return result;
}
};
// To match chakra we support GUIDs with and without {} delimiters as input
// and produce GUIDs with {} delimiters as output
template <> struct Converter<VARIANT, winrt::guid>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&)
{
}
winrt::guid Convert(const VARIANT& value)
{
if (value.vt == VT_BSTR || value.vt == VT_LPWSTR)
{
// We need to convert our string to a winrt::guid. winrt::guid has a
// constructor that takes a string and does this conversion, however
// if it fails to parse it calls abort which is not acceptable. And
// it requires the incoming string to not have delimiting {}.
// So instead we use IIDFromString to parse and then create a
// winrt::guid from that. IIDFromString requires the IID to have
// delimiting {}s which we don't. So if the string doesn't start with
// { we copy the string into a buffer with delimting braces.
static const size_t guidWithBracesAndWithNullLength =
ARRAYSIZE(L"{e0f5602a-f641-4889-a09e-71c9e1642dd5}");
static const size_t guidWithoutBracesAndWithNullLength =
ARRAYSIZE(L"e0f5602a-f641-4889-a09e-71c9e1642dd5");
std::wstring guidBuffer;
const wchar_t* valueStr = value.bstrVal;
size_t valueStrWithNullLength = wcslen(value.bstrVal) + 1;
if (valueStr[0] != L'{' &&
valueStrWithNullLength == guidWithoutBracesAndWithNullLength)
{
guidBuffer = L'{';
guidBuffer.append(valueStr);
guidBuffer += L'}';
valueStr = guidBuffer.c_str();
valueStrWithNullLength = guidBuffer.length();
}
IID parsedGuidAsIID;
if (FAILED(IIDFromString(valueStr, &parsedGuidAsIID)))
{
winrt::throw_hresult(E_INVALIDARG);
}
return winrt::guid{
(uint32_t)parsedGuidAsIID.Data1, (uint16_t)parsedGuidAsIID.Data2,
(uint16_t)parsedGuidAsIID.Data3,
std::array<uint8_t, 8>{
parsedGuidAsIID.Data4[0],
parsedGuidAsIID.Data4[1],
parsedGuidAsIID.Data4[2],
parsedGuidAsIID.Data4[3],
parsedGuidAsIID.Data4[4],
parsedGuidAsIID.Data4[5],
parsedGuidAsIID.Data4[6],
parsedGuidAsIID.Data4[7],
}};
}
winrt::throw_hresult(E_INVALIDARG);
}
};
// Convert from VARIANT to cpp/winrt type
template <> struct Converter<VARIANT, winrt::Windows::Foundation::TimeSpan>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&
dispatchAdapter)
: m_dispatchAdapter(dispatchAdapter)
{
}
winrt::Windows::Foundation::TimeSpan Convert(const VARIANT& value)
{
switch (value.vt)
{
// We need to include the specific allowed VTs below instead
// of just relying on the number converter because the default
// case from the converter returns 0, whereas here we want
// to throw an invalidarg exception for the default case.
case VT_I1:
case VT_UI1:
case VT_I2:
case VT_UI2:
case VT_I4:
case VT_UI4:
case VT_I8:
case VT_UI8:
case VT_R4:
case VT_R8:
case VT_DATE:
{
// For the general number case, the value being sent from JS is assumed to be
// in milliseconds, which is the default tick format of Date objects. All we
// need to do is convert to hundred-nanosecond ticks for TimeSpan.
double milliseconds = Converter<VARIANT, double>(m_dispatchAdapter).Convert(value);
int64_t hundredNanoseconds =
std::llround(milliseconds * kHundredNanosecondsPerMillisecond);
return winrt::Windows::Foundation::TimeSpan(hundredNanoseconds);
}
default:
winrt::throw_hresult(E_INVALIDARG);
}
}
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
};
template <typename TIn>
struct Converter<TIn, variant_if_similar_t<TIn, winrt::Windows::Foundation::TimeSpan>>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&)
{
}
VARIANT Convert(const winrt::Windows::Foundation::TimeSpan& value)
{
VARIANT result{VT_R8};
result.dblVal = static_cast<double>(value.count()) / kHundredNanosecondsPerMillisecond;
return result;
}
};
template <> struct Converter<VARIANT, winrt::Windows::Foundation::DateTime>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&
dispatchAdapter)
: m_dispatchAdapter(dispatchAdapter)
{
}
winrt::Windows::Foundation::DateTime Convert(const VARIANT& value)
{
switch (value.vt)
{
// We need to include the specific allowed VTs below instead
// of just relying on the number converter because the default
// case from the converter returns 0, whereas here we want
// to throw an invalidarg exception for the default case.
case VT_I1:
case VT_UI1:
case VT_I2:
case VT_UI2:
case VT_I4:
case VT_UI4:
case VT_I8:
case VT_UI8:
case VT_R4:
case VT_R8:
case VT_DATE:
{
double jsTime = Converter<VARIANT, double>(m_dispatchAdapter).Convert(value);
int64_t winRTTime = std::llround(JsTimeToWinRTTime(jsTime));
return winrt::Windows::Foundation::DateTime(
winrt::Windows::Foundation::TimeSpan(winRTTime));
}
default:
winrt::throw_hresult(E_INVALIDARG);
}
}
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
};
template <typename TIn>
struct Converter<TIn, variant_if_similar_t<TIn, winrt::Windows::Foundation::DateTime>>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&)
{
}
VARIANT Convert(const winrt::Windows::Foundation::DateTime& value)
{
VARIANT result{VT_DATE};
result.date = WinRTTimeToVariantTime(value.time_since_epoch().count());
return result;
}
};
template <typename TIn> struct Converter<TIn, variant_if_similar_t<winrt::guid, TIn>>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&
dispatchAdapter)
: m_dispatchAdapter(dispatchAdapter)
{
}
VARIANT Convert(const winrt::guid& value)
{
// to_hstring will produce a GUID string with {} delimiters
// which matches the output we want.
return Converter<winrt::hstring, VARIANT>(m_dispatchAdapter)
.Convert(winrt::to_hstring(value));
}
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
};
// Convert to/from enums. Enums in WinRT are either Int32 or UInt32
template <typename TEnum>
struct Converter<
TEnum, std::enable_if_t<
(std::is_enum_v<TEnum> ||
std::is_enum_v<std::remove_reference_t<TEnum>>)&&std::is_signed_v<TEnum>,
VARIANT>>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&
dispatchAdapter)
: m_dispatchAdapter(dispatchAdapter)
{
}
VARIANT Convert(TEnum value)
{
static_assert(sizeof(value) == sizeof(int32_t));
return Converter<int32_t, VARIANT>(m_dispatchAdapter)
.Convert(static_cast<int32_t>(value));
}
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
};
template <typename TEnum>
struct Converter<
TEnum, std::enable_if_t<
(std::is_enum_v<TEnum> ||
std::is_enum_v<std::remove_reference_t<TEnum>>)&&!std::is_signed_v<TEnum>,
VARIANT>>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&
dispatchAdapter)
: m_dispatchAdapter(dispatchAdapter)
{
}
VARIANT Convert(TEnum value)
{
static_assert(sizeof(value) == sizeof(uint32_t));
return Converter<uint32_t, VARIANT>(m_dispatchAdapter)
.Convert(static_cast<uint32_t>(value));
}
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
};
template <typename TEnum>
struct Converter<
std::enable_if_t<
(std::is_enum_v<TEnum> || std::is_enum_v<std::remove_reference_t<TEnum>>), VARIANT>,
TEnum>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&
dispatchAdapter)
: m_dispatchAdapter(dispatchAdapter)
{
}
TEnum Convert(VARIANT value)
{
return static_cast<TEnum>(
Converter<VARIANT, uint32_t>(m_dispatchAdapter).Convert(value));
}
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
};
// PropertyValue conversion
template <> struct Converter<VARIANT, winrt::Windows::Foundation::IPropertyValue>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&
dispatchAdapter)
: m_dispatchAdapter(dispatchAdapter)
{
}
winrt::Windows::Foundation::IPropertyValue Convert(const VARIANT& value)
{
winrt::Windows::Foundation::IInspectable propertyValueAsInspectable{nullptr};
switch (value.vt)
{
#define VARIANT_TO_PROPERTY_VALUE_CASE(Variant_VT_TYPE, WinRTType, PropertyValueCreateFn) \
case Variant_VT_TYPE: \
propertyValueAsInspectable = \
winrt::Windows::Foundation::PropertyValue::PropertyValueCreateFn( \
Converter<VARIANT, WinRTType>(m_dispatchAdapter).Convert(value)); \
break
VARIANT_TO_PROPERTY_VALUE_CASE(VT_BOOL, bool, CreateBoolean);
VARIANT_TO_PROPERTY_VALUE_CASE(VT_BSTR, winrt::hstring, CreateString);
VARIANT_TO_PROPERTY_VALUE_CASE(VT_I1, byte, CreateUInt8);
VARIANT_TO_PROPERTY_VALUE_CASE(VT_UI1, byte, CreateUInt8);
VARIANT_TO_PROPERTY_VALUE_CASE(VT_I2, int16_t, CreateInt16);
VARIANT_TO_PROPERTY_VALUE_CASE(VT_UI2, uint16_t, CreateUInt16);
VARIANT_TO_PROPERTY_VALUE_CASE(VT_I4, int32_t, CreateInt32);
VARIANT_TO_PROPERTY_VALUE_CASE(VT_UI4, uint32_t, CreateUInt32);
VARIANT_TO_PROPERTY_VALUE_CASE(VT_INT, int32_t, CreateInt32);
VARIANT_TO_PROPERTY_VALUE_CASE(VT_UINT, uint32_t, CreateUInt32);
VARIANT_TO_PROPERTY_VALUE_CASE(VT_I8, int64_t, CreateInt64);
VARIANT_TO_PROPERTY_VALUE_CASE(VT_UI8, uint64_t, CreateUInt64);
VARIANT_TO_PROPERTY_VALUE_CASE(VT_R4, float, CreateSingle);
VARIANT_TO_PROPERTY_VALUE_CASE(VT_R8, double, CreateDouble);
VARIANT_TO_PROPERTY_VALUE_CASE(
VT_DATE, winrt::Windows::Foundation::DateTime, CreateDateTime);
VARIANT_TO_PROPERTY_VALUE_CASE(
VT_FILETIME, winrt::Windows::Foundation::DateTime, CreateDateTime);
default:
winrt::hresult_error(E_NOTIMPL);
break;
case VT_EMPTY:
case VT_NULL:
break;
#undef VARIANT_TO_PROPERTY_VALUE_CASE
}
return propertyValueAsInspectable.as<winrt::Windows::Foundation::IPropertyValue>();
}
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
};
template <> struct Converter<winrt::Windows::Foundation::IPropertyValue, VARIANT>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&
dispatchAdapter)
: m_dispatchAdapter(dispatchAdapter)
{
}
VARIANT Convert(const winrt::Windows::Foundation::IPropertyValue& value)
{
switch (value.Type())
{
#define PROPERTY_VALUE_TO_VARIANT_CASE(PropertyTypeEnum, WinRTType, PropertyTypeMethodName) \
case winrt::Windows::Foundation::PropertyType::PropertyTypeEnum: \
return Converter<WinRTType, VARIANT>(m_dispatchAdapter) \
.Convert(value.PropertyTypeMethodName())
default:
winrt::hresult_error(E_NOTIMPL);
break;
case winrt::Windows::Foundation::PropertyType::Empty:
return {VT_EMPTY};
PROPERTY_VALUE_TO_VARIANT_CASE(String, winrt::hstring, GetString);
PROPERTY_VALUE_TO_VARIANT_CASE(UInt8, uint8_t, GetUInt8);
PROPERTY_VALUE_TO_VARIANT_CASE(Int16, int16_t, GetInt16);
PROPERTY_VALUE_TO_VARIANT_CASE(UInt16, uint16_t, GetUInt16);
PROPERTY_VALUE_TO_VARIANT_CASE(Int32, int32_t, GetInt32);
PROPERTY_VALUE_TO_VARIANT_CASE(UInt32, uint32_t, GetUInt32);
PROPERTY_VALUE_TO_VARIANT_CASE(Int64, int64_t, GetInt64);
PROPERTY_VALUE_TO_VARIANT_CASE(UInt64, uint64_t, GetUInt64);
PROPERTY_VALUE_TO_VARIANT_CASE(Single, float, GetSingle);
PROPERTY_VALUE_TO_VARIANT_CASE(Double, double, GetDouble);
PROPERTY_VALUE_TO_VARIANT_CASE(Char16, int16_t, GetChar16);
PROPERTY_VALUE_TO_VARIANT_CASE(Boolean, bool, GetBoolean);
PROPERTY_VALUE_TO_VARIANT_CASE(
DateTime, winrt::Windows::Foundation::DateTime, GetDateTime);
PROPERTY_VALUE_TO_VARIANT_CASE(
TimeSpan, winrt::Windows::Foundation::TimeSpan, GetTimeSpan);
PROPERTY_VALUE_TO_VARIANT_CASE(Guid, winrt::guid, GetGuid);
#undef PROPERTY_VALUE_TO_VARIANT_CASE
}
return {VT_NULL};
}
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
};
#pragma warning(4 : 4996)
// WinRT struct to VARIANT Converter.
template <typename StructT>
struct Converter<
StructT,
std::enable_if_t<
std::is_class_v<StructT> && std::is_standard_layout_v<StructT> &&
!std::is_base_of_v<winrt::Windows::Foundation::IUnknown, StructT> &&
!std::is_base_of_v<
winrt::Windows::Foundation::IUnknown, std::remove_reference_t<StructT>> &&
!TIsVector_v<StructT> && !TIsVectorView_v<StructT> && !TIsArrayView_v<StructT> &&
!TIsComArray_v<StructT> && !is_similar_v<StructT, winrt::hstring> &&
!is_similar_v<StructT, winrt::guid> &&
!is_similar_v<StructT, winrt::Windows::Foundation::TimeSpan> &&
!is_similar_v<StructT, winrt::Windows::Foundation::DateTime>,
VARIANT>>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&
dispatchAdapter)
: m_dispatchAdapter(dispatchAdapter)
{
}
VARIANT Convert(const StructT& value)
{
auto boxed = winrt::box_value(value);
return Converter<winrt::Windows::Foundation::IInspectable, VARIANT>(m_dispatchAdapter)
.Convert(boxed);
}
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
};
// VARIANT to WinRT struct Converter.
template <typename StructT>
struct Converter<
std::enable_if_t<
std::is_class_v<StructT> && std::is_standard_layout_v<StructT> &&
!std::is_base_of_v<winrt::Windows::Foundation::IUnknown, StructT> &&
!std::is_base_of_v<
winrt::Windows::Foundation::IUnknown, std::remove_reference_t<StructT>> &&
!TIsVector_v<StructT> && !TIsVectorView_v<StructT> && !TIsArrayView_v<StructT> &&
!TIsComArray_v<StructT> && !is_similar_v<StructT, winrt::hstring> &&
!is_similar_v<StructT, winrt::guid> &&
!is_similar_v<StructT, winrt::Windows::Foundation::TimeSpan> &&
!is_similar_v<StructT, winrt::Windows::Foundation::DateTime>,
VARIANT>,
StructT>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&
dispatchAdapter)
: m_dispatchAdapter(dispatchAdapter)
{
}
StructT Convert(const VARIANT& valueAsVariant)
{
if (valueAsVariant.vt == VT_DISPATCH || valueAsVariant.vt == VT_UNKNOWN)
{
winrt::com_ptr<ICoreWebView2PrivateRemoteDictionary> valueAsRemoteDictionary;
valueAsVariant.pdispVal->QueryInterface(
IID_PPV_ARGS(valueAsRemoteDictionary.put()));
if (valueAsRemoteDictionary)
{
return Converter<ICoreWebView2PrivateRemoteDictionary*, StructT>(
m_dispatchAdapter)
.Convert(valueAsRemoteDictionary.get());
}
}
auto boxed =
Converter<VARIANT, winrt::Windows::Foundation::IInspectable>(m_dispatchAdapter)
.Convert(valueAsVariant);
return winrt::unbox_value<StructT>(boxed);
}
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
};
template <typename RefT> struct Converter<VARIANT, winrt::Windows::Foundation::IReference<RefT>>
{
Converter(const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&
dispatchAdapter)
: m_dispatchAdapter(dispatchAdapter)
{
}
winrt::Windows::Foundation::IReference<RefT> Convert(const VARIANT& valueAsVariant)
{
if (valueAsVariant.vt == VT_NULL || valueAsVariant.vt == VT_EMPTY)
{
return {nullptr};
}
else
{
return {Converter<VARIANT, RefT>(m_dispatchAdapter).Convert(valueAsVariant)};
}
}
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
};
} // namespace wv2winrt_impl
O
// Copyright (C) Microsoft Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <windows.h>
// Must be included before any cppwinrt headers
#include <wv2winrt/base.h>
#include <winrt/Microsoft.Web.WebView2.Core.h>
#include "wv2winrt/converter.h"
#include "wv2winrt/dispatchcontainer.h"
namespace wv2winrt_impl
{
typedef const wchar_t* const* const DispatchProperties;
struct DispatchBase
: winrt::implements<
DispatchBase, IDispatch, winrt::Windows::Foundation::IInspectable,
ICoreWebView2PrivateDispatchContainer, ICoreWebView2PrivateDispatchContainer2,
ICoreWebView2PrivateDispatchContainer3, ICoreWebView2PrivateDispatchContainer4>
{
// IDispatch methods
HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT* typeInfoCount) override;
HRESULT STDMETHODCALLTYPE
GetTypeInfo(UINT typeInfoCount, LCID localeId, ITypeInfo** typeInfo) override;
HRESULT STDMETHODCALLTYPE GetIDsOfNames(
REFIID riid, LPOLESTR* names, unsigned int namesCount, LCID localeId,
DISPID* dispId) override;
HRESULT STDMETHODCALLTYPE Invoke(
DISPID dispId, REFIID riid, LCID localeId, WORD flags, DISPPARAMS* dispParams,
VARIANT* result, EXCEPINFO* excepInfo, UINT* argErr) override;
// ICoreWebView2PrivateDispatchContainer methods
HRESULT STDMETHODCALLTYPE GetInnerObject(IUnknown**) override
{
return E_NOTIMPL;
};
HRESULT STDMETHODCALLTYPE GetBasisVariant(VARIANT*) override
{
return E_NOTIMPL;
};
HRESULT STDMETHODCALLTYPE GetPropertyNames(wchar_t***, size_t*) override
{
return E_NOTIMPL;
};
HRESULT STDMETHODCALLTYPE GetScriptBehavior(DWORD* behavior) override
{
*behavior = DispatchContainerScriptBehaviorNone;
return S_OK;
};
// ICoreWebView2PrivateDispatchContainer2 methods
HRESULT STDMETHODCALLTYPE IsPropertyCacheable(DISPID, BOOL* isCacheable) override
{
*isCacheable = FALSE;
return S_OK;
}
// ICoreWebView2PrivateDispatchContainer3 methods
HRESULT STDMETHODCALLTYPE GetPropertiesPrecacheability(BOOL**, size_t*) override
{
return E_NOTIMPL;
};
// ICoreWebView2PrivateDispatchContainer4 methods
HRESULT STDMETHODCALLTYPE GetOutArrayParameterInfo(int**, LPWSTR**, size_t*) override
{
return E_NOTIMPL;
}
__declspec(noinline) static bool LookupProperty(
DispatchProperties properties, LPOLESTR const& query, size_t& idx, size_t count);
};
} // namespace wv2winrt_impl
<00>+// Copyright (C) Microsoft Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <windows.h>
// Must be included before any cppwinrt headers
#include <wv2winrt/base.h>
#include <winrt/Microsoft.Web.WebView2.Core.h>
#include "wv2winrt/converter.h"
#include "wv2winrt/returnaggregator.h"
namespace wv2winrt_impl
{
// This is a helper class rather than a base class because GetIDsOfNames and Invoke
// must only be called after the more derived type has a chance to handle GetIDsOfNames
// and Invoke. So that type can explicitly use the helper class.
template <typename TVector, bool TIsWritable, typename TVectorValue> struct DispatchVectorHelper
{
DispatchVectorHelper(
const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&
dispatchAdapter,
DISPID idOffset)
: m_dispatchAdapter(dispatchAdapter), m_idOffset(idOffset)
{
}
HRESULT STDMETHODCALLTYPE GetIDsOfNames(LPOLESTR* names, DISPID* dispId)
{
HRESULT hr = S_OK;
try
{
if (wcscmp(L"length", names[0]) == 0)
{
*dispId = m_idOffset;
}
else
{
size_t nameAsIdx = std::stol(names[0]);
const DISPID id =
static_cast<DISPID>(m_idOffset + s_arrayIndiciesOffset + nameAsIdx);
*dispId = id;
}
}
catch (const std::invalid_argument&)
{
hr = DISP_E_MEMBERNOTFOUND;
}
return hr;
}
HRESULT STDMETHODCALLTYPE Invoke(
const TVector& vector, DISPID dispId, WORD flags, DISPPARAMS* dispParams,
VARIANT* result)
{
HRESULT hr = DISP_E_MEMBERNOTFOUND;
const uint32_t originalVectorSize = vector.Size();
const uint32_t namesIdx = dispId - m_idOffset - s_arrayIndiciesOffset;
if (dispId == m_idOffset)
{
// length property
try
{
if (flags == DISPATCH_PROPERTYGET)
{
*result =
Converter<decltype(originalVectorSize), VARIANT>(m_dispatchAdapter)
.Convert(originalVectorSize);
hr = S_OK;
}
else if (flags == DISPATCH_PROPERTYPUT)
{
hr = E_INVALIDARG;
if constexpr (TIsWritable)
{
int targetVectorSize =
Converter<VARIANT, decltype(targetVectorSize)>(m_dispatchAdapter)
.Convert(*(dispParams->rgvarg));
if (targetVectorSize >= 0)
{
EnsureSize(vector, static_cast<uint32_t>(targetVectorSize), false);
hr = S_OK;
}
}
}
}
catch (winrt::hresult_error)
{
hr = winrt::to_hresult();
}
catch (...)
{
hr = E_UNEXPECTED;
}
}
else
{
try
{
// If we are on an array, we don't know if we are getting an
// element in the array or if we are getting a method, which
// would look like we are extending off the end of the array.
if (flags == DISPATCH_PROPERTYGET && namesIdx < originalVectorSize)
{
auto resultAsWinRT = vector.GetAt(namesIdx);
*result = Converter<decltype(resultAsWinRT), VARIANT>(m_dispatchAdapter)
.Convert(resultAsWinRT);
hr = S_OK;
}
else if (flags == DISPATCH_PROPERTYPUT)
{
if constexpr (TIsWritable)
{
// Setting a value larger than the size of a JS array
// increases the size of the JS array to fit.
EnsureSize(vector, namesIdx + 1);
vector.SetAt(
namesIdx, Converter<VARIANT, TVectorValue>(m_dispatchAdapter)
.Convert(*(dispParams->rgvarg)));
hr = S_OK;
}
}
}
catch (winrt::hresult_error)
{
hr = winrt::to_hresult();
}
catch (...)
{
hr = E_UNEXPECTED;
}
}
return hr;
}
private:
void EnsureSize(const TVector& vector, uint32_t newVectorSize, bool atLeast = true)
{
const uint32_t originalVectorSize = vector.Size();
if (newVectorSize > originalVectorSize)
{
uint32_t currentVectorSize = originalVectorSize;
while (newVectorSize > currentVectorSize++)
{
vector.Append(GetDefaultValue<TVectorValue>());
}
}
else if (newVectorSize < originalVectorSize && !atLeast)
{
uint32_t currentVectorSize = originalVectorSize;
while (newVectorSize < currentVectorSize--)
{
vector.RemoveAtEnd();
}
}
}
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
DISPID m_idOffset = 0;
static const size_t s_arrayIndiciesOffset = 1;
};
// This is a helper class rather than a base class because GetIDsOfNames and Invoke
// must only be called after the more derived type has a chance to handle GetIDsOfNames
// and Invoke. So that type can explicitly use the helper class.
template <typename TInner, bool TIsWritable, typename TMapValue> struct DispatchMapHelper
{
DispatchMapHelper(
const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter&
dispatchAdapter,
DISPID idOffset)
: m_dispatchAdapter(dispatchAdapter), m_idOffset(idOffset)
{
}
HRESULT STDMETHODCALLTYPE GetIDsOfNames(LPOLESTR* names, DISPID* dispId)
{
HRESULT hr = S_OK;
if (wcscmp(names[0], L"getAllKeyNames") == 0)
{
*dispId = m_idOffset;
}
else
{
auto itr = m_nameToIdMap.find(names[0]);
if (itr != m_nameToIdMap.end())
{
*dispId = itr->second;
}
else
{
const size_t idx = m_names.size();
const DISPID id = static_cast<DISPID>((m_idOffset + s_knownIds) + idx);
std::wstring nameAsWstring = names[0];
m_names.push_back(nameAsWstring);
m_nameToIdMap.try_emplace(nameAsWstring, id);
*dispId = id;
}
}
return hr;
}
const std::vector<winrt::hstring> GetKeyNames(const TInner& map)
{
std::vector<winrt::hstring> keys(map.Size());
auto itr = map.First();
size_t idx = 0;
if (itr.HasCurrent())
{
do
{
keys[idx++] = itr.Current().Key();
} while (itr.MoveNext());
}
return keys;
}
HRESULT STDMETHODCALLTYPE Invoke(
const TInner& inner, DISPID dispId, WORD flags, DISPPARAMS* dispParams, VARIANT* result)
{
HRESULT hr = DISP_E_MEMBERNOTFOUND;
if (dispId < m_idOffset + s_knownIds)
{
if (dispId == m_idOffset)
{
try
{
if (flags == DISPATCH_METHOD)
{
auto returnAggregator =
winrt::make_self<wv2winrt_impl::ReturnAggregator>(2, false);
*(returnAggregator->AddParameter(L"cacheable")) =
Converter<bool, VARIANT>(m_dispatchAdapter).Convert(!TIsWritable);
std::vector<winrt::hstring> keyNamesAsVectorHstring =
GetKeyNames(inner);
winrt::array_view<winrt::hstring> keyNamesAsArrayViewHstring(
keyNamesAsVectorHstring);
*(returnAggregator->AddParameter(L"keyNames")) =
Converter<winrt::array_view<winrt::hstring>, VARIANT>(
m_dispatchAdapter)
.Convert(keyNamesAsArrayViewHstring);
result->vt = VT_DISPATCH;
returnAggregator.as<::IDispatch>().copy_to(&result->pdispVal);
hr = S_OK;
}
}
catch (winrt::hresult_error)
{
hr = winrt::to_hresult();
}
catch (...)
{
hr = E_UNEXPECTED;
}
}
}
else
{
const size_t namesIdx = dispId - (m_idOffset + s_knownIds);
if (namesIdx < m_names.size())
{
try
{
const std::wstring& propertyName = m_names[namesIdx];
if (flags == DISPATCH_PROPERTYGET)
{
if (inner.HasKey(propertyName))
{
auto resultAsWinRT = inner.Lookup(propertyName);
*result =
Converter<decltype(resultAsWinRT), VARIANT>(m_dispatchAdapter)
.Convert(resultAsWinRT);
}
else
{
*result = {VT_NULL};
}
hr = S_OK;
}
else if (flags == DISPATCH_PROPERTYPUT)
{
if constexpr (TIsWritable)
{
inner.Insert(
propertyName, Converter<VARIANT, TMapValue>(m_dispatchAdapter)
.Convert(*(dispParams->rgvarg)));
hr = S_OK;
}
}
}
catch (winrt::hresult_error)
{
hr = winrt::to_hresult();
}
catch (...)
{
hr = E_UNEXPECTED;
}
}
}
return hr;
}
private:
winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter m_dispatchAdapter;
DISPID m_idOffset = 0;
static const size_t s_knownIds = 1;
std::map<std::wstring, DISPID> m_nameToIdMap;
std::vector<std::wstring> m_names;
};
} // namespace wv2winrt_impl
<00>// Copyright (C) Microsoft Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <basetsd.h>
#include <windows.h>
namespace wv2winrt_impl
{
// These should be in sync with the ones in webview2private.idl
enum DispatchContainerScriptBehavior
{
DispatchContainerScriptBehaviorNone = 0,
DispatchContainerScriptBehaviorVector,
DispatchContainerScriptBehaviorMap
};
struct __declspec(uuid("2E324595-31A2-4797-9F23-A657B22A1E4B"))
ICoreWebView2PrivateDispatchContainer : ::IUnknown
{
virtual HRESULT STDMETHODCALLTYPE GetInnerObject(IUnknown** object) = 0;
virtual HRESULT STDMETHODCALLTYPE GetBasisVariant(VARIANT* basis) = 0;
virtual HRESULT STDMETHODCALLTYPE
GetPropertyNames(wchar_t*** names, size_t* namesLength) = 0;
virtual HRESULT STDMETHODCALLTYPE GetScriptBehavior(DWORD* behaviorIdx) = 0;
};
struct __declspec(uuid("349f926b-227f-40ef-a359-b941253ed0d3"))
ICoreWebView2PrivateDispatchContainer2 : ::IUnknown
{
virtual HRESULT STDMETHODCALLTYPE
IsPropertyCacheable(DISPID propertyId, BOOL* isCacheable) = 0;
};
struct __declspec(uuid("6251dc5f-b565-43a6-83e4-39cd5e9d9729"))
ICoreWebView2PrivateDispatchContainer3 : ::IUnknown
{
virtual HRESULT STDMETHODCALLTYPE
GetPropertiesPrecacheability(BOOL** boolsOut, size_t* propertiesLengthOut) = 0;
};
struct __declspec(uuid("e4970e01-8008-4092-9c5c-28d147394f41"))
ICoreWebView2PrivateDispatchContainer4 : ::IUnknown
{
virtual HRESULT STDMETHODCALLTYPE
GetOutArrayParameterInfo(int** indexes, LPWSTR** names, size_t* length) = 0;
};
} // namespace wv2winrt_impl
<EFBFBD>// Copyright (C) Microsoft Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <windows.h>
namespace wv2winrt_impl
{
// Creates an aggregate IDispatch object that combines the provided
// winrt event event args and source type in the following manner:
// * root - The root object is a modified version of the WinRT event args
// * target - The target property is the source of the event
// * detail - An array in which 0 is the unmodified WinRT event args, and the rest are all
// the other params to invoke
// * type - The name of the event
//
// This also supports the case where there is no source or the source is
// null or the event args are null. In the case that there is no source
// the target will still exist but will be null.
// In the case that the event args are null, the detail array will still
// exist but its 0 index will be null.
HRESULT CreateAggregateEventArgs(
LPCWSTR eventName, IDispatch* source, VARIANT* unmodifiedDelegateParamsAsVARIANT,
const ULONG unmodifiedDelegateParamsAsVARIANTCount, IDispatch** aggregateEventArgs);
} // namespace wv2winrt_impl<00>// Copyright (C) Microsoft Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
// Must be included before any cppwinrt headers
#include <wv2winrt/base.h>
#include <winrt/Microsoft.Web.WebView2.Core.h>
namespace wv2winrt_impl
{
typedef HRESULT CreateFn(
const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter& dispatchAdapter,
IDispatch** dispatch);
typedef winrt::com_ptr<IDispatch> CreateFromInstanceFn(
IInspectable* objectAsABI,
const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter& dispatchAdapter);
struct GlobalEntry
{
LPCWSTR name;
CreateFn* createFunction;
};
struct InstanceConstructibleEntry
{
LPCWSTR name;
bool isBoxedStruct;
CreateFromInstanceFn* createFunction;
bool operator<(const InstanceConstructibleEntry& rhs) const
{
return wcscmp(name, rhs.name) == -1;
}
};
extern const GlobalEntry s_globalEntries[];
extern const size_t s_globalEntriesCount;
extern const InstanceConstructibleEntry s_instanceConstructibleEntries[];
extern const size_t s_instanceConstructibleEntriesCount;
} // namespace wv2winrt_impl
// Copyright (C) Microsoft Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
// Must be included before any cppwinrt headers
#include <wv2winrt/base.h>
#include <winrt/Microsoft.Web.WebView2.Core.h>
namespace wv2winrt_impl
{
HRESULT STDMETHODCALLTYPE CreateDispatchFromName(
LPCWSTR name,
const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter& dispatchAdapter,
IDispatch** dispatch);
HRESULT STDMETHODCALLTYPE CreateDispatchFromInspectable(
IInspectable* object,
const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter& dispatchAdapter,
IDispatch** dispatch, bool* is_cacheable);
} // namespace wv2winrt_impl
<00>// Copyright (C) Microsoft Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <windows.h>
namespace wv2winrt_impl
{
interface __declspec(uuid("F2A70B4A-FA05-45DA-9A4E-7BE0467E18E7"))
ICoreWebView2PrivateRemoteDictionary : public IUnknown
{
virtual HRESULT STDMETHODCALLTYPE GetValue(void** result) = 0;
};
} // namespace wv2winrt_impl
C// Copyright (C) Microsoft Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <map>
#include <windows.h>
#include "wv2winrt/dispatchbase.h"
#include "wv2winrt/uniquevariant.h"
namespace wv2winrt_impl
{
struct ReturnAggregator : winrt::implements<ReturnAggregator, DispatchBase>
{
ReturnAggregator(const size_t outParamCount, const bool hasReturnValue);
// Add a named out parameter. Uses this peculiar signature so that it can
// be called easily with an out parameter that will write to the variant
// value.
VARIANT* AddParameter(LPCWSTR name);
void SetReturnValue(const VARIANT& value);
// IDispatch methods
HRESULT STDMETHODCALLTYPE GetIDsOfNames(
REFIID riid, LPOLESTR* names, unsigned int namesCount, LCID localeId,
DISPID* dispId) override;
HRESULT STDMETHODCALLTYPE Invoke(
DISPID dispId, REFIID riid, LCID localeId, WORD flags, DISPPARAMS* dispParams,
VARIANT* result, EXCEPINFO* excepInfo, UINT* argErr) override;
// ICoreWebView2PrivateDispatchContainer4 methods
HRESULT STDMETHODCALLTYPE
GetOutArrayParameterInfo(int** indexes, LPWSTR** names, size_t* length) override;
HRESULT STDMETHODCALLTYPE AddOutArrayParameterInfoEntry(LPWSTR, int);
private:
std::map<std::wstring, size_t> m_parameterNameToIdxMap;
std::vector<UniqueVariant> m_parameterValues;
std::vector<LPWSTR> m_OutArrayParameterNames;
std::vector<int> m_OutArrayParameterIndexes;
};
} // namespace wv2winrt_impl
<00>// Copyright (C) Microsoft Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
namespace wv2winrt_impl
{
// The bulk of this code is copied and simplified from base::Time.
// In cpp/winrt the DateTime and TimeSpan classes are simply type specializations
// of std::chrono::time_point and std::chrono::duration, respectively. They use
// 100-nanosecond ticks and the Windows epoch (1/1/1601).
// Offset in days of the VARIANT DATE epoch (1899-12-30 00:00:00 UTC) from the
// Windows epoch (1601-01-01 00:00:00 UTC). This value is derived from the
// following:
// ((1899-1601)*365 + 363 + 72)
// where 363 is the number of days in 1899 before 12/30, and 72 is the number
// of leap year days between 1601 and 1899 (exluding 1700 and 1800):
// (1899-1601)/4 - 2
constexpr uint64_t kWinRTToVariantDays = 109205;
// Offset in days of the VARIANT DATE epoch (1899-12-30 00:00:00 UTC) from the
// JS Date UNIX epoch (1970-01-01 00:00:00 UTC). This value is derived from the
// following:
// ((1970-1900)*365 + 2 + 17)
// where 2 is the number of days from 12/30/1899 to 1/1/1900, and 16 is the number
// of leap year days between 1899 and 1970 (excluding 1900):
// (1970-1899)/4 - 1
constexpr uint64_t kVariantToJsDays = 25569;
constexpr uint64_t kWinRTToJsDays = 134774; // kWinRTToVariantDays + kVariantToJsDays;
// JS time is measured in millisecond ticks.
// Each day is 24 * 60 * 60 * 1000 = 86400000 ticks
constexpr uint64_t kMillisecondsPerDay = 86400000;
// WinRT uses FileTime which is measured in 100-nanosecond ticks.
// Millisecond = 10^-3, HundredNanosecond = 10^-7, diff = 10^4
constexpr uint64_t kHundredNanosecondsPerMillisecond = 10000;
constexpr uint64_t kHundredNanosecondsPerDay =
kMillisecondsPerDay * kHundredNanosecondsPerMillisecond;
// Converts a DATE (double, fractional days since DATE epoch 12/30/1899)
// to JS time (uint64_t, count of milliseconds since UNIX epoch 1/1/1970)
inline int64_t VariantTimeToJsTime(const DATE& date)
{
// DATEs are weird - the day is signed and represents +/- that many days from
// the epoch. But the fractional part of the day is unsigned. To fix for this
// we separate the days from the fractional day part, then add back the
// absolute value of the fractional day to get a true unsigned day count.
// Example: -10.2 DATE becomes -10 + abs(-0.2) = -9.8
double countDay;
double fractionalDay = std::modf(date, &countDay);
double daysSinceVariantEpoch = countDay + std::abs(fractionalDay);
// Move from Variant DATE epoch to JS UNIX epoch
double daysSinceJsEpoch = daysSinceVariantEpoch - kVariantToJsDays;
// Then we convert to milliseconds
int64_t millisecondsSinceJsEpoch = std::llround(daysSinceJsEpoch * kMillisecondsPerDay);
return millisecondsSinceJsEpoch;
}
inline double JsTimeToWinRTTime(const double& time)
{
// JS Time is in milliseconds since UNIX epoch. First, move to the Windows epoch.
double millisecondsSinceWindowsEpoch = time + (kWinRTToJsDays * kMillisecondsPerDay);
// Then convert to 100-nanoseconds
return millisecondsSinceWindowsEpoch * kHundredNanosecondsPerMillisecond;
}
inline DATE WinRTTimeToVariantTime(const int64_t& time)
{
// Convert to Days
double daysSinceWindowsEpoch = static_cast<double>(time) / kHundredNanosecondsPerDay;
// Convert from Windows epoch days to DATE epoch days
double daysSinceVariantEpoch = daysSinceWindowsEpoch - kWinRTToVariantDays;
// Once again, DATEs are weird with the signed day, but always positive
// fractional day piece. To transform a normal days amount into DATE we need
// convert the fractional piece to be 1+fractional and change the sign if the
// value is negative.
double countDay;
double fractionalDay = std::modf(daysSinceVariantEpoch, &countDay);
if (fractionalDay == 0.0)
{
// There's an interesting edge-case when there is no fractional day part and
// a negative day count. For the function below, as
// fractional day goes to 0, the resulting difference goes to 2. For example
// -1.00001 becomes -2.99999, a difference of 1.99998 (almost 2). Normally
// this is what we want, but for 0 fractional day we don't want to change,
// so we return the count directly.
return countDay;
}
return (countDay - 1) + copysign(1 + fractionalDay, daysSinceVariantEpoch);
}
} // namespace wv2winrt_impl
<00>// Copyright (C) Microsoft Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <windows.h>
namespace wv2winrt_impl
{
struct UniqueVariant : public VARIANT
{
UniqueVariant();
UniqueVariant(const VARIANT&);
~UniqueVariant();
VARIANT* addressof();
void reset();
void reset(const VARIANT&);
VARIANT* reset_and_addressof();
VARIANT release();
private:
void init();
void close();
UniqueVariant(const UniqueVariant&) = delete;
UniqueVariant& operator=(const UniqueVariant&) = delete;
};
} // namespace wv2winrt_implr
// Copyright (C) Microsoft Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "wv2winrt/asyncdispatch.h"
#include "wv2winrt/uniquevariant.h"
#include <winrt/Windows.Foundation.h>
namespace wv2winrt_impl
{
struct DispatchAsyncResult : winrt::implements<
DispatchAsyncResult, ICoreWebView2PrivateDispatchAsyncResult,
ICoreWebView2PrivateDispatchAsyncResult2,
ICoreWebView2PrivateDispatchAsyncFinishedHandler,
ICoreWebView2PrivateDispatchAsyncInfo>
{
DispatchAsyncResult()
{
}
// ICoreWebView2PrivateDispatchAsyncResult
virtual HRESULT STDMETHODCALLTYPE
SetCompletedHandler(ICoreWebView2PrivateDispatchAsyncFinishedHandler* completedCallback)
{
m_completedCallback.copy_from(completedCallback);
return CheckCompletedCallback();
}
// ICoreWebView2PrivateDispatchAsyncFinishedHandler
HRESULT STDMETHODCALLTYPE Invoke(HRESULT errorCode, VARIANT* result) override
{
if (!m_completed)
{
m_completed = true;
if (result != nullptr)
{
VariantCopy(m_result.reset_and_addressof(), result);
}
else
{
m_result.reset();
m_result.vt = VT_EMPTY;
}
m_errorCode = errorCode;
}
return CheckCompletedCallback();
}
HRESULT STDMETHODCALLTYPE Cancel() override
{
if (m_asyncInfo)
{
m_asyncInfo.Cancel();
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE SetAsyncInfo(winrt::Windows::Foundation::IAsyncInfo asyncInfo)
{
m_asyncInfo = asyncInfo;
return S_OK;
}
private:
HRESULT CheckCompletedCallback()
{
HRESULT hr = S_OK;
if (m_completed && m_completedCallback && !m_invokeStarted)
{
m_invokeStarted = true;
hr = m_completedCallback->Invoke(m_errorCode, m_result.addressof());
}
return hr;
}
winrt::com_ptr<ICoreWebView2PrivateDispatchAsyncFinishedHandler> m_completedCallback;
winrt::Windows::Foundation::IAsyncInfo m_asyncInfo;
bool m_completed = false;
bool m_invokeStarted = false;
UniqueVariant m_result;
HRESULT m_errorCode = S_OK;
};
HRESULT CreateDispatchAsyncResult(ICoreWebView2PrivateDispatchAsyncResult** asyncResult)
{
winrt::make<DispatchAsyncResult>().copy_to(asyncResult);
return S_OK;
}
} // namespace wv2winrt_impl
x// Copyright (C) Microsoft Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "wv2winrt/dispatchbase.h"
#include "wv2winrt/uniquevariant.h"
namespace wv2winrt_impl
{
HRESULT DispatchBase::GetTypeInfoCount(UINT* /* typeInfoCount */)
{
return E_NOTIMPL;
}
HRESULT DispatchBase::GetTypeInfo(
UINT /* typeInfoCount */, LCID /* localeId */, ITypeInfo** /* typeInfo */)
{
return E_NOTIMPL;
}
HRESULT DispatchBase::GetIDsOfNames(
REFIID riid, LPOLESTR*, unsigned int namesCount, LCID localeId, DISPID*)
{
if (riid != IID_NULL || localeId != LOCALE_USER_DEFAULT || namesCount != 1)
{
return E_INVALIDARG;
}
return S_OK;
}
HRESULT DispatchBase::Invoke(
DISPID, REFIID riid, LCID localeId, WORD flags, DISPPARAMS* dispParams, VARIANT*,
EXCEPINFO*, UINT*)
{
if (riid != IID_NULL || localeId != LOCALE_USER_DEFAULT)
{
return E_INVALIDARG;
}
if (flags == DISPATCH_PROPERTYPUT)
{
if (dispParams->cNamedArgs != 1U || dispParams->rgdispidNamedArgs == nullptr)
{
return E_INVALIDARG;
}
}
else
{
if (dispParams->cNamedArgs != 0U || dispParams->rgdispidNamedArgs != nullptr)
{
return E_INVALIDARG;
}
}
return S_OK;
}
// static
bool DispatchBase::LookupProperty(
DispatchProperties properties, LPOLESTR const& query, size_t& idx, size_t count)
{
DispatchProperties const end = &(properties[count]);
DispatchProperties entry = std::lower_bound(
properties, end, query,
[](const wchar_t* const lhs, LPOLESTR const rhs) { return wcscmp(lhs, rhs) == -1; });
if (entry == end || wcscmp(query, *entry) == -1)
{
return false;
}
idx = std::distance(properties, entry);
return true;
}
} // namespace wv2winrt_impl
<00>#// Copyright (C) Microsoft Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "wv2winrt/eventargsdispatch.h"
#include "wv2winrt/dispatchbase.h"
#include "wv2winrt/uniquevariant.h"
namespace wv2winrt_impl
{
// Class that merges event args and source winrt event objects into one
// aggregate object that has a target and detail properties. This merges
// the unmodified event args with custom properties for target and detail.
struct AggregateEventArgs : winrt::implements<AggregateEventArgs, DispatchBase>
{
AggregateEventArgs(
LPCWSTR eventName, IDispatch* source, VARIANT* unmodifiedDelegateParamsAsVARIANT,
const ULONG unmodifiedDelegateParamsAsVARIANTCount)
{
m_typeString.vt = VT_BSTR;
m_typeString.bstrVal = SysAllocString(eventName);
m_source.copy_from(source);
PROPVARIANT vector_propvariant;
vector_propvariant.vt = VT_VECTOR | VT_VARIANT;
vector_propvariant.capropvar.cElems = unmodifiedDelegateParamsAsVARIANTCount;
vector_propvariant.capropvar.pElems = reinterpret_cast<PROPVARIANT*>(
CoTaskMemAlloc(sizeof(PROPVARIANT) * unmodifiedDelegateParamsAsVARIANTCount));
for (uint32_t idx = 0; idx < unmodifiedDelegateParamsAsVARIANTCount; ++idx)
{
UniqueVariant unmodifiedParamAsVARIANT;
if (idx == 0) // Handling the event args
{
VariantCopy(
m_unmodifiedEventArgsAsVARIANT.reset_and_addressof(),
&unmodifiedDelegateParamsAsVARIANT[idx]);
if (m_unmodifiedEventArgsAsVARIANT.vt == VT_DISPATCH &&
m_unmodifiedEventArgsAsVARIANT.pdispVal != nullptr)
{
m_unmodifiedEventArgsAsIDispatch.copy_from(
m_unmodifiedEventArgsAsVARIANT.pdispVal);
m_detailValue.vt = VT_DISPATCH;
m_unmodifiedEventArgsAsIDispatch.copy_to(&m_detailValue.pdispVal);
}
else if (
m_unmodifiedEventArgsAsVARIANT.vt == VT_DISPATCH &&
m_unmodifiedEventArgsAsVARIANT.pdispVal == nullptr)
{
m_detailValue.pdispVal = nullptr;
m_detailValue.vt = VT_NULL;
}
else
{
VariantCopy(
m_detailValue.reset_and_addressof(),
m_unmodifiedEventArgsAsVARIANT.addressof());
}
vector_propvariant.capropvar.pElems[idx] =
*(reinterpret_cast<PROPVARIANT*>(m_detailValue.addressof()));
}
else
{
VariantCopy(
unmodifiedParamAsVARIANT.reset_and_addressof(),
&unmodifiedDelegateParamsAsVARIANT[idx]);
vector_propvariant.capropvar.pElems[idx] =
*(reinterpret_cast<PROPVARIANT*>(unmodifiedParamAsVARIANT.addressof()));
}
}
static_assert(sizeof(PROPVARIANT) == sizeof(VARIANT));
m_detailVector.reset(*reinterpret_cast<VARIANT*>(&vector_propvariant));
}
// IDispatch methods
// GetIDsOfNames knows about hardcoded target and detail properties. Other names
// fall through to the unmodified event args. To avoid ID collisions the unmodified
// IDs are offset.
HRESULT STDMETHODCALLTYPE GetIDsOfNames(
REFIID riid, LPOLESTR* names, unsigned int namesCount, LCID localeId,
DISPID* dispId) override
{
HRESULT hr = DispatchBase::GetIDsOfNames(riid, names, namesCount, localeId, dispId);
if (SUCCEEDED(hr))
{
hr = DISP_E_MEMBERNOTFOUND;
if (wcscmp(names[0], L"target") == 0)
{
*dispId = s_targetId;
hr = S_OK;
}
else if (wcscmp(names[0], L"detail") == 0)
{
*dispId = s_detailId;
hr = S_OK;
}
else if (wcscmp(names[0], L"type") == 0)
{
*dispId = s_typeId;
hr = S_OK;
}
else if (m_unmodifiedEventArgsAsIDispatch != nullptr)
{
// If its not one of our known names that we're adding to the event args, then
// lets ask the actual event args.
hr = m_unmodifiedEventArgsAsIDispatch->GetIDsOfNames(
riid, names, namesCount, localeId, dispId);
if (SUCCEEDED(hr))
{
// 0 is a special DISPID that refers to the current object
// Our names are injected after 0 and before all other DISPIDs
// so if its not 0, then we move the ID down to make room.
if (*dispId > 0)
{
*dispId += s_dispIdOffset;
}
}
}
}
return hr;
}
HRESULT STDMETHODCALLTYPE Invoke(
DISPID dispId, REFIID riid, LCID localeId, WORD flags, DISPPARAMS* dispParams,
VARIANT* result, EXCEPINFO* excepInfo, UINT* argErr) override
{
HRESULT hr = DispatchBase::Invoke(
dispId, riid, localeId, flags, dispParams, result, excepInfo, argErr);
bool modifiedId = false;
if (SUCCEEDED(hr))
{
hr = DISP_E_MEMBERNOTFOUND;
if (flags == DISPATCH_PROPERTYGET)
{
switch (dispId)
{
case s_targetId:
{
if (m_source != nullptr)
{
result->vt = VT_DISPATCH;
m_source.copy_to(&result->pdispVal);
}
else
{
result->vt = VT_NULL;
}
modifiedId = true;
hr = S_OK;
break;
}
case s_detailId:
{
*result = m_detailVector;
modifiedId = true;
hr = S_OK;
break;
}
case s_typeId:
{
VariantCopy(result, m_typeString.addressof());
modifiedId = true;
hr = S_OK;
break;
}
}
}
}
if (FAILED(hr) && !modifiedId && m_unmodifiedEventArgsAsIDispatch != nullptr)
{
DISPID effectiveDispId = dispId;
if (effectiveDispId > s_dispIdOffset)
{
effectiveDispId -= s_dispIdOffset;
}
hr = m_unmodifiedEventArgsAsIDispatch->Invoke(
effectiveDispId, riid, localeId, flags, dispParams, result, excepInfo, argErr);
}
return hr;
}
// ICoreWebView2PrivateDispatchContainer methods
// If someone tries to unwrap this IDispatch object there is no directly corresponding
// winrt object to this aggregate object. Instead since the aggregate object is
// mostly the event args plus extra properties, we unwrap to the event args.
HRESULT STDMETHODCALLTYPE GetInnerObject(IUnknown** object) override
{
HRESULT hr = DISP_E_MEMBERNOTFOUND;
if (m_unmodifiedEventArgsAsIDispatch != nullptr)
{
hr = S_OK;
*object = m_unmodifiedEventArgsAsIDispatch.as<IUnknown>().detach();
}
return hr;
}
HRESULT STDMETHODCALLTYPE GetBasisVariant(VARIANT* basis) override
{
VariantCopy(basis, m_unmodifiedEventArgsAsVARIANT.addressof());
return S_OK;
}
private:
winrt::com_ptr<IDispatch> m_source; // The source of the event
// The event args of the event as an IDispatch.
winrt::com_ptr<IDispatch> m_unmodifiedEventArgsAsIDispatch;
UniqueVariant m_unmodifiedEventArgsAsVARIANT;
UniqueVariant m_detailVector; // The detail property array
UniqueVariant m_typeString; // The name of the event
// The 0 index of the detail array that is the unmodified event args
UniqueVariant m_detailValue;
// The DISPID of the known properties
static const DISPID s_targetId = 1;
static const DISPID s_detailId = 2;
static const DISPID s_typeId = 3;
// The offset for all the DISPIDs on the event args.
static const DISPID s_dispIdOffset = s_typeId;
};
HRESULT CreateAggregateEventArgs(
LPCWSTR eventName, IDispatch* source, VARIANT* unmodifiedDelegateParamsAsVARIANT,
const ULONG unmodifiedDelegateParamsAsVARIANTCount, IDispatch** aggregateEventArgs)
{
winrt::make<AggregateEventArgs>(
eventName, source, unmodifiedDelegateParamsAsVARIANT,
unmodifiedDelegateParamsAsVARIANTCount)
.as<IDispatch>()
.copy_to(aggregateEventArgs);
return S_OK;
}
} // namespace wv2winrt_impl
<EFBFBD>// Copyright (C) Microsoft Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "wv2winrt/main.h"
#include "wv2winrt/globals.h"
namespace wv2winrt_impl
{
const InstanceConstructibleEntry* LookupInstanceConstructibleEntry(LPCWSTR query)
{
const InstanceConstructibleEntry* last =
&(s_instanceConstructibleEntries[s_instanceConstructibleEntriesCount]);
InstanceConstructibleEntry queryEntry{query, false, nullptr};
const InstanceConstructibleEntry* it =
std::lower_bound(s_instanceConstructibleEntries, last, queryEntry);
return (it == last || queryEntry < *it) ? nullptr : &(*it);
}
HRESULT STDMETHODCALLTYPE CreateDispatchFromName(
LPCWSTR name,
const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter& dispatchAdapter,
IDispatch** dispatch)
{
for (size_t globalEntriesIdx = 0; globalEntriesIdx < s_globalEntriesCount;
++globalEntriesIdx)
{
if (wcscmp(s_globalEntries[globalEntriesIdx].name, name) == 0)
{
return s_globalEntries[globalEntriesIdx].createFunction(dispatchAdapter, dispatch);
}
}
return DISP_E_MEMBERNOTFOUND;
}
HRESULT STDMETHODCALLTYPE CreateDispatchFromInspectable(
IInspectable* objectAsABI,
const winrt::Microsoft::Web::WebView2::Core::ICoreWebView2DispatchAdapter& dispatchAdapter,
IDispatch** result, bool* is_cacheable)
{
if (!objectAsABI)
{
return E_POINTER;
}
*result = nullptr;
HSTRING classNameAsHSTRING = nullptr;
HRESULT hr = objectAsABI->GetRuntimeClassName(&classNameAsHSTRING);
if (SUCCEEDED(hr))
{
hr = DISP_E_MEMBERNOTFOUND;
LPCWSTR classNameAsLPCWSTR = WindowsGetStringRawBuffer(classNameAsHSTRING, nullptr);
const InstanceConstructibleEntry* entry =
LookupInstanceConstructibleEntry(classNameAsLPCWSTR);
if (entry)
{
auto obj = entry->createFunction(objectAsABI, dispatchAdapter);
*result = obj.detach();
*is_cacheable = !(entry->isBoxedStruct);
hr = S_OK;
}
}
WindowsDeleteString(classNameAsHSTRING);
return hr;
}
} // namespace wv2winrt_impl
j
// Copyright (C) Microsoft Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "wv2winrt/returnaggregator.h"
wv2winrt_impl::ReturnAggregator::ReturnAggregator(
const size_t outParamCount, const bool hasReturnValue)
: m_parameterValues(outParamCount + (hasReturnValue ? 1 : 0))
{
}
VARIANT* wv2winrt_impl::ReturnAggregator::AddParameter(LPCWSTR name)
{
const size_t idx = m_parameterNameToIdxMap.size();
m_parameterNameToIdxMap.emplace(name, idx);
assert(idx < m_parameterValues.size());
return m_parameterValues[idx].reset_and_addressof();
}
void wv2winrt_impl::ReturnAggregator::SetReturnValue(const VARIANT& value)
{
VariantCopy(AddParameter(L"value"), &value);
}
// IDispatch methods
HRESULT wv2winrt_impl::ReturnAggregator::GetIDsOfNames(
REFIID riid, LPOLESTR* names, unsigned int namesCount, LCID localeId, DISPID* dispId)
{
HRESULT hr = DispatchBase::GetIDsOfNames(riid, names, namesCount, localeId, dispId);
if (SUCCEEDED(hr))
{
hr = DISP_E_MEMBERNOTFOUND;
auto nameToIdxItr = m_parameterNameToIdxMap.find(names[0]);
if (nameToIdxItr != m_parameterNameToIdxMap.end())
{
*dispId = static_cast<DISPID>(nameToIdxItr->second + 1);
hr = S_OK;
}
}
return hr;
}
HRESULT wv2winrt_impl::ReturnAggregator::Invoke(
DISPID dispId, REFIID riid, LCID localeId, WORD flags, DISPPARAMS* dispParams,
VARIANT* result, EXCEPINFO* excepInfo, UINT* argErr)
{
HRESULT hr = DispatchBase::Invoke(
dispId, riid, localeId, flags, dispParams, result, excepInfo, argErr);
if (SUCCEEDED(hr))
{
hr = DISP_E_MEMBERNOTFOUND;
if (flags == DISPATCH_PROPERTYGET)
{
size_t entryIdx = dispId - 1;
if (entryIdx < m_parameterValues.size())
{
hr = VariantCopy(result, m_parameterValues[entryIdx].addressof());
}
}
}
return hr;
}
HRESULT wv2winrt_impl::ReturnAggregator::AddOutArrayParameterInfoEntry(LPWSTR name, int index)
{
m_OutArrayParameterNames.push_back(name);
m_OutArrayParameterIndexes.push_back(index);
return S_OK;
}
HRESULT wv2winrt_impl::ReturnAggregator::GetOutArrayParameterInfo(
int** indexes, LPWSTR** names, size_t* length)
{
if (m_OutArrayParameterNames.size() == 0 || m_OutArrayParameterIndexes.size() == 0)
{
return E_NOTIMPL;
}
*names = m_OutArrayParameterNames.data();
*indexes = m_OutArrayParameterIndexes.data();
*length = m_OutArrayParameterNames.size();
return S_OK;
}<00>// Copyright (C) Microsoft Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "wv2winrt/uniquevariant.h"
wv2winrt_impl::UniqueVariant::UniqueVariant()
{
init();
}
wv2winrt_impl::UniqueVariant::UniqueVariant(const VARIANT& other) : VARIANT(other)
{
}
wv2winrt_impl::UniqueVariant::~UniqueVariant()
{
close();
}
VARIANT* wv2winrt_impl::UniqueVariant::addressof()
{
return this;
}
void wv2winrt_impl::UniqueVariant::reset()
{
close();
init();
}
void wv2winrt_impl::UniqueVariant::reset(const VARIANT& other)
{
close();
VARIANT::operator=(other);
}
VARIANT* wv2winrt_impl::UniqueVariant::reset_and_addressof()
{
reset();
return addressof();
}
VARIANT wv2winrt_impl::UniqueVariant::release()
{
VARIANT result(*this);
// Note, we're explicitly not calling close here.
// The whole point of release is we're leaking
// the struct to the caller.
init();
return result;
}
void wv2winrt_impl::UniqueVariant::init()
{
::VariantInit(this);
}
void wv2winrt_impl::UniqueVariant::close()
{
::VariantClear(this);
}
$winrt::Windows::Foundation::TimeSpan duration{ Converter<VARIANT, int64_t>(m_dispatchAdapter).Convert(*(dispParams->rgvarg)) };
winrt::Windows::Foundation::DateTime resultAsWinRT{ duration };
*result = Converter<decltype(resultAsWinRT), VARIANT>(m_dispatchAdapter).Convert(resultAsWinRT);
<EFBFBD>auto resultAsWinRT = m_innerObject.time_since_epoch().count();
*result = Converter<decltype(resultAsWinRT), VARIANT>(m_dispatchAdapter).Convert(resultAsWinRT);
<00>winrt::Windows::Foundation::TimeSpan ticks{ Converter<VARIANT, int64_t>(m_dispatchAdapter).Convert(*(dispParams->rgvarg)) };
winrt::Windows::Foundation::DateTime updated { ticks };
m_innerObject = updated;
<00>auto resultAsWinRT = m_innerObject.count();
*result = Converter<decltype(resultAsWinRT), VARIANT>(m_dispatchAdapter).Convert(resultAsWinRT);
<00>winrt::Windows::Foundation::TimeSpan updated{ Converter<VARIANT, int64_t>(m_dispatchAdapter).Convert(*(dispParams->rgvarg)) };
m_innerObject = updated;
̩<1C>|<00><00><>RSDS<44>mƜ(l
M<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>j}D:\a\_work\1\s\third_party\edge_webview2\win\winmd_code_gen\wv2winrt\obj\Win32\Release\wv2winrt.pdbh<00> t_CorExeMainmscoree.dll<00>% @ <00>P<00>8<00><00>h<00><00><00> 4VS_VERSION_INFO<00><04><>3
3
?DVarFileInfo$Translation<00>pStringFileInfoL000004b0<00>LCommentsTool to generate COM IDispatch wrappers for WinRT classes from winmd files.LCompanyNameMicrosoft Corporation: FileDescriptionwv2winrt8 FileVersion1.0.2592.51: InternalNamewv2winrt.exe<00>8LegalCopyrightCopyright <00> Microsoft Corporation. All rights reserved.B OriginalFilenamewv2winrt.exe2 ProductNamewv2winrt< ProductVersion1.0.2592.51@ Assembly Version1.0.2592.51<00>$<?xml version="1.0" encoding="utf-8"?>
<!-- Allow this desktop app to use WinRT. Described in the following:
https://blogs.windows.com/windowsdeveloper/2019/04/30/enhancing-non-packaged-desktop-apps-using-windows-runtime-components/
All activatable runtimeclasses must be listed below with their own
activatableClass entry.
-->
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="wv2winrt.app"/>
<file name="winrt_winmd.dll">
<!-- Any exposed winrt class with a constructor or statics must appear here -->
<activatableClass
name="winrt_winmd.Root"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1"
/>
</file>
</assembly>
 <00>>@(0<>(3 *<2A>H<EFBFBD><48> <02><>($0<>( 10  `<60>He0\
+<01>7<04>N0L0
+<01>70 <00><04><02>010  `<60>He I<>N+<2B>VA<1C><><EFBFBD>4<EFBFBD><34>~u<>S<EFBFBD>2<EFBFBD>;<3B><><EFBFBD>c<EFBFBD><63><EFBFBD>Y<EFBFBD><59> v0<76><05>0<EFBFBD>ܠ3<03>A<11><><EFBFBD> u<03>0  *<2A>H<EFBFBD><48>  0~1 0 UUS10U
Washington10URedmond10U
Microsoft Corporation1(0&UMicrosoft Code Signing PCA 20110 231019195156Z 241016195156Z0t1 0 UUS10U
Washington10URedmond10U
Microsoft Corporation10UMicrosoft Corporation0<6E>"0  *<2A>H<EFBFBD><48> <03>0<>
<02><00>Ȳe`{<0F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>†1<C286><31><EFBFBD>4<EFBFBD><34>"嬦~G<>=z<><7A>j~<1D><>;a<>4F<34><46>=<3D><><EFBFBD>qo<71>_h'6<>a0<61>Q<EFBFBD>=yM<79>$EZ<06><>4<11> ro9<6F><39><EFBFBD><EFBFBD>I<EFBFBD> <09>Fp%!W&P3`<60>A<17>܊<EFBFBD>?Ԏݫ]G1 <0B><><1C>
<EFBFBD>V<18><> <0B><><EFBFBD><EFBFBD><06>.i<><69>tK<74>/֫5ir<1F>ѻ<EFBFBD><D1BB><EFBFBD><EFBFBD>ZP<5A>^<5E>b<EFBFBD>߶<EFBFBD>Ǩ<EFBFBD>W<EFBFBD><57><17><><EFBFBD>]H_<48>U<EFBFBD>ϝO<CF9D>.<2E><>\<5C>I)+ <0C>l<EFBFBD><6C><EFBFBD>Â<EFBFBD>X<EFBFBD>H<19><>[U>A<02>f,3<><33><EFBFBD>@ <20>V<EFBFBD><56>g<EFBFBD><EFBFBD><7F><EFBFBD>%<25>`<15><>SM<53>=ͩ<><01><>s0<73>o0U%0
+<01>7
+0U<14>Ub<55><62>el<65><6C>ڷ<EFBFBD>0<EFBFBD>J<EFBFBD><6A>0EU>0<<3C>:0810U Microsoft Corporation10U 230217+5016170U#0<16>Hnd<6E>Pӂ<>77"<22>m<EFBFBD><6D>u<02>0TUM0K0I<30>G<EFBFBD>E<EFBFBD>Chttp://www.microsoft.com/pkiops/crl/MicCodSigPCA2011_2011-07-08.crl0a+U0S0Q+0<02>Ehttp://www.microsoft.com/pkiops/certs/MicCodSigPCA2011_2011-07-08.crt0 U<01>00  *<2A>H<EFBFBD><48>  <03><>ejX<6A>$ <0A><><EFBFBD>p<EFBFBD><70>4<EFBFBD><34>b<EFBFBD><62>s<1C>Hf0<66>`<60>Iw<49><15>u<EFBFBD><75><EFBFBD><1B>eA<65>*<2A>l<EFBFBD>I<EFBFBD><49><EFBFBD><0F>)A^<>WE)<29> <0B><>1<EFBFBD><31>*{K<>bV<62><56>nH<6E>
l<EFBFBD><EFBFBD>D<EFBFBD><EFBFBD>P<EFBFBD>Ô<EFBFBD>R<1A><>y<EFBFBD>ߐ<EFBFBD>Yw<59>sLr=Tx><3E><><0F>o<EFBFBD>E<EFBFBD>q<18>m/H }Z A[<5B> <0B>J"<22><>3<EFBFBD><33>f\US<55><02>5n<35>6Kp<4B>NvJ<76><4A><EFBFBD>}<7D><>G<EFBFBD><EFBFBD><C28F>̷=xx<78><78><EFBFBD>Y<<3C>?<3F>Ӈ<EFBFBD><D387><0E> <0B><> 0_^<5E><>\ <09>~r<><s<>.<2E><><EFBFBD><04><><EFBFBD>}<7D><><EFBFBD><EFBFBD><EFBFBD>X<EFBFBD><58>${H<><48><EFBFBD>.}u<><75>?<3F><>-<2D>A^
<EFBFBD>O1oQ<19>l_B<1E><>Z;Xr<58><72><EFBFBD><EFBFBD><EFBFBD><18><>`<03><><0F> ?<3F><><17><><EFBFBD>{fe RB<1D>U<EFBFBD><55>rd<72><64><EFBFBD>:<1F><>s<0F>:<3A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"<22><>//E<1E><><EFBFBD>c<EFBFBD>@C<>)<29><><03>i<EFBFBD>S0<53><30>%<25>_<>;O4y<34><79>&o<>I.<0E>/<2F>`O<>14<31><34>T<EFBFBD><54><EFBFBD><08> <20>Lm<4C><6D> _<>P<EFBFBD><50>δay=<3D><><1B><><1C> <09>򪻿H<F2AABBBF>3<EFBFBD>VI<56><49>nyy<79>#`v<>B<EFBFBD>xȢ<78>6<EFBFBD>v<EFBFBD>Ҩ<EFBFBD>$ór<C3B3><72>RˬYD~z<><7A><EFBFBD>Il<7F><10>|<7C><><EFBFBD><EFBFBD>@<1E>c0|<7C>l<EFBFBD><1C>d %<25><><EFBFBD>&<26><><19>W,<2C><>G<EFBFBD><47><EFBFBD><EFBFBD><EFBFBD>0<EFBFBD>z0<7A>b<>
a<0E><>0  *<2A>H<EFBFBD><48>  0<><30>1 0 UUS10U
Washington10URedmond10U
Microsoft Corporation1200U)Microsoft Root Certificate Authority 20110 110708205909Z 260708210909Z0~1 0 UUS10U
Washington10URedmond10U
Microsoft Corporation1(0&UMicrosoft Code Signing PCA 20110<31>"0  *<2A>H<EFBFBD><48> <03>0<>
<02><00><><EFBFBD>r.<2E><>n<EFBFBD><6E>M4<4D><34><EFBFBD>X!<21>B*k<>ZP<5A><50>8I<><EFBFBD> <1E>7k<37><12> <0B>8™<06><>9<EFBFBD>1BӉ yd<79>~<7E>`$l<><6C>I<EFBFBD><49>h^<5E>ߛS<DF9B>
,ï٩+<2B>z <09>זY<D796>`<05>fv<66>2R&/<2F><>PϳD<CFB3>]<5D><>.u<>h<EFBFBD><68>m<EFBFBD>:\<5C><16>F<EFBFBD><46>8d<38>nd5x<35><78>c-<2D>@<40><><EFBFBD><EFBFBD> <0A>\y<>I)<29> <0A><>w<><77>=<3D><><EFBFBD>+ZMV(<28>zr<7A>:<3A>I^<5E><><EFBFBD>C<EFBFBD><43><EFBFBD>{<7B>{<7B><1B>><3E><>]<5D><>O<EFBFBD><1A><>/Y<><59>;-<2D>3Xŷ><3E>=<3D><><EFBFBD><EFBFBD>8~ҝ<>,<2C>NV<4E>!5%<25>9ndS<7F><53><0F>#<23><><EFBFBD><EFBFBD><03><><EFBFBD>_<EFBFBD><5F>R<EFBFBD><52><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!t%_(<28><>'(8%<25>9J6<4A>|<7C><><EFBFBD>#<23><>f<EFBFBD>aj<>(I<>_<EFBFBD><5F>%]<5D>!K>RĵW?$<03><>z[/<2F>#<23>p]QFw<46><77><02>_<EFBFBD><5F><15><><1B>UK<55>9<EFBFBD><0F>#I<><18>D|E<><45><EFBFBD>rz<72>r<EFBFBD>$߿F<DFBF><46><EFBFBD><EFBFBD><57><DB83>MI0<49><30><EFBFBD><EFBFBD><EFBFBD>[<5B><><EFBFBD>ݰf<DDB0><66><EFBFBD><EFBFBD>{<7B><><EFBFBD>K<EFBFBD>I)<29>(<28><>}g<><67><EFBFBD>bx_<78>/<2F><>W<EFBFBD>\<5C>w((<28><>m<EFBFBD>(<28>,<2C>@7O<37><4F><EFBFBD>D<EFBFBD><44> L<>ԥC/t<><74>n<EFBFBD>x X,]`<60><>>O3<4F>ڰ<EFBFBD>ޞN<DE9E><4E><EFBFBD><EFBFBD>F<EFBFBD>l<EFBFBD><6C><EFBFBD>ֈ<EFBFBD> <01><><01>0<EFBFBD><01>0 +<01>70UHnd<6E>Pӂ<>77"<22>m<EFBFBD><6D>u<02>0 +<01>7 
SubCA0 U<01>0U<01>0<01>0U#0<16>r-:1<>C<EFBFBD>N<><4E><EFBFBD><EFBFBD>1<EFBFBD>#<23>40ZUS0Q0O<30>M<EFBFBD>K<EFBFBD>Ihttp://crl.microsoft.com/pki/crl/products/MicRooCerAut2011_2011_03_22.crl0^+R0P0N+0<02>Bhttp://www.microsoft.com/pki/certs/MicRooCerAut2011_2011_03_22.crt0<74><30>U <04><>0<EFBFBD><30>0<EFBFBD><30> +<01>7.0<><30>0?+3http://www.microsoft.com/pkiops/docs/primarycps.htm0@+042 Legal_policy_statement. 0  *<2A>H<EFBFBD><48>  <03>g򆥘<67>Ty.<2E><>tg"<22> <0B><11>c<EFBFBD><63>B<EFBFBD>}<7D>y <0C><>e_.,><3E><>r<EFBFBD>m<EFBFBD><6D><EFBFBD>?<3F>
<EFBFBD>;<3B>G<EFBFBD><47><EFBFBD>i<EFBFBD>c<EFBFBD>"5<><35>]e<><65>}<7D>FPU<50> <0C>|<7C>K<1C><B<>Rа<52>k<EFBFBD>>.)<29><>=<1B>Եw<>9<EFBFBD><39>d<EFBFBD>D=xz#<23>}<7D><>t<EFBFBD><74><EFBFBD><EFBFBD>&F*Š<10><><EFBFBD> <0C><>h<EFBFBD>h.<2E><>*?*kXIc inZ<6E><5A><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>F+<2B><>;н5<D0BD>n%<25><><EFBFBD>'<27><><EFBFBD><EFBFBD><0E><>(<28><>M= <0B><08><><1F>2<18><><EFBFBD>-<2D>[<5B><>I9
<EFBFBD>
<EFBFBD>ƭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><15>QEX82q'<><7F>'<27><>,: i<><69>Y<EFBFBD>hno<6E><6F>t<EFBFBD>@<06>*(><3E>?Mf <0B><>M<EFBFBD><4D><EFBFBD>o}E<>v<EFBFBD>@*e<><65>]Rb<52><62>c6<63><36><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><16><>'<27>ͥ<EFBFBD><CDA5><EFBFBD>]cA<63>[<07><>>w<06><06>u<14>aa<61><61><EFBFBD><EFBFBD><04><>A<EFBFBD>(<28><>e/<2F><><EFBFBD><EFBFBD>\<5C><>֡F<D6A1>Y<EFBFBD><59><EFBFBD> KH<10><><1F><><C5B1>?Ew5<>Ң<EFBFBD><D2A2>zz"<22>H<EFBFBD><1F><>G#<23><><EFBFBD><EFBFBD><EFBFBD>k<EFBFBD>K<EFBFBD><4B><EFBFBD>ux<1A><>7<EFBFBD>yK<>ֳ#hu<68><75><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <0B><>i;<3B><>0<EFBFBD>L<><4C><EFBFBD>umc<6D>=ѝVNO<4E><4F>W"<22>x2!z<>A
<EFBFBD>?<3F><>̤]<5D><><EFBFBD><EFBFBD>WqVNHE<48>Bɛv[
<EFBFBD>Hk<EFBFBD>y<EFBFBD><EFBFBD><EFBFBD>mmj<EFBFBD>Rs zP<7A>1<EFBFBD>00<30>,0<><30>0~1 0 UUS10U
Washington10URedmond10U
Microsoft Corporation1(0&UMicrosoft Code Signing PCA 20113<03>A<11><><EFBFBD> u<03>0  `<60>He<00><><EFBFBD>0 *<2A>H<EFBFBD><48>  1 
+<01>70
+<01>7 10 
+<01>70/ *<2A>H<EFBFBD><48>  1" W)<29>p<><70><EFBFBD> <0A><>4]S;<3B>.<2E>`<60><><EFBFBD>J<EFBFBD>BIK:<3A><>0h
+<01>7 1Z0X<30>8<EFBFBD>6Microsoft Edge WebView2 SDK<><1C>https://www.microsoft.com 0  *<2A>H<EFBFBD><48> <04>y<1B><>\q"<22>"n<><6E><EFBFBD><EFBFBD><EFBFBD><EFBFBD>K<EFBFBD><4B><EFBFBD><EFBFBD>-0};<3B><>d<08>0<EFBFBD>gN<><4E>UEW 7<>n+5<>"<22><1A><>nU2<1C>VY<56>8<EFBFBD>2<EFBFBD><32>5<EFBFBD><35>S<EFBFBD>R͆<>CxG<><47><EFBFBD><EFBFBD><EFBFBD>&Mѷn2M<32><4D><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֗m<D697><6D><06><>7<EFBFBD><37><17> "<0E><><EFBFBD><EFBFBD> _*#<23><>&Q<>vbVz~<7E><>n<EFBFBD><39>Qz6<7A><36>:W<>ɯ<EFBFBD><10><> <0B>|3<>k<EFBFBD>ٰ'<27><>OCy<43><79>xo^6<><36><EFBFBD>2<><32>yE !<21>]<5D><>!<21>S<EFBFBD>6Q<36><1D>}<7D>Ȧ<EFBFBD><C8A6>'4<>B<EFBFBD>.<2E>2<EFBFBD>K<><4B><EFBFBD><EFBFBD><EFBFBD>6B<0F>I<EFBFBD><65>J<EFBFBD>%%g<>j2<6A><32>>Ρ<><17>0<EFBFBD><17>
+<01>71<><17>0<EFBFBD>| *<2A>H<EFBFBD><48> <02><>m0<6D>i10  `<60>He0<>R *<2A>H<EFBFBD><48>  <04><>A<04>=0<>9
+<01>Y
010  `<60>He <01><><EFBFBD><EFBFBD>@ޤ%<25>(<28><><EFBFBD>#~w<>J;e0Sع<53><1B>fFr<>20240611092334.314Z0<04><01><><EFBFBD>Ѥ<EFBFBD><D1A4>0<EFBFBD><30>1 0 UUS10U
Washington10URedmond10U
Microsoft Corporation1%0#U Microsoft America Operations1'0%U nShield TSS ESN:8603-05E0-D9471%0#UMicrosoft Time-Stamp Service<63><65><11>0<EFBFBD> 0<><08>3<01><>E<EFBFBD>'<27><><16><01>0  *<2A>H<EFBFBD><48>  0|1 0 UUS10U
Washington10URedmond10U
Microsoft Corporation1&0$UMicrosoft Time-Stamp PCA 20100 231206184555Z 250305184555Z0<5A><30>1 0 UUS10U
Washington10URedmond10U
Microsoft Corporation1%0#U Microsoft America Operations1'0%U nShield TSS ESN:8603-05E0-D9471%0#UMicrosoft Time-Stamp Service0<65>"0  *<2A>H<EFBFBD><48> <03>0<>
<02><00><>P<EFBFBD><50><EFBFBD><1F>{<7B>o'<27>8VO<><4F><01>&<26><>4qĵ<71><C4B5> <0C>B T<>>_W<5F>Y)<29><>M4![<5B><><EFBFBD>iz<69><7A>gw<67>A<EFBFBD> o<><14><> g<>{<7B><0F><> =\H<1C>n<EFBFBD>6<1C><><EFBFBD><EFBFBD>w]zݱ<7A>ڔ<EFBFBD><<3C>Iv<49><16>L<EFBFBD>eb|G<><47>tz&<17><>b<EFBFBD><62>o <0C><><EFBFBD>]<2ڃ<32>~<00>'<27><>ح<EFBFBD><D8AD>?<3F>tu<74>2#<23><>U<EFBFBD><12><>-<2D><>֛<EFBFBD>J<EFBFBD>~@<40>soK<0F><><EFBFBD><EFBFBD><EFBFBD>+<>+<2B>K<EFBFBD>.<2E><>{®I|<7C>iX<10>qωY<CF89><59>H'<27>ǔ<EFBFBD><C794><EFBFBD><05><>]<18>(<28>q<EFBFBD><71><EFBFBD><EFBFBD><EFBFBD>ʫl<CAAB>\<14><>ÄЉ<C384><D089><EFBFBD>ܬ <09><>FjH<6A>q<>=H <0B><><EFBFBD>2Ƥ $<24><>N<EFBFBD>9<18>E<EFBFBD><45><EFBFBD><EFBFBD><EFBFBD><EFBFBD>nAgS^<5E>a<EFBFBD>H<<3C><><EFBFBD>"<22><><37><DD90><[*bft6<74>o4<6F><34>hg<68>v<EFBFBD><76> h<>*pw<70>é0<C3A9><30>>:<3A><>A<EFBFBD><1C><>p@<40><><EFBFBD> g<><67><EFBFBD>S;ݡEAGE8<45><38>r;W<>D<EFBFBD><44><EFBFBD>e<EFBFBD><65><1E><EFBFBD>"<22><08>n<EFBFBD>T<EFBFBD>P<EFBFBD>W6v<02>Ih<49><15><><EFBFBD>x7<78><37><EFBFBD><EFBFBD>8<EFBFBD><38>s<EFBFBD>+<2B><>"yhO<1B>-,I<><49><EFBFBD>N5#:>q<><19><><1D><>lj<6C><6A><EFBFBD> <20><><EFBFBD><03><><08>-<2D><><1E><><EFBFBD><EFBFBD>:
<EFBFBD><EFBFBD>6Q<12><>lqݹ 1<03><><EFBFBD><EFBFBD><EFBFBD><14>8<14><>0\<01><>I0<49>E0U<14><><EFBFBD><EFBFBD>}<7D>!4J<<3C><>ND<4E><44><18>-`0U#0<16><14><>]^b]<5D><><EFBFBD><EFBFBD>e<EFBFBD>S5<19>r0_UX0V0T<30>R<EFBFBD>P<EFBFBD>Nhttp://www.microsoft.com/pkiops/crl/Microsoft%20Time-Stamp%20PCA%202010(1).crl0l+`0^0\+0<02>Phttp://www.microsoft.com/pkiops/certs/Microsoft%20Time-Stamp%20PCA%202010(1).crt0 U<01>00U%<01> 0
+0U<01><07>0  *<2A>H<EFBFBD><48>  <03><00>HH<48>T<>l<EFBFBD><6C><EFBFBD>OИS<16><><EFBFBD>I<><49><EFBFBD><EFBFBD><0F><>L<EFBFBD><4C>4I<34><49>O<08>q<EFBFBD>n<EFBFBD><6E><EFBFBD>1J<><11><>K<EFBFBD>=3<><33><EFBFBD><05>+U)<29><><T<>0<06>̢.<2E><ӿ<J<><4A>O<EFBFBD>W<><57>ej^(3v<33>!<1A>M<>:G6 <0B><>s E暓<45>3<EFBFBD>\I<>E5<><35><{.<12>e<02>Xf%9<><01><><13>n<EFBFBD><6E>n۲!9<>\<5C><>D%!<21><>g*${L.<1A><><EFBFBD>t<EFBFBD><74>X<EFBFBD>]?Ѝ<><D08D>x<EFBFBD><0E><><EFBFBD>l<EFBFBD>o&<26>]no<6E>y<EFBFBD><79>#<23><><EFBFBD><EFBFBD>|<07>.SmmE<6D>0:t<><74><13>d<EFBFBD>?<3F><>_<>l<01>2<EFBFBD><32><EFBFBD>d<><64>iƛ$<24><04><>oj<6F><6A><EFBFBD>(<28><>!1MXB<58><42>a<>)D<><44>#<17>G<EFBFBD><47>o<>b<EFBFBD>bSpgD<67><44><EFBFBD>Gv<47><76>ń<EFBFBD>x<EFBFBD>e<>Q<EFBFBD><51><EFBFBD>u/<2F><01><><EFBFBD><EFBFBD>K<EFBFBD>{<7B><><EFBFBD> <0C><><1D><>#<23>a<EFBFBD>Oǵ<><02><>e<EFBFBD><65><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <0A>"w<><77><0F>YC<18>&<26><><EFBFBD>S30 <11>aRn4<16>m<EFBFBD>{<7B><02><>.<2E><><EFBFBD><EFBFBD><EFBFBD>lw<6C><62>CU}<7D>\}<7D>ѽ<EFBFBD>ܪ;m<><6D>V<EFBFBD>?<3F><><EFBFBD><19>ǫig<69><67><EFBFBD>&>[LS<4C>D@<40><1E><><EFBFBD>z<18><>d<EFBFBD><64>R<EFBFBD><52><EFBFBD>a}A<><41>-t<><74><EFBFBD><1D>$<24><0F>v<EFBFBD>E|#(<28>!<21><13><>7<EFBFBD>V<EFBFBD><56>B!7Ľ<37>0<>q0<71>Y<>3<15><>k<EFBFBD><02>I<EFBFBD>0  *<2A>H<EFBFBD><48>  0<><30>1 0 UUS10U
Washington10URedmond10U
Microsoft Corporation1200U)Microsoft Root Certificate Authority 20100 210930182225Z 300930183225Z0|1 0 UUS10U
Washington10URedmond10U
Microsoft Corporation1&0$UMicrosoft Time-Stamp PCA 20100<30>"0  *<2A>H<EFBFBD><48> <03>0<>
<02><00><><EFBFBD>L<EFBFBD><4C>r! y<><79><EFBFBD>$y<>Ղ<><D582><EFBFBD><EFBFBD>ҩlNu<4E><75>5W<35>lJ<6C>⽹>`3<>\O<>f<EFBFBD><66>SqZ<71>~JZ<4A><5A>6g<36>F# <0C><><13>w2<77><18>`}jR<6A>D<EFBFBD><44><EFBFBD>Fk<14><>v<EFBFBD><76>P<EFBFBD><50>D<EFBFBD>q\Q17<31>
8n<EFBFBD><EFBFBD><EFBFBD><0F>&S|9a<7A>ri<72><1D><><EFBFBD>6<EFBFBD>5&dژ;<3B>{3<><33>[~<7E><1C>R<EFBFBD><52><EFBFBD>b%<25>j<0F>]<5D><><EFBFBD>S<EFBFBD><53><EFBFBD><EFBFBD>VM<56>ݼ<EFBFBD><DDBC><EFBFBD>9,Q<><51>pi <0A>6-p<>1<EFBFBD>5(<28>㴇$<24><>ɏ~<7E>T<EFBFBD><54><EFBFBD>U<>mh;<3B>F<EFBFBD><46><EFBFBD><EFBFBD>z)7<><37><EFBFBD><EFBFBD>E<EFBFBD>Fn<46>2<EFBFBD><32><EFBFBD>0\O,<2C>b<EFBFBD>͹⍈䖬J<><4A>q<EFBFBD>[g`<60><><EFBFBD><EFBFBD>=<3D> <20>s}A<>Fu<46><75>_4<5F><12><><EFBFBD><EFBFBD> }~<7E>ٞE߶r/<2F>}_<><5F>۪~6<>6L<36>+n<>Q<><51><03><>s<EFBFBD>M7t<37>4<><0F><10><>G<18><><EFBFBD><EFBFBD>|?Lۯ^<5E><><EFBFBD><EFBFBD>s=CN<43>39L<39><02>Bh.<10><>QF<51>ѽjZas<>g<EFBFBD>^<5E>(v<02>3<20><><EFBFBD>
<EFBFBD>co <0C>6d<36>[<5B><><EFBFBD>!]_0t<30><74><EFBFBD>عP<D8B9> <0B>a<EFBFBD>65<18>G<EFBFBD><47><1B><><EFBFBD><EFBFBD><1C>k<EFBFBD>\RQ]<12>%<25><>Pzl<7A>r<><72><EFBFBD><17><><<15>7<>?x<>E<EFBFBD><45><1E><>riƮ{<7B><>>j<>.<2E><01><><01>0<EFBFBD><01>0 +<01>70# +<01>7*<2A>R<EFBFBD><64><C49A><EFBFBD><F5)<29><10>/<04>0U<14><>]^b]<5D><><EFBFBD><EFBFBD>e<EFBFBD>S5<19>r0\U U0S0Q +<01>7L<37>}0A0?+3http://www.microsoft.com/pkiops/Docs/Repository.htm0U% 0
+0 +<01>7 
SubCA0 U<01>0U<01>0<01>0U#0<16><14><><56><CB8F>\bh<62>=<3D><>[<5B>Κ<18>0VUO0M0K<30>I<EFBFBD>G<EFBFBD>Ehttp://crl.microsoft.com/pki/crl/products/MicRooCerAut_2010-06-23.crl0Z+N0L0J+0<02>>http://www.microsoft.com/pki/certs/MicRooCerAut_2010-06-23.crt0  *<2A>H<EFBFBD><48>  <03><00>U}<7D>*<2A><>,g1$[<5B><>rK<72><4B>o<EFBFBD>\<14>>NGdx<64><06><>=13<31>9<EFBFBD><39>q6?<3F>dl|<7C>u9m<39>1<><EFBFBD>lѡ<6C>"<22><>fg:SMݘ<4D><DD98>x<>6.<2E><><EFBFBD>V<03><05><><EFBFBD>i<EFBFBD><69> <09>{<7B>jo<6A>)<29>n<EFBFBD>?Hu<01><18>m<EFBFBD> <0C>m#T<>xSu$W<>ݟ<EFBFBD><DD9F>=<3D><>h<EFBFBD>e<EFBFBD><65>V<EFBFBD><56><EFBFBD><EFBFBD>(U'<27>$<24>@<40><><19>]='<27>@<40>8<EFBFBD><38><EFBFBD>)<29>ü<17>T<EFBFBD>B<EFBFBD><42> <0C><><19><><EFBFBD> j<>BRu<52>6<EFBFBD><1D>as.,k{n?, x<>[<5B>I<EFBFBD>t <0C><EFBFBD>=<3D>J>f;O<><4F><EFBFBD>2ٖ<><D996><EFBFBD><EFBFBD><01><><EFBFBD>t<EFBFBD><74>Lro<10>u0<75>4<EFBFBD>z<EFBFBD>P<EFBFBD>
X<EFBFBD>@<<3C>Tm<54>ctH,<2C>NG-<2D>q<>d<EFBFBD>$<24>smʎ <09><>WITd<54>s<EFBFBD>[D<01>Z<19>k <0A><>(<28>g($<24>8K<38>n<EFBFBD>!TkjEG<><47><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>^O<><4F><EFBFBD>Lv<4C>WT <09>iD~|<7C>als<6C>
<EFBFBD><EFBFBD>Af=i<><69><EFBFBD>AI~~<7E><><EFBFBD><EFBFBD>;<3B><><15><><EFBFBD>><3E>1Q<31><51><EFBFBD><02><><EFBFBD>{<15><>p<EFBFBD><70><EFBFBD><EFBFBD>(<1A> <0B>6ںL<DABA><4C><EFBFBD>
<EFBFBD>4<EFBFBD>$5g+<2B> <0A><EFBFBD><E68C99>"<22><>'B=%<25><>tt[jў><3E>~<7E>13}<7D><><EFBFBD>{<7B>8pDѐ<44>ȫ:<3A>:b<62>pcSM<53><4D><EFBFBD>m<EFBFBD><10>qj<10>U3X<33><58>pf<70><66><EFBFBD>M0<4D>50<><30><EFBFBD><EFBFBD>Ѥ<EFBFBD><D1A4>0<EFBFBD><30>1 0 UUS10U
Washington10URedmond10U
Microsoft Corporation1%0#U Microsoft America Operations1'0%U nShield TSS ESN:8603-05E0-D9471%0#UMicrosoft Time-Stamp Service<63>#
0+<00><><EFBFBD>d<EFBFBD> <0C><><EFBFBD><EFBFBD>/<2F><>Q<><51><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>0<EFBFBD><30><EFBFBD>~0|1 0 UUS10U
Washington10URedmond10U
Microsoft Corporation1&0$UMicrosoft Time-Stamp PCA 20100  *<2A>H<EFBFBD><48>  <00>-0"20240611015514Z20240612015514Z0t0:
+<01>Y
1,0*0
<00>-0 <0A>0<12>0
<00>~<7E>06
+<01>Y
1(0&0 
+<01>Y
<02>
0<07> <20>
0<01><>0  *<2A>H<EFBFBD><48>  <03>f<><66>+H$<24><00><><EFBFBD><EFBFBD>_<EFBFBD><5F>p<EFBFBD>b<><62><13><><EFBFBD><EFBFBD>L<EFBFBD><4C><1E><>f<>^D<><44>!R<>8<EFBFBD><38><EFBFBD><EFBFBD>P<>ΓcM<63>{<11><17><>6?E<>2[. +<2B>ʒ<EFBFBD><CA92><EFBFBD>4<><34><EFBFBD>bt<62><74><EFBFBD>mO<16>L<>p<EFBFBD>k<6B><1F>5<EFBFBD>><3E><>db<64><11>%@E<>dkf<6B> <0B><1D><>my<6D>}<7D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Rf<52><66>}<7D>mnGế<47><E1BABF>"<22><><07>c<EFBFBD>
T<1C>y<><79>wHf<48><66>0<EFBFBD>Z<EFBFBD>H@<40><05>j+<2B><>~<7E>//<15>#{<7B><16><>G<EFBFBD><47>9<EFBFBD><39><EFBFBD>q<EFBFBD><71><EFBFBD>?p<><70>٧"<22>齁h<E9BD81><0F>֥<EFBFBD>PK<>A<1A><><EFBFBD><EFBFBD> <0B><07><>EV<45><56><EFBFBD><EFBFBD>x1<78> 0<> 0<><30>0|1 0 UUS10U
Washington10URedmond10U
Microsoft Corporation1&0$UMicrosoft Time-Stamp PCA 20103<01><>E<EFBFBD>'<27><><16><01>0  `<60>He<00><>J0 *<2A>H<EFBFBD><48>  1  *<2A>H<EFBFBD><48>  0/ *<2A>H<EFBFBD><48>  1" *<2A><>֦<EFBFBD><D6A6>_<EFBFBD><5F>n<18><><EFBFBD><EFBFBD><15>6U<36>,<2C>K<EFBFBD><4B><ߪ$<24>0<EFBFBD><30> *<2A>H<EFBFBD><48>  /1<><31>0<EFBFBD><30>0<EFBFBD><30>0<EFBFBD><30> <20>w<EFBFBD>>aK<61><4B><EFBFBD><EFBFBD>8<EFBFBD><38>h<EFBFBD><1E><>H<EFBFBD><48>F<EFBFBD>?<3F>*##<23>x0<78><30>0<EFBFBD><30><EFBFBD>~0|1 0 UUS10U
Washington10URedmond10U
Microsoft Corporation1&0$UMicrosoft Time-Stamp PCA 20103<01><>E<EFBFBD>'<27><><16><01>0" -<2D>>><3E>LGx<47>`@Q<13><><EFBFBD>Uڵg<DAB5>eO<65><4F>K<><4B>0  *<2A>H<EFBFBD><48>  <04><00>ԤD <0B><19>e<1F>5<EFBFBD>}<7D><08><12><><EFBFBD>O{A߉c0<63><30>!%<><7F><EFBFBD><EFBFBD>b<EFBFBD><62>%<25><> K<>S<EFBFBD><53>)S<><02>[<5B><><16><1D><><EFBFBD><EFBFBD><><06>U<EFBFBD><55>?y'<27><>@<40>v<14>><3E>5<35>h<EFBFBD>O\S<><53><EFBFBD><EFBFBD><<3C>j<><6A><05>\<06><>d<03>\#.<2E>t=<3D>I|<7C>6]<5D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>8w+<2B>aGOe<4F>F9<46>(<28>bP]<5D><1A><><EFBFBD>LbB5|<7C>Gaʼn|օ<><D685><EFBFBD>V<><56>@<00><>:{<7B> <0A>\<1C>Aor{x<14><><EFBFBD><EFBFBD><1D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><7F><EFBFBD><EFBFBD>d\<5C>n<EFBFBD>G<EFBFBD>M<EFBFBD><4D><EFBFBD>m:<3A>CO77<37>J<>a<EFBFBD>2 <20>к6<D0BA>z k<><6B>u *!<21><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>q<>y<EFBFBD>=<3D><16>
<1D><><EFBFBD>b
D<EFBFBD><EFBFBD>@<40><><EFBFBD><EFBFBD>z)ɎR.<2E>7<EFBFBD>0grl<><6C>¾<EFBFBD>wY8]T<><54><EFBFBD>e<EFBFBD>_o<5F> +<2B><EFBFBD><7F>|<7C>4@<40>L<EFBFBD>ٓPSI31<33>/<2F>><3E>=L`o<><6F>F<EFBFBD>T<EFBFBD><54>o<EFBFBD>G<EFBFBD>z<EFBFBD>11<31><03>MO<4D><4F>9qj<71><6A>/<2F>ZMГSa<>5|<7C><>Z<EFBFBD><5A><EFBFBD><EFBFBD><1E><><EFBFBD>a<7F>e<><04>!AϪ<06>aZJ<5A>۝<EFBFBD><DB9D><EFBFBD>&`<60>[Gfx<66><78><EFBFBD><EFBFBD> 6+7<><1F><00>w<EFBFBD>w<EFBFBD><77>w<EFBFBD>m@<40>Q<EFBFBD><51>B<EFBFBD><42><EFBFBD>3<EFBFBD>us<75><73><EFBFBD><1A><04><19><>faBb<42>[<5B>K<EFBFBD>7<EFBFBD><37><EFBFBD><EFBFBD><1F><><EFBFBD><EFBFBD><EFBFBD>wN<17><>1<EFBFBD>