Add a managed .net dll to a cpp dll project

Pages: 12
Jun 9, 2023 at 3:57pm
That fails.

Well, what exactly "fails", and what exactly is the problem or error messages you are seeing?! 🤔
Last edited on Jun 9, 2023 at 7:01pm
Jun 14, 2023 at 4:30pm
I am attempting a project with the posted examples. I first created ManagedDLLTest project into which i put the first bit of code. Then I started the WrapperLibrary project into which I pasted the next to bits of code. Enclosed are the solution tree and the errors from the second project.
https://imgur.com/a/wqedOlV
https://imgur.com/a/tbmVUM5

Comments?
Jun 14, 2023 at 5:50pm
As mentioned several times before: If you want to call any classes/methods of "ManagedDLLTest" from your "WrapperLibrary" project, you have to add the "ManagedDLLTest" to the references of the "WrapperLibrary" project, in the Solution Explorer.

https://cplusplus.com/forum/general/285501/#msg1240215


(also, be sure that the "WrapperLibrary" was created as "CLR Class Library (.NET Framework) [C++]" project type)
Last edited on Jun 14, 2023 at 5:55pm
Jun 14, 2023 at 7:03pm
That would be this one?
https://imgur.com/a/FMxbjf0
Jun 14, 2023 at 7:06pm
I did add the reference as suggested, and same result.
Jun 14, 2023 at 9:11pm
Last edited on Jun 14, 2023 at 9:28pm
Jun 15, 2023 at 12:33pm
Thanks for the example. I was able to load it into VS and also ran the app and it all worked.
As to my problem. Instead of the NativeCPPApp in the example, I need to execute the WrapperLibrary.dll from the Tradestation platform using Easylanguage. In Easylanguage, running a dll looks like this: DefineDLLFunc: "WrapperLibrary.dll", string, "FunctionName", string;
What precedes "FunctionName" is the return type and what comes after is the argument(s). AND, the WrapperLibrary.dll must use the __stdcall calling convention.

Then to use the dll function in Easylanguage one would write:
var: string MyString("");
MyString = FunctionName("FunctionInputArgument");

Any idea what the WrapperLibrary.dll might look like for the above situation?
Jun 15, 2023 at 1:37pm
If you want the "stdcall" calling convention, then simply add __stdcall to the function declaration(s) in "WrapperLibrary.h".

Replace "FunctionName" with the actual name of the function, e.g. "MySayHelloWrapper" in the example.

It is totally not clear how Easylanguage – whatever that is – passes strings to the DLL function, and how it expects the DLL to return a string. Does it work with wchar_t* (Unicode) or with char_t* (ANSI) pointers? Or something else? If we assume that we are dealing with wchar_t* pointers, then the function declaration that takes a string as its single parameter and that returns a string looks like this:

WARPPERLIBRARY_API wchar_t* __stdcall MyExampleFunction(wchar_t *parameter);

(Replace wchar_t* with char* and StringToHGlobalUni() with StringToHGlobalAnsi(), if you want to return ANSI instead of Unicode)

Be aware: The caller (application) takes ownership of the returned string buffer! The application is required to pass the string pointer to MyFreeString(), in order to release the memory, when it is no longer needed. Otherwise you get memory leak !!!
Last edited on Jun 15, 2023 at 1:51pm
Jun 15, 2023 at 2:22pm
I will try what you suggested. I don't know if Easylanguage uses wchar_t* or char_t*, or something else. I only know the owners of Easylanguage (Tradestation) say any dll must use the __stdcall calling convention. I have been using this for years, but recently the owner of the dll on the other end (Ninjatrader) has changed their dll to managed .NET, so Easylanguage cannot work with it without an intermediate (wrapper) dll.
Jun 15, 2023 at 2:49pm
Doesn't "Easylanguage" (Tradestation) provide some sort of SDK, or at least a full example on how to create/export a function from a "native" DLL so that it can be called from Easylanguage code?

If the signature of the function exported from your "wrapper" DLL doesn't match exactly what the calling code (i.e. Easylanguage) is assuming, then you will get undefined behavior – which can mean anything from crashes to "weird" results.
Last edited on Jun 15, 2023 at 4:20pm
Jun 15, 2023 at 10:29pm
In this statement: WARPPERLIBRARY_API wchar_t* __stdcall MyExampleFunction(wchar_t *parameter);

Does the *parameter just receive the value of the string being passed from my calling app? It could just as well be *Parm1 then?

The calling app statement would be (for instance)
DefineDLLFunc: "TestDLL.dll", string, "MySayHelloWrapper", string;

var: string GetString("");
print(MySayHelloWrapper("Hello from Tradestation");

Jun 15, 2023 at 11:01pm
Does the *parameter just receive the value of the string being passed from my calling app? It could just as well be *Parm1 then?

Parameter wchar_t *parameter retrieves a pointer to the memory buffer where the NULL-terminated Unicode (UTF-16) string is located.
https://www.tutorialspoint.com/cprogramming/c_strings.htm

This is a standard way of how strings are passed in C code. In C++ code, we also may pass std::wstring or std::string objects.

Either way, it only works, if the calling application actually passes the string in that way!

BTW: The name of the parameter is arbitrary. You can call it "Param1" or "thingamabob" or whatever you like 😛
Last edited on Jun 16, 2023 at 8:40am
Jun 16, 2023 at 9:46am
Easylanguage does provide instructions for using EL with dll's. They also provide a dll called TSKit.dll. To use the TSKit.dll, it must be imported into a dll being created for the purpose of working with EL. However it is not a requirement to use the TSKit.dll. It just enables certain capabilities that you can't get if you don't use the TSKit.dll, such as working with EL data structures and objects. The dll NtDirect.dll works with EL and does not incorporate the TSKit.dll, so that's an example of where it's not needed. Unfortunately, NtDirect.dll is being made obsolete and being replace by NinjaTraderClient.dll which is a managed .Net dll, unlike the NtDirect.dll. The only example in the instructions on how to create a dll that works with EL is this:

4.) Standard C Calling Convention
DLL functions must be exported using the "standard C" calling convention in order for TradeStation to locate them. Additionally, exported functions should be listed in the EXPORTS section of the DLL project's module-definition (.DEF) file. The C++ code example below illustrates the use of __stdcall notation in a function prototype. This is the function prototype for a DLL function called EXAMPLEONCREATE, a function which receives a pointer to an IEasyLanguageObject as its sole argument, and returnsan integer:
int __stdcall EXAMPLEONCREATE( IEasyLanguageObject * pELObj ) ;
Jun 16, 2023 at 10:06am
As said before, their statement regarding calling conventions is contradictory, because the standard "C calling convention" is __cdecl, not __stdcall. The latter is the "Win32 API calling convention" and usually only used with certain Windows system DLLs.
https://learn.microsoft.com/en-us/cpp/cpp/cdecl?view=msvc-170
https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170

This is the function prototype for a DLL function called EXAMPLEONCREATE, a function which receives a pointer to an IEasyLanguageObject as its sole argument, and returns an integer:
int __stdcall EXAMPLEONCREATE( IEasyLanguageObject *pELObj );

Anyhow, if they say that the function prototype must be as follows, because they will assume that your function has that prototype when they call it, then you must use exactly that prototype for your DLL function, or it certainly is not going to work:

int __stdcall YourFunctionNameGoesHere(IEasyLanguageObject *pELObj);

Of course, if that is the case, then they must provide you with the definition of the IEasyLanguageObject type, usually in the form of a header (.h) file, because that is not a standard C/C++ type but something totally specific to "EasyLanguage"! 😒

And, of course, it means that you can not take a string as function parameter, or return a string – at least not in a direct way – because the only parameter that you get is a pointer to an IEasyLanguageObject object and you have to return an int value.

(possibly, you could do something like pELObj->GetParameter() or pELObj->SetResult() or something in that vein, but as long as you don't show us the definition of the proprietary IEasyLanguageObject type, we can only make guesses here...)
Last edited on Jun 16, 2023 at 11:32am
Jun 16, 2023 at 3:01pm
Some info from the TS sdk guide:
https://imgur.com/a/JRFIVp1
Jun 16, 2023 at 3:44pm
Okay, with this information, it would seem that different types of parameters can be passed from EasyLanguage to C/C++ DLL.

If you want to pass a String, then you have to declare the parameter as char* pointer; if you want to pass an Int, then you have to declare the parameter as int; if you want to pass a Float, then you have to declare the parameter as float; if you want to pass an IEasyLanguageObject (whatever that is), then you have to declare the parameter as IEasyLanguageObject* pointer (whatever its definition is).

This also means that, as far as I can tell, passing Unicode (wchar_t*) strings is not possible, and therefore you will have to use ANSI (char*) strings. Consequently, you will have to use Marshal::StringToHGlobalAnsi() for the marshaling of the "managed" string.

Be aware: Any Unicode characters in the original string that can not be represented in your system's ANSI codepage will be destroyed!

One thing that still is unclear: If we return a char* pointer from the C/C++ DLL to EasyLanguage, then how do we pass this exact pointer back into the C/C++ DLL later, so that the memory buffer can be freed?
Last edited on Jun 16, 2023 at 4:01pm
Jun 16, 2023 at 5:12pm
I have created a dll which will receive and return a string to Tradestation. Easylanguage has three character classes: BigEndianUnicode, UTF-8, and Unicode.
Last edited on Jun 16, 2023 at 5:14pm
Jun 18, 2023 at 12:38pm
You would want to use "Unicode" (i.e. UTF-16, little endian), because that is what .NET Framework and the Win32 API use natively.

Note: Unicode characters can be encoded in many different ways, but in the context of Microsoft Windows, the term "Unicode" is often used synonymously with UTF-16 (little endian) – even though UTF-8 or UTF-32 are equally valid "Unicode" encodings!

Still, according to the table that you posted earlier, Easylanguage Strings have to be passed as char* pointers to the C/C++ DLL.
https://imgur.com/a/JRFIVp1

This kind of excludes UTF-16, which requires wchar_t*, i.e. 2 bytes per character – whereas char* uses 1 byte per character (or multi-byte encoding). Anyway, char* alone doesn't say which exact character encoding they want/expect! ASCII? Windows-1252? UFT-8 ???
Last edited on Jun 19, 2023 at 10:28pm
Topic archived. No new replies allowed.
Pages: 12