I have a third part DLL written in Visual Basic that I'm trying to use from C++. I don't have it source and header files, and just have documentation about which its classes and methods including their signature.
I found some articles stating that I could not use that dll directly because it was written in Visual Basic, which is managed, and I should use it through COM by
Registering the DLL: regasm /codebase /tlb:ThirdPartyDll.tlb ThirdPartyDll.dll
Importing it: #import "../Debug/ThirdPartyDll.tlb"
Initializing COM: CoInitialize(NULL);
Instantiating the object: ThirdPartyClassPtr ptrThirdPartyClass(_uuidof(ThirdPartyDll::ThirdPartyClass));
Calling a method of the object: ptrThirdPartyClass->ThirdPartyClassMethod();
I'm having the following 2 problems
A. The dll was registered successfully in step #1 with warnings such as the following one that I ignored because they mentioned classes that I don't need.
Type library exporter warning processing ThirdPartyDll.AnotherClassThatIDontUse, ThirdPartyDll. Warning: Type library exporter encountered a type that derives from a generic class and is not marked as [ClassInterface(ClassInterfaceType.None)]. Class interfaces cannot be exposed for such types. Consider marking the type with [ClassInterface(ClassInterfaceType.None)] and exposing an explicit interface as the default interface to COM using the ComDefaultInterface attribute.
B. None of the methods available in ThirdPartyClassPtr class are visible in the C++ code. The only methods that can be called are the following ones, and they were not defined by the ThirdPartyClass, but by something else (probably by the compiler when it processed the import command).
AddRef
GetIDsOfName
GetTypeInfo
GetTypeInfoCount
Invoke
QueryInterface
Release
Any ideas what could be wrong?
If it is a VB.NET Dll, to learn how it works, I would start with writing a dummy project (C#, VB, whatever you prefer) using the dll, then you see the methodes, properties and so on, and then you should be able to translate this
Related
I'm running into a very strange problem trying to compile and use a windows runtime component within an UWP application (VS2017 community 15.9.13 with NetCore.UniversalWindowsPlatform 6.2.8, compiled without /clr but with /ZW).
It is basically something like the Grayscaletransform. The runtime component is actually working as expected, now I wanted to remove some unused code. However, as soon as I remove it from a particular file and recompile, it indeed compiles, links, but the DLL does not load any more.
Here's some example code that I have to put in:
ref class DummyU sealed
{
public:
DummyU() {}
};
DummyU^ CreateDummyU()
{
return ref new DummyU();
}
The code just makes it work, although it is a) not referenced at all and b) does not do anything useful.
The result of removing it:
Exception thrown at 0x0EFF322F (vccorlib140d_app.dll) in TestAppUWP.exe: 0xC0000005: Access violation reading location 0x00000000.
in
STDAPI DllGetActivationFactory(_In_ HSTRING activatibleClassId, _Deref_out_ IActivationFactory** ppFactory)
{
return Platform::Details::GetActivationFactory(Microsoft::WRL::Details::ModuleBase::module_, activatibleClassId, ppFactory);
}
function in dllexports.cpp which is part of VS. The module_ becomes NULL.
Does anyone have an idea if there are any known bugs with respect to the windows runtime not being initialized/used properly if there is no explicit instantiation of a ref class in a file?
EDIT 1:
Here's the link to the full source code:
What's happening here is that you're mixing modes a bit. Since you've compiled your C++ code with the /CX flag, you've told the compiler to enable winrt extensions to produce a WinRT DLL. In practice though, none of your code is actually using the CX extensions to implement classes. You're using WRL and standards C++. The compiler looks at the DLL, finds no CX-style WinRT classes, and doesn't set up the module, accordingly.
This is basically an untested & unsupported case, since you've chosen to say that you want to expose ref classes by picking a UWP component library project type, but then didn't actually provide any ref classes. It happens that under the hood, /CX effectively uses WRL, so you can nudge it along and initialize the state to work correctly, but you're kinda hacking the implementation details of the system.
There are two options I would recommend, either works: just make the project a non-CX Win32 DLL and init the module as described above. Or, better yet, flip over to C++ /WinRT, which will give you better support for the WinRT types than /CX and allow you to more easily mix in the classic COM types in your implementation. You can get started by just turning off the /CX flag in the compiler switches, then start updating the code accordingly.
Ben
You might have wrong .winmd file for your component. WinRT components made in C++ produce two outputs, dll and winmd. Both must match. It's possible you have them from different builds.
Another possible reason is error in manifest. The manifest of the app must include all referenced runtime components.
BTW, for native DLLs written in classic C++ and exposing C API, deployment is simpler, you include a DLL in the package and they just work, with [DllImport] if you're consuming them from C#.
Update: You can replace that ref class with the following code, works on my PC.
struct ModuleStaticInitialize
{
ModuleStaticInitialize()
{
Microsoft::WRL::Module<Microsoft::WRL::InProc>::GetModule();
}
};
static ModuleStaticInitialize s_moduleInit;
Probably a bug in Microsoft's runtime somewhere.
I have the following setup:
CSharp.dll, a C# dll
CppCli.dll, a Mixed-Mode C++/Cli dll.
Native.dll, a native C++ dll.
The native project declares
class Native
{
public:
virtual void Add(int a);
};
which is implemented in the mixed mode project:
class Mixed : public Native
{
public:
virtual void Add(int a);
ICSharpInterface^ MakeManaged();
};
Since the base class is defined in Native, I can pass my implementation to other code in native. But now I want to test this class.
If I use #pragma make_public(Mixed); it will only make a struct public, without any functions visible to the outside.
If I try to link to the mixed-mode dll from another mixed-mode dll, I get linker errors because it's a native class and the mixed-mode dll generates no .lib to link against.
And if I try to __declspec(dllexport) the class, the Visual Studio complains because the interface exposes managed stuff.
So my question is:
How do I instantiate (link to) this class in my tests? I would be happy with any solution that shows how to create an instance where I can call its public interface on, doesn't matter if from C++, C++/Cli or from C#.
You are missing an important step, you haven't yet considered how a native program is going to create an instance of the Mixed object. Which is non-trivial, it does require getting the CLR loaded and initialized so it can execute managed code. Keep in mind that the client code does not do this automatically, it doesn't know beans about the CLR, it only knows about Native.dll. There are three basic ways to get this done:
You can expose managed classes as COM objects, very simple to do with the [ComVisible] attribute. Possible to do directly from C#, you don't need the C++/CLI wrapper. The usual disadvantage is that the client code has to use COM to instantiate the object and make calls on it, not the kind of code that programmers like to write.
You can host the CLR yourself, the most efficient and flexible solution. This magazine article gives an introduction, beware that it is dated.
The C++/CLI compiler gives you a way to give you an unmanaged exported function that can execute managed code. It auto-generates a stub that gets the CLR loaded and initialized, if necessary.
Focusing a bit on the last bullet, since that's what you probably like, what you need here is a factory function, one that creates an instance of the Mixed class and returns a Native* back to the caller. So it can call ptr->Add() and invoke Mixed::Add(). That can look like this:
extern "C" __declspec(dllexport)
Native* CreateObject() {
return new Mixed;
}
Also gets you the import .lib that you can link in your native project. Do beware the disadvantages, they are significant. It is not exactly fast since the stub must check if the CLR is initialized yet and make the native-to-managed transition. The error reporting is extremely lousy since you have no decent way to diagnose exceptions that are thrown in the C# code. And memory management is an issue, the caller has to be able to successfully destroy the returned object which requires all modules to use the exact same CRT. The kind of problems that COM solves.
The exact same technique is available in C# as well by using an IL rewriter. Gieseke's unmanaged exports template is popular.
I need to load a DLL file in Lua to connect different APIs. I know that C type dlls can be loaded, but what I have is a dll file produced in C++.
The code (in C++) that produced this library was of the form:
// MyAPI.h
namespace MyAPI
{
public class MyFirstClass
{
public:
MyFirstClass();
void performSomeMethod(int arg);
}
}
which then produced the dll file MyAPI.dll. When I now try to import this in Lua, using:
require "MyAPI"
it immediately gives the error: error loading module 'MyAPI' from file '.\MyAPI.dll': The specified procedure could not be found. I do not understand what this means, or how to get rid of it. Can C++ libraries in general not be included by Lua (i.e. should I write another C wrapper?) or is there a way to do this?
Yes, it can be done. Expose a C-function loader luaopen_MyAPI, where you can call a function that uses any kind of C++ Lua Wrapper, such as LuaBridge, LuaBind or others. If your calls in C++ don't conform to the rules of the bindings, such as lifetime management, passing objects by value, etc, you might need to wrap the classes into bindable classes.
For an example see pugilua
pugilua_lib.h - module loader API
pugilua_lib.cpp - wrapper classes and a LuaBridge binding
pugilua.cpp - calling the bindings from the module loader
You need to export a C function named luaopen_ MyAPI that follows the C-Lua API. The rest of the code can be C++.
My understanding is that you will need to have a C wrapper with a C entry point rather than a C++ entry point. C++ does name mangling so it can change dynamically depending on the compiler as well as the method signature, etc.
Here is Anatomy of a Lua to C Call which you may find helpful.
Also see this stack overflow discussion on what goes on with dll loading.
And here is another stack overflow discussion on require and dll loading.
This is a brief post on the name mangling problem.
I would like to accomplish a simple task:
I want to produce a C++/CLI lib that calls some .NET routines, and exposes 1 static method that I can call from purely native C++ app. I want to statically link to that lib from my native app. The signature of the method that the native C++ app would call should be
void (unsigned char* data, int length, _TCHAR* args[])
I am pretty new to C++/CLI and C++ in general. So, can you please help me and answer these questions:
For my tiny C++/CLI project, I assume the type needs to be class library with lib as output, targeting vc9 runtime (so that I can be sure it is available on end users PCs). Am I correct in this assumption?
Can you provide an example of the outline of the method with that signature I will need to write in my C++/CLI project. In particular how should I do conversion to CLR types properly (i.e. byte[], int32, and string)? And how do I decorate that method with something like "extern "C" __declspec(dllexport)" to make this method callable from my native C++ app?
How would I separate the code between cpp and h files in C++/CLI properly?
Finally how would I actually call it from my native app once I add lib reference?
Thank you.
Class library: correct, but you'll also need to change your project's configuration type from Dynamic Library to Static Library. I'm not sure what you mean by 'targeting vc9 runtime' – you need to target the same runtime as the native code that will be using your static library.
Since this is a static library, no __declspec(dllexport) is needed. If you want to know how to do conversion to .NET types, you'll need to post what your code is actually doing. In general, you'll want Marshal::Copy to copy a C-array into a .NET array, and marshal_as<> to copy C-strings into .NET strings, but there's still the question as to whether that data is intended to be mutable and needs to be marshaled back to native types before returning...
The exact same as in C++ – declaration in a header, definition in a source file.
The exact same as any other function – #include the header containing the declaration and call the function.
I have a task to interface with a dll from a third party company using C++.
The dll package comes with:
the dll itself
a sample Java implementation - consists of a java wrapper(library) generated using the SWIG tool and the the java source file
documentation that states all the public datatypes, enumeration and member functions.
My other colleague is using Java(based on the example in package) to interface with the dll while I'm asked to use C++. The Java example looks straight forward... just import the wrapper and instantiate any class described in the docs..
More info on the dll:
From the docs, it says the dll was programmed using C++
From a hexdump, it shows that it was compiled using VC90 (VS C++ 2008 right?) and something from Dinkumware.
From a depends.exe output, the functions seems to be wrapped under JNI. For example: _Java_mas_com_oa_rollings_as_apiJNI_Server_1disconnect#20
My dilemma:
The dll company is not changing anything in the dll and not providing any other info.
How do i use the member functions in the class from the dll?
I did some simple LoadLibrary() and GetProcAddress and manage to get the address of the public member functions.
But i dunno how to use the functions that has the datatype parameters defined in the dll. For example:
From the docs, the member function is defined as:
void Server::connect(const StringArray, const KeyValueMap) throw(std::invalid_argument,std::out_of_range)
typedef std::map Server::KeyValueMap
typedef std::vector Server::StringArray
how do i call that function in C++. The std::map and std::vector in my compiler (VS 2005) has different functions listing that the one in the dll. For example, from the depends.exe output:
std::map // KeyValueMap - del, empty, get, has_1key,set
std::vector // StringArray - add, capacity, clear, get, isEMPTY, reserve, set, size
Any advice/strategy on how i should solve this? Is it possible to simply instantiate the class like the Java example?
If you are trying to use VS 2005 to try and interface with a DLL that is built using VS2008, your attempts will be mostly doomed unless you can use a plain C interface. Given your description, this is not the case; The runtime libraries differ between VS2005 and VS2008 so there is little chance that the object layout has stayed the same between compilers. The 'something from Dinkumware' that you're referring to is most likely the C++ standard library as ISTR that Microsoft uses the Dinkumware one.
With your above example you're also missing several important pieces of information - the types you describe (Server::StringArray and Server::KeyValueMap) are standard library containers. OK fine, but standard library containers of what? These containers are templates and unless you know the exact types these templates have been instantiated with, you're a little stuck.
Is this DLL intended to be called from C++ at all? The fact that it export a JNI interface suggests that it might not be in the first place. Does it export any other public symbols apart from those that are of the format _Java_...?
Of course if there is no other way in and you must use C++ instead of Java, you might want to look into embedding a JVM into your C++ app and use that to call through to the C++ dll. It's not what I'd call an elegant solution but it might well work.
I don't quite understand the use of C++ standard library data types here. How can Java code provide a std::map argument? Are the arguments you pass in always just "opaque" values you would get as output from a previous call to the library? That's the only way you're going to be able to make it work from code under a different runtime.
Anyway...
When you make a JNI module, you run javah.exe and it generates a header file with declarations like:
JNIEXPORT void JNICALL Java_Native_HelloWorld(JNIEnv *, jobject);
Do you have any such header file for the module?
These symbols are exported as extern "C" if I recall correctly, so if you can get the correct signatures, you should have no issues with name mangling or incompatible memory allocators, etc..
The "#20" at the end of the method signature means that the function is declared "stdcall" and that 20 bytes are put on the stack when the function is called. All these methods should start with a JNIEnv* and a jobject, these will total 8 bytes I believe, on a 32-bit environment, so that leaves 12 bytes of parameters you will need to know in order to generate a correct function prototype.
Once you figure out what the parameters are, you can generate something like this:
typedef void (__stdcall *X)(JNIEnv *, jobject, jint i, jboolean b);
Then, you can cast the result of GetProcAddress to an X and call it from your C++ code.
X x = (X)GetProcAddress(module, "name");
if (x) x(params...);
Unfortunately, what you have doesn't quite look like what I have seen in the past. I am used to having to deal with Java data types from C/C++ code, but it looks like this module is dealing with C++ data types in Java code, so I don't know how relevant any of my experience is. Hopefully this is some help, at least.