I'm curently trying to get registration-free COM working with Excel as the client, and a .NET dll as the server. Currently I'm simply trying to get a proof-of-concept working but am having trouble.
Obviously, as I am using Excel, I can't simply use a client manifest living alongside the executable, so I'm using Microsoft.Windows.ActCtx
(link)
I have the client manifest, assembly manifest, and dll all in the same location.
Unfortunately, what works in C# doesn't appear to work in Excel / VBA and I'm stumped as to the reason. While the C# test client works perfectly, VBA gives a 80070002 error, with message Method 'CreateObject' of object 'IActCtx' failed.
I have a .NET dll (COMTestService.dll) exposing a single class / interface to COM (COMTestObject
/ ICOMTestObject
), as here:
[ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[Guid("EEE50CDF-D8EC-4F38-B986-C231EC45171E")]
public interface ICOMTestObject
{
[ComVisible(true)]
string GetString(int number);
}
[ComVisible(true), ClassInterfaceAttribute(ClassInterfaceType.None), ComDefaultInterface(typeof(ICOMTestObject))]
[Guid("6E54611B-8B56-49E0-9415-E59B0774A4BE")]
public class COMTestObject : ICOMTestObject
{
public COMTestObject()
{
}
public string GetString(int number)
{
return string.Format("The number is: {0}", number);
}
}
The client manifest (COMTestService_Client.manifest):
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly
manifestVersion="1.0"
xmlns="urn:schemas-microsoft-com:asm.v1" >
<assemblyIdentity
name="client"
version="1.0.0.0" />
<dependency>
<dependentAssembly>
<assemblyIdentity
name="COMTestService"
version="1.0.0.0"
processorArchitecture="msil" />
</dependentAssembly>
</dependency>
</assembly>
The assembly manifest (COMTestService.manifest):
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly
manifestVersion="1.0"
xmlns="urn:schemas-microsoft-com:asm.v1" >
<assemblyIdentity
name="COMTestService"
version="1.0.0.0"
processorArchitecture="msil" />
<clrClass
clsid="{6E54611B-8B56-49E0-9415-E59B0774A4BE}"
progid="COMTestService.COMTestObject"
threadingModel="Both"
name="COMTestService.COMTestObject"
runtimeVersion="v4.0.30319">
</clrClass>
<file
name="COMTestService.dll"
hashalg="SHA1">
</file>
</assembly>
The VBA client code:
Dim actCtx As Object
Set actCtx = CreateObject("Microsoft.Windows.ActCtx")
actCtx.Manifest = "...\COMTestService_Client.manifest"
Dim testObject As Object
Set testObject = actCtx.CreateObject("COMTestService.COMTestObject") 'This line throws...
Dim text As String
text = thing.GetString(42)
Debug.Print text
The C# client code:
var actCtxType = System.Type.GetTypeFromProgID("Microsoft.Windows.ActCtx");
dynamic actCtx = System.Activator.CreateInstance(actCtxType);
actCtx.Manifest = @"...\COMTestService_Client.manifest";
var type = System.Type.GetTypeFromProgID("COMTestService.COMTestObject");
dynamic obj = System.Activator.CreateInstance(type);
dynamic s = obj.GetString(42);
EDIT
The plot thickens... Just for fun, I wrote a quick COM-visible, REGISTERED helper class to do the object creation in C#, then pass it back, using a method along the lines of public object CreateObject(string manifestPath, string typeName)
Now, calling this from a C# exe works fine, but calling it from VBA fails (80070002 again, message: The system cannot find the file specified.). Now I'm even more confused...
Thanks in advance for any help, and if I need to supply any more info just let me know and I'll be glad to oblige!
Using Process Monitor, I discovered that the dll was being searched for in C:/Program Files/Microsoft Office/Office11/. I moved all my dlls over into there and the error was gone.
On a sidenote, if anybody knows how to tell Excel not to look there for my files but instead where the .tlb was found, I'm interested. (I already tried adding the path to the PATH environment variable)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With