Marshal history tokens

This commit is contained in:
Jérôme Laban 2019-05-16 10:03:12 -04:00
commit 52400632c9
6 changed files with 319 additions and 123 deletions

View file

@ -9,16 +9,47 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <iostream> #include <iostream>
#include <Windows.h>
#include <strsafe.h>
#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; using namespace CalculationManager;
class CalcDisplay : public ICalcDisplay { class CalcDisplay : public ICalcDisplay
{
private: private:
CalculatorManager_CreateParams _params; CalculatorManager_CreateParams _params;
public: public:
CalcDisplay(CalculatorManager_CreateParams params) { CalcDisplay(CalculatorManager_CreateParams params)
{
_params = params; _params = params;
} }
@ -69,20 +100,13 @@ public:
virtual void SetMemorizedNumbers(const std::vector<std::wstring>& memorizedNumbers) override virtual void SetMemorizedNumbers(const std::vector<std::wstring>& memorizedNumbers) override
{ {
std::wstring_convert<std::codecvt_utf8<wchar_t>> convert; 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++) for (size_t i = 0; i < memorizedNumbers.size(); i++)
{ {
auto str = convert.to_bytes(memorizedNumbers[i]); auto str = memorizedNumbers[i];
auto pData = new char[str.size() + 1]; auto pData = new wchar_t[str.size() + 1]{};
str.copy(pData, str.size(), 0);
#if !defined(__EMSCRIPTEN__)
strcpy_s(pData, str.size()+1, str.data());
#else
strcpy(pData, str.data());
#endif
numbers[i] = pData; numbers[i] = pData;
} }
@ -102,7 +126,8 @@ public:
} }
}; };
class ResourceProvider : public CalculationManager::IResourceProvider { class ResourceProvider : public CalculationManager::IResourceProvider
{
private: private:
CalculatorManager_CreateParams _params; CalculatorManager_CreateParams _params;
@ -112,14 +137,9 @@ public:
_params = params; _params = params;
} }
virtual std::wstring GetCEngineString(const std::wstring& id) override { virtual std::wstring GetCEngineString(const std::wstring& id) override
{
std::wstring_convert<std::codecvt_utf8<wchar_t>> convert; return _params.GetCEngineString(_params.ResourceState, id.data());
auto str = convert.to_bytes(id);
auto res = _params.GetCEngineString(_params.ResourceState, str.data());
return convert.from_bytes(res);
} }
}; };
@ -128,6 +148,13 @@ CalculatorManager* AsManager(void* manager)
return static_cast<CalculatorManager*>(manager); return static_cast<CalculatorManager*>(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) void* CalculatorManager_Create(CalculatorManager_CreateParams* pParams)
{ {
auto calcDisplay = new CalcDisplay(*pParams); auto calcDisplay = new CalcDisplay(*pParams);
@ -207,14 +234,14 @@ void CalculatorManager_SetMemorizedNumbersString(void* manager)
AsManager(manager)->SetMemorizedNumbersString(); 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); auto res = AsManager(manager)->GetResultForRadix(radix, precision);
std::wstring_convert<std::codecvt_utf8<wchar_t>> convert; auto out = new wchar_t[res.size() + 1]{};
auto str = convert.to_bytes(res); res.copy(out, res.size(), 0);
return str.data(); return out;
} }
void CalculatorManager_SetPrecision(void* manager, int precision) void CalculatorManager_SetPrecision(void* manager, int precision)
@ -261,3 +288,77 @@ void CalculatorManager_SetInHistoryItemLoadMode(void* manager, bool isHistoryIte
{ {
AsManager(manager)->SetInHistoryItemLoadMode(isHistoryItemLoadMode); AsManager(manager)->SetInHistoryItemLoadMode(isHistoryItemLoadMode);
} }
GetHistoryItemResult* MarshalHistoryItem(std::shared_ptr<CalculationManager::HISTORYITEM>& 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<std::wstring, int> 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<std::shared_ptr<CalculationManager::HISTORYITEM>>& 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);
}

View file

@ -28,10 +28,10 @@ typedef void (*OnNoRightParenAddedFunc)(void* state);
typedef void (*MaxDigitsReachedFunc)(void* state); typedef void (*MaxDigitsReachedFunc)(void* state);
typedef void (*BinaryOperatorReceivedFunc)(void* state); typedef void (*BinaryOperatorReceivedFunc)(void* state);
typedef void (*OnHistoryItemAddedFunc)(void* state, unsigned int addedItemIndex); 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 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 { struct CalculatorManager_CreateParams {
void* CalculatorState; void* CalculatorState;
@ -58,6 +58,26 @@ struct CalculatorManager_CreateParams {
#endif #endif
extern "C" { 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_Create(CalculatorManager_CreateParams* params);
DLL_EXPORT void CalculatorManager_SendCommand(void* manager, int command); DLL_EXPORT void CalculatorManager_SendCommand(void* manager, int command);
DLL_EXPORT void CalculatorManager_SetRadix(void* manager, RADIX_TYPE iRadixType); 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 void CalculatorManager_MemorizedNumberClearAll(void* manager);
DLL_EXPORT bool CalculatorManager_IsEngineRecording(void* manager); DLL_EXPORT bool CalculatorManager_IsEngineRecording(void* manager);
DLL_EXPORT void CalculatorManager_SetMemorizedNumbersString(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_SetPrecision(void* manager, int precision);
DLL_EXPORT void CalculatorManager_UpdateMaxIntDigits(void* manager); DLL_EXPORT void CalculatorManager_UpdateMaxIntDigits(void* manager);
DLL_EXPORT const char* CalculatorManager_DecimalSeparator(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 size_t CalculatorManager_MaxHistorySize(void* manager);
DLL_EXPORT int CalculatorManager_GetCurrentDegreeMode(void* manager); DLL_EXPORT int CalculatorManager_GetCurrentDegreeMode(void* manager);
DLL_EXPORT void CalculatorManager_SetInHistoryItemLoadMode(void* manager, bool isHistoryItemLoadMode); DLL_EXPORT void CalculatorManager_SetInHistoryItemLoadMode(void* manager, bool isHistoryItemLoadMode);
void* MarshalHistoryItem(std::shared_ptr<CalculationManager::HISTORYITEM>& historyItem, bool& retflag);
void* MarshalHistoryItems(std::vector<std::shared_ptr<CalculationManager::HISTORYITEM>>& 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);
} }

View file

@ -57,7 +57,7 @@ namespace CalculationManager
[DllImport("CalcManager")] [DllImport("CalcManager")]
public static extern void CalculatorManager_SetMemorizedNumbersString(IntPtr nativeManager); 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); public static extern string CalculatorManager_GetResultForRadix(IntPtr nativeManager, int radix, int precision);
[DllImport("CalcManager")] [DllImport("CalcManager")]
@ -84,6 +84,15 @@ namespace CalculationManager
[DllImport("CalcManager")] [DllImport("CalcManager")]
public static extern void CalculatorManager_SetInHistoryItemLoadMode(IntPtr nativeManager, bool isHistoryItemLoadMode); 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 IntPtr GetCEngineStringFunc(IntPtr state, string id);
public delegate void BinaryOperatorReceivedFunc(IntPtr state); public delegate void BinaryOperatorReceivedFunc(IntPtr state);
public delegate void SetPrimaryDisplayCallbackFunc(IntPtr state, string displayStringValue, bool isError); public delegate void SetPrimaryDisplayCallbackFunc(IntPtr state, string displayStringValue, bool isError);
@ -157,9 +166,8 @@ namespace CalculationManager
var numbers = new List<String>(); var numbers = new List<String>();
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
// TODO Use native encoding instead. var value = Marshal.PtrToStringUni(Marshal.ReadIntPtr(newMemorizedNumbers, i));
var value = Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(newMemorizedNumbers, i)); numbers.Add(value);
numbers.Add(Encoding.UTF8.GetString(Encoding.ASCII.GetBytes(value)));
} }
manager.SetMemorizedNumbers(numbers); manager.SetMemorizedNumbers(numbers);
@ -183,7 +191,7 @@ namespace CalculationManager
Debug.WriteLine($"CalculatorManager.BinaryOperatorReceivedCallback"); 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; var manager = GCHandle.FromIntPtr((IntPtr)state).Target as CalculatorDisplay;
manager.SetPrimaryDisplay(displayStringValue, isError); manager.SetPrimaryDisplay(displayStringValue, isError);
@ -199,22 +207,38 @@ namespace CalculationManager
Debug.WriteLine($"CalculatorManager.SetIsInErrorCallback({isError})"); 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 provider = GCHandle.FromIntPtr((IntPtr)state).Target as EngineResourceProvider;
var ret = provider.GetCEngineString(resourceId) ?? ""; var r = provider.GetCEngineString(resourceId) ?? "";
var retBytes = Encoding.UTF8.GetBytes(ret); return Marshal.StringToHGlobalUni(r);
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;
} }
} }
[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 public partial class CalculatorManager : ICalcDisplay
{ {

View file

@ -219,16 +219,62 @@ namespace CalculationManager
public char DecimalSeparator() public char DecimalSeparator()
=> NativeDispatch.CalculatorManager_DecimalSeparator(_nativeManager); => NativeDispatch.CalculatorManager_DecimalSeparator(_nativeManager);
public List<HISTORYITEM> GetHistoryItems() => throw new NotImplementedException(); public List<HISTORYITEM> GetHistoryItems()
{
var pResult = NativeDispatch.CalculatorManager_GetHistoryItems(_nativeManager);
return UnmarshalHistoryItemsResult(pResult);
}
public List<HISTORYITEM> GetHistoryItems(CalculationManager.CALCULATOR_MODE mode) public List<HISTORYITEM> GetHistoryItems(CalculationManager.CALCULATOR_MODE mode)
{ {
Debug.WriteLine($"CalculatorManager.GetHistoryItems({mode})"); var pResult = NativeDispatch.CalculatorManager_GetHistoryItemsWithMode(_nativeManager, mode);
return UnmarshalHistoryItemsResult(pResult);
return new List<HISTORYITEM>(); }
private static List<HISTORYITEM> UnmarshalHistoryItemsResult(IntPtr pResult)
{
var result = Marshal.PtrToStructure<GetHistoryItemsResult>(pResult);
var output = new List<HISTORYITEM>();
for (var i = 0; i < result.ItemsCount; i++)
{
var historyResultItem = Marshal.PtrToStructure<GetHistoryItemResult>(Marshal.ReadIntPtr(result.HistoryItems, i * Marshal.SizeOf<IntPtr>()));
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<IntPtr>()));
var tokenValue = Marshal.ReadInt32(historyResultItem.TokenValues, i * Marshal.SizeOf<int>());
historyItem.historyItemVector.spTokens.Append((tokenString, tokenValue));
}
return historyItem;
}
public HISTORYITEM GetHistoryItem(int uIdx)
{
var pResult = NativeDispatch.CalculatorManager_GetHistoryItem(_nativeManager, uIdx);
var result = Marshal.PtrToStructure<GetHistoryItemResult>(pResult);
return UnmarshalHistoryItemResult(result);
} }
public HISTORYITEM GetHistoryItem(int uIdx) => throw new NotImplementedException();
public bool RemoveHistoryItem(int uIdx) public bool RemoveHistoryItem(int uIdx)
=> NativeDispatch.CalculatorManager_RemoveHistoryItem(_nativeManager, uIdx); => NativeDispatch.CalculatorManager_RemoveHistoryItem(_nativeManager, uIdx);

View file

@ -100,7 +100,7 @@ namespace CalculatorApp
{ {
if (m_historyCallbackReference != null) if (m_historyCallbackReference != null)
{ {
if (m_callbackReference.Target is ViewModel.HistoryViewModel historyVM) if (m_historyCallbackReference.Target is ViewModel.HistoryViewModel historyVM)
{ {
historyVM.OnHistoryItemAdded(addedItemIndex); historyVM.OnHistoryItemAdded(addedItemIndex);
} }

View file

@ -306,7 +306,7 @@ namespace CalculatorApp
try try
{ {
serializedHistoryItem = SerializeHistoryItem(it); serializedHistoryItem = SerializeHistoryItem(it);
historyContainer.Values.Add(index.ToString(), serializedHistoryItem); historyContainer.Values[index.ToString()] = serializedHistoryItem;
} }
catch (Exception e) catch (Exception e)
{ {