Add a managed .net dll to a cpp dll project

Pages: 12
That fails.

Well, what exactly "fails", and what exactly is the problem or error messages you are seeing?! 🤔
Last edited on
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?
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
That would be this one?
https://imgur.com/a/FMxbjf0
I did add the reference as suggested, and same result.
Last edited on
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?
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
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.
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
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");

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
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 ) ;
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
Some info from the TS sdk guide:
https://imgur.com/a/JRFIVp1
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
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
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
Topic archived. No new replies allowed.
Pages: 12