9

I have the following function contained in a DLL I wrote (c++) that I debugged in Excel, and worked just fine:

float _stdcall ReturnT(LPCSTR FileName)
{

// Extracts the generic language string from the (importing BSTR  
// would import kanji or whatever) and converts it into a wstring
wstring str = CA2T(FileName);

// Sets the string to find as _t or _T followed by 2 or 3 digits and a subsequent _ or .
wregex ToFind(L"_[tT]\\d{2,3}(_|.)");
wsmatch TStr;

regex_search(str, TStr, ToFind);    // Now the wsmatch variable contains all the info about the matching
wstring T = TStr.str(0).erase(0, 2);    // Removes the first 2 characters
T.erase(T.end() - 1);               // Removes the last character

// Checks if T is 3 digits or not (2 digits) and eventually add a "."
wstring TVal = L"";
if (T.size() == 3)
{
    TVal += T.substr(0, 2) + L"." + T.substr(2, 3);
}
else if (T.size() == 2)
{
    TVal += T;
}

// Converts T string to a float
const float TValue = (float) _wtof(TVal.c_str());

return TValue;
}

If FileName is for example foo_T024.lol, this function correctly returns a float (in C++, or Single in VBA) with the value of 2.4 .

I call the function from VBA (both from Excel and the other environment) as:

Private Declare Function ReturnT Lib "[myDLLname]" (ByVal FileName As String) As Single

If I do the same from the other environment and use the function on the same string, I get an **ERROR** and sadly nothing else, because I can't debug (being this a proprietary application).

What could be the problem?

EDIT: I found out that this other environment is actually SAX, which is basically identical to VBA.

EDIT: I managed to link Visual Studio with the application, so I could check what's imported and what is wrong. FileName looks correctly imported, (I used also a VARIANT-input approach to see if that was the issue, which it wasn't) but I receive an error at this line:

wregex ToFind(L"_[tT]\\d{2,3}(\\_|\\.)");

The error is:

Unhandled exception at 0x75F0C54F in NSI2000.exe: Microsoft C++ exception: std::regex_error at memory location 0x0018E294.

And it stops by xthrow.cpp at this point:

#if _HAS_EXCEPTIONS

#include <regex>

_STD_BEGIN
_CRTIMP2_PURE _NO_RETURN(__CLRCALL_PURE_OR_CDECL _Xregex_error(regex_constants::error_type _Code))
    {   // report a regex_error
    _THROW_NCEE(regex_error, _Code);
    }                                     <--- Code stops here
_STD_END
 #endif /* _HAS_EXCEPTIONS */

EDIT: My VS version is 2013, the platformtoolset is the "Visual Studio 2013 - Windows XP (v120_xp)". My compiler version is: "Version 18.00.21005.1 for x64"

Noldor130884
  • 974
  • 2
  • 16
  • 40
  • Does the function has been registered in system? – Maciej Los May 10 '17 at 11:25
  • No, and apparently it doesn't need to. The function is defined in the same `extern "C"` block of other functions, which seem to work just fine. – Noldor130884 May 10 '17 at 11:32
  • Have you tried registering it to see if it fixes the issue? It could be an arbitrary .dll that's loaded as part of the IDE in Excel, but not in your other application. – SierraOscar May 10 '17 at 11:45
  • Is there some reason you aren't saying what the "other environment" is? – Rich Holton May 10 '17 at 11:51
  • It's a proprietary application with a developement environment. Since it is something related to work, I'd prefer not to say. – Noldor130884 May 10 '17 at 12:09
  • I tried to register using both system32 and SysWOW64 commands, but it says "cannot find entry point". It is very much likely though, since this is a company computer, that I am not allowed to do that. – Noldor130884 May 10 '17 at 12:15
  • Is the other environment (SAX) a 64-bit program? I assume the VBA you were using is 32-bit. – Rich Holton May 10 '17 at 13:16
  • you are correct, 32 bit – Noldor130884 May 10 '17 at 13:56
  • 2
    This code suffers pretty heavily from a "failure is not an option" approach. No way to tell the caller that the filename could not be converted to a float. And it certainly will fail in a very nasty and undiagnosable way if there is no regex match. Like it would if the "other environment" passes a BSTR instead of a LPCSTR, the normal marshalling for strings. Albeit not so likely that it bombs with a std::regex_error exception, you'll have to post the stack trace to get a better guess. And document the VS version, early ones had a lot of regex bugs. – Hans Passant May 12 '17 at 15:47
  • All the checks to ensure that there is a file which WILL give a convertable filename have been written in VBA, but thus is not the problem. Nor it is BSTR instead of LPCSTR (I can anyway import a variant and obtain its BstrVal and work with that, which I tried, and got the same error). VS version is the 2010, but, let me stress it again: it worked fine when I tested the same import in Excel. – Noldor130884 May 14 '17 at 13:32
  • Sorry, VS version is 2013, not 2010. Toolset is version VS 2013 - Windows XP (v120_xp) – Noldor130884 May 15 '17 at 06:37
  • Does it work if you remove all the function's code, but just return a fixed float value? If it does, it means the function's code is failing. I would put a trace at each step. – Simon Mourier May 15 '17 at 06:46
  • What do you mean? If I just build a function that returns a float, I have no problem or whatsoever. The function code *is* failing, and exactly at the regex. – Noldor130884 May 15 '17 at 07:00
  • Your other environment may have a memory leak or something like that that breaks the dll function execution, I recomnd compiling the dll as an ActiveX dll that is COM compliant, Chances are that it will be more stable integrating with your target environment – Siyon DP May 16 '17 at 13:10

1 Answers1

2

Turns out something was wrong with the string I've been importing. I do not understand what, since when I debugged the program, they looked fine. I solved by importing a SAFEARRAY of strings (which required me to change the whole function and the VBA code as well), whose BSTR value could be accessed as follows:

int _stdcall FilenameSort(LPSAFEARRAY* StringArray)
{
    // Fills a vector with the wstring values
    char** StrPtr = 0;
    long LowerBound = 0;  SafeArrayGetLBound(*StringArray, 1, &LowerBound);
    long UpperBound = 0;  SafeArrayGetUBound(*StringArray, 1, &UpperBound);
    const long Dimension = UpperBound - LowerBound;
    SafeArrayAccessData(*StringArray, reinterpret_cast<void**>(&StrPtr));

    BSTR element;
    vector<wstring> wstrArr;

    for (long i = 0; i <= Dimension; ++i)
    {
        SafeArrayGetElement(*StringArray, &i, &element);
        wstring ws(element, SysStringLen(element));
        wstrArr.push_back(ws);
    }

Having converted all the BSTRs in wstrings correctly, I could work with wregexs without any problem.

Noldor130884
  • 974
  • 2
  • 16
  • 40
  • 1
    Marshalling your BSTRs into STL strings before working with them sounds right, it is what I do. http://exceldevelopmentplatform.blogspot.co.uk/2017/02/bstrs-should-be-treated-as-data.html – S Meaden May 19 '17 at 08:08