Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DLL function not working in a VBA environment but working in Excel VBA

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"

like image 365
Noldor130884 Avatar asked May 10 '17 11:05

Noldor130884


People also ask

How do you call a DLL in Excel VBA?

You can access DLL functions and commands in VBA by using the Declare statement. This statement has one syntax for commands and one for functions. The optional Public and Private keywords specify the scope of the imported function: the entire Visual Basic project or just the Visual Basic module, respectively.

What is DLL in VBA?

DLLs (dynamic-link libraries) are portable libraries that can be created by one application and used by another. In particular one can create a DLL in C then have its functions run from Excel by calling them from VBA.

Where does excel look for DLLs?

Your DLL files are located in C:\Windows\System32.


1 Answers

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.

like image 171
Noldor130884 Avatar answered Oct 20 '22 00:10

Noldor130884