Login Page - Create Account

Support Board


Date/Time: Thu, 28 Nov 2024 00:49:59 +0000



[Programming Help] - LoadLibrary works in test wrapper but not in SC study?

View Count: 264

[2023-06-16 01:01:33]
User133994 - Posts: 80
Support,

Should any special considerations be given for using LoadLibrary/GetProcAddress in a study function?

this test wrapper works fine:

#include <windows.h>
#include <iostream>

typedef float(*HelloWorldFunction)(float);

int main() {
// Load the DLL
HMODULE hDLL = LoadLibraryExW(L"C:\\SierraChart\\vlk\\DLLvlkfunctions.dll", NULL, LOAD_WITH_ALTERED_SEARCH_PATH);


if (hDLL == NULL) {
std::cout << "Failed to load DLL. Error code: " << GetLastError() << std::endl;
return 1;
}

// Get the hello_world function address
HelloWorldFunction helloWorld = reinterpret_cast<HelloWorldFunction>(GetProcAddress(hDLL, "hello_world"));
if (helloWorld == NULL) {
std::cout << "Failed to get function address. Error code: " << GetLastError() << std::endl;
FreeLibrary(hDLL);
return 1;
}

// Call the hello_world function
float result = helloWorld(5.0f);
std::cout << "Result: " << result << std::endl;

// Free the DLL module
FreeLibrary(hDLL);
return 0;
}

this study snippet throws exceptions:


typedef float(*HelloWorldFunction)(float);

...
struct pDllWrapper
...
HMODULE hDLL = LoadLibraryExW(L"C:\\SierraChart\\vlk\\DLLvlkfunctions.dll", NULL, LOAD_WITH_ALTERED_SEARCH_PATH);

if (hDLL == NULL)
{
SCString LogMessage;
LogMessage.Format("pDW Failed to load DLL. Error code: %lu", GetLastError());
sendDebugOnce(sc, LogMessage, r_lastDebugString_);
throw std::runtime_error("pDW Failed to load DLL");
}

// Get the hello_world function address
helloWorld = reinterpret_cast<HelloWorldFunction>(GetProcAddress(hDLL, "hello_world"));
if (helloWorld == NULL)
{
SCString LogMessage;
LogMessage.Format("pDW Failed to get function address. Error code: %lu", GetLastError());
sendDebugOnce(sc, LogMessage, r_lastDebugString_);
FreeLibrary(hDLL);
throw std::runtime_error("pDW Failed to get function address");
}

float callHelloWorld(float num) {
// Call the hello_world function
return helloWorld(num);
}

bool runHelloWorld(SCStudyInterfaceRef& sc, SCInputRef& Input_showmessag, float num, float& result) {

try {
result = callHelloWorld(num);
if (Input_showmessag.GetYesNo()) { // Check if debug messages should be shown
SCString LogMessage;
LogMessage.Format("pDW Result: %f", result);
sendDebugOnce(sc, LogMessage, r_lastDebugString_);
}
return true; // Indicate success
} catch (std::runtime_error& e) {
SCString LogMessage;
LogMessage.Format("pDW Exception: %s", e.what());
sendDebugOnce(sc, LogMessage, r_lastDebugString_);
return false; // Indicate failure
}

}
...

inside scsf_dllCallTest...
if (sc.Index == 0)
{
// pointer initialization

pDW = reinterpret_cast<pDllWrapper*>(sc.GetPersistentPointer(pDllWrapper_pkey));

// assign persistent pointer to pDllWrapper struct
if (pDW == nullptr)
sc.SetPersistentPointer(pDllWrapper_pkey, new pDllWrapper(sc, r_lastDebugString));

}

// Use the pDW
float result;
if (!pDW->runHelloWorld(sc, Input_show_debug, 5.0f, result)) {
// Handle error case
SCString LogMessage;
LogMessage.Format("!!!ERROR =%d.", sc.Index);
sendDebugOnce(sc, LogMessage, r_lastDebugString);
} else {
// Use result
if (Input_show_debug.GetYesNo() ){
SCString LogMessage;
LogMessage.Format("Sending message 1x =%d. pdw input: %f, result:%f ", sc.Index, 5.0f, result);
sendDebugOnce(sc, LogMessage, r_lastDebugString);
}
}


Yes, I do use sc.LastCallToFunction to delete pDW. I have tried initializing pDW outside the sc.Index = 0 block, but that doesn't seem to help.

The hello world function simply multiplies the input x2: thus you see in the output 5.00 and 10.00.

The message log shows a CPU exception, but then proceeds to call the DLL function and has the proper outputs(?):
Warning: The Custom DLL study "_install.scsf_dllCallTest" has just caused a CPU exception. | 2023-06-15 20:48:28.488 *
Warning: This Custom DLL study may cause Sierra Chart to be unstable until you remove the study from the chart and restart Sierra Chart. | 2023-06-15 20:48:28.488 *
Chart: NQU23_FUT_CME[M] 5 Min #1 | Study: _install v0.07 | pDW Result: 10.000000 | 2023-06-15 20:48:28.679
Chart: NQU23_FUT_CME[M] 5 Min #1 | Study: _install v0.07 | Sending message 1x =0. pdw input: 5.000000, result:10.000000 | 2023-06-15 20:48:28.679
Chart: NQU23_FUT_CME[M] 5 Min #1 | Study: _install v0.07 | pDW Result: 10.000000 | 2023-06-15 20:48:28.679
Chart: NQU23_FUT_CME[M] 5 Min #1 | Study: _install v0.07 | Sending message 1x =1. pdw input: 5.000000, result:10.000000 | 2023-06-15 20:48:28.679
Chart: NQU23_FUT_CME[M] 5 Min #1 | Study: _install v0.07 | pDW Result: 10.000000 | 2023-06-15 20:48:28.679
Chart: NQU23_FUT_CME[M] 5 Min #1 | Study: _install v0.07 | Sending message 1x =2. pdw input: 5.000000, result:10.000000 | 2023-06-15 20:48:28.679
Chart: NQU23_FUT_CME[M] 5 Min #1 | Study: _install v0.07 | pDW Result: 10.000000 | 2023-06-15 20:48:28.679
Chart: NQU23_FUT_CME[M] 5 Min #1 | Study: _install v0.07 | Sending message 1x =3. pdw input: 5.000000, result:10.000000 | 2023-06-15 20:48:28.679
Chart: NQU23_FUT_CME[M] 5 Min #1 | Study: _install v0.07 | pDW Result: 10.000000 | 2023-06-15 20:48:28.679

Any ideas why the CPU exception is thrown for this simple example? It does appear at the beginning..maybe before something is loaded?

Also, if you have a working DLL call study that uses LoadLibrary/GetProcAddress in a study with an external DLL file that doesn't have CPU exceptions in the log, please provide a copy to me so I can begin with a working example.

Maybe there is an obvious answer that I am missing. Please help.

Your assistance is much appreciated.

To post a message in this thread, you need to log in with your Sierra Chart account:

Login

Login Page - Create Account