From 52400632c9c1474c03066d2f3accf158f90e9117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Laban?= Date: Thu, 16 May 2019 10:03:12 -0400 Subject: [PATCH] Marshal history tokens --- src/CalcManager/CCalcManager.cpp | 289 ++++++++++++------ src/CalcManager/CCalcManager.h | 31 +- .../CalcManager/CalculatorManager.Interop.cs | 56 +++- .../CalcManager/CalculatorManager.cs | 62 +++- .../Common/CalculatorDisplay.cs | 2 +- .../ViewModels/HistoryViewModel.cs | 2 +- 6 files changed, 319 insertions(+), 123 deletions(-) diff --git a/src/CalcManager/CCalcManager.cpp b/src/CalcManager/CCalcManager.cpp index 7ffb32af..d9ece638 100644 --- a/src/CalcManager/CCalcManager.cpp +++ b/src/CalcManager/CCalcManager.cpp @@ -9,118 +9,138 @@ #include #include #include +#include +#include + +#define DBGPRINT(kwszDebugFormatString, ...) _DBGPRINT(__FUNCTIONW__, __LINE__, kwszDebugFormatString, __VA_ARGS__) + +VOID _DBGPRINT(LPCWSTR kwszFunction, INT iLineNumber, LPCWSTR kwszDebugFormatString, ...) +{ + INT cbFormatString = 0; + va_list args; + PWCHAR wszDebugString = NULL; + size_t st_Offset = 0; + + va_start(args, kwszDebugFormatString); + + cbFormatString = _scwprintf(L"[%s:%d] ", kwszFunction, iLineNumber) * sizeof(WCHAR); + cbFormatString += _vscwprintf(kwszDebugFormatString, args) * sizeof(WCHAR) + 2; + + /* Depending on the size of the format string, allocate space on the stack or the heap. */ + wszDebugString = (PWCHAR)_malloca(cbFormatString); + + /* Populate the buffer with the contents of the format string. */ + StringCbPrintfW(wszDebugString, cbFormatString, L"[%s:%d] ", kwszFunction, iLineNumber); + StringCbLengthW(wszDebugString, cbFormatString, &st_Offset); + StringCbVPrintfW(&wszDebugString[st_Offset / sizeof(WCHAR)], cbFormatString - st_Offset, kwszDebugFormatString, args); + + OutputDebugStringW(wszDebugString); + + _freea(wszDebugString); + va_end(args); +} using namespace CalculationManager; -class CalcDisplay : public ICalcDisplay { - +class CalcDisplay : public ICalcDisplay +{ private: - CalculatorManager_CreateParams _params; + CalculatorManager_CreateParams _params; public: - CalcDisplay(CalculatorManager_CreateParams params) { - _params = params; - } + CalcDisplay(CalculatorManager_CreateParams params) + { + _params = params; + } - // Inherited via ICalcDisplay - virtual void SetPrimaryDisplay(const std::wstring& pszText, bool isError) override - { - std::wstring_convert> convert; - auto str = convert.to_bytes(pszText); + // Inherited via ICalcDisplay + virtual void SetPrimaryDisplay(const std::wstring& pszText, bool isError) override + { + std::wstring_convert> convert; + auto str = convert.to_bytes(pszText); - _params.SetPrimaryDisplay(_params.CalculatorState, str.data(), isError); - } + _params.SetPrimaryDisplay(_params.CalculatorState, str.data(), isError); + } - virtual void SetIsInError(bool isInError) override - { - _params.SetIsInError(_params.CalculatorState, isInError); - } + virtual void SetIsInError(bool isInError) override + { + _params.SetIsInError(_params.CalculatorState, isInError); + } - virtual void SetExpressionDisplay( - std::shared_ptr>> const& /*tokens*/, - std::shared_ptr>> const& /*commands*/) override - { - } + virtual void SetExpressionDisplay( + std::shared_ptr>> const& /*tokens*/, + std::shared_ptr>> const& /*commands*/) override + { + } - virtual void SetParenthesisNumber(unsigned int count) override - { - _params.SetParenthesisNumber(_params.CalculatorState, count); - } + virtual void SetParenthesisNumber(unsigned int count) override + { + _params.SetParenthesisNumber(_params.CalculatorState, count); + } - virtual void OnNoRightParenAdded() override - { - _params.OnNoRightParenAdded(_params.CalculatorState); - } + virtual void OnNoRightParenAdded() override + { + _params.OnNoRightParenAdded(_params.CalculatorState); + } - virtual void MaxDigitsReached() override - { - _params.MaxDigitsReached(_params.CalculatorState); - } + virtual void MaxDigitsReached() override + { + _params.MaxDigitsReached(_params.CalculatorState); + } - virtual void BinaryOperatorReceived() override - { - _params.BinaryOperatorReceived(_params.CalculatorState); - } + virtual void BinaryOperatorReceived() override + { + _params.BinaryOperatorReceived(_params.CalculatorState); + } - virtual void OnHistoryItemAdded(unsigned int addedItemIndex) override - { - _params.OnHistoryItemAdded(_params.CalculatorState, addedItemIndex); - } + virtual void OnHistoryItemAdded(unsigned int addedItemIndex) override + { + _params.OnHistoryItemAdded(_params.CalculatorState, addedItemIndex); + } - virtual void SetMemorizedNumbers(const std::vector& memorizedNumbers) override - { - std::wstring_convert> convert; + virtual void SetMemorizedNumbers(const std::vector& memorizedNumbers) override + { + auto numbers = new const wchar_t* [memorizedNumbers.size()] {}; - const char** numbers = new const char* [memorizedNumbers.size()]; + for (size_t i = 0; i < memorizedNumbers.size(); i++) + { + auto str = memorizedNumbers[i]; + auto pData = new wchar_t[str.size() + 1]{}; + str.copy(pData, str.size(), 0); + numbers[i] = pData; + } - for (size_t i = 0; i < memorizedNumbers.size(); i++) - { - auto str = convert.to_bytes(memorizedNumbers[i]); - auto pData = new char[str.size() + 1]; + _params.SetMemorizedNumbers(_params.CalculatorState, (unsigned int)memorizedNumbers.size(), numbers); -#if !defined(__EMSCRIPTEN__) - strcpy_s(pData, str.size()+1, str.data()); -#else - strcpy(pData, str.data()); -#endif - numbers[i] = pData; - } + for (size_t i = 0; i < memorizedNumbers.size(); i++) + { + delete[] numbers[i]; + } - _params.SetMemorizedNumbers(_params.CalculatorState, (unsigned int)memorizedNumbers.size(), numbers); + delete[] numbers; + } - for (size_t i = 0; i < memorizedNumbers.size(); i++) - { - delete[] numbers[i]; - } - - delete[] numbers; - } - - virtual void MemoryItemChanged(unsigned int indexOfMemory) override - { - _params.MemoryItemChanged(_params.CalculatorState, indexOfMemory); - } + virtual void MemoryItemChanged(unsigned int indexOfMemory) override + { + _params.MemoryItemChanged(_params.CalculatorState, indexOfMemory); + } }; -class ResourceProvider : public CalculationManager::IResourceProvider { +class ResourceProvider : public CalculationManager::IResourceProvider +{ private: - CalculatorManager_CreateParams _params; + CalculatorManager_CreateParams _params; public: - ResourceProvider(CalculatorManager_CreateParams params) - { - _params = params; - } + ResourceProvider(CalculatorManager_CreateParams params) + { + _params = params; + } - virtual std::wstring GetCEngineString(const std::wstring& id) override { - - std::wstring_convert> convert; - auto str = convert.to_bytes(id); - - auto res = _params.GetCEngineString(_params.ResourceState, str.data()); - - return convert.from_bytes(res); - } + virtual std::wstring GetCEngineString(const std::wstring& id) override + { + return _params.GetCEngineString(_params.ResourceState, id.data()); + } }; CalculatorManager* AsManager(void* manager) @@ -128,13 +148,20 @@ CalculatorManager* AsManager(void* manager) return static_cast(manager); } +const wchar_t* ToWChar(std::wstring& str) +{ + auto out = new wchar_t[str.size() + 1]{}; + str.copy(out, str.size() + 1, 0); + return out; +} + void* CalculatorManager_Create(CalculatorManager_CreateParams* pParams) { - auto calcDisplay = new CalcDisplay(*pParams); - auto resProvider = new ResourceProvider(*pParams); + auto calcDisplay = new CalcDisplay(*pParams); + auto resProvider = new ResourceProvider(*pParams); - auto cm = new CalculatorManager(calcDisplay, resProvider); - return cm; + auto cm = new CalculatorManager(calcDisplay, resProvider); + return cm; } void CalculatorManager_SendCommand(void* manager, int command) @@ -207,14 +234,14 @@ void CalculatorManager_SetMemorizedNumbersString(void* manager) AsManager(manager)->SetMemorizedNumbersString(); } -const char* CalculatorManager_GetResultForRadix(void* manager, int radix, int precision) +const wchar_t* CalculatorManager_GetResultForRadix(void* manager, int radix, int precision) { auto res = AsManager(manager)->GetResultForRadix(radix, precision); - std::wstring_convert> convert; - auto str = convert.to_bytes(res); + auto out = new wchar_t[res.size() + 1]{}; + res.copy(out, res.size(), 0); - return str.data(); + return out; } void CalculatorManager_SetPrecision(void* manager, int precision) @@ -234,7 +261,7 @@ const char* CalculatorManager_DecimalSeparator(void* manager) std::wstring_convert> convert; auto str = convert.to_bytes(res); - return str.data(); + return str.data(); } bool CalculatorManager_RemoveHistoryItem(void* manager, int uIdx) @@ -261,3 +288,77 @@ void CalculatorManager_SetInHistoryItemLoadMode(void* manager, bool isHistoryIte { AsManager(manager)->SetInHistoryItemLoadMode(isHistoryItemLoadMode); } + +GetHistoryItemResult* MarshalHistoryItem(std::shared_ptr& historyItem) +{ + auto itemResult = new GetHistoryItemResult{}; + + itemResult->expression = ToWChar(historyItem->historyItemVector.expression); + itemResult->result = ToWChar(historyItem->historyItemVector.result); + + unsigned int tokenCount; + historyItem->historyItemVector.spTokens->GetSize(&tokenCount); + itemResult->TokenCount = tokenCount; + + auto tokenStrings = new const wchar_t* [tokenCount] {}; + auto tokenValues = new int32_t[tokenCount]{}; + + DBGPRINT(L"TokenCount: %d (int32_t: %d)\n", tokenCount, sizeof(int32_t)); + + for (uint32_t j = 0; j < tokenCount; j++) + { + std::pair pair; + + if (SUCCEEDED(historyItem->historyItemVector.spTokens->GetAt(j, &pair))) + { + tokenStrings[j] = ToWChar(pair.first); + tokenValues[j] = (int32_t)pair.second; + DBGPRINT(L"\tPair: %ws;%d\n", pair.first.data(), tokenValues[j]); + } + } + + itemResult->TokenStrings = tokenStrings; + itemResult->TokenValues = tokenValues; + + return itemResult; +} + +void* MarshalHistoryItems(std::vector>& historyItems) +{ + auto result = new GetHistoryItemsResult{}; + + result->ItemsCount = (int32_t)historyItems.size(); + + auto resultsArray = new GetHistoryItemResult*[result->ItemsCount]; + result->HistoryItems = (void*)resultsArray; + + for (size_t i = 0; i < historyItems.size(); i++) + { + auto historyItem = historyItems[i]; + + resultsArray[i] = MarshalHistoryItem(historyItem); + } + + return result; +} + +void* CalculatorManager_GetHistoryItems(void* manager) +{ + auto historyItems = AsManager(manager)->GetHistoryItems(); + + return MarshalHistoryItems(historyItems); +} + +void* CalculatorManager_GetHistoryItemsWithMode(void* manager, int mode) +{ + auto historyItems = AsManager(manager)->GetHistoryItems((CALCULATOR_MODE)mode); + + return MarshalHistoryItems(historyItems); +} + +void* CalculatorManager_GetHistoryItem(void* manager, int index) +{ + auto historyItem = AsManager(manager)->GetHistoryItem(index); + + return MarshalHistoryItem(historyItem); +} diff --git a/src/CalcManager/CCalcManager.h b/src/CalcManager/CCalcManager.h index 5ce62c9d..e8cf8cbd 100644 --- a/src/CalcManager/CCalcManager.h +++ b/src/CalcManager/CCalcManager.h @@ -28,10 +28,10 @@ typedef void (*OnNoRightParenAddedFunc)(void* state); typedef void (*MaxDigitsReachedFunc)(void* state); typedef void (*BinaryOperatorReceivedFunc)(void* state); typedef void (*OnHistoryItemAddedFunc)(void* state, unsigned int addedItemIndex); -typedef void (*SetMemorizedNumbersFunc)(void* state, unsigned int count, const char** memorizedNumbers); +typedef void (*SetMemorizedNumbersFunc)(void* state, unsigned int count, const wchar_t** memorizedNumbers); typedef void (*MemoryItemChangedFunc)(void* state, unsigned int indexOfMemory); -typedef const char* (*GetCEngineStringFunc)(void* state, const char* id); +typedef const wchar_t* (*GetCEngineStringFunc)(void* state, const wchar_t* id); struct CalculatorManager_CreateParams { void* CalculatorState; @@ -58,6 +58,26 @@ struct CalculatorManager_CreateParams { #endif extern "C" { + + struct GetHistoryItemsResult + { + int32_t ItemsCount; + void* HistoryItems; + }; + + struct GetHistoryItemResult + { + const wchar_t* expression; + const wchar_t* result; + + int32_t TokenCount; + const wchar_t** TokenStrings; + int32_t* TokenValues; + + int32_t CommandCount; + void** Commands; + }; + DLL_EXPORT void* CalculatorManager_Create(CalculatorManager_CreateParams* params); DLL_EXPORT void CalculatorManager_SendCommand(void* manager, int command); DLL_EXPORT void CalculatorManager_SetRadix(void* manager, RADIX_TYPE iRadixType); @@ -73,7 +93,7 @@ extern "C" { DLL_EXPORT void CalculatorManager_MemorizedNumberClearAll(void* manager); DLL_EXPORT bool CalculatorManager_IsEngineRecording(void* manager); DLL_EXPORT void CalculatorManager_SetMemorizedNumbersString(void* manager); - DLL_EXPORT const char* CalculatorManager_GetResultForRadix(void* manager, int radix, int precision); + DLL_EXPORT const wchar_t* CalculatorManager_GetResultForRadix(void* manager, int radix, int precision); DLL_EXPORT void CalculatorManager_SetPrecision(void* manager, int precision); DLL_EXPORT void CalculatorManager_UpdateMaxIntDigits(void* manager); DLL_EXPORT const char* CalculatorManager_DecimalSeparator(void* manager); @@ -82,5 +102,10 @@ extern "C" { DLL_EXPORT size_t CalculatorManager_MaxHistorySize(void* manager); DLL_EXPORT int CalculatorManager_GetCurrentDegreeMode(void* manager); DLL_EXPORT void CalculatorManager_SetInHistoryItemLoadMode(void* manager, bool isHistoryItemLoadMode); + void* MarshalHistoryItem(std::shared_ptr& historyItem, bool& retflag); + void* MarshalHistoryItems(std::vector>& historyItems); + DLL_EXPORT void* CalculatorManager_GetHistoryItemsWithMode(void* manager, int mode); + DLL_EXPORT void* CalculatorManager_GetHistoryItems(void* manager); + DLL_EXPORT void* CalculatorManager_GetHistoryItem(void* manager, int index); } diff --git a/src/Calculator.Shared/CalcManager/CalculatorManager.Interop.cs b/src/Calculator.Shared/CalcManager/CalculatorManager.Interop.cs index 8cb0f3dc..a9b7a2ff 100644 --- a/src/Calculator.Shared/CalcManager/CalculatorManager.Interop.cs +++ b/src/Calculator.Shared/CalcManager/CalculatorManager.Interop.cs @@ -57,7 +57,7 @@ namespace CalculationManager [DllImport("CalcManager")] public static extern void CalculatorManager_SetMemorizedNumbersString(IntPtr nativeManager); - [DllImport("CalcManager")] + [DllImport("CalcManager", CharSet = CharSet.Unicode)] public static extern string CalculatorManager_GetResultForRadix(IntPtr nativeManager, int radix, int precision); [DllImport("CalcManager")] @@ -84,6 +84,15 @@ namespace CalculationManager [DllImport("CalcManager")] public static extern void CalculatorManager_SetInHistoryItemLoadMode(IntPtr nativeManager, bool isHistoryItemLoadMode); + [DllImport("CalcManager")] + public static extern IntPtr CalculatorManager_GetHistoryItems(IntPtr nativeManager); + + [DllImport("CalcManager")] + public static extern IntPtr CalculatorManager_GetHistoryItemsWithMode(IntPtr nativeManager, CALCULATOR_MODE mode); + + [DllImport("CalcManager")] + public static extern IntPtr CalculatorManager_GetHistoryItem(IntPtr nativeManager, int uIdx); + public delegate IntPtr GetCEngineStringFunc(IntPtr state, string id); public delegate void BinaryOperatorReceivedFunc(IntPtr state); public delegate void SetPrimaryDisplayCallbackFunc(IntPtr state, string displayStringValue, bool isError); @@ -157,9 +166,8 @@ namespace CalculationManager var numbers = new List(); for (int i = 0; i < count; i++) { - // TODO Use native encoding instead. - var value = Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(newMemorizedNumbers, i)); - numbers.Add(Encoding.UTF8.GetString(Encoding.ASCII.GetBytes(value))); + var value = Marshal.PtrToStringUni(Marshal.ReadIntPtr(newMemorizedNumbers, i)); + numbers.Add(value); } manager.SetMemorizedNumbers(numbers); @@ -183,7 +191,7 @@ namespace CalculationManager Debug.WriteLine($"CalculatorManager.BinaryOperatorReceivedCallback"); } - public static void SetPrimaryDisplayCallback(IntPtr state, string displayStringValue, bool isError) + public static void SetPrimaryDisplayCallback(IntPtr state, [MarshalAs(UnmanagedType.LPWStr)] string displayStringValue, bool isError) { var manager = GCHandle.FromIntPtr((IntPtr)state).Target as CalculatorDisplay; manager.SetPrimaryDisplay(displayStringValue, isError); @@ -199,23 +207,39 @@ namespace CalculationManager Debug.WriteLine($"CalculatorManager.SetIsInErrorCallback({isError})"); } - public static IntPtr GetCEngineStringCallback(IntPtr state, string resourceId) + public static IntPtr GetCEngineStringCallback(IntPtr state, [MarshalAs(UnmanagedType.LPWStr)] string resourceId) { var provider = GCHandle.FromIntPtr((IntPtr)state).Target as EngineResourceProvider; - var ret = provider.GetCEngineString(resourceId) ?? ""; + var r = provider.GetCEngineString(resourceId) ?? ""; - var retBytes = Encoding.UTF8.GetBytes(ret); - var retPtr = Marshal.AllocHGlobal(retBytes.Length + 1); - Marshal.WriteByte(retPtr + retBytes.Length, 0); - Marshal.Copy(retBytes, 0, retPtr, retBytes.Length); - - Debug.WriteLine($"CalculatorManager.GetCEngineStringCallback({resourceId},{ret})"); - - return retPtr; + return Marshal.StringToHGlobalUni(r); } } - public partial class CalculatorManager : ICalcDisplay + + [StructLayout(LayoutKind.Sequential)] + public struct GetHistoryItemsResult + { + public int ItemsCount; + public IntPtr HistoryItems; + } + + [StructLayout(LayoutKind.Sequential)] + public struct GetHistoryItemResult + { + public string expression; + public string result; + + public int TokenCount; + public IntPtr TokenStrings; + public IntPtr TokenValues; + + public int CommandCount; + public IntPtr Commands; + } + + + public partial class CalculatorManager : ICalcDisplay { private GCHandle _displayCallbackHandle; diff --git a/src/Calculator.Shared/CalcManager/CalculatorManager.cs b/src/Calculator.Shared/CalcManager/CalculatorManager.cs index c440731f..2b754e83 100644 --- a/src/Calculator.Shared/CalcManager/CalculatorManager.cs +++ b/src/Calculator.Shared/CalcManager/CalculatorManager.cs @@ -219,17 +219,63 @@ namespace CalculationManager public char DecimalSeparator() => NativeDispatch.CalculatorManager_DecimalSeparator(_nativeManager); - public List GetHistoryItems() => throw new NotImplementedException(); + public List GetHistoryItems() + { + var pResult = NativeDispatch.CalculatorManager_GetHistoryItems(_nativeManager); + return UnmarshalHistoryItemsResult(pResult); + } - public List GetHistoryItems(CalculationManager.CALCULATOR_MODE mode) - { - Debug.WriteLine($"CalculatorManager.GetHistoryItems({mode})"); + public List GetHistoryItems(CalculationManager.CALCULATOR_MODE mode) + { + var pResult = NativeDispatch.CalculatorManager_GetHistoryItemsWithMode(_nativeManager, mode); + return UnmarshalHistoryItemsResult(pResult); + } - return new List(); - } + private static List UnmarshalHistoryItemsResult(IntPtr pResult) + { + var result = Marshal.PtrToStructure(pResult); + var output = new List(); - public HISTORYITEM GetHistoryItem(int uIdx) => throw new NotImplementedException(); - public bool RemoveHistoryItem(int uIdx) + for (var i = 0; i < result.ItemsCount; i++) + { + var historyResultItem = Marshal.PtrToStructure(Marshal.ReadIntPtr(result.HistoryItems, i * Marshal.SizeOf())); + + var historyItem = UnmarshalHistoryItemResult(historyResultItem); + + output.Add(historyItem); + } + + return output; + } + + private static HISTORYITEM UnmarshalHistoryItemResult(GetHistoryItemResult historyResultItem) + { + var historyItem = new HISTORYITEM(); + historyItem.historyItemVector.expression = historyResultItem.expression; + historyItem.historyItemVector.result = historyResultItem.result; + historyItem.historyItemVector.spTokens = new CalculatorList<(string, int)>(); + + for (var i = 0; i < historyResultItem.TokenCount; i++) + { + var tokenString = Marshal.PtrToStringUni(Marshal.ReadIntPtr(historyResultItem.TokenStrings, i * Marshal.SizeOf())); + + var tokenValue = Marshal.ReadInt32(historyResultItem.TokenValues, i * Marshal.SizeOf()); + + historyItem.historyItemVector.spTokens.Append((tokenString, tokenValue)); + } + + return historyItem; + } + + public HISTORYITEM GetHistoryItem(int uIdx) + { + var pResult = NativeDispatch.CalculatorManager_GetHistoryItem(_nativeManager, uIdx); + var result = Marshal.PtrToStructure(pResult); + + return UnmarshalHistoryItemResult(result); + } + + public bool RemoveHistoryItem(int uIdx) => NativeDispatch.CalculatorManager_RemoveHistoryItem(_nativeManager, uIdx); public void ClearHistory() diff --git a/src/Calculator.Shared/Common/CalculatorDisplay.cs b/src/Calculator.Shared/Common/CalculatorDisplay.cs index 43f3eb71..2d838e3b 100644 --- a/src/Calculator.Shared/Common/CalculatorDisplay.cs +++ b/src/Calculator.Shared/Common/CalculatorDisplay.cs @@ -100,7 +100,7 @@ namespace CalculatorApp { if (m_historyCallbackReference != null) { - if (m_callbackReference.Target is ViewModel.HistoryViewModel historyVM) + if (m_historyCallbackReference.Target is ViewModel.HistoryViewModel historyVM) { historyVM.OnHistoryItemAdded(addedItemIndex); } diff --git a/src/Calculator.Shared/ViewModels/HistoryViewModel.cs b/src/Calculator.Shared/ViewModels/HistoryViewModel.cs index 66e32701..ee9f169a 100644 --- a/src/Calculator.Shared/ViewModels/HistoryViewModel.cs +++ b/src/Calculator.Shared/ViewModels/HistoryViewModel.cs @@ -306,7 +306,7 @@ namespace CalculatorApp try { serializedHistoryItem = SerializeHistoryItem(it); - historyContainer.Values.Add(index.ToString(), serializedHistoryItem); + historyContainer.Values[index.ToString()] = serializedHistoryItem; } catch (Exception e) {