Closed bertstomphorst closed 5 years ago
@bertstomphorst It looks like you're trying to use COM. But DllExport works for P/Invoke
[return: MarshalAs(UnmanagedType.IDispatch)] // <<< a COM IDispatch pointer that you're trying for
static object CreateBroker()
Here's about default marshaling and data types: https://github.com/3F/DllExport/wiki/Quick-start#about-data-types
Hi Denis, I don't think that's the issue. The Class1 is correctly recognized in VBA. The variable 'class1' represents the object. When I add a string and int-property returning a fixed value, I can see these values in the local variable inspector in VBA. This usageof IDispatch is as mentioned by Robert Giesecke on Stackoverflow: https://stackoverflow.com/a/6340601/10205407
The issue is when ClassLibrary1.Class1 does it's first call to ClassLibrary2.Class2 (pointing to referenced dll), it can't find the dll. But it's compiled at the same time, and both dll's are in the same folder. So what can be the reason that ClassLibrary1.dll can't find ClassLibrary2.dll?
The Class1 is correctly recognized in VBA. When I add a string and int-property returning a fixed value, I can see these values in the local variable inspector in VBA.
Marshaling for IDispatch works basically as a pointer(that I already mentioned above) to the object on the heap. I'm not using VBA, but if you have only problem for types from different assemblies, then you need to view loading of domain and its types. Or try native usage for intptr.
For domains example:
As you should understand, your ClassLibrary1 assembly does not contain Class2 type. Now CLR will try to load this into used domain by information about referenced assemblies.
it can't find the dll. But it's compiled at the same time, and both dll's are in the same folder.
Therefore, you can also try with AssemblyResolve or even with additional domain with unwrapping types.
Here, I have old code for some related loader, try to experiment:
upd.: forgot to say,
both dll's are in the same folder
You need to focus on host side and its searching for dependencies. Usually this is the application's directory only. I'm not sure how VBA implements loading, but if you will use LoadLibraryEx for SEARCH_DLL_LOAD_DIR it will also add the directory that contains the loaded dll to the beginning of the list of directories that are searched for the dependencies. So it can also affect for loading in CLR.
Thank you so far Denis, I will dive into it and share my experience here
Thanx Denis, got it work with following change: In Class1.DoNothingOnClass2 (where Class2 was initialized), change body of DoNothingOnClass2() from
public void DoNothingOnClass2()
{
new Class2().DoNothing();
}
to
public void DoNothingOnClass2()
{
string path = new FileInfo(Assembly.GetExecutingAssembly().Location).DirectoryName;
var assemblyname = "ClassLibrary2";
var typename = "Class2";
dynamic class2 = AppDomain.CurrentDomain.CreateInstanceFromAndUnwrap($@"{path}\{assemblyname}.dll", $"{assemblyname}.{typename}");
class2.DoNothing();
}
After that, found that AssemblyResolve works better, because it loads all types from referenced assembly, and in ClassLibrary1 everything is typed. Solution (for others reference): static class UnmanagedExport (from sample project) should be:
static class UnmanagedExport
{
static UnmanagedExport()
=> AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
=> Assembly.LoadFrom($@"{new FileInfo(args.RequestingAssembly.Location).DirectoryName}\{args.Name.Split(',')[0]}.dll");
[DllExport]
[return: MarshalAs(UnmanagedType.IDispatch)]
static object CreateBroker()
=> new Class1();
}
Using an DllExported-dll as a broker between VBA and other .NET code (separate dll's) doesn't seem to work.
How to reproduce
See attached project DllExportTest.zip
Build de project. In a VBA-module (I used Access):
(be sure to correct the path in the Declare Function to point to the built dll)
Execute the RunTest()
VBA gives "'Could not load file or assembly 'ClassLibrary2, version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of iets dependencies. The system cannot find the file specified."