I have a COM object called Test and the .rgs files looks as follows. I do see that this class is registered in the registery at the location HKEY_LOCAL_MACHINE>>SOFTWARE>>Classes>>CLSID.
HKCR
{
NoRemove CLSID
{
ForceRemove {17899D17-698D-4781-894C-3BAA80F3D4BB} = s 'Test Class'
{
ForceRemove 'Programmable'
InprocServer32 = s '%MODULE%'
{
val ThreadingModel = s 'Apartment'
}
val AppID = s '{D2A47892-4C98-11D6-8C6D-00105A1790CD}'
'TypeLib' = s '{9A887890-4C99-11d6-8C6D-00105A1790CD}'
}
}
}
When I create an instance of this object inside a C++ project it works fine. The code used is:
ATLTRACE( _T( " | CoCreateInstance Test\n" ) );
hr = m_Test.CoCreateInstance(CLSID_Test, NULL, CLSCTX_INPROC_SERVER);
if (FAILED(hr))
CREATE_COM_OBJECT_ERROR(_T("Test"));
However when I try to call this object from .NET application it errors out saying "An unhandled exception of type 'System.Runtime.InteropServices.COMException' occurred in PatternEditor.exe
Additional information: Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))". The code used is as follows:
public partial class MainWindow : Window
{
Main m_Main = new Main();
Test m_Test;
public MainWindow()
{
InitializeComponent();
//This line errors
m_Test = m_Main.Test;
}
}
Usually, the easiest way to use COM objects inside .NET is creating a reference in the project (the tab COM). It will generate a "stub" and you can use as simple .NET code.
Other way is through reflection. This answer has an idea: C# COM and attaching events
Related
I'm trying to integrate a Brother QL-700 label printer into a C# application that I'm writing. I've created a console application to test the printer with and added the following code (taken from the SDK on the Brother website):
class Program
{
private const string TEMPLATE_DIRECTORY = #"c:\program files\brother bpac3 sdk\templates\";
private const string TEMPLATE_FRAME = #"NamePlate2.LBX";
static void Main(string[] args)
{
string templatePath = TEMPLATE_DIRECTORY;
templatePath += TEMPLATE_FRAME;
IDocument doc = new bpac.Document();
if (doc.Open(templatePath) != false)
{
doc.GetObject("objCompany").Text = "Company";
doc.GetObject("objName").Text = "Your name here...";
doc.StartPrint("", PrintOptionConstants.bpoDefault);
doc.PrintOut(1, PrintOptionConstants.bpoDefault);
doc.EndPrint();
doc.Close();
}
else
{
Console.WriteLine("Open() error: " + doc.ErrorCode);
Console.ReadLine();
}
}
}
The application stops on the line where I create a new instance of bpac.Document and it throws the following error message:
System.Runtime.InteropServices.COMException: 'Retrieving the COM class factory for component with CLSID {B940C105-7F01-46FE-BF41-E040B9BDA83D} failed due to the following error: 80040154 Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG)).'
There are several other posts on Stack Overflow about this issue and I have tried some of the commonly suggested fixes:
The DLL in question is definitely in the Windows registry
I have changed the application architecture on the console application to x86
I'm still unable to make any progress. Does anyone else have any other ideas?
I have a 32-bit program (written in C++) that can connect to some different devices and as long as it is 32-bit everything works fine. However, now I need to build it as a 64-bit program but then I came across some problems with Windows Phone 7.
I found out that a dll (written in C#) that I rebuilt as 64-bit throws exception at this line:
MultiTargetingConnectivity connectivity = new MultiTargetingConnectivity(CultureInfo.CurrentUICulture.LCID);
The exception is:
An unhandled exception of type 'Microsoft.SmartDevice.Connectivity.DatastoreException' occurred in Microsoft.SmartDevice.Connectivity.dll
Additional information: Retrieving the COM class factory for component with CLSID {349AB2E8-71B6-4069-AD9C-1170849DA64C} failed due to the following error: 80040154 Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG)).
(For example, if I try to run this example program it works in 32-bit but throws that exception in 64-bit at the same line)
When I searched for that CLSID in the registry I found a path to to "C:\Program Files (x86)\Common Files\Microsoft Shared\Phone Tools\CoreCon\11.0\Bin\ConMan2.dll" so I registered that dll using regsvr32 but I still get the same exception.
UPDATE:
Since I might need to create a workaround instead of finding a 64bit version of ConMan2.dll, I post a bit of my current dll here if anybody can show me a possible workaround so that it will work in both 32 and 64 bit.
namespace WP7DLL
{
// Interface declaration.
[Guid("11111111-1111-1111-1111-111111111111")]
public interface IWP7DLL
{
int GetStatus();
};
[ClassInterface(ClassInterfaceType.None)]
[Guid("22222222-2222-2222-2222-222222222222")]
public class WP7DLL : IWP7DLL
{
public WP7DLL() { }
public int GetStatus()
{
//Line that gives an exception in 64 bit
MultiTargetingConnectivity connectivity = new MultiTargetingConnectivity(CultureInfo.CurrentUICulture.LCID);
...
...
}
}
}
The COM server with CLSID = {349AB2E8-71B6-4069-AD9C-1170849DA64C} is implemented in C:\Program Files (x86)\Common Files\Microsoft Shared\Phone Tools\CoreCon\11.0\Bin\ConMan2.dll
There’s no 64-bit version of that DLL.
And you can’t use a 32-bit DLLs directly from a 64 bit process.
There’s a workaround. You can create another project, 32-bit EXE, that will call that 32-bit DLL however you want, and implement any IPC to interact with your main 64-bit application.
For the specific IPC mechanism, if you only need to invoke a single relatively long task and wait for it to complete, command-like app + command-line arguments + exit code may me enough for you.
If you need to issue many calls, I’d choose WCF over named pipe transport. If you’ll choose this way, below is some sample code implementing that .EXE.
/// <summary>The class from the shared assembly that defines WCF endpoint, and named events</summary>
public static class InteropShared
{
// Host signals it's ready and listening. Replace the zero GUID with a new one
public static readonly EventWaitHandle eventHostReady = new EventWaitHandle( false, EventResetMode.AutoReset, #"{00000000-0000-0000-0000-000000000000}" );
// Client asks the host to quit. Replace the zero GUID with a new one
public static readonly EventWaitHandle eventHostShouldStop = new EventWaitHandle( false, EventResetMode.AutoReset, #"{00000000-0000-0000-0000-000000000000}" );
const string pipeBaseAddress = #"net.pipe://localhost";
/// <summary>Pipe name</summary>
// Replace the zero GUID with a new one.
public const string pipeName = #"00000000-0000-0000-0000-000000000000";
/// <summary>Base addresses for the hosted service.</summary>
public static Uri baseAddress { get { return new Uri( pipeBaseAddress ); } }
/// <summary>Complete address of the named pipe endpoint.</summary>
public static Uri endpointAddress { get { return new Uri( pipeBaseAddress + '/' + pipeName ); } }
}
static class Program
{
/// <summary>The main entry point for the application.</summary>
[STAThread]
static void Main()
{
// The class implementing iYourService interface that calls that 32-bit DLL
YourService singletoneInstance = new YourService();
using( ServiceHost host = new ServiceHost( singletoneInstance, InteropShared.baseAddress ) )
{
// iYourService = [ServiceContract]-marked interface from the shared assembly
host.AddServiceEndpoint( typeof( iYourService ), new NetNamedPipeBinding(), InteropShared.pipeName );
host.Open();
InteropShared.eventHostReady.Set();
// Wait for quit request
InteropShared.eventHostShouldStop.WaitOne();
host.Close();
}
}
}
Suppose I have a Host / Plugin scenario:
Host:
static void Main(string[] args)
{
var path = #"D:\Plugin.dll";
var assembly = Assembly.LoadFile(path);
var type = assembly.GetType("Plugin.K");
var method = type.GetMethod("Run");
var instance = Activator.CreateInstance(type);
method.Invoke(instance, new object[] {});
}
Plugin:
public class K {
public void Run() {
// EXCEPTION THROWN HERE:
var x = Activator.CreateInstance("Plugin", "Plugin.K");
}
}
Then why is the following exception thrown?
An exception of type 'System.IO.FileNotFoundException' occurred in mscorlib.dll but was not handled in user code
Additional information: Could not load file or assembly 'Plugin' or one of its dependencies. The system cannot find the file specified.
Isn't the assembly already loaded in the AppDomain?
Per MSDN:
The LoadFrom method of the Assembly class loads an assembly given its file location. Loading assemblies with this method uses a different load context.
The recommended way is to use the static (Shared in Visual Basic) Load method of the System.Reflection.Assembly class.
See the above link for additional options.
The assembly is already loaded by the appdomain.
after I looked over the source code of Activator.CreateInstance
I found a solution for you:
public class K
{
public void Run()
{
//var f1 = Assembly.GetAssembly(typeof (K)).CreateInstance("Plugin.K");
//var f2 = Assembly.GetExecutingAssembly().CreateInstance("Plugin.K");
//var f3 = Activator.CreateInstance(typeof(K));
//won't throw exception
var x = Activator.CreateInstance(null, "Plugin.K");
}
}
the problem was inside the activator.createinstance, when the activator tried to load the assembly name and then the assembly.
when you pass null as assembly name the activator will use:
assembly = RuntimeAssembly.GetExecutingAssembly(ref stackMark);
note: examples f1-3 also work.
To debug this turn on Fusion logging in .net
How to enable assembly bind failure logging (Fusion) in .NET
If it is a failure to find a dependency then that will be present in the logs.
If not, it will give you more detailed info on why the exception is being thrown.
I am trying to use the C# interface to the mobile broadband API. The code below compiles and intellisense displays all of the COM methods, but the code does not execute correctly.
MbnInterfaceManager mbnInfMgr = new MbnInterfaceManager();
IMbnConnectionProfile conProfile = (IMbnConnectionProfile)mbnInfMgr;
string xmlBuff = conProfile.GetProfileXmlData();
The following error is produced:
Unable to cast COM object of type 'System.__ComObject' to interfacetype
'MbnApi.IMbnConnectionProfile'.
This operation failed because the QueryInterface call on the COM component
for the interface with IID '{DCBBBAB6-2010-4BBB-AAEE-338E368AF6FA}' failed
due to the following error:
No such interface supported(Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).
Microsoft lists the calls as below:
IMbnConnectionProfile Interface Method C# Signature
Delete public void Delete();
GetProfileXmlData public string GetProfileXmlData();
UpdateProfile public void UpdateProfile( string strProfile);
It looks as if I need to specify the interface but can't seem to find out how to do this.
Can any one show me how to do this please?
By calling IMbnInterfaceManager::GetInterface or IMbnInterfaceManager::GetInterfaces methods.
E.g.
MbnInterfaceManager mbnInfMgr = new MbnInterfaceManager();
IMbnInterfaceManager infManager = (IMbnInterfaceManager)mbnInfMgr;
//obtain the IMbnInterface passing interfaceID
string interfaceID = “{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}”;
IMbnInterface mbnInterface= infMgr.GetInterface(interfaceID);
MbnConnectionProfileManager mbnProfMgr = new MbnConnectionProfileManager();
IMbnConnectionProfileManager profileManager =
(IMbnConnectionProfileManager)mbnProfMgr;
IMbnConnectionProfile[] profArr =
(IMbnConnectionProfile[])profileManager.GetConnectionProfiles(mbnInterface);
I'm trying to use AppDomain to load and unload assemblies run-time. I'm trying to get the example on MSDN working in my application before implementing assembly loading, but I'm running into issues - the DoCallback-invokation fails with exception
Could not load file or assembly '[MyPluginAssembly], Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null' or one of its dependencies. The
system cannot find the file specified.
My assembly ([MyPluginAssembly]) is running loaded by a host application (i.e. it is a plugin). The plugins AppDomain seem to be the application-domain (i.e. it is not sandboxed in a separate domain). I've tried loading the entry/calling/executing-assembly in the new domain to ensure [MyPluginAssembly] is loaded, but even though these calls return non-null I still get the exception above.
The code I use (as in the example on MSDN + the code to load the "parent"-assemblies):
public class PingPong : MarshalByRefObject
{
private string greetings = "PING!";
public static void Main()
{
AppDomain otherDomain = AppDomain.CreateDomain("otherDomain");
// All of these Load()-calls returns non-null
Assembly entryAssembly = otherDomain.Load(Assembly.GetEntryAssembly().GetName());
Assembly callingAssembly = otherDomain.Load(Assembly.GetCallingAssembly().GetName());
Assembly executingAssembly = otherDomain.Load(Assembly.GetExecutingAssembly().GetName());
PingPong pp = new PingPong();
pp.MyCallBack();
pp.greetings = "PONG!";
otherDomain.DoCallBack(new CrossAppDomainDelegate(pp.MyCallBack));
// Output:
// PING! from defaultDomain
// PONG! from defaultDomain
}
// Callback will always execute within defaultDomain due to inheritance from
// MarshalByRefObject
public void MyCallBack()
{
string name = AppDomain.CurrentDomain.FriendlyName;
if (name == AppDomain.CurrentDomain.SetupInformation.ApplicationName)
{
name = "defaultDomain";
}
Console.WriteLine(greetings + " from " + name);
}
}
What circumstances can cause the exception I get?
You should look at the CreateInstanceFromAndUnwrap method. It is the one to use for sandboxed add-in scenarios like yours. System.AddIn (MAF) is using this method to load the add-in pipeline segments.