From 266797015de2ada69bc794bc7d7a750c1c8e2135 Mon Sep 17 00:00:00 2001 From: Jeyaram Jeyaraj Date: Tue, 30 May 2017 16:36:40 -0700 Subject: [PATCH] Implement of RTObjCInterop to be consumed via built packages and open source the code. - Fixing various issues with packaging - Open sourcing the code - This removed the old way of copying binaries around, from now one we will generate it directly from the source code. Fixes #2737, #2746 --- RTObjCInterop/RTObjCInterop.sln | 46 ++ .../RTObjCInterop/RTObjCInterop.vcxproj | 218 ++++++ .../RTObjCInterop.vcxproj.filters | 38 ++ RTObjCInterop/RTObjCInterop/dllmain.cpp | 27 + RTObjCInterop/RTObjCInterop/export.def | 52 ++ .../RTObjCInterop/src/InteropBase.mm | 81 +++ .../RTObjCInterop/src/ObjCHelpers.mm | 495 ++++++++++++++ RTObjCInterop/RTObjCInterop/src/RTHelpers.mm | 631 ++++++++++++++++++ RTObjCInterop/RTObjCInterop/src/RTObject.mm | 55 ++ .../WinObjC.Frameworks.UWP.Core/Readme.txt | 0 ...ObjC.Frameworks.UWP.Core.Packageable.props | 18 + ...jC.Frameworks.UWP.Core.Packageable.targets | 26 + ...inObjC.Frameworks.UWP.Core.Packaging.props | 22 + ...ObjC.Frameworks.UWP.Core.Packaging.targets | 3 + .../WinObjC.Frameworks.UWP.Core.nuproj | 29 +- ...inObjC.Frameworks.UWP.Core.Packaging.props | 22 - ...ObjC.Frameworks.UWP.Core.Packaging.targets | 35 - .../WinObjC.Frameworks.UWP.Core.props | 3 - .../WinObjC.Frameworks.UWP.Core.targets | 41 -- build/build.sln | 15 - 20 files changed, 1724 insertions(+), 133 deletions(-) create mode 100644 RTObjCInterop/RTObjCInterop.sln create mode 100644 RTObjCInterop/RTObjCInterop/RTObjCInterop.vcxproj create mode 100644 RTObjCInterop/RTObjCInterop/RTObjCInterop.vcxproj.filters create mode 100644 RTObjCInterop/RTObjCInterop/dllmain.cpp create mode 100644 RTObjCInterop/RTObjCInterop/export.def create mode 100644 RTObjCInterop/RTObjCInterop/src/InteropBase.mm create mode 100644 RTObjCInterop/RTObjCInterop/src/ObjCHelpers.mm create mode 100644 RTObjCInterop/RTObjCInterop/src/RTHelpers.mm create mode 100644 RTObjCInterop/RTObjCInterop/src/RTObject.mm rename {build => RTObjCInterop}/WinObjC.Frameworks.UWP.Core/Readme.txt (100%) create mode 100644 RTObjCInterop/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.Packageable.props create mode 100644 RTObjCInterop/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.Packageable.targets create mode 100644 RTObjCInterop/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.Packaging.props create mode 100644 RTObjCInterop/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.Packaging.targets rename {build => RTObjCInterop}/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.nuproj (65%) delete mode 100644 build/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.Packaging.props delete mode 100644 build/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.Packaging.targets delete mode 100644 build/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.props delete mode 100644 build/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.targets diff --git a/RTObjCInterop/RTObjCInterop.sln b/RTObjCInterop/RTObjCInterop.sln new file mode 100644 index 0000000000..31dff4dacb --- /dev/null +++ b/RTObjCInterop/RTObjCInterop.sln @@ -0,0 +1,46 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26117.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RTObjCInterop", "RTObjCInterop\RTObjCInterop.vcxproj", "{E332B155-82FE-4038-9D20-968F8F97AC3E}" +EndProject +Project("{5DD5E4FA-CB73-4610-85AB-557B54E96AA9}") = "WinObjC.Frameworks.UWP.Core", "WinObjC.Frameworks.UWP.Core\WinObjC.Frameworks.UWP.Core.nuproj", "{D9206FF8-86EF-477F-A022-AB3969D55876}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|ARM = Debug|ARM + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|ARM = Release|ARM + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E332B155-82FE-4038-9D20-968F8F97AC3E}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {E332B155-82FE-4038-9D20-968F8F97AC3E}.Debug|ARM.ActiveCfg = Debug|ARM + {E332B155-82FE-4038-9D20-968F8F97AC3E}.Debug|ARM.Build.0 = Debug|ARM + {E332B155-82FE-4038-9D20-968F8F97AC3E}.Debug|x86.ActiveCfg = Debug|Win32 + {E332B155-82FE-4038-9D20-968F8F97AC3E}.Debug|x86.Build.0 = Debug|Win32 + {E332B155-82FE-4038-9D20-968F8F97AC3E}.Release|Any CPU.ActiveCfg = Release|Win32 + {E332B155-82FE-4038-9D20-968F8F97AC3E}.Release|ARM.ActiveCfg = Release|ARM + {E332B155-82FE-4038-9D20-968F8F97AC3E}.Release|ARM.Build.0 = Release|ARM + {E332B155-82FE-4038-9D20-968F8F97AC3E}.Release|x86.ActiveCfg = Release|Win32 + {E332B155-82FE-4038-9D20-968F8F97AC3E}.Release|x86.Build.0 = Release|Win32 + {D9206FF8-86EF-477F-A022-AB3969D55876}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D9206FF8-86EF-477F-A022-AB3969D55876}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D9206FF8-86EF-477F-A022-AB3969D55876}.Debug|ARM.ActiveCfg = Debug|ARM + {D9206FF8-86EF-477F-A022-AB3969D55876}.Debug|ARM.Build.0 = Debug|ARM + {D9206FF8-86EF-477F-A022-AB3969D55876}.Debug|x86.ActiveCfg = Debug|x86 + {D9206FF8-86EF-477F-A022-AB3969D55876}.Debug|x86.Build.0 = Debug|x86 + {D9206FF8-86EF-477F-A022-AB3969D55876}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D9206FF8-86EF-477F-A022-AB3969D55876}.Release|Any CPU.Build.0 = Release|Any CPU + {D9206FF8-86EF-477F-A022-AB3969D55876}.Release|ARM.ActiveCfg = Release|ARM + {D9206FF8-86EF-477F-A022-AB3969D55876}.Release|ARM.Build.0 = Release|ARM + {D9206FF8-86EF-477F-A022-AB3969D55876}.Release|x86.ActiveCfg = Release|x86 + {D9206FF8-86EF-477F-A022-AB3969D55876}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/RTObjCInterop/RTObjCInterop/RTObjCInterop.vcxproj b/RTObjCInterop/RTObjCInterop/RTObjCInterop.vcxproj new file mode 100644 index 0000000000..44c9dc95df --- /dev/null +++ b/RTObjCInterop/RTObjCInterop/RTObjCInterop.vcxproj @@ -0,0 +1,218 @@ + + + + + Debug + ARM + + + Debug + Win32 + + + Release + ARM + + + Release + Win32 + + + + {e332b155-82fe-4038-9d20-968f8f97ac3e} + DynamicLibrary + RTObjCInterop + en-US + 14.0 + true + uap10.0 + Windows Store + 10.0.14393.0 + 10.0.10586.0 + 10.0 + Universal Windows + true + + + + DynamicLibrary + true + v141 + + + DynamicLibrary + true + v141 + + + DynamicLibrary + false + true + v141 + + + DynamicLibrary + false + true + v141 + + + + + + + + + + + + + + + + + + + + + + + false + false + true + + + false + false + true + + + false + false + true + + + false + false + true + + + + NotUsing + false + + + Console + false + false + export.def + + + -Wno-microsoft -Wno-extern-initializer -Wno-ignored-attributes -DWINAPI_FAMILY=WINAPI_FAMILY_APP -DOBJCWINRT_EXPORT=__declspec(dllexport) -ffunction-sections -fdata-sections -d2bigobj + + + $(WINOBJC_SDK_ROOT)\include;$(WINOBJC_SDK_ROOT)\include\Platform\$(TargetOsAndVersion)\;$(WINOBJC_SDK_ROOT)\Frameworks\include;$(WINOBJC_SDK_ROOT)\include\xplat;%(IncludePaths) + + + + MultiThreadedDebugDLL + DEBUG=1 + + + + + NotUsing + false + MultiThreadedDebugDLL + + + Console + false + false + export.def + + + -Wno-microsoft -Wno-extern-initializer -Wno-ignored-attributes -DWINAPI_FAMILY=WINAPI_FAMILY_APP -DOBJCWINRT_EXPORT=__declspec(dllexport) -ffunction-sections -fdata-sections -d2bigobj + + + $(WINOBJC_SDK_ROOT)\include;$(WINOBJC_SDK_ROOT)\include\Platform\$(TargetOsAndVersion)\;$(WINOBJC_SDK_ROOT)\Frameworks\include;$(WINOBJC_SDK_ROOT)\include\xplat;%(IncludePaths) + + Full + true + + + + + + + NotUsing + false + + + Console + false + false + export.def + + + -Wno-microsoft -Wno-extern-initializer -Wno-ignored-attributes -DWINAPI_FAMILY=WINAPI_FAMILY_APP -DOBJCWINRT_EXPORT=__declspec(dllexport) -ffunction-sections -fdata-sections -d2bigobj + + + $(WINOBJC_SDK_ROOT)\include;$(WINOBJC_SDK_ROOT)\include\Platform\$(TargetOsAndVersion)\;$(WINOBJC_SDK_ROOT)\Frameworks\include;$(WINOBJC_SDK_ROOT)\include\xplat;%(IncludePaths) + + + + MultiThreadedDebugDLL + DEBUG=1 + + + + + NotUsing + false + + + Console + false + false + export.def + + + -Wno-microsoft -Wno-extern-initializer -Wno-ignored-attributes -DWINAPI_FAMILY=WINAPI_FAMILY_APP -DOBJCWINRT_EXPORT=__declspec(dllexport) -ffunction-sections -fdata-sections -d2bigobj + + + $(WINOBJC_SDK_ROOT)\include;$(WINOBJC_SDK_ROOT)\include\Platform\$(TargetOsAndVersion)\;$(WINOBJC_SDK_ROOT)\Frameworks\include;$(WINOBJC_SDK_ROOT)\include\xplat;%(IncludePaths) + + Full + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/RTObjCInterop/RTObjCInterop/RTObjCInterop.vcxproj.filters b/RTObjCInterop/RTObjCInterop/RTObjCInterop.vcxproj.filters new file mode 100644 index 0000000000..7f9a07fc56 --- /dev/null +++ b/RTObjCInterop/RTObjCInterop/RTObjCInterop.vcxproj.filters @@ -0,0 +1,38 @@ + + + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/RTObjCInterop/RTObjCInterop/dllmain.cpp b/RTObjCInterop/RTObjCInterop/dllmain.cpp new file mode 100644 index 0000000000..1f8de0965f --- /dev/null +++ b/RTObjCInterop/RTObjCInterop/dllmain.cpp @@ -0,0 +1,27 @@ +//****************************************************************************** +// +// Copyright (c) Microsoft. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#include + +BOOL APIENTRY DllMain(HMODULE hDLL, DWORD ul_reason_for_call, LPVOID /* lpReserved */) { + switch (ul_reason_for_call) { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hDLL); + break; + } + + return TRUE; +} diff --git a/RTObjCInterop/RTObjCInterop/export.def b/RTObjCInterop/RTObjCInterop/export.def new file mode 100644 index 0000000000..3366c0134e --- /dev/null +++ b/RTObjCInterop/RTObjCInterop/export.def @@ -0,0 +1,52 @@ +LIBRARY RTObjCInterop + EXPORTS + rt_dynamic_cast + fastEnumArrayImpl + fastEnumIteratorImpl + SizeByEnumeration + getPropertyValueArrayInfo + convertNSDictionaryToPropertySet + convertNSErrorToPropertySet + convertPropertySetToNSDictionary + propertyValueCreator + convertNSDateToWinRT + convertWinRTToNSDate + convertNSURLToWinRTStorageFile + convertNSURLToWinRTUri + convertWinRTStorageFileToNSURL + convertWinRTUriToNSURL + convertNSNumberToPropertyValue + convertNSStringToPropertyValue + _OBJC_CLASS_RTObject DATA + __objc_class_name_RTObject CONSTANT + _OBJC_CLASS_WFGUID DATA + __objc_class_name_WFGUID CONSTANT + _OBJC_CLASS_RTKeyValuePair DATA + __objc_class_name_RTKeyValuePair CONSTANT + _OBJC_CLASS_ListenerMgr DATA + __objc_class_name_ListenerMgr CONSTANT + _OBJC_CLASS_RTProxiedNSArray DATA + __objc_class_name_RTProxiedNSArray CONSTANT + _OBJC_CLASS_RTProxiedNSArrayFull DATA + __objc_class_name_RTProxiedNSArrayFull CONSTANT + _OBJC_CLASS_RTProxiedNSMutableArray DATA + __objc_class_name_RTProxiedNSMutableArray CONSTANT + _OBJC_CLASS_RTProxiedNSMutableArrayFull DATA + __objc_class_name_RTProxiedNSMutableArrayFull CONSTANT + _OBJC_CLASS_RTProxiedIterableNSArray DATA + __objc_class_name_RTProxiedIterableNSArray CONSTANT + _OBJC_CLASS_RTProxiedIterableNSArrayFull DATA + __objc_class_name_RTProxiedIterableNSArrayFull CONSTANT + _OBJC_CLASS_RTProxiedNSDictionaryKeyEnumerator DATA + __objc_class_name_RTProxiedNSDictionaryKeyEnumerator CONSTANT + _OBJC_CLASS_RTProxiedNSDictionary DATA + __objc_class_name_RTProxiedNSDictionary CONSTANT + _OBJC_CLASS_RTProxiedNSMutableDictionary DATA + __objc_class_name_RTProxiedNSMutableDictionary CONSTANT + _OBJC_CLASS_RTProxiedKeyValuePair DATA + __objc_class_name_RTProxiedKeyValuePair CONSTANT + _OBJC_CLASS_RTProxiedObservableNSMutableArray DATA + __objc_class_name_RTProxiedObservableNSMutableArray CONSTANT + _OBJC_CLASS_RTProxiedObservableNSMutableDictionary DATA + __objc_class_name_RTProxiedObservableNSMutableDictionary CONSTANT + diff --git a/RTObjCInterop/RTObjCInterop/src/InteropBase.mm b/RTObjCInterop/RTObjCInterop/src/InteropBase.mm new file mode 100644 index 0000000000..64f4f0c1f5 --- /dev/null +++ b/RTObjCInterop/RTObjCInterop/src/InteropBase.mm @@ -0,0 +1,81 @@ +//****************************************************************************** +// +// Copyright (c) Microsoft. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#include +#import + +// TODO[5668270] This could use NSUUID, which is backed by a GUID already. +@implementation WFGUID { + GUID _guid; +} + +- (unsigned long)Data1 { + return _guid.Data1; +} + +- (unsigned short)Data2 { + return _guid.Data2; +} + +- (unsigned short)Data3 { + return _guid.Data3; +} + +- (unsigned char*)Data4 { + return _guid.Data4; +} + +- (void)setData1:(unsigned long)val { + _guid.Data1 = val; +} + +- (void)setData2:(unsigned short)val { + _guid.Data2 = val; +} + +- (void)setData3:(unsigned short)val { + _guid.Data3 = val; +} + ++ (instancetype)guidWithGUID:(const GUID)guid { + WFGUID* ret = [WFGUID alloc]; + [[ret initWithGUID:guid] autorelease]; + return ret; +} + +- initWithGUID:(const GUID)guid { + _guid = guid; + return self; +} + +- (GUID)guidValue { + return _guid; +} + +@end + +@implementation RTKeyValuePair { +} + +- (id)key { + return nil; +} + +- (id)value { + return nil; +} + +@end diff --git a/RTObjCInterop/RTObjCInterop/src/ObjCHelpers.mm b/RTObjCInterop/RTObjCInterop/src/ObjCHelpers.mm new file mode 100644 index 0000000000..dca903af18 --- /dev/null +++ b/RTObjCInterop/RTObjCInterop/src/ObjCHelpers.mm @@ -0,0 +1,495 @@ +//****************************************************************************** +// +// Copyright (c) Microsoft. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#import +#import +#import + +namespace CommonConvertors { +Microsoft::WRL::ComPtr _convertNSArrayToPropertyValue(id obj); +Microsoft::WRL::ComPtr _convertToPropertyValueType(id item); +id _convertInspectableArrayToNSArray(Microsoft::WRL::ComPtr ip); +id _convertIntArrayToNSArray(Microsoft::WRL::ComPtr ip); +id _convertUIntArrayToNSArray(Microsoft::WRL::ComPtr ip); +id _convertSingleArrayToNSArray(Microsoft::WRL::ComPtr ip); +id _convertDoubleArrayToNSArray(Microsoft::WRL::ComPtr ip); +id _convertStringArrayToNSArray(Microsoft::WRL::ComPtr ip); +id _convertMapToNSDictionary(Microsoft::WRL::ComPtr ip); +id _convertPropertyValueToObjC(Microsoft::WRL::ComPtr obj); + +ComPtr propertyValueCreator() { + ComPtr propValueCreator; + THROW_NS_IF_FAILED(ABI::Windows::Foundation::GetActivationFactory(HString::MakeReference(L"Windows.Foundation.PropertyValue").Get(), + &propValueCreator)); + return propValueCreator; +} + +ComPtr _convertToPropertyValueType(id item) { + if (item == nil) { + return nullptr; + } + ComPtr propValueCreator = propertyValueCreator(); + ComPtr propValue; + if ([item isKindOfClass:[NSString class]]) { + HSTRING hstr = ToWRLConvertor::convert(item); + THROW_NS_IF_FAILED(propValueCreator->CreateString(hstr, propValue.GetAddressOf())); + WindowsDeleteString(hstr); + } else if ([item isKindOfClass:[NSArray class]]) { + propValue = _convertNSArrayToPropertyValue(item); + } else if ([item isKindOfClass:[NSDictionary class]]) { + propValue = convertNSDictionaryToPropertySet(item); + } else if ([item isKindOfClass:[NSNumber class]]) { + const char* type = [item objCType]; + if (strstr("cilsq", type) != NULL) { + THROW_NS_IF_FAILED( + propValueCreator->CreateInt64(ToWRLConvertor::convert(item), propValue.GetAddressOf())); + } else if (strstr("CILSQ", type) != NULL) { + THROW_NS_IF_FAILED( + propValueCreator->CreateUInt64(ToWRLConvertor::convert(item), propValue.GetAddressOf())); + } else if (strcmp("f", type) == 0) { + THROW_NS_IF_FAILED( + propValueCreator->CreateSingle(ToWRLConvertor::convert(item), propValue.GetAddressOf())); + } else if (strcmp("d", type) == 0) { + THROW_NS_IF_FAILED( + propValueCreator->CreateDouble(ToWRLConvertor::convert(item), propValue.GetAddressOf())); + } + } + return propValue; +} + +ComPtr _convertNSArrayToPropertyValue(id obj) { + if (obj == nil) { + return nullptr; + } + ComPtr propValueCreator = propertyValueCreator(); + // This array will maintain the lifetime of the ComPtrs till the function exits. + std::vector> arr; + std::vector arrIInspectable; + for (id item in obj) { + ComPtr comObj = _convertToPropertyValueType(item); + arr.push_back(comObj.Get()); + arrIInspectable.push_back(comObj.Detach()); + } + ComPtr returnObj; + if (arrIInspectable.size()) { + THROW_NS_IF_FAILED( + propValueCreator->CreateInspectableArray(arrIInspectable.size(), arrIInspectable.data(), returnObj.GetAddressOf())); + } + return returnObj; +} + +ComPtr convertNSDictionaryToPropertySet(id obj) { + if (obj == nil) { + return nullptr; + } + ComPtr propertySet; + Windows::Foundation::ActivateInstance(HString::MakeReference(L"Windows.Foundation.Collections.PropertySet").Get(), &propertySet); + ComPtr> _map; + ComPtr> _mapView; + THROW_NS_IF_FAILED(propertySet.As(&_map)); + boolean replaced; + for (id key in obj) { + if ([key isKindOfClass:[NSString class]]) { + id value = obj[key]; + ComPtr propValue = _convertToPropertyValueType(value); + _map->Insert(nsStrToHstr(key).Get(), propValue.Get(), &replaced); + } + } + THROW_NS_IF_FAILED(_map->GetView(_mapView.GetAddressOf())); + return _mapView; +} + +ComPtr convertNSErrorToPropertySet(id obj) { + if (obj == nil) { + return nullptr; + } + ComPtr propertySet; + Windows::Foundation::ActivateInstance(HString::MakeReference(L"Windows.Foundation.Collections.PropertySet").Get(), &propertySet); + ComPtr> _map; + ComPtr> _mapView; + THROW_NS_IF_FAILED(propertySet.As(&_map)); + ComPtr propValue = _convertToPropertyValueType([NSNumber numberWithLongLong:(int64_t)[obj code]]); + NSString* code = @"code"; + boolean replaced; + _map->Insert(nsStrToHstr(code).Get(), propValue.Get(), &replaced); + id userInfo = [obj userInfo]; + for (id key in userInfo) { + if ([key isKindOfClass:[NSString class]]) { + id value = userInfo[key]; + propValue = _convertToPropertyValueType(value); + _map->Insert(nsStrToHstr(key).Get(), propValue.Get(), &replaced); + } + } + THROW_NS_IF_FAILED(_map->GetView(_mapView.GetAddressOf())); + return _mapView; +} + +id _convertMapToNSDictionary(ComPtr ip) { + if (ip == nullptr) { + return nil; + } + id value; + ComPtr> _map; + ComPtr> _mapView; + if (SUCCEEDED(ip.As(&_map))) { + THROW_NS_IF_FAILED(_map->GetView(_mapView.GetAddressOf())); + value = convertPropertySetToNSDictionary(_mapView); + } else if (SUCCEEDED(ip.As(&_mapView))) { + value = convertPropertySetToNSDictionary(_mapView); + } else { + THROW_NS_HR(E_NOINTERFACE); + } + return value; +} + +id _convertPropertyValueToObjC(ComPtr obj) { + if (obj == nullptr) { + return nil; + } + PropertyType type; + THROW_NS_IF_FAILED(obj->get_Type(&type)); + id value; + switch (type) { + case PropertyType_Inspectable: { + value = _convertMapToNSDictionary(obj); + break; + } + case PropertyType_InspectableArray: { + value = _convertInspectableArrayToNSArray(obj); + break; + } + case PropertyType_Int64Array: + case PropertyType_Int32Array: + case PropertyType_Int16Array: + case PropertyType_Char16Array: + case PropertyType_BooleanArray: { + value = _convertIntArrayToNSArray(obj); + break; + } + case PropertyType_UInt64Array: + case PropertyType_UInt32Array: + case PropertyType_UInt16Array: + case PropertyType_UInt8Array: { + value = _convertUIntArrayToNSArray(obj); + break; + } + case PropertyType_SingleArray: { + value = _convertSingleArrayToNSArray(obj); + ; + break; + } + case PropertyType_DoubleArray: { + value = _convertDoubleArrayToNSArray(obj); + break; + } + case PropertyType_StringArray: { + value = _convertStringArrayToNSArray(obj); + break; + } + case PropertyType_String: { + HSTRING val; + THROW_NS_IF_FAILED(obj->GetString(&val)); + value = hstrToNSStr(val, true); + break; + } + case PropertyType_Single: { + FLOAT val; + THROW_NS_IF_FAILED(obj->GetSingle(&val)); + value = ToObjcConvertor::convert(val); + break; + } + case PropertyType_Double: { + double val; + THROW_NS_IF_FAILED(obj->GetDouble(&val)); + value = ToObjcConvertor::convert(val); + break; + } + case PropertyType_Int64: + case PropertyType_Int32: + case PropertyType_Int16: + case PropertyType_Char16: + case PropertyType_Boolean: { + INT64 val; + THROW_NS_IF_FAILED(obj->GetInt64(&val)); + value = ToObjcConvertor::convert(val); + break; + } + case PropertyType_UInt64: + case PropertyType_UInt32: + case PropertyType_UInt16: + case PropertyType_UInt8: { + UINT64 val; + THROW_NS_IF_FAILED(obj->GetUInt64(&val)); + value = ToObjcConvertor::convert(val); + break; + } + default: + return nil; + } + return value; +} + +id _convertStringArrayToNSArray(ComPtr ip) { + UINT32 length; + HSTRING* arr; + if (ip == nullptr) { + return nil; + } + NSMutableArray* values = [[[NSMutableArray alloc] init] autorelease]; + THROW_NS_IF_FAILED(ip->GetStringArray(&length, &arr)); + for (UINT32 i = 0; i < length; i++) { + [values addObject:hstrToNSStr(arr[i], true)]; + } + NSArray* value = [NSArray arrayWithArray:values]; + CoTaskMemFree(arr); + return value; +} + +id _convertDoubleArrayToNSArray(ComPtr ip) { + UINT32 length; + DOUBLE* arr; + if (ip == nullptr) { + return nil; + } + NSMutableArray* values = [[[NSMutableArray alloc] init] autorelease]; + THROW_NS_IF_FAILED(ip->GetDoubleArray(&length, &arr)); + for (UINT32 i = 0; i < length; i++) { + [values addObject:[NSNumber numberWithDouble:arr[i]]]; + } + NSArray* value = [NSArray arrayWithArray:values]; + CoTaskMemFree(arr); + return value; +} + +id _convertSingleArrayToNSArray(ComPtr ip) { + UINT32 length; + FLOAT* arr; + if (ip == nullptr) { + return nil; + } + NSMutableArray* values = [[[NSMutableArray alloc] init] autorelease]; + THROW_NS_IF_FAILED(ip->GetSingleArray(&length, &arr)); + for (UINT32 i = 0; i < length; i++) { + [values addObject:[NSNumber numberWithFloat:arr[i]]]; + } + NSArray* value = [NSArray arrayWithArray:values]; + CoTaskMemFree(arr); + return value; +} + +id _convertUIntArrayToNSArray(ComPtr ip) { + UINT32 length; + UINT64* arr; + if (ip == nullptr) { + return nil; + } + NSMutableArray* values = [[[NSMutableArray alloc] init] autorelease]; + THROW_NS_IF_FAILED(ip->GetUInt64Array(&length, &arr)); + for (UINT32 i = 0; i < length; i++) { + [values addObject:[NSNumber numberWithUnsignedLongLong:arr[i]]]; + } + NSArray* value = [NSArray arrayWithArray:values]; + CoTaskMemFree(arr); + return value; +} + +id _convertIntArrayToNSArray(ComPtr ip) { + UINT32 length; + INT64* arr; + if (ip == nullptr) { + return nil; + } + NSMutableArray* values = [[[NSMutableArray alloc] init] autorelease]; + THROW_NS_IF_FAILED(ip->GetInt64Array(&length, &arr)); + for (UINT32 i = 0; i < length; i++) { + [values addObject:[NSNumber numberWithLongLong:arr[i]]]; + } + NSArray* value = [NSArray arrayWithArray:values]; + CoTaskMemFree(arr); + return value; +} + +id _convertInspectableArrayToNSArray(ComPtr ip) { + UINT32 length; + IInspectable** arr; + if (ip == nullptr) { + return nil; + } + NSMutableArray* values = [[[NSMutableArray alloc] init] autorelease]; + THROW_NS_IF_FAILED(ip->GetInspectableArray(&length, &arr)); + for (UINT32 i = 0; i < length; i++) { + ComPtr com = arr[i]; + ComPtr propValue; + THROW_NS_IF_FAILED(com.As(&propValue)); + [values addObject:_convertPropertyValueToObjC(propValue)]; + } + NSArray* value = [NSArray arrayWithArray:values]; + CoTaskMemFree(arr); + return value; +} + +id convertPropertySetToNSDictionary(ComPtr> ip) { + ComPtr*>> iterable; + ComPtr*>> iterator; + if (ip == nullptr) { + return nil; + } + THROW_NS_IF_FAILED(ip.As(&iterable)); + THROW_NS_IF_FAILED(iterable->First(&iterator)); + boolean hasCurrent = false; + THROW_NS_IF_FAILED(iterator->get_HasCurrent(&hasCurrent)); + NSMutableDictionary* _dictionary = [[[NSMutableDictionary alloc] init] autorelease]; + while (hasCurrent) { + ComPtr> kvp; + THROW_NS_IF_FAILED(iterator->get_Current(&kvp)); + HSTRING keyHstr; + THROW_NS_IF_FAILED(kvp->get_Key(&keyHstr)); + NSString* key = hstrToNSStr(keyHstr, true); + id value; + ComPtr obj; + THROW_NS_IF_FAILED(kvp->get_Value(obj.GetAddressOf())); + ComPtr obj1; + ComPtr> obj2; + ComPtr> obj3; + if (SUCCEEDED(obj.As(&obj1))) { + value = _convertPropertyValueToObjC(obj1); + } else if (SUCCEEDED(obj.As(&obj2)) || SUCCEEDED(obj.As(&obj3))) { + value = _convertMapToNSDictionary(obj); + } else { + THROW_NS_HR(E_NOINTERFACE); + } + [_dictionary setObject:value forKey:key]; + THROW_NS_IF_FAILED(iterator->MoveNext(&hasCurrent)); + } + NSDictionary* _ret = [NSDictionary dictionaryWithDictionary:_dictionary]; + return _ret; +} + +ABI::Windows::Foundation::DateTime convertNSDateToWinRT(NSDate* obj) { + const int64_t hundredNanoSecondsFactor = 10000000; + // This constant is the summation of two 100 nanosecond ticks constants, first one (116444736000000000) is for + // converting Windows epoch (Jan 1 1601 00:00:00) to Unix epoch (Jan 1 1970 00:00:00) and + // the other (9783072000000000) is for converting from Unix epoch to NSDate's reference date (Jan 1 2001 00:00:00). + const int64_t hundredNanoSecondTicksFromWindowsEpochToNSDateReferenceDate = 126227808000000000; + // The time interval we get from NSDate is in seconds. We convert it to 100 nanoseconds ticks. + int64_t timeInterval = (int64_t)([obj timeIntervalSinceReferenceDate] * hundredNanoSecondsFactor); + timeInterval = timeInterval + hundredNanoSecondTicksFromWindowsEpochToNSDateReferenceDate; + ABI::Windows::Foundation::DateTime date; + date.UniversalTime = timeInterval; + return date; +} + +NSDate* convertWinRTToNSDate(ABI::Windows::Foundation::DateTime dt) { + const int64_t hundredNanoSecondsFactor = 10000000; + const int64_t hundredNanoSecondTicksFromWindowsEpochToNSDateReferenceDate = 126227808000000000; + // timeInterval is 100 nanosecond ticks from Jan 1 1601 00:00. + // Convert timeInterval to 100 nanosecond ticks from Jan 1 2001. + double timeInterval = dt.UniversalTime - hundredNanoSecondTicksFromWindowsEpochToNSDateReferenceDate; + // Convert 100 nanosecond ticks to seconds; + timeInterval = timeInterval / hundredNanoSecondsFactor; + NSDate* date = [NSDate dateWithTimeIntervalSinceReferenceDate:timeInterval]; + return date; +} + +ComPtr convertNSURLToWinRTStorageFile(NSURL* obj) { + return nullptr; +} + +ComPtr convertNSURLToWinRTUri(NSURL* obj) { + ComPtr uriFactory; + ComPtr comObj; + THROW_NS_IF_FAILED( + ABI::Windows::Foundation::GetActivationFactory(HString::MakeReference(L"Windows.Foundation.Uri").Get(), &uriFactory)); + THROW_NS_IF_FAILED(uriFactory->CreateUri(nsStrToHstr([obj absoluteString]).Get(), comObj.GetAddressOf())); + return comObj; +} + +NSURL* convertWinRTStorageFileToNSURL(const ComPtr storageFile) { + NSURL* n = [NSURL URLWithStorageFile:storageFile.Get()]; + return n; +} + +NSURL* convertWinRTUriToNSURL(const ComPtr uri) { + HSTRING hstr; + THROW_NS_IF_FAILED(uri->get_AbsoluteUri(&hstr)); + return [NSURL URLWithString:hstrToNSStr(hstr, true)]; +} + +ComPtr convertNSNumberToPropertyValue(NSNumber* obj) { + ComPtr inst; + THROW_NS_IF_FAILED( + ABI::Windows::Foundation::GetActivationFactory(HString::MakeReference(L"Windows.Foundation.PropertyValue").Get(), &inst)); + ComPtr ret; + const char* type = [obj objCType]; + if (strstr("cC", type) != NULL) { + THROW_NS_IF_FAILED(inst->CreateUInt8(ToWRLConvertor::convert(obj), ret.GetAddressOf())); + return ret; + } + + if (strstr("il", type) != NULL) { + THROW_NS_IF_FAILED(inst->CreateInt32(ToWRLConvertor::convert(obj), ret.GetAddressOf())); + return ret; + } + + if (strstr("s", type) != NULL) { + THROW_NS_IF_FAILED(inst->CreateInt16(ToWRLConvertor::convert(obj), ret.GetAddressOf())); + return ret; + } + + if (strstr("q", type) != NULL) { + THROW_NS_IF_FAILED(inst->CreateInt64(ToWRLConvertor::convert(obj), ret.GetAddressOf())); + return ret; + } + + if (strstr("IL", type) != NULL) { + THROW_NS_IF_FAILED(inst->CreateUInt32(ToWRLConvertor::convert(obj), ret.GetAddressOf())); + return ret; + } + + if (strstr("S", type) != NULL) { + THROW_NS_IF_FAILED(inst->CreateUInt16(ToWRLConvertor::convert(obj), ret.GetAddressOf())); + return ret; + } + + if (strstr("Q", type) != NULL) { + THROW_NS_IF_FAILED(inst->CreateUInt64(ToWRLConvertor::convert(obj), ret.GetAddressOf())); + return ret; + } + + if (strcmp("f", type) == 0) { + THROW_NS_IF_FAILED(inst->CreateSingle(ToWRLConvertor::convert(obj), ret.GetAddressOf())); + return ret; + } + + if (strcmp("d", type) == 0) { + THROW_NS_IF_FAILED(inst->CreateDouble(ToWRLConvertor::convert(obj), ret.GetAddressOf())); + return ret; + } + + return nullptr; +} + +ComPtr convertNSStringToPropertyValue(NSString* obj) { + ComPtr inst; + THROW_NS_IF_FAILED( + ABI::Windows::Foundation::GetActivationFactory(HString::MakeReference(L"Windows.Foundation.PropertyValue").Get(), &inst)); + ComPtr ret; + Microsoft::WRL::Wrappers::HString hstr; + hstr.Attach(ToWRLConvertor::convert(obj)); + THROW_NS_IF_FAILED(inst->CreateString(hstr.Get(), ret.GetAddressOf())); + return ret; +} +} // namespace CommonConvertors diff --git a/RTObjCInterop/RTObjCInterop/src/RTHelpers.mm b/RTObjCInterop/RTObjCInterop/src/RTHelpers.mm new file mode 100644 index 0000000000..830348fd7c --- /dev/null +++ b/RTObjCInterop/RTObjCInterop/src/RTHelpers.mm @@ -0,0 +1,631 @@ +//****************************************************************************** +// +// Copyright (c) Microsoft. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#import +#import +#import +#import + +using namespace Microsoft::WRL; + +NSUInteger fastEnumArrayImpl(id self, NSFastEnumerationState* state, id* buffer, NSUInteger len) { + NSUInteger count = 0; + NSUInteger first = state->state; + NSUInteger arrayLen = [self count]; + + if (first == 0) { + state->itemsPtr = buffer; + state->mutationsPtr = &state->extra[0]; + } + + while ((count < len) && ((first + count) < arrayLen)) { + buffer[count] = [self objectAtIndex:first + count]; + count++; + } + + state->state = first + count; + return count; +} + +NSUInteger fastEnumIteratorImpl(id self, NSFastEnumerationState* state, id* buffer, NSUInteger len) { + NSUInteger count = 0; + + if (state->state == 0) { + state->itemsPtr = buffer; + state->mutationsPtr = &state->extra[0]; + + state->state = 1; + buffer[count] = [self first]; + if (buffer[count] == nil) { + state->state = 2; + return 0; + } + count++; + } + + if (state->state == 1) { + while (count < len) { + buffer[count] = [self next]; + if (buffer[count] == nil) { + state->state = 2; + break; + } + count++; + } + } + + return count; +} + +UINT32 SizeByEnumeration(id obj) { + NSFastEnumerationState state = { 0 }; + UINT32 totalCount = 0; + id items[16] = { 0 }; + for (;;) { + int count = [obj countByEnumeratingWithState:&state objects:items count:ARRAY_COUNT(items)]; + if (!count) + break; + totalCount += (UINT32)count; + } + return totalCount; +} + +void getPropertyValueArrayInfo(ComPtr comPtr, unsigned int& res, void** resPtr) { + PropertyType type; + THROW_NS_IF_FAILED(comPtr->get_Type(&type)); + switch (type) { + case PropertyType_UInt8Array: + comPtr->GetUInt8Array(&res, (BYTE**)resPtr); + break; + case PropertyType_Int16Array: + comPtr->GetInt16Array(&res, (INT16**)resPtr); + break; + case PropertyType_UInt16Array: + comPtr->GetUInt16Array(&res, (UINT16**)resPtr); + break; + case PropertyType_Int32Array: + comPtr->GetInt32Array(&res, (INT32**)resPtr); + break; + case PropertyType_UInt32Array: + comPtr->GetUInt32Array(&res, (UINT32**)resPtr); + break; + case PropertyType_Int64Array: + comPtr->GetInt64Array(&res, (INT64**)resPtr); + break; + case PropertyType_UInt64Array: + comPtr->GetUInt64Array(&res, (UINT64**)resPtr); + break; + case PropertyType_SingleArray: + comPtr->GetSingleArray(&res, (FLOAT**)resPtr); + break; + case PropertyType_DoubleArray: + comPtr->GetDoubleArray(&res, (DOUBLE**)resPtr); + break; + case PropertyType_Char16Array: + comPtr->GetChar16Array(&res, (WCHAR**)resPtr); + break; + case PropertyType_BooleanArray: + comPtr->GetBooleanArray(&res, (BOOLEAN**)resPtr); + break; + case PropertyType_StringArray: + comPtr->GetStringArray(&res, (HSTRING**)resPtr); + break; + case PropertyType_InspectableArray: + comPtr->GetInspectableArray(&res, (IInspectable***)resPtr); + break; + + default: + THROW_NS_HR(E_NOTIMPL); + break; + } +} + +@implementation RTProxiedNSArray +- (ComPtr)getInternalComObj { + return adapter->getInternalComObj(); +} + +- (instancetype)initWithAdapter:(std::unique_ptr)arrayAdapter { + if (self = [super init]) { + adapter = std::move(arrayAdapter); + } + return self; +} + +- (NSUInteger)count { + return adapter->count(); +} + +- (id)objectAtIndex:(NSUInteger)index { + return adapter->objectAtIndex(index); +} + +- (BOOL)isCArray { + return adapter->isCArray(); +} + +- (void*)ptr { + return adapter->ptr(); +} +@end + +@implementation RTProxiedNSArrayFull +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState*)state objects:(id __unsafe_unretained[])buffer count:(NSUInteger)len { + return fastEnumArrayImpl(self, state, buffer, len); +} +@end + +@implementation RTProxiedNSMutableArray +- (ComPtr)getInternalComObj { + return adapter->getInternalComObj(); +} + +- (instancetype)initWithAdapter:(std::unique_ptr)arrayAdapter { + if (self = [super init]) { + adapter = std::move(arrayAdapter); + } + return self; +} + +- (NSUInteger)count { + return adapter->count(); +} + +- (id)objectAtIndex:(NSUInteger)index { + return adapter->objectAtIndex(index); +} + +- (BOOL)isCArray { + return adapter->isCArray(); +} + +- (void*)ptr { + return adapter->ptr(); +} + +- (void)insertObject:(id)obj atIndex:(NSUInteger)idx { + adapter->insertObjectAtIndex(obj, idx); +} + +- (void)removeObjectAtIndex:(NSUInteger)idx { + adapter->removeObjectAtIndex(idx); +} + +- (void)addObject:(id)anObject { + adapter->appendObject(anObject); +} + +- (void)removeLastObject { + [self removeObjectAtIndex:[self count] - 1]; +} + +- (void)replaceObjectAtIndex:(NSUInteger)idx withObject:(id)obj { + adapter->replaceObjectAtIndexWithObject(idx, obj); +} +@end + +@implementation RTProxiedObservableNSMutableArray { + StrongId _mgr; +} + +- (ComPtr)getInternalComObj { + return adapter->getInternalComObj(); +} + +- (instancetype)initWithAdapter:(std::unique_ptr)arrayAdapter { + if (self = [super init]) { + _mgr.attach([[ListenerMgr alloc] initWith:self]); + adapter = std::move(arrayAdapter); + } + return self; +} + +- (NSUInteger)count { + return adapter->count(); +} + +- (id)objectAtIndex:(NSUInteger)index { + return adapter->objectAtIndex(index); +} + +- (BOOL)isCArray { + return adapter->isCArray(); +} + +- (void*)ptr { + return adapter->ptr(); +} + +- (void)insertObject:(id)obj atIndex:(NSUInteger)idx { + adapter->insertObjectAtIndex(obj, idx); +} + +- (void)removeObjectAtIndex:(NSUInteger)idx { + adapter->removeObjectAtIndex(idx); +} + +- (void)addObject:(id)anObject { + adapter->appendObject(anObject); +} + +- (void)removeLastObject { + [self removeObjectAtIndex:[self count] - 1]; +} + +- (void)replaceObjectAtIndex:(NSUInteger)idx withObject:(id)obj { + adapter->replaceObjectAtIndexWithObject(idx, obj); +} + +- (void)registerSelf { + adapter->registerSelf(self); +} + +- (void)unregisterSelf { + adapter->unregisterSelf(); +} + +- (EventRegistrationToken)addObserver:(RTCollectionListener)receiver { + return [_mgr addObserver:receiver]; +} + +- (void)removeObserver:(EventRegistrationToken)receiverToken { + [_mgr removeObserver:receiverToken]; +} + +- (void)notify:(RTCollectionOperation)op at:(unsigned int)idx { + [_mgr notify:op value:[NSNumber numberWithUnsignedInt:idx]]; +} +@end + +@implementation RTProxiedObservableNSMutableDictionary { + StrongId _mgr; +} + +- (ComPtr)getInternalComObj { + return adapter->getInternalComObj(); +} + +- (instancetype)initWithAdapter:(std::unique_ptr)dictionaryAdapter { + if (self = [super init]) { + _mgr.attach([[ListenerMgr alloc] initWith:self]); + adapter = std::move(dictionaryAdapter); + } + return self; +} + +- (id)objectForKey:(id)key { + return adapter->objectForKey(key); +} + +- (id)keyEnumerator { + return adapter->keyEnumerator(); +} + +- (unsigned int)count { + return adapter->count(); +} + +- (NSArray*)allKeys { + return adapter->allKeys(); +} + +- (NSArray*)allKeysForObject:(id)obj { + return adapter->allKeysForObject(obj); +} + +- (NSArray*)allValues { + return adapter->allValues(); +} + +- (void)setObject:(id)obj forKey:(id)key { + adapter->setObject(obj, key); +} + +- (void)setObject:(id)obj forKeyedSubscript:(id)key { + adapter->setObject(obj, key); +} + +- (void)removeObjectForKey:(id)key { + adapter->removeObjectForKey(key); +} + +- (void)removeAllObjects { + adapter->removeAllObjects(); +} + +- (void)removeObjectsForKeys:(NSArray*)keys { + adapter->removeObjectsForKeys(keys); +} + +- (void)addEntriesFromDictionary:(NSDictionary*)otherDict { + adapter->addEntriesFromDictionary(otherDict); +} + +- (void)addEntriesFromDictionaryNoReplace:(NSDictionary*)otherDict { + adapter->addEntriesFromDictionaryNoReplace(otherDict); +} + +- (void)setDictionary:(NSDictionary*)otherDict { + adapter->setDictionary(otherDict); +} + +- (void)registerSelf { + adapter->registerSelf(self); +} + +- (void)unregisterSelf { + adapter->unregisterSelf(); +} + +- (EventRegistrationToken)addObserver:(RTCollectionListener)receiver { + return [_mgr addObserver:receiver]; +} + +- (void)removeObserver:(EventRegistrationToken)receiverToken { + [_mgr removeObserver:receiverToken]; +} + +- (void)notify:(RTCollectionOperation)op atKey:(id)key { + [_mgr notify:op value:key]; +} +@end + +@implementation RTProxiedNSMutableArrayFull +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState*)state objects:(id __unsafe_unretained[])buffer count:(NSUInteger)len { + return fastEnumArrayImpl(self, state, buffer, len); +} +@end + +@implementation RTProxiedIterableNSArray +- (ComPtr)getInternalComObj { + return adapter->getInternalComObj(); +} + +- (instancetype)initWithAdapter:(std::unique_ptr)arrayAdapter { + if (self = [super init]) { + adapter = std::move(arrayAdapter); + } + return self; +} + +- (NSUInteger)count { + return adapter->count(); +} + +- (id)objectAtIndex:(NSUInteger)index { + return adapter->objectAtIndex(index); +} + +- (BOOL)isCArray { + return adapter->isCArray(); +} + +- (void*)ptr { + return adapter->ptr(); +} + +- (id)first { + return adapter->first(); +} + +- (id)next { + return adapter->next(); +} +@end + +@implementation RTProxiedIterableNSArrayFull +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState*)state objects:(id __unsafe_unretained[])buffer count:(NSUInteger)len { + return fastEnumArrayImpl(self, state, buffer, len); +} +@end + +@implementation RTProxiedNSDictionaryKeyEnumerator +- (id)initWithMap:(IInspectable*)map adapter:(std::unique_ptr)enumeratorAdapter { + if (self = [super init]) { + adapter = std::move(enumeratorAdapter); + adapter->initWithMap(map); + } + + return self; +} + +- (id)nextObject { + return adapter->nextObject(); +} +@end + +@implementation RTProxiedNSDictionary +- (ComPtr)getInternalComObj { + return adapter->getInternalComObj(); +} + +- (instancetype)initWithAdapter:(std::unique_ptr)dictionaryAdapter { + if (self = [super init]) { + adapter = std::move(dictionaryAdapter); + } + + return self; +} + +- (id)objectForKey:(id)key { + return adapter->objectForKey(key); +} + +- (id)keyEnumerator { + return adapter->keyEnumerator(); +} + +- (unsigned int)count { + return adapter->count(); +} + +- (NSArray*)allKeys { + return adapter->allKeys(); +} + +- (NSArray*)allKeysForObject:(id)obj { + return adapter->allKeysForObject(obj); +} + +- (NSArray*)allValues { + return adapter->allValues(); +} +@end + +@implementation RTProxiedNSMutableDictionary +- (ComPtr)getInternalComObj { + return adapter->getInternalComObj(); +} + +- (instancetype)initWithAdapter:(std::unique_ptr)dictionaryAdapter { + if (self = [super init]) { + adapter = std::move(dictionaryAdapter); + } + + return self; +} + +- (id)objectForKey:(id)key { + return adapter->objectForKey(key); +} + +- (id)keyEnumerator { + return adapter->keyEnumerator(); +} + +- (unsigned int)count { + return adapter->count(); +} + +- (NSArray*)allKeys { + return adapter->allKeys(); +} + +- (NSArray*)allKeysForObject:(id)obj { + return adapter->allKeysForObject(obj); +} + +- (NSArray*)allValues { + return adapter->allValues(); +} + +- (void)setObject:(id)obj forKey:(id)key { + adapter->setObject(obj, key); +} + +- (void)setObject:(id)obj forKeyedSubscript:(id)key { + adapter->setObject(obj, key); +} + +- (void)removeObjectForKey:(id)key { + adapter->removeObjectForKey(key); +} + +- (void)removeAllObjects { + adapter->removeAllObjects(); +} + +- (void)removeObjectsForKeys:(NSArray*)keys { + adapter->removeObjectsForKeys(keys); +} + +- (void)addEntriesFromDictionary:(NSDictionary*)otherDict { + adapter->addEntriesFromDictionary(otherDict); +} + +- (void)addEntriesFromDictionaryNoReplace:(NSDictionary*)otherDict { + adapter->addEntriesFromDictionaryNoReplace(otherDict); +} + +- (void)setDictionary:(NSDictionary*)otherDict { + adapter->setDictionary(otherDict); +} +@end + +@implementation RTProxiedKeyValuePair +- (void)setAdapter:(std::unique_ptr)keyValuePairAdapter { + adapter = std::move(keyValuePairAdapter); +} + +- (id)key { + return adapter->key(self.comObj); +} + +- (id)value { + return adapter->value(self.comObj); +} +@end + +@implementation ListenerMgr { + id _owner; + StrongId _listeners; + __int64 _nextToken; +} + +- (id)init { + [super init]; + _listeners.attach([[NSMutableDictionary alloc] init]); + _nextToken = 1; + return self; +} + +- (id)initWith:(id)owner { + [self init]; + _owner = owner; + return self; +} + +- (void)setOwner:(id)owner { + _owner = owner; +} + +- (EventRegistrationToken)addObserver:(RTCollectionListener)receiver { + EventRegistrationToken t; + t.value = _nextToken; + + [receiver retain]; + [_listeners setObject:receiver forKey:[NSNumber numberWithLongLong:t.value]]; + _nextToken++; + + if ([_listeners count] == 1) { + [_owner registerSelf]; + } + + return t; +} + +- (void)removeObserver:(EventRegistrationToken)receiverToken { + NSNumber* k = [NSNumber numberWithLongLong:receiverToken.value]; + RTCollectionListener receiver = [_listeners objectForKey:k]; + if (receiver != nil) { + [_listeners removeObjectForKey:k]; + [receiver release]; + if ([_listeners count] == 0) { + [_owner unregisterSelf]; + } + } +} + +- (void)notify:(RTCollectionOperation)op value:(id)val { + for (RTCollectionListener listener in [_listeners objectEnumerator]) { + listener(_owner, op, val); + } +} + +- (NSArray*)listeners { + return [_listeners allValues]; +} +@end diff --git a/RTObjCInterop/RTObjCInterop/src/RTObject.mm b/RTObjCInterop/RTObjCInterop/src/RTObject.mm new file mode 100644 index 0000000000..968dce05d4 --- /dev/null +++ b/RTObjCInterop/RTObjCInterop/src/RTObject.mm @@ -0,0 +1,55 @@ +//****************************************************************************** +// +// Copyright (c) Microsoft. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +// This has to be @impled in a .mm file because we need to create the ivars for the comptr. + +#import +#import + +#include + +#import + +@implementation RTObject ++ (instancetype)alloc { + NSLog(@"Cannot allocate WinRT components through alloc/new! Use static instantiators.", NSStringFromClass(self)); + assert(0); + return nil; +} + ++ (instancetype)createWith:(IInspectable*)obj { + // We need to do no checking here since we're just mimicing a base object. The real testing happens in derived classes. + return _createBareRTObj(obj); +} + +@end + +id rt_dynamic_cast(Class classType, RTObject* rtObject) { + // Oddly, WinRT can return nullptr from successful function calls. + // When this happens we simply return nil to objC users. + // The user might not check if the object was nil and could make this call, which can result + // in an exception when we try to get the underlying IInspectable from the comObj using Get() method. + if (rtObject == nil) { + return nil; + } + + if ([rtObject comObj] == nullptr) { + // This is unexpected. + THROW_NS_HR_MSG(E_UNEXPECTED, "Underlying COM object is NULL"); + } + + return [classType createWith:[rtObject comObj].Get()]; +} diff --git a/build/WinObjC.Frameworks.UWP.Core/Readme.txt b/RTObjCInterop/WinObjC.Frameworks.UWP.Core/Readme.txt similarity index 100% rename from build/WinObjC.Frameworks.UWP.Core/Readme.txt rename to RTObjCInterop/WinObjC.Frameworks.UWP.Core/Readme.txt diff --git a/RTObjCInterop/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.Packageable.props b/RTObjCInterop/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.Packageable.props new file mode 100644 index 0000000000..7a66b837f9 --- /dev/null +++ b/RTObjCInterop/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.Packageable.props @@ -0,0 +1,18 @@ + + + + uap10.0 + false + false + true + true + + + + <_MainProjectOutput> + $(IsPackable) + $(IsNuGetized) + + + + \ No newline at end of file diff --git a/RTObjCInterop/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.Packageable.targets b/RTObjCInterop/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.Packageable.targets new file mode 100644 index 0000000000..ae168523c2 --- /dev/null +++ b/RTObjCInterop/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.Packageable.targets @@ -0,0 +1,26 @@ + + + + + + + <_IncludeFiles Include="$(WINOBJC_SDK_ROOT)\include\Platform\Universal Windows\**\InteropBase.h"/> + <_IncludeFiles Include="$(WINOBJC_SDK_ROOT)\include\Platform\Universal Windows\**\RTHelpers.h"/> + <_IncludeFiles Include="$(WINOBJC_SDK_ROOT)\include\Platform\Universal Windows\**\ObjCHelpers.h"/> + <_IncludeFiles Include="$(WINOBJC_SDK_ROOT)\include\Platform\Universal Windows\**\ObjCHelperCommonConvertors.h"/> + <_IncludeFiles Include="$(WINOBJC_SDK_ROOT)\include\Platform\Universal Windows\**\ObjCHelperAsyncImplementation.h"/> + + + build\include\UWP\%(Filename)%(Extension) + + + + build\lib\$(TargetOsAndVersion)\$(PlatformTarget)\%(Filename)%(Extension) + + + + build\lib\$(TargetOsAndVersion)\$(PlatformTarget)\%(Filename)%(Extension) + + + + \ No newline at end of file diff --git a/RTObjCInterop/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.Packaging.props b/RTObjCInterop/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.Packaging.props new file mode 100644 index 0000000000..530d4f1c10 --- /dev/null +++ b/RTObjCInterop/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.Packaging.props @@ -0,0 +1,22 @@ + + + + WinObjC.Frameworks.UWP.Core + WinObjC.Frameworks.UWP.Core + Microsoft + Microsoft + WinObjC.Frameworks.UWP.Core + WinObjC.Frameworks.UWP.Core + + + + + + + Copyright © Microsoft + WinObjC.Frameworks.UWP.Core + false + false + uap10.0 + + \ No newline at end of file diff --git a/RTObjCInterop/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.Packaging.targets b/RTObjCInterop/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.Packaging.targets new file mode 100644 index 0000000000..851ef183b1 --- /dev/null +++ b/RTObjCInterop/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.Packaging.targets @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/build/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.nuproj b/RTObjCInterop/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.nuproj similarity index 65% rename from build/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.nuproj rename to RTObjCInterop/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.nuproj index 259704211a..fb6a0eb700 100644 --- a/build/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.nuproj +++ b/RTObjCInterop/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.nuproj @@ -1,8 +1,8 @@ - - + - + + Debug @@ -35,19 +35,13 @@ - - 59537c2b-0319-49a8-9e2e-eea635eee515 - $(MSBuildThisFileDirectory)..\..\ + build\OutputPackages\$(Configuration)\ + d9206ff8-86ef-477f-a022-ab3969d55876 - - - - - @@ -55,13 +49,14 @@ PreserveNewest - - - + + + + + + - - - \ No newline at end of file + diff --git a/build/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.Packaging.props b/build/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.Packaging.props deleted file mode 100644 index cdf8a5f974..0000000000 --- a/build/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.Packaging.props +++ /dev/null @@ -1,22 +0,0 @@ - - - - - WinObjC.Frameworks.UWP.Core - WinObjC.Frameworks.UWP.Core - Microsoft - Microsoft - WinObjC.Frameworks.UWP.Core - WinObjC.Frameworks.UWP.Core - - - - - - - Copyright © Microsoft - WinObjC.Frameworks.UWP.Core - https://avatars2.githubusercontent.com/u/6154722?v=3&s=200 - - - \ No newline at end of file diff --git a/build/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.Packaging.targets b/build/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.Packaging.targets deleted file mode 100644 index 425f91bdfd..0000000000 --- a/build/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.Packaging.targets +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - <_DepsFiles Include="$(StarboardBasePath)\deps\prebuilt\**\RTObjCInterop.dll"/> - <_DepsFiles Include="$(StarboardBasePath)\deps\prebuilt\**\RTObjCInterop.lib"/> - - - build\deps\prebuilt\%(RecursiveDir)%(Filename)%(Extension) - - - - <_IncludeFiles Include="$(StarboardBasePath)\include\Platform\Universal Windows\**\InteropBase.h"/> - <_IncludeFiles Include="$(StarboardBasePath)\include\Platform\Universal Windows\**\RTHelpers.h"/> - <_IncludeFiles Include="$(StarboardBasePath)\include\Platform\Universal Windows\**\ObjCHelpers.h"/> - <_IncludeFiles Include="$(StarboardBasePath)\include\Platform\Universal Windows\**\ObjCHelperCommonConvertors.h"/> - <_IncludeFiles Include="$(StarboardBasePath)\include\Platform\Universal Windows\**\ObjCHelperAsyncImplementation.h"/> - - - build\include\%(RecursiveDir)%(Filename)%(Extension) - - - - build\$(PackageId).props - - - build\$(PackageId).targets - - - - - \ No newline at end of file diff --git a/build/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.props b/build/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.props deleted file mode 100644 index 405faa930b..0000000000 --- a/build/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.props +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/build/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.targets b/build/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.targets deleted file mode 100644 index 7e41fa74be..0000000000 --- a/build/WinObjC.Frameworks.UWP.Core/WinObjC.Frameworks.UWP.Core.targets +++ /dev/null @@ -1,41 +0,0 @@ - - - - Universal Windows - - - - - - <_DllsFromPackage Include="$(MSBuildThisFileDirectory)\lib\$(TargetOsAndVersion)\$(PlatformTarget)\*.dll"/> - <_DllsFromPackage Include="$(MSBuildThisFileDirectory)\lib\$(TargetOsAndVersion)\$(PlatformTarget)\$(Configuration)\*.dll"/> - - <_DllsFromPackage Include="$(MSBuildThisFileDirectory)\deps\prebuilt\$(TargetOsAndVersion)\$(PlatformTarget)\*.dll"/> - <_DllsFromPackage Include="$(MSBuildThisFileDirectory)\deps\prebuilt\$(TargetOsAndVersion)\$(PlatformTarget)\$(Configuration)\*.dll"/> - - - - - - $(MSBuildThisFileDirectory)\include\;%(InternalSystemIncludePaths); - - - - $(MSBuildThisFileDirectory)\lib\$(TargetOsAndVersion)\$(PlatformTarget)\;$(MSBuildThisFileDirectory)\lib\$(TargetOsAndVersion)\$(PlatformTarget)\$(Configuration)\;$(MSBuildThisFileDirectory)\deps\prebuilt\$(TargetOsAndVersion)\$(PlatformTarget)\;$(MSBuildThisFileDirectory)\deps\prebuilt\$(TargetOsAndVersion)\$(PlatformTarget)\$(Configuration)\;%(AdditionalLibraryDirectories); - RTObjCInterop.lib;%(AdditionalDependencies); - - - - - - - - true - - - - \ No newline at end of file diff --git a/build/build.sln b/build/build.sln index 62338d69ed..1f6fa82e92 100644 --- a/build/build.sln +++ b/build/build.sln @@ -791,8 +791,6 @@ Project("{5DD5E4FA-CB73-4610-85AB-557B54E96AA9}") = "WinObjC.Frameworks.ThirdPar EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WinObjC Frameworks UWP Core Package", "WinObjC Frameworks UWP Core Package", "{6950E151-2219-4A37-9137-0AEAE08428E4}" EndProject -Project("{5DD5E4FA-CB73-4610-85AB-557B54E96AA9}") = "WinObjC.Frameworks.UWP.Core", "WinObjC.Frameworks.UWP.Core\WinObjC.Frameworks.UWP.Core.nuproj", "{59537C2B-0319-49A8-9E2E-EEA635EEE515}" -EndProject Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "NuprojInitializer", "..\common\NuprojInitializer.msbuildproj", "{417B0D00-F90E-47BB-9085-BE7E412C9DA8}" EndProject Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "NugetRestore", "..\common\NugetRestore.msbuildproj", "{B2C6186E-B340-49D8-888E-76ED83752E43}" @@ -2313,18 +2311,6 @@ Global {DFDF94D9-2A0A-4F9B-953B-6BF383858AD3}.Release|ARM.Build.0 = Release|ARM {DFDF94D9-2A0A-4F9B-953B-6BF383858AD3}.Release|x86.ActiveCfg = Release|x86 {DFDF94D9-2A0A-4F9B-953B-6BF383858AD3}.Release|x86.Build.0 = Release|x86 - {59537C2B-0319-49A8-9E2E-EEA635EEE515}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {59537C2B-0319-49A8-9E2E-EEA635EEE515}.Debug|Any CPU.Build.0 = Debug|Any CPU - {59537C2B-0319-49A8-9E2E-EEA635EEE515}.Debug|ARM.ActiveCfg = Debug|ARM - {59537C2B-0319-49A8-9E2E-EEA635EEE515}.Debug|ARM.Build.0 = Debug|ARM - {59537C2B-0319-49A8-9E2E-EEA635EEE515}.Debug|x86.ActiveCfg = Debug|x86 - {59537C2B-0319-49A8-9E2E-EEA635EEE515}.Debug|x86.Build.0 = Debug|x86 - {59537C2B-0319-49A8-9E2E-EEA635EEE515}.Release|Any CPU.ActiveCfg = Release|Any CPU - {59537C2B-0319-49A8-9E2E-EEA635EEE515}.Release|Any CPU.Build.0 = Release|Any CPU - {59537C2B-0319-49A8-9E2E-EEA635EEE515}.Release|ARM.ActiveCfg = Release|ARM - {59537C2B-0319-49A8-9E2E-EEA635EEE515}.Release|ARM.Build.0 = Release|ARM - {59537C2B-0319-49A8-9E2E-EEA635EEE515}.Release|x86.ActiveCfg = Release|x86 - {59537C2B-0319-49A8-9E2E-EEA635EEE515}.Release|x86.Build.0 = Release|x86 {417B0D00-F90E-47BB-9085-BE7E412C9DA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {417B0D00-F90E-47BB-9085-BE7E412C9DA8}.Debug|Any CPU.Build.0 = Debug|Any CPU {417B0D00-F90E-47BB-9085-BE7E412C9DA8}.Debug|ARM.ActiveCfg = Debug|Any CPU @@ -2730,7 +2716,6 @@ Global {BEF15618-E03F-4A44-A797-9150C979B09F} = {F0F1B2A3-6924-4A09-99CE-D08CD8BCF392} {60A07842-5D75-45E8-9FCF-C126E608B654} = {7B338049-F463-44B0-B7BD-F8EA16750085} {DFDF94D9-2A0A-4F9B-953B-6BF383858AD3} = {4BC1549F-F4C2-42D0-9F77-C323F751EA04} - {59537C2B-0319-49A8-9E2E-EEA635EEE515} = {6950E151-2219-4A37-9137-0AEAE08428E4} {417B0D00-F90E-47BB-9085-BE7E412C9DA8} = {7B338049-F463-44B0-B7BD-F8EA16750085} {B2C6186E-B340-49D8-888E-76ED83752E43} = {7B338049-F463-44B0-B7BD-F8EA16750085} {C881C664-A5BA-455A-AC87-388DC1B69102} = {E1BA5F74-6863-437D-9AF5-72666F6D25B5}