[dasher: 138/217] XML settings implementation for Windows with '/Config file.xml' command line option.



commit cd31d2d696aa3c04b4ddc364ec903dab504c1dac
Author: unknown <lbaudoin google com>
Date:   Tue Dec 8 20:57:16 2015 -0700

    XML settings implementation for Windows with '/Config file.xml' command line option.

 Src/DasherCore/DasherCore_vc2013.vcxproj |    2 +
 Src/DasherCore/XmlSettingsStore.cpp      |   14 ++-
 Src/Win32/AppSettings.cpp                |  312 +++---------------------------
 Src/Win32/AppSettings.h                  |   57 +-----
 Src/Win32/Common/WinOptions.cpp          |   46 -----
 Src/Win32/Common/WinOptions.h            |    5 -
 Src/Win32/Common/WinUTF8.cpp             |   28 ++-
 Src/Win32/Common/WinUTF8.h               |    4 +
 Src/Win32/Dasher.cpp                     |    4 +-
 Src/Win32/Dasher.h                       |    2 +-
 Src/Win32/DasherWindow.cpp               |   38 +++-
 Src/Win32/DasherWindow.h                 |    7 +-
 Src/Win32/WinMain.cpp                    |   18 ++-
 13 files changed, 125 insertions(+), 412 deletions(-)
---
diff --git a/Src/DasherCore/DasherCore_vc2013.vcxproj b/Src/DasherCore/DasherCore_vc2013.vcxproj
index 9a38ee8..eaa6149 100644
--- a/Src/DasherCore/DasherCore_vc2013.vcxproj
+++ b/Src/DasherCore/DasherCore_vc2013.vcxproj
@@ -284,6 +284,7 @@
     <ClCompile Include="UserLogParam.cpp" />
     <ClCompile Include="UserLogTrial.cpp" />
     <ClCompile Include="WordGeneratorBase.cpp" />
+    <ClCompile Include="XmlSettingsStore.cpp" />
     <ClCompile Include="XMLUtil.cpp" />
   </ItemGroup>
   <ItemGroup>
@@ -367,6 +368,7 @@
     <ClInclude Include="UserLogParam.h" />
     <ClInclude Include="UserLogTrial.h" />
     <ClInclude Include="WordGeneratorBase.h" />
+    <ClInclude Include="XmlSettingsStore.h" />
     <ClInclude Include="XMLUtil.h" />
   </ItemGroup>
   <ItemGroup>
diff --git a/Src/DasherCore/XmlSettingsStore.cpp b/Src/DasherCore/XmlSettingsStore.cpp
index f9a6914..02c212a 100644
--- a/Src/DasherCore/XmlSettingsStore.cpp
+++ b/Src/DasherCore/XmlSettingsStore.cpp
@@ -4,6 +4,16 @@
 #include <fstream>
 #include <string.h>
 #include <algorithm>
+#include <locale>
+#include <codecvt>
+
+#if defined(_WIN32) || defined(_WIN64) 
+#include "WinUTF8.h"
+#define strcasecmp _stricmp 
+#define widen(a) WinUTF8::widen(a)
+#else
+#define widen((a)) (a)
+#endif
 
 namespace Dasher {
 namespace {
@@ -27,7 +37,7 @@ XmlSettingsStore::XmlSettingsStore(const std::string& filename,
 
 bool XmlSettingsStore::Load() {
   bool result = true;
-  std::ifstream f(filename_);
+  std::ifstream f(widen(filename_));
   if (f.good()) {
     f.close();
     if (!ParseFile(filename_, true /* user */)) {
@@ -88,7 +98,7 @@ bool XmlSettingsStore::Save() {
   try {
     modified_ = false;
     std::ofstream out;
-    out.open(filename_, std::ios::out | std::ios::trunc);
+    out.open(widen(filename_), std::ios::out | std::ios::trunc);
     out << "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
     out << "<settings>\n";
     for (const auto& p : long_settings_) {
diff --git a/Src/Win32/AppSettings.cpp b/Src/Win32/AppSettings.cpp
index 420ae24..a8f01b4 100644
--- a/Src/Win32/AppSettings.cpp
+++ b/Src/Win32/AppSettings.cpp
@@ -1,5 +1,7 @@
 #include "WinCommon.h"
 
+#include <stdio.h>
+
 #include ".\AppSettings.h"
 #include "../Common/AppSettingsData.h"
 #include ".\Dasher.h"
@@ -8,147 +10,49 @@
 using namespace WinUTF8;
 using namespace std;
 
-CAppSettings::CAppSettings(Dasher::CDasher *pDasher, HWND hWnd)
+CAppSettings::CAppSettings(Dasher::CDasher *pDasher, HWND hWnd, Dasher::CSettingsStore* settings_store) : 
settings_store_(settings_store)
 {
   m_hWnd = hWnd;
   m_pDasher = pDasher;
 
-  // Initialise registry stuff
-
- // Windows requires strings as Tstring
-  Tstring TGroup, TProduct;
-  UTF8string_to_wstring("Inference Group", TGroup);
-  UTF8string_to_wstring("Dasher3", TProduct);
-
-  // Get hold of HKEY_CURRENT_USER\Software
-  HKEY SoftwareKey;
-  if(GetOrCreate(HKEY_CURRENT_USER, TEXT("Software"), KEY_WRITE, &SoftwareKey) != 0) {
-    // Can't open or create key - do something...
-    // Probably flag registry as failed and just return default options
-    exit(1);                    // give up for now.
-  }
-
-  // Then HKEY_CURRENT_USER\Software\<Group>
-  HKEY GroupKey;
-  if(GetOrCreate(SoftwareKey, TGroup.c_str(), KEY_WRITE, &GroupKey) != 0) {
-    exit(1);
-  }
-  RegCloseKey(SoftwareKey);
-
-  // Then HKEY_CURRENT_USER\Software\<Group>\<Product>
-  if(GetOrCreate(GroupKey, TProduct.c_str(), KEY_ALL_ACCESS, &ProductKey) != 0) {
-    exit(1);
-  }
-  RegCloseKey(GroupKey);
-
- // ---
-
-
-  m_pBoolTable = new bp_info[NUM_OF_APP_BPS];
-  m_pLongTable = new lp_info[NUM_OF_APP_LPS];
-  m_pStringTable = new sp_info[NUM_OF_APP_SPS];
-
-  for(int ii = 0; ii < NUM_OF_APP_BPS; ii++) {
-    m_pBoolTable[ii].key = app_boolparamtable[ii].key;
-    if(!LoadSetting(app_boolparamtable[ii].regName, &m_pBoolTable[ii].value))
-      m_pBoolTable[ii].value = app_boolparamtable[ii].defaultValue;
-    m_pBoolTable[ii].defaultVal = app_boolparamtable[ii].defaultValue;
-    m_pBoolTable[ii].humanReadable = app_boolparamtable[ii].humanReadable;
-    m_pBoolTable[ii].persistent = app_boolparamtable[ii].persistent == Persistence::PERSISTENT;
-    m_pBoolTable[ii].regName = app_boolparamtable[ii].regName;
-  } 
-    
-  for(int ii = 0; ii < NUM_OF_APP_LPS; ii++) {
-    m_pLongTable[ii].key = app_longparamtable[ii].key;
-    if(!LoadSetting(app_longparamtable[ii].regName, &m_pLongTable[ii].value))
-      m_pLongTable[ii].value = app_longparamtable[ii].defaultValue;
-    m_pLongTable[ii].defaultVal = app_longparamtable[ii].defaultValue;
-    m_pLongTable[ii].humanReadable = app_longparamtable[ii].humanReadable;
-    m_pLongTable[ii].persistent = app_longparamtable[ii].persistent == Persistence::PERSISTENT;
-    m_pLongTable[ii].regName = app_longparamtable[ii].regName;
-  }
-
-  for(int ii = 0; ii < NUM_OF_APP_SPS; ii++) {
-    m_pStringTable[ii].key = app_stringparamtable[ii].key;
-    if(!LoadSetting(app_stringparamtable[ii].regName, &m_pStringTable[ii].value))
-      m_pStringTable[ii].value = app_stringparamtable[ii].defaultValue;
-    m_pStringTable[ii].defaultVal = app_stringparamtable[ii].defaultValue;
-    m_pStringTable[ii].humanReadable = app_stringparamtable[ii].humanReadable;
-    m_pStringTable[ii].persistent = app_stringparamtable[ii].persistent == Persistence::PERSISTENT;
-    m_pStringTable[ii].regName = app_stringparamtable[ii].regName;
-  }
+  settings_store_->AddParameters(app_boolparamtable, NUM_OF_APP_BPS);
+  settings_store_->AddParameters(app_longparamtable, NUM_OF_APP_LPS);
+  settings_store_->AddParameters(app_stringparamtable, NUM_OF_APP_SPS);
 }
 
 CAppSettings::~CAppSettings(void)
 {
-  RegCloseKey(ProductKey);
-
-  delete[] m_pBoolTable;
-  delete[] m_pLongTable;
-  delete[] m_pStringTable;
 }
 
 bool CAppSettings::GetBoolParameter(int iParameter) {
-  if( iParameter < END_OF_BPS )
-    return m_pDasher->GetBoolParameter(iParameter);
-  else
-    return m_pBoolTable[iParameter - FIRST_APP_BP].value;
+  return settings_store_->GetBoolParameter(iParameter);
 }
 
 void CAppSettings::SetBoolParameter(int iParameter, bool bValue) {
-  if( iParameter < END_OF_BPS )
-    m_pDasher->SetBoolParameter(iParameter , bValue);
-  else {
-    m_pBoolTable[iParameter - FIRST_APP_BP].value = bValue;
-    SaveSetting(m_pBoolTable[iParameter - FIRST_APP_BP].regName, bValue);
-
-    m_pDasher->HandleEvent(iParameter);
-  }
+  settings_store_->SetBoolParameter(iParameter, bValue);
+  m_pDasher->HandleEvent(iParameter);
 }
 
 long CAppSettings::GetLongParameter(int iParameter) {
-  if( iParameter < END_OF_LPS)
-    return m_pDasher->GetLongParameter(iParameter);
-  else
-    return m_pLongTable[iParameter - FIRST_APP_LP].value;
+  return settings_store_->GetLongParameter(iParameter);
 }
 
 void CAppSettings::SetLongParameter(int iParameter, long iValue) {
-  if( iParameter < END_OF_LPS )
-    m_pDasher->SetLongParameter(iParameter, iValue);
-  else {
-    m_pLongTable[iParameter - FIRST_APP_LP].value = iValue;
-    SaveSetting(m_pLongTable[iParameter - FIRST_APP_LP].regName, iValue); 
-    m_pDasher->HandleEvent(iParameter);
-  }
+  settings_store_->SetLongParameter(iParameter, iValue);
+  m_pDasher->HandleEvent(iParameter);
 }
 
 std::string CAppSettings::GetStringParameter(int iParameter) {
-  if(iParameter < END_OF_SPS)
-    return m_pDasher->GetStringParameter(iParameter);
-  else
-    return m_pStringTable[iParameter - FIRST_APP_SP].value;
+  return settings_store_->GetStringParameter(iParameter);
 }
 
 void CAppSettings::SetStringParameter(int iParameter, const std::string &strValue) {
-  if(iParameter < END_OF_SPS)
-    m_pDasher->SetStringParameter(iParameter, strValue);
-  else {
-    m_pStringTable[iParameter - FIRST_APP_SP].value = strValue;
-    SaveSetting(m_pStringTable[iParameter - FIRST_APP_SP].regName, strValue);
-    m_pDasher->HandleEvent(iParameter);
-  }
+  settings_store_->SetStringParameter(iParameter, strValue);
+  m_pDasher->HandleEvent(iParameter);
 }
 
 void CAppSettings::ResetParamater(int iParameter) {
-  if(iParameter < END_OF_SPS)
-    m_pDasher->ResetParameter(iParameter);
-  else if(iParameter < END_OF_APP_BPS)
-    SetBoolParameter(iParameter, app_boolparamtable[iParameter - FIRST_APP_BP].defaultValue);
-  else if(iParameter < END_OF_APP_LPS)
-    SetLongParameter(iParameter, app_longparamtable[iParameter - FIRST_APP_LP].defaultValue);
-  else
-    SetStringParameter(iParameter, app_stringparamtable[iParameter - FIRST_APP_SP].defaultValue);
+  settings_store_->ResetParameter(iParameter);
 }
 
 void CAppSettings::GetPermittedValues(int iParameter, vector<string> &vList) {
@@ -158,205 +62,41 @@ void CAppSettings::GetPermittedValues(int iParameter, vector<string> &vList) {
   m_pDasher->GetPermittedValues(iParameter,vList);
 }
 
-// Functions for accessing persistent storage (stolen from WinOptions)
-
-bool CAppSettings::LoadSetting(const std::string &Key, bool *Value) {
-  Tstring TKey;
-  UTF8string_to_wstring(Key, TKey);
-  BYTE *Data = 0;
-
-  if(!GetlpByte(TKey, &Data)) {
-    delete[]Data;
-    return false;
-  }
-
-  if((DWORD) * Data == 0)
-    *Value = false;
-  else
-    *Value = true;
-
-  delete[]Data;
-  return true;
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-bool CAppSettings::LoadSetting(const std::string &Key, long *Value) {
-  Tstring TKey;
-  UTF8string_to_wstring(Key, TKey);
-  BYTE *Data = 0;
-
-  if(!GetlpByte(TKey, &Data)) {
-    delete[]Data;
-    return false;
-  }
-
-  // Evil casting to make sure I can retrieve signed longs, even
-  // though windows registry only stores +ve values.
-  *Value = *((long *)Data);
-  delete[]Data;
-  return true;
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-bool CAppSettings::LoadSettingT(const std::string &Key, Tstring *TValue) {
-  Tstring TKey;
-  UTF8string_to_wstring(Key, TKey);
-  BYTE *Data = 0;
-
-  if(!GetlpByte(TKey, &Data)) {
-    delete[]Data;
-    return false;
-  }
-
-  *TValue = (TCHAR *) Data;
-  delete[]Data;
-
-  return true;
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-bool CAppSettings::LoadSetting(const std::string &Key, std::string *Value) {
-
-  Tstring str;
-  if(LoadSettingT(Key, &str)) {
-    wstring_to_UTF8string(str, *Value);
-    return true;
-
-  }
-  return false;
-
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-static TCHAR FormatWindowPlacement[] = TEXT("%u,%u,%d,%d,%d,%d,%d,%d,%d,%d,%d");
+static const char FormatWindowPlacement[] = "%u,%u,%d,%d,%d,%d,%d,%d,%d,%d,%d";
 
 /////////////////////////////////////////////////////////////////////////////
 #ifndef _WIN32_WCE
 
-void CAppSettings::SaveSetting(const std::string &Key, const LPWINDOWPLACEMENT pwp, int sp) {
+void CAppSettings::SaveWindowPlacement(int iParameter, const LPWINDOWPLACEMENT pwp, int sp) {
   DASHER_ASSERT(pwp != NULL);
 
-  TCHAR t[200];
-  _stprintf(t, FormatWindowPlacement, pwp->flags, pwp->showCmd, pwp->ptMinPosition.x, pwp->ptMinPosition.y, 
pwp->ptMaxPosition.x, pwp->ptMaxPosition.y, pwp->rcNormalPosition.left, pwp->rcNormalPosition.top, 
pwp->rcNormalPosition.right, pwp->rcNormalPosition.bottom,sp);
-
-  Tstring ts(t);
-  SaveSettingT(Key, ts);
-
+  char t[200];
+  sprintf_s(t, sizeof(t), FormatWindowPlacement, pwp->flags, pwp->showCmd, pwp->ptMinPosition.x, 
pwp->ptMinPosition.y, pwp->ptMaxPosition.x, pwp->ptMaxPosition.y, pwp->rcNormalPosition.left, 
pwp->rcNormalPosition.top, pwp->rcNormalPosition.right, pwp->rcNormalPosition.bottom,sp);
+  SetStringParameter(iParameter, t);
 }
 
 /////////////////////////////////////////////////////////////////////////////
 
-bool CAppSettings::LoadSetting(const std::string &Key, LPWINDOWPLACEMENT pwp, int* psp) {
+bool CAppSettings::LoadWindowPlacement(int iParameter, LPWINDOWPLACEMENT pwp, int* psp) {
   DASHER_ASSERT(pwp != NULL);
 
-  Tstring str;
-
-  if(!LoadSettingT(Key, &str))
+  auto str = GetStringParameter(iParameter);
+  if (str.empty())
     return false;
 
   WINDOWPLACEMENT wp;
-  int nRead = _stscanf(str.c_str(), FormatWindowPlacement,
+  int nRead = sscanf_s(str.c_str(), FormatWindowPlacement,
                        &wp.flags, &wp.showCmd,
                        &wp.ptMinPosition.x, &wp.ptMinPosition.y,
                        &wp.ptMaxPosition.x, &wp.ptMaxPosition.y,
                        &wp.rcNormalPosition.left, &wp.rcNormalPosition.top,
                        &wp.rcNormalPosition.right, &wp.rcNormalPosition.bottom, psp);
 
-  if(nRead < 10)
+  if(nRead != 11)
     return false;
   wp.length = sizeof(wp);
-
   *pwp = wp;
   return true;
-
 }
 
 #endif
-/////////////////////////////////////////////////////////////////////////////
-
-void CAppSettings::SaveSetting(const std::string &Key, bool Value) {
-  if(Value)
-    SaveSetting(Key, 1l);
-  else
-    SaveSetting(Key, 0l);
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CAppSettings::SaveSetting(const std::string &Key, long Value) {
-  Tstring TKey;
-  UTF8string_to_wstring(Key, TKey);
-  // Evil casting. Registry stores DWORD's (unsigned longs)
-  // I'm forcing in signed longs and if I force them out again in the same
-  // way I should get a sensible result.
-  DWORD *RegValue = (DWORD *) & Value;
-  DWORD MemAllow = sizeof(DWORD);
-  LONG ErrVal = RegSetValueEx(ProductKey, TKey.c_str(), 0,
-                              REG_DWORD, (const unsigned char *)RegValue, MemAllow);
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CAppSettings::SaveSettingT(const std::string &Key, const Tstring &TValue) {
-  Tstring TKey;
-  UTF8string_to_wstring(Key, TKey);
-
-  DWORD MemAllow = (TValue.size() + 1) * sizeof(TCHAR);
-
-  //const unsigned char* StrInput = (const unsigned char*) Value.c_str();
-  //LONG ErrVal = RegSetValueEx(ProductKey, TKey.c_str(), 0,
-  //      REG_SZ, StrInput, MemAllow);
-
-  LONG ErrVal = RegSetValueEx(ProductKey, TKey.c_str(), 0,
-                              REG_SZ, (CONST BYTE *) TValue.c_str(), MemAllow);
-
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void CAppSettings::SaveSetting(const std::string &Key, const std::string &Value) {
-
-  // DJW20031107 - i think Values should also be converted to Tstring
-  Tstring TValue;
-  UTF8string_to_wstring(Value, TValue);
-
-  SaveSettingT(Key, TValue);
-}
-
-// Used for getting a handle on the Dasher key in the constructor.
-int CAppSettings::GetOrCreate(HKEY hKey, LPCTSTR lpSubKey, REGSAM samDesired, HKEY *lpNewKey) {
-  if(!(RegOpenKeyEx(hKey, lpSubKey, 0, samDesired, lpNewKey) == ERROR_SUCCESS)) {
-
-    if(!(RegCreateKeyEx(hKey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, samDesired, NULL, lpNewKey, NULL) 
== ERROR_SUCCESS)) {
-
-      return (1);
-    }
-  }
-  return 0;
-}
-
-bool CAppSettings::GetlpByte(const Tstring &Key, BYTE **Data) const {
-  *Data = new BYTE[1];
-  unsigned long datasize = sizeof(BYTE[1]);
-  DWORD Type;
-
-  LONG ErrVal = RegQueryValueEx(ProductKey, Key.c_str(), 0, &Type, *Data, &datasize);
-  while(ErrVal == ERROR_MORE_DATA) {
-    delete[] * Data;
-    *Data = new BYTE[datasize];
-    ErrVal = RegQueryValueEx(ProductKey, Key.c_str(), 0, &Type, *Data, &datasize);
-  }
-
-  // Perhaps I should spend lots of time working out why the registry doesn't work.
-  // when this fails. Would probably just confuse users though. Users with a broken
-  // registry can live with defaults :)
-  if((ErrVal == ERROR_SUCCESS) && (*Data != 0))
-    return true;
-  else
-    return false;
-}
-
diff --git a/Src/Win32/AppSettings.h b/Src/Win32/AppSettings.h
index 5753a43..1d9f203 100644
--- a/Src/Win32/AppSettings.h
+++ b/Src/Win32/AppSettings.h
@@ -1,7 +1,9 @@
 #pragma once
 
 #include "../Common/AppSettingsHeader.h"
+#include "../DasherCore/SettingsStore.h"
 
+#include <memory>
 #include <vector>
 #include <string>
 
@@ -28,8 +30,8 @@ namespace Dasher {
 class CAppSettings
 {
 public:
-
-  CAppSettings(Dasher::CDasher *pDasher, HWND hWnd);
+  // The constructor takes ownership of the settings_store.   
+  CAppSettings(Dasher::CDasher *pDasher, HWND hWnd, Dasher::CSettingsStore* settings_store);
   ~CAppSettings(void);
 
   ///
@@ -48,8 +50,8 @@ public:
   void GetPermittedValues(int iParameter, std::vector<std::string> &vList);
 
   #ifndef _WIN32_WCE
-  bool LoadSetting(const std::string & Key, LPWINDOWPLACEMENT pwp, int* psp);
-  void SaveSetting(const std::string & Key, const LPWINDOWPLACEMENT pwp, int sp);
+  bool LoadWindowPlacement(int iParameter, LPWINDOWPLACEMENT pwp, int* psp);
+  void SaveWindowPlacement(int iParameter, const LPWINDOWPLACEMENT pwp, int sp);
   #endif
 
   void SetHwnd(HWND hWnd) {
@@ -62,54 +64,9 @@ public:
   };
 
 private:
-  struct bp_info {
-    int key;
-    std::string regName;
-    bool persistent;
-    bool value;
-    bool defaultVal;
-    std::string humanReadable;
-  };
-  struct lp_info {
-    int key;
-    std::string regName;
-    bool persistent;
-    long value;
-    long defaultVal;
-    std::string humanReadable;
-  };
-  struct sp_info {
-    int key;
-    std::string regName;
-    bool persistent;
-    std::string value;
-    std::string defaultVal;
-    std::string humanReadable;
-  };
-
-  bp_info *m_pBoolTable;
-  lp_info *m_pLongTable;
-  sp_info *m_pStringTable;
 
   Dasher::CDasher *m_pDasher;
   HWND m_hWnd;
 
-  bool LoadSetting(const std::string & Key, bool * Value);
-  bool LoadSetting(const std::string & Key, long *Value);
-  bool LoadSetting(const std::string & Key, std::string * Value);
-  bool LoadSettingT(const std::string & Key, Tstring * Value);
-
-  void SaveSetting(const std::string & Key, bool Value);
-  void SaveSetting(const std::string & Key, long Value);
-  void SaveSetting(const std::string & Key, const std::string & Value);
-
-  void SaveSettingT(const std::string & Key, const Tstring & TValue);
-
-  // Platform Specific helpers
-  HKEY ProductKey;
-  int GetOrCreate(HKEY hKey, LPCTSTR lpSubKey, REGSAM samDesired, HKEY * lpNewKey);
-  // CARE! Users of GetlpByte must call delete[] on *Data after use.
-  bool GetlpByte(const Tstring & key, BYTE ** Data) const;
-
-
+  std::unique_ptr<Dasher::CSettingsStore> settings_store_;
 };
diff --git a/Src/Win32/Common/WinOptions.cpp b/Src/Win32/Common/WinOptions.cpp
index b1a124a..3ab0f75 100644
--- a/Src/Win32/Common/WinOptions.cpp
+++ b/Src/Win32/Common/WinOptions.cpp
@@ -133,52 +133,6 @@ bool CWinOptions::LoadSetting(const std::string &Key, std::string *Value) {
 
 /////////////////////////////////////////////////////////////////////////////
 
-static TCHAR FormatWindowPlacement[] = TEXT("%u,%u,%d,%d,%d,%d,%d,%d,%d,%d");
-
-/////////////////////////////////////////////////////////////////////////////
-#ifndef _WIN32_WCE
-
-void CWinOptions::SaveSetting(const std::string &Key, const LPWINDOWPLACEMENT pwp) {
-  DASHER_ASSERT(pwp != NULL);
-
-  TCHAR t[200];
-  _stprintf(t, FormatWindowPlacement, pwp->flags, pwp->showCmd, pwp->ptMinPosition.x, pwp->ptMinPosition.y, 
pwp->ptMaxPosition.x, pwp->ptMaxPosition.y, pwp->rcNormalPosition.left, pwp->rcNormalPosition.top, 
pwp->rcNormalPosition.right, pwp->rcNormalPosition.bottom);
-
-  Tstring ts(t);
-  SaveSettingT(Key, ts);
-
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-bool CWinOptions::LoadSetting(const std::string &Key, LPWINDOWPLACEMENT pwp) {
-  DASHER_ASSERT(pwp != NULL);
-
-  Tstring str;
-
-  if(!LoadSettingT(Key, &str))
-    return false;
-
-  WINDOWPLACEMENT wp;
-  int nRead = _stscanf(str.c_str(), FormatWindowPlacement,
-                       &wp.flags, &wp.showCmd,
-                       &wp.ptMinPosition.x, &wp.ptMinPosition.y,
-                       &wp.ptMaxPosition.x, &wp.ptMaxPosition.y,
-                       &wp.rcNormalPosition.left, &wp.rcNormalPosition.top,
-                       &wp.rcNormalPosition.right, &wp.rcNormalPosition.bottom);
-
-  if(nRead != 10)
-    return false;
-  wp.length = sizeof(wp);
-
-  *pwp = wp;
-  return true;
-
-}
-
-#endif
-/////////////////////////////////////////////////////////////////////////////
-
 void CWinOptions::SaveSetting(const std::string &Key, bool Value) {
   if(Value)
     SaveSetting(Key, 1l);
diff --git a/Src/Win32/Common/WinOptions.h b/Src/Win32/Common/WinOptions.h
index 2aa7ca1..6a7faf6 100644
--- a/Src/Win32/Common/WinOptions.h
+++ b/Src/Win32/Common/WinOptions.h
@@ -22,11 +22,6 @@ public:
   CWinOptions(const std::string & Group, const std::string & Product);
    ~CWinOptions();
 
-#ifndef _WIN32_WCE
-  bool LoadSetting(const std::string & Key, LPWINDOWPLACEMENT pwp);
-  void SaveSetting(const std::string & Key, const LPWINDOWPLACEMENT pwp);
-#endif
-
 private:
   // Platform Specific settings file management
     bool LoadSetting(const std::string & Key, bool * Value);
diff --git a/Src/Win32/Common/WinUTF8.cpp b/Src/Win32/Common/WinUTF8.cpp
index 3c548da..9e5b7d8 100644
--- a/Src/Win32/Common/WinUTF8.cpp
+++ b/Src/Win32/Common/WinUTF8.cpp
@@ -6,6 +6,9 @@
 //
 /////////////////////////////////////////////////////////////////////////////
 
+#include <locale>
+#include <codecvt>
+
 #include "WinCommon.h"
 
 #include "WinUTF8.h"
@@ -75,16 +78,21 @@ string WinUTF8::wstring_to_UTF8string(const wchar_t *Input) {
 }
 
 void WinUTF8::wstring_to_UTF8string(const wchar_t *Input, string &Output) {
+    size_t len = wcslen(Input);
+  int size_needed = WideCharToMultiByte(CP_UTF8, 0, Input, len, nullptr, 0, nullptr, nullptr);
+  Output.resize(size_needed);
+  WideCharToMultiByte(CP_UTF8, 0, Input, (int)Output.size(), &Output[0], size_needed, NULL, NULL);
+  return;
+}
 
-  const std::size_t BufferSize = wcslen(Input) + 1;
-  const wchar_t *Buffer = Input;
-
-  const std::size_t BufferSize2 = BufferSize * 2;
-  char *Buffer2 = new char[BufferSize2];
-
-  WideCharToMultiByte(CP_UTF8, 0, Buffer, -1, Buffer2, BufferSize2, NULL, NULL);
+std::wstring_convert<std::codecvt_utf8<wchar_t, 0x10ffff, std::consume_header>, wchar_t> utf16conv;
+std::wstring WinUTF8::widen(const char* utf8) {
+  return utf16conv.from_bytes(utf8);
+}
+std::wstring WinUTF8::widen(const std::string& utf8) {
+    return utf16conv.from_bytes(utf8);
+}
 
-  Output = Buffer2;
-  delete[]Buffer2;
-  return;
+std::string WinUTF8::narrow(const wchar_t* wide) {
+  return utf16conv.to_bytes(wide).substr(3);  // Remove the BOM.
 }
diff --git a/Src/Win32/Common/WinUTF8.h b/Src/Win32/Common/WinUTF8.h
index 40c7d8f..cef6543 100644
--- a/Src/Win32/Common/WinUTF8.h
+++ b/Src/Win32/Common/WinUTF8.h
@@ -25,5 +25,9 @@ namespace WinUTF8 {
   void wstring_to_UTF8string(const std::wstring & Input, std::string & Output);
   void wstring_to_UTF8string(const wchar_t *Input, std::string &Output);
   std::string wstring_to_UTF8string(const wchar_t* Input);
+
+  std::wstring widen(const char* utf8);
+  std::wstring widen(const std::string& utf8);
+  std::string narrow(const wchar_t* wide);
 }
 #endif                          /* #ifndef __WinUTF8_h__ */
diff --git a/Src/Win32/Dasher.cpp b/Src/Win32/Dasher.cpp
index 1769e3b..a307e2c 100644
--- a/Src/Win32/Dasher.cpp
+++ b/Src/Win32/Dasher.cpp
@@ -32,8 +32,8 @@ using namespace WinUTF8;
 
 CONST UINT WM_DASHER_FOCUS = RegisterWindowMessage(L"WM_DASHER_FOCUS");
 
-CDasher::CDasher(HWND Parent, CDasherWindow *pWindow, CEdit *pEdit)
- : CDashIntfScreenMsgs(new CWinOptions( "Inference Group", "Dasher3")), m_hParent(Parent), 
m_pWindow(pWindow), m_pEdit(pEdit) {
+CDasher::CDasher(HWND Parent, CDasherWindow *pWindow, CEdit *pEdit, Dasher::CSettingsStore* settings)
+ : CDashIntfScreenMsgs(settings), m_hParent(Parent), m_pWindow(pWindow), m_pEdit(pEdit) {
   // This class will be a wrapper for the Dasher 'control' - think ActiveX
 
 #ifndef _WIN32_WCE
diff --git a/Src/Win32/Dasher.h b/Src/Win32/Dasher.h
index 01a9146..ed21aa2 100644
--- a/Src/Win32/Dasher.h
+++ b/Src/Win32/Dasher.h
@@ -26,7 +26,7 @@ namespace Dasher {
 class CDasher : public CDashIntfScreenMsgs
 {
 public:
-  CDasher(HWND Parent, CDasherWindow *pWindow, CEdit *pEdit);
+  CDasher(HWND Parent, CDasherWindow *pWindow, CEdit *pEdit, Dasher::CSettingsStore* settings);
   ~CDasher(void);
 
   // The following functions will not be part of the final interface
diff --git a/Src/Win32/DasherWindow.cpp b/Src/Win32/DasherWindow.cpp
index 1b47e04..4d84f83 100644
--- a/Src/Win32/DasherWindow.cpp
+++ b/Src/Win32/DasherWindow.cpp
@@ -25,6 +25,8 @@
 
 #include "Widgets/Toolbar.h"
 #include "WinCommon.h"
+#include "WinOptions.h"
+#include "../DasherCore/XmlSettingsStore.h"
 #include <windows.h>
 #include "resource.h"
 
@@ -35,11 +37,23 @@ using namespace std;
 
 #define IDT_TIMER1 200
 
+namespace {
+class XmlErrorDisplay : public CMessageDisplay {
+public:
+    void Message(const std::string &strText, bool bInterrupt) override {
+        std::wstring text;
+        WinUTF8::UTF8string_to_wstring(strText, text);
+        // TODO: find a way to localize.
+        MessageBox(nullptr, text.c_str(), L"Configuration Error", MB_ICONERROR|MB_ICONSTOP);
+    }
+};
+} // namespace
+
 // NOTE: There were previously various bits and pieces in this class from 
 // text services framework stuff, which were never really finished. If
 // required, look in version control history (prior to May 2007).
 
-CDasherWindow::CDasherWindow() {
+CDasherWindow::CDasherWindow(const CString& xml_config_file) : xml_config_file_(xml_config_file) {
   m_bFullyCreated = false;
   m_pAppSettings = 0;
   m_pToolbar = 0;
@@ -66,7 +80,21 @@ HWND CDasherWindow::Create() {
   Tstring WindowTitle;
   WinLocalisation::GetResourceString(IDS_APP_TITLE, &WindowTitle);
 
-  m_pAppSettings = new CAppSettings(0, 0);
+  static XmlErrorDisplay display;
+  Dasher::CSettingsStore* settings;
+  if (xml_config_file_.IsEmpty()) {
+      settings = new CWinOptions("Inference Group", "Dasher3");
+  }
+  else {
+      std::string utf8_path = WinUTF8::narrow(xml_config_file_);
+      auto xml_settings = new Dasher::XmlSettingsStore(utf8_path, &display);
+      xml_settings->Load();
+      // Save the defaults if needed.
+      xml_settings->Save();
+      settings = xml_settings;
+  }
+
+  m_pAppSettings = new CAppSettings(0, 0, settings);  // Takes ownership of the settings store.
   int iStyle(m_pAppSettings->GetLongParameter(APP_LP_STYLE));
 
   HWND hWnd;
@@ -85,7 +113,7 @@ HWND CDasherWindow::Create() {
   m_pEdit->Create(hWnd, m_pAppSettings->GetBoolParameter(APP_BP_TIME_STAMP));
   m_pEdit->SetFont(m_pAppSettings->GetStringParameter(APP_SP_EDIT_FONT), 
m_pAppSettings->GetLongParameter(APP_LP_EDIT_FONT_SIZE));
 
-  m_pDasher = new CDasher(hWnd, this, m_pEdit);
+  m_pDasher = new CDasher(hWnd, this, m_pEdit, settings);
 
   // Create a CAppSettings
   m_pAppSettings->SetHwnd(hWnd);
@@ -130,14 +158,14 @@ void CDasherWindow::SaveWindowState() const {
   wp.length = sizeof(WINDOWPLACEMENT);
 
   if (GetWindowPlacement(&wp)) {//function call succeeds
-    m_pAppSettings->SaveSetting("WindowState", &wp, m_pSplitter->GetPos());
+    m_pAppSettings->SaveWindowPlacement(APP_SP_WINDOW_STATE, &wp, m_pSplitter->GetPos());
   }
 }
 
 bool CDasherWindow::LoadWindowState() {
   WINDOWPLACEMENT wp;
   int splitterPos = -1;
-  if (m_pAppSettings->LoadSetting("WindowState", &wp, &splitterPos)) {
+  if (m_pAppSettings->LoadWindowPlacement(APP_SP_WINDOW_STATE, &wp, &splitterPos)) {
     if (splitterPos != -1) {
       m_pSplitter->SetPos(splitterPos);
     }
diff --git a/Src/Win32/DasherWindow.h b/Src/Win32/DasherWindow.h
index 9385169..dc77c19 100644
--- a/Src/Win32/DasherWindow.h
+++ b/Src/Win32/DasherWindow.h
@@ -9,6 +9,8 @@
 #ifndef __DasherWindow_h__
 #define __DasherWindow_h__
 
+#include <memory>
+
 #include "Widgets/Splitter.h"
 #include "Widgets/StatusControl.h"
 #include "Widgets/Edit.h"
@@ -23,7 +25,7 @@ class CDasherWindow :
        public CSplitterOwner 
 {
 public:
-       CDasherWindow();
+  CDasherWindow(const CString& xml_config_file);
        ~CDasherWindow();
 
        DECLARE_WND_CLASS(_T("DASHER"))
@@ -88,7 +90,8 @@ private:
        HICON m_hIconSm;
 
        HMENU m_hMenu;
-
+  CString xml_config_file_;
+  std::unique_ptr<Dasher::CSettingsStore> setting_store_;
        // Misc window handling
        void Layout();
 };
diff --git a/Src/Win32/WinMain.cpp b/Src/Win32/WinMain.cpp
index 58cc4f3..a7b9b21 100644
--- a/Src/Win32/WinMain.cpp
+++ b/Src/Win32/WinMain.cpp
@@ -7,7 +7,7 @@
 /////////////////////////////////////////////////////////////////////////////
 
 #include "WinCommon.h"
-
+#include <shellapi.h>
 // Visual leak detector
 // #ifdef _DEBUG
 // #include "vld/vld.h"
@@ -29,7 +29,7 @@ public:
   Control is passed to the main GUI loop, and only returns when the main window closes.
   */
   HRESULT Run(int nShowCmd){
-    m_pDasherWindow = new CDasherWindow;
+    m_pDasherWindow = new CDasherWindow(xml_config_file_);
 
     m_pDasherWindow->Create();
     m_pDasherWindow->Show(nShowCmd);
@@ -48,8 +48,20 @@ public:
     return iRet;
   };
 
-  static VOID CALLBACK HandleWinEvent(HWINEVENTHOOK hWinEventHook, DWORD event, HWND hwnd, LONG idObject, 
LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime);
+  bool ParseCommandLine(LPCTSTR lpCmdLine, HRESULT* pnRetCode) {
+         int argc;
+         auto argv = CommandLineToArgvW(lpCmdLine, &argc);
+         for (int i = 0; i < argc; ++i) {
+                   if (wcsicmp(argv[i], L"/config") == 0 && i + 1 < argc) {
+            xml_config_file_ = argv[i + 1];
+                   }
+         }
+         LocalFree(argv);
+         return CAtlExeModuleT::ParseCommandLine(lpCmdLine, pnRetCode);
+  }
 
+  static VOID CALLBACK HandleWinEvent(HWINEVENTHOOK hWinEventHook, DWORD event, HWND hwnd, LONG idObject, 
LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime);
+  CString xml_config_file_;
 } DasherApp;
 
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]