PageRenderTime 27ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/reposit/rpxl/functioncall.cpp

https://gitlab.com/hardlianotion/quantlib-old
C++ | 190 lines | 104 code | 35 blank | 51 comment | 34 complexity | 8f5f48ab49b075d6bb27e924ff85eaca MD5 | raw file
  1. /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
  2. /*
  3. Copyright (C) 2006, 2007, 2008 Eric Ehlers
  4. This file is part of QuantLib, a free-software/open-source library
  5. for financial quantitative analysts and developers - http://quantlib.org/
  6. QuantLib is free software: you can redistribute it and/or modify it
  7. under the terms of the QuantLib license. You should have received a
  8. copy of the license along with this program; if not, please email
  9. <quantlib-dev@lists.sf.net>. The license is also available online at
  10. <http://quantlib.org/license.shtml>.
  11. This program is distributed in the hope that it will be useful, but WITHOUT
  12. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  13. FOR A PARTICULAR PURPOSE. See the license for more details.
  14. */
  15. #include <rp/exception.hpp>
  16. #include <rpxl/repositoryxl.hpp>
  17. #include <rpxl/functioncall.hpp>
  18. #include <rpxl/xloper.hpp>
  19. #include <rpxl/convert_oper.hpp>
  20. #include <sstream>
  21. #include <string>
  22. namespace reposit {
  23. FunctionCall *FunctionCall::instance_ = 0;
  24. FunctionCall::FunctionCall(const std::string functionName) :
  25. functionName_(functionName),
  26. callerDimensions_(CallerDimensions::Uninitialized),
  27. error_(false) {
  28. RP_REQUIRE(!instance_, "Multiple attempts to initialize global FunctionCall object");
  29. instance_ = this;
  30. Excel(xlfCaller, &xCaller_, 0);
  31. if (xCaller_->xltype == xltypeRef || xCaller_->xltype == xltypeSRef) {
  32. Excel(xlfReftext, &xReftext_, 1, &xCaller_);
  33. refStr_ = ConvertOper(xReftext_());
  34. callerType_ = CallerType::Cell;
  35. } else if (xCaller_->xltype & xltypeErr) {
  36. callerType_ = CallerType::VBA;
  37. } else if (xCaller_->xltype == xltypeMulti) {
  38. callerType_ = CallerType::Menu;
  39. } else {
  40. callerType_ = CallerType::Unknown;
  41. }
  42. }
  43. FunctionCall::~FunctionCall() {
  44. if (!error_) {
  45. if (callerType_ == CallerType::Cell) {
  46. RepositoryXL::instance().clearError();
  47. } else if (callerType_ == CallerType::VBA || callerType_ == CallerType::Menu) {
  48. RepositoryXL::instance().clearVbaError();
  49. }
  50. }
  51. instance_ = 0;
  52. }
  53. FunctionCall &FunctionCall::instance() {
  54. RP_REQUIRE(instance_, "Attempt to reference uninitialized FunctionCall object");
  55. return *instance_;
  56. }
  57. const XLOPER *FunctionCall::callerArray() {
  58. if (!xMulti_->xltype) Excel(xlCoerce, &xMulti_, 2, &xCaller_, TempInt(xltypeMulti));
  59. return &xMulti_;
  60. }
  61. const std::string &FunctionCall::addressString() {
  62. if (address_.empty()) {
  63. Xloper xAddress;
  64. Excel(xlfGetCell, &xAddress, 2, TempNum(1), &xCaller_);
  65. address_ = ConvertOper(xAddress());
  66. }
  67. return address_;
  68. }
  69. CallerDimensions::Type FunctionCall::callerDimensions() {
  70. // Determine dimensions of calling range.
  71. // At present we're only interested in row vs. column,
  72. // this could be extended to detect scalar / matrix.
  73. if (callerDimensions_ == CallerDimensions::Uninitialized) {
  74. const XLOPER *xMulti = callerArray();
  75. if (xMulti->val.array.rows == 1 && xMulti->val.array.columns > 1)
  76. callerDimensions_ = CallerDimensions::Row;
  77. else
  78. callerDimensions_ = CallerDimensions::Column;
  79. }
  80. return callerDimensions_;
  81. }
  82. // Code to determine whether we've been called from the Excel function wizard.
  83. // This test is very expensive in terms of CPU.
  84. //
  85. // This code is based on code from MSDN and has inherited some bugs from the
  86. // MSDN version:
  87. // 1) The Function Wizard dialog is assumed to be any window of class
  88. // "bosa_sdm_XL" but that class can also indicate the "Edit->Replace" dialog
  89. // 2) The main excel parent window is identified only by the LOWORD half of its
  90. // DWORD handle
  91. //
  92. // Consequently there is the risk that this function will return false positives
  93. // i.e. we'll conclude that we've been called from the Function Wizard when in
  94. // fact we've been called while
  95. // 1) the "Edit->Replace" dialog is active
  96. // 2) some other Excel session is displaying the Function Wizard or
  97. // "Edit->Replace" dialog
  98. typedef struct {
  99. bool bFuncWiz;
  100. short hwndXLMain;
  101. } EnumStruct;
  102. // The class name of the window for the Function Wizard dialog. Various
  103. // versions of Excel may suffix this string with additional characters.
  104. #define WIZ_ID_BUF "bosa_sdm_XL"
  105. #define WIZ_ID_BUF_LEN 12
  106. // Called by EnumWindows (below) for each open window
  107. bool CALLBACK EnumProc(HWND hwnd, EnumStruct *pEnum) {
  108. // Retrieve the class name of the current window. We only want to
  109. // compare the resulting string with the "bosa_sdm_XL" value so we set
  110. // the buffer size such that any trailing characters are truncated.
  111. char class_name[WIZ_ID_BUF_LEN];
  112. GetClassName(hwnd, class_name, WIZ_ID_BUF_LEN);
  113. if (stricmp(class_name, WIZ_ID_BUF) == 0) {
  114. // Apparently this window is the Excel Function Wizard dialog.
  115. // Now check whether the ID of this window's parent matches that of
  116. // our main Excel window as returned by xlGetHwnd (below).
  117. if (LOWORD((DWORD) GetParent(hwnd)) == pEnum->hwndXLMain) {
  118. pEnum->bFuncWiz = TRUE; // We've (probably) been called from the wizard
  119. return false; // Tell EnumWindows to stop
  120. }
  121. }
  122. return true; // Tell EnumWindows to continue
  123. }
  124. short int getWinID() {
  125. // Retrieve the LOWORD half of the DWORD handle
  126. // of the main Excel window.
  127. XLOPER xHwndMain;
  128. Excel(xlGetHwnd, &xHwndMain, 0);
  129. return xHwndMain.val.w;
  130. }
  131. bool FunctionCall::calledByFunctionWizard() {
  132. // ID of the main Excel window. This value is retrieved once
  133. // for this running instance of the Addin.
  134. static short int winID = getWinID();
  135. // Call EnumWindows which iteratively calls EnumProc which sets
  136. // enm.bFuncWiz if the Excel Function Wizard dialog is detected.
  137. EnumStruct enm = { false, winID };
  138. EnumWindows((WNDENUMPROC)EnumProc, (LPARAM)&enm);
  139. return enm.bFuncWiz;
  140. }
  141. std::string FunctionCall::callerName() const {
  142. if (callerType_ == CallerType::Cell) {
  143. Xloper xName;
  144. Excel(xlfGetDef, &xName, 1, FunctionCall::instance().callerAddress());
  145. if (xName->xltype == xltypeStr)
  146. return ConvertOper(xName());
  147. return "";
  148. } else {
  149. return "VBA";
  150. }
  151. }
  152. }