Silverlight 4 and COM Interop - silverlight

I've created a ComVisible-class:
[Guid("73a3f91f-baa9-46ab-94b8-e526c22054a4"), ComVisible(true)]
public interface ITest
{
void Foo();
}
[Guid("99f72d92-b302-4fde-89bb-2dac899f5a48"), ComVisible(true)]
public class Class1 : ITest
{
public void Foo() { }
}
and registered it via
regasm ComClassTest.dll /tlb:ComClassTest.tlb
into the registry.
When I try to call it in my Silverlight 4 out-of-browser, elevated trust application like this:
var foo = AutomationFactory.CreateObject("ComClassTest.Class1");
I get an exception "{System.Exception: Failed to create an object instance for the specified ProgID."
However, I am able to call AutomationFactory.CreateObject("Word.Application") without an Exception and to call Activator.CreateInstance(Type.GetTypeFromProgID("ComClassTest.Class1")) in a normal C#-console application if I copy the ComClassTest.dll into the bin-directory.
What have I forgotton?

First thing to do is test that you can create the object from somewhere else such as VBScript. Create a .vbs file with the content:-
o = CreateObject("ComClassTest.Class1")
If that doesn't generate an error then there is something specifically that SL OOB is upset with otherwise your problem isn't really related to Silverlight at all.
Consider making the following changes to your COM code.
Its often easier to specify ComVisible(true) at the assembly level. You can do that from the application tab of the project properties on the Assembly Information dialog. You can also get Visual Studio to register the assembly with COM and build time using the option found on the build tab of the project properties.
Its a good idea to be specific about the ComInterfaceType you want to expose.
Things get really messy if you expose the class interface directly generally you only want the interface you have defined to be used and that this be the default interface for the class. In addition it probably better to stick to COM naming conventions for the default interface of a class.
Finally (and possibly crucially in your case) its a good idea to be explicit about the ProgId to use for the class.
Applying the above and we get:-
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("73a3f91f-baa9-46ab-94b8-e526c22054a4")]
public interface _Class1
{
void Foo();
}
[ClassInterface(ClassInterfaceType.None)]
[Guid("99f72d92-b302-4fde-89bb-2dac899f5a48")]
[ProgId("ComClassTest.Class1")]
public class Class1 : _Class1
{
public void Foo() { }
}

Related

AssemblyLoadContext.Unload does not unload a Wpf Library

I am writing here the same issue posted on Github since I don't see much traffic there recently.
.NET Core Version: 3.1.9 and .Net 5
Windows version: 10.0.18363
Does the bug reproduce also in WPF for .NET Framework 4.8?: AssemblyLoadContext not supported
I am trying to load and unload on demand a Wpf App library (and all the related dependencies). Everything works, but none of the assemblies get unloaded when calling the Unload method.
If I replace the Wpf library with a .Net Core library containing a few sample methods, I can see the library removed from VS Modules window after a couple of GC iterations.
If I'm not wrong I should expect AssemblyLoadContext to load WpfLibrary and related dependencies (PresentationCore, PresentationFramework etc), but WpfLibrary is the only one loaded. All the other dependencies seems be loaded in the default context. May be that I misunderstood how it works, but to me seems that the framework dependencies prevent the unloading.
Also I am not sure if the problem I am reporting is related to this and/or this.
I attached a sample project which is structured like this:
Project 1 (MainApp, a console project with added System.Windows.Forms reference to enable message pump)
class Program
{
class WpfAppAssemblyLoadContext : AssemblyLoadContext
{
public WpfAppAssemblyLoadContext() : base(true) { }
protected override Assembly Load(AssemblyName assemblyName) => null;
}
[MethodImpl(MethodImplOptions.NoInlining),]
public static void TestRun()
{
var context = new WpfAppAssemblyLoadContext();
var assembly = context.LoadFromAssemblyPath($"{Environment.CurrentDirectory}\\WpfLibrary.dll");
var inst = (IProxy) assembly.CreateInstance("WpfLibrary.MainWindow");
inst.ShowWindow();
inst.CloseWindow();
context.Unload();
assembly = null;
context = null;
inst = null;
}
[STAThread,]
static void Main(string[] args)
{
TestRun();
for (var i = 0; i < 100; i++) {
GC.Collect();
GC.WaitForPendingFinalizers();
}
Application.Run();
}
}
Project 2 (ProxyInterface)
namespace ProxyInterface
{
public interface IProxy
{
void ShowWindow();
void CloseWindow();
}
}
Project 3 (a regular wpf library with implementation of interface in Project 2 )
namespace WpfLibrary
{
public partial class MainWindow : Window, IProxy
{
public MainWindow()
{
InitializeComponent();
}
public void ShowWindow() { Show();}
public void CloseWindow() { Close();}
}
}
UnloadWpfLibrary.zip
(Solution file inside "MainApp" folder)
Further updates:
DotNet team added the issue to "Future Milestone", therefore I have to deduce that they recognized this as a bug. I have no idea on when we will see Wpf working with AssemblyLoadContext.
Seems to be that there is a workaround which involve splitting the target assembly into two separate assemblies. I attached the project with the suggested modifications and this time one of the two assemblies is unloaded, but all of the others are still loaded included WpfLibrary.
UnloadWpfLibraryWithWorkaround.zip
I think that for me it's time to give up and recur to IPC (named pipes) although I am not sure if this could be a valid replacement.
May be I missed something and someone more expert can do further progress and attach here the project with the correct modifications, it would be of great benefit for all the users that want to use ALC to load and unload WPF.
It would be a total of 4 projects just to load and unload a wpf assembly on demand and this is not exactly clean, but if the final result is the same it would be acceptable.

Nancyfx localization

I'm testing localization in Nancy and able to get it to work using EMBEDDED resource files but the issue is I don't want embedded resource files because I want them to be allowed to be edited via the GUI or using the file (if I go the DB route or setting the resource file as "content").
According to the doucmentation you should be able to override it to support using a database but I'm unable to get this to work (https://github.com/NancyFx/Nancy/wiki/Localization):
public class ResourceManager : ResourceBasedTextResource
{
public ResourceManager(IResourceAssemblyProvider resourceAssemblyProvider) : base(resourceAssemblyProvider)
{
}
public new string this[string key, NancyContext context]
{
get
{
return "HELO!";
}
}
}
This was just me messing around but I was hoping in the Razor view when I did #Text.Localization. it should return "HELO!" for everything... however it is not working
There really isn't a question in your post so I'm going to have to guess a bit and assume that you're not getting any exception but rather you're not seeing the "HELO!" in your view
Simply implementing a new ResourceBasedTextResource class is not enough. This is a core component and as such you are going to explicitly have to tell Nancy to use it. You do this by overriding the InternalConfiguration property of your Bootstrapper and tell Nancy to use your implementation instead
You can see it in the DemoBootstrapper of the demo that is linked from that wiki page https://github.com/NancyFx/Nancy/blob/8970ac9d6c7cf46e6060f0b83117c19fa18085c2/src/Nancy.Demo.Razor.Localization/DemoBootstrapper.cs#L11
Also, if you are not going to use resource files, then you should look into inheriting from ITextResource interface instead. It's a simple interface so it should be straight forward.
HTH

MEF and loading EntityTypeConfiguration in runtime

You cannot vote on your own post
0
Hi.
I am developing this (http://arg-co.com/SabteNam%20-%20Copy.zip) windows application, and for my DAL I use Entity Framework. But every single extension has its own EntityTypeConfiguration, so I decided to use [Import] and [Export] to add them in OnModelCreating method of my DbContext.The problem here is that, in 'SabteNamDbContext' class which is located on 'SabteNamDataAccess' library, the '_Configs' is not initialized so I cant iterate it and add its items to 'modelBuilder.Configurations'.
In the source code of 'SampleConfiguration' class, I commented out '[Export(typeof(IDbConfiguration))]' but even Uncommenting this part of code, do not cause application to work properly.
Intresting point is that, if I use the following code in 'Main' windows form, the '_Configs' would be initialized :
[ImportMany(typeof(IDbConfiguration))]
public IEnumerable<EntityTypeConfiguration<object>> _Configs { get; set; }
How can this be fixed ?
While I realize this is probably no longer of use to you, we use a variation on this model from OdeToCode, which I advise you read.
In our case, we have created an interface for our extensions in general, not just for the entity configuration like Scott did, which allows us not only to load the configurations, but also factory and test data per extension, add new permission types to the core application, etc.
Our OnModelCreating looks something like this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// load core object mappings
modelBuilder.Configurations.Add(new UserConfiguration());
modelBuilder.Configurations.Add(new PermissionConfiguration());
// get plugin assemblies
var catalog = new DirectoryCatalog("bin");
var container = new CompositionContainer(catalog);
container.ComposeParts();
var plugins = container.GetExportedValues<IPlugin>();
// load plugin object mappings
foreach (IPlugin plugin in plugins)
{
plugin.RegisterDomainEntities(modelBuilder.Configurations);
}
base.OnModelCreating(modelBuilder);
}

Silverlight client, datacontract, and private readonly members

I have a Silverlight client and a WCF service that I want to have share a class:
[DataContract]
public class DatesAreFun
{
[DataMember]
private readonly DateTime _date;
[DataMember]
private readonly bool _isFun;
public DateTime DateTime { get { return _date; } }
public bool IsFun { get { return _isFun; } }
public DatesAreFun(DateTime date, bool isFun)
{
_date = date;
_isFun = fun;
}
}
The WCF side seems to send the appropriate data across the wire just fine, but the Silverlight side doesn't like it one bit. It is treating the WCF service DatesAreFun class as a different class than my DatesAreFun class.
Any suggestions on how best to remedy this? Thanks!
This is a common issue and has been covered here more than a few times.
When you add your service reference, make sure you click the Advanced button, then ensure you have ticked the Reuse types in referenced assemblies checkbox, and selected the Reuse types in all referenced assemblies option.
You also have to create a new class library assembly that targets the Silverlight runtime. This is because the class library referenced by the WCF services will target the full (or maybe the client profile) version of the .Net framework, which a Silverlight assembly cannot do (in fact a Silverlight assembly can only reference other Silverlight targeted assemblies). In your new class library you can reference the same physical files that the full version of the class library is using, this is detailed more here (i had the same question once upon a time...). You could also pick your way through this bunch of search results for related questions.
Depending on how you do things you may find you also have to trawl through the Reference.cs file of the Service Reference, and change the namespaces of the named data entities. (This file will get regenerated if you update or reconfigure the service reference).

AppDomain.GetData method not accessible?

I am developing a Silverlight 3 application and I would like to delegate all unexpected error handling in a single instance of a class I have named ErrorHandler. This class has one method named HandleApplicationException, plus a couple of other methods to handle more specialized errors.
In my application I am using Unity for dependency injection, but since I want the error handling object to be available even when the Unity container is not yet set up, I register the object as AppDomain global data in the App class constructor, this way:
public App()
{
this.Startup += this.Application_Startup;
this.Exit += this.Application_Exit;
this.UnhandledException += this.Application_UnhandledException;
AppDomain.CurrentDomain.SetData("ErrorHandler", new ErrorHandler());
InitializeComponent();
}
And in case of unhandled exception, I retrieve the error handler object and use it this way:
private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
{
e.Handled = true;
var errorHandler = AppDomain.CurrentDomain.GetData("ErrorHandler") as ErrorHandler;
Debug.Assert(errorHandler != null, "No ErrorHandler registered.");
errorHandler.HandleApplicationException(e.ExceptionObject);
}
The problem is that the AppDomain.GetData method in the Application_UnhandledException method is throwing a MethodAccessException. I don't understand why, as I am just invoking a public method on the AppDomain class. I have used a similar approach in other applications and it worked fine (anyway these were not Silverlight applications).
So, what's going on? Am I doing something wrong?
Ok, I got it. From MSDN documentation:
This member has a
SecurityCriticalAttribute attribute,
which restricts it to internal use by
the .NET Framework for Silverlight
class library. Application code that
uses this member throws a
MethodAccessException.
I have resorted to storing the error handler in a public property in the App class, then I access it using ((App)Application.Current).ErrorHandler. I don't like doing things this way but I suppose it is ok in this special case.
Why can't you just use a static instance of ErrorHandler? I.e. have something like ErrorHandler.Current?
It looks like you're trying to manually construct a poor man's IoC framework to be honest.
Consider doing some research on Unity/Ninject and see for yourself why strongly-typed decoupling is better.

Resources