I'm trying to set up a way to manage file associations for my program in C#. I already set the correct values in the registry with WiX, and found a wrapper for ApplicationAssociationRegistrationUI which should allow me to open the GUI to set file associations. But it doesn't work. I get the following exception: Element not found. (Exception from HRESULT: 0x80070490)
The wrapper:
namespace FileAssociation
{
[ClassInterface(ClassInterfaceType.None)]
[ComImport]
[Guid("1968106d-f3b5-44cf-890e-116fcb9ecef1")]
[TypeLibType(TypeLibTypeFlags.FCanCreate)]
public sealed class ApplicationAssociationRegistrationUI : IApplicationAssociationRegistrationUI
{
[MethodImpl(MethodImplOptions.InternalCall)]
public extern void LaunchAdvancedAssociationUI(string appRegistryName);
}
[CoClass(typeof(ApplicationAssociationRegistrationUI))]
[ComImport]
[Guid("1f76a169-f994-40ac-8fc8-0959e8874710")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[TypeLibImportClass(typeof(ApplicationAssociationRegistrationUI))]
public interface IApplicationAssociationRegistrationUI
{
void LaunchAdvancedAssociationUI([MarshalAs(UnmanagedType.LPWStr)] string appRegistryName);
}
}
Usage:
var assocUi = new ApplicationAssociationRegistrationUI();
try
{
assocUi.LaunchAdvancedAssociationUI(InstanceManager.ProgId);
}
catch
{
MessageBox.Show("Could not display the file association manager. Please repair the installation and try again.", "Error", MessageBoxButton.OK, MessageBoxImage.Warning);
}
finally
{
Marshal.ReleaseComObject(assocUi);
}
Again, all the correct keys exist in the registry. This is not the first time COM Interop fails miserably for me so I am beginning to think that I must be missing something important. I tried checking "Register for COM Interop" in the project properties, and I tried making it COM-Visible.
I am aware that this only works on Vista or newer, which is fine since my program doesn't support XP anyway. I'm testing it on Windows 8.1, both as Admin and as normal user.
EDIT: It works on Windows 7! On MSDN it does not say that this API was deprecated in Win8...
What have I done wrong? Is there an easier way to do this which I don't know about?
Finally found the problem!!!
Starting from Windows 8, the program needs to have company information (I think this is a bug, since it isn't mentioned on Microsoft's site.)
So make sure to fill out this attribute in AssemblyInfo.cs:
[assembly: AssemblyCompany("YourCompany")]
If it's an empty string it won't work!
Related
I've struggle several hours on that and I can't find what I'm doing wrong.
I created a new C# dll project, here is the content of the only class it contain:
using System;
using System.Runtime.InteropServices;
namespace PolygonSl {
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class Config {
[ComVisible(true)]
public string GetCompany() {
return "POL";
}
}
}
I basically remove everything from it trying to make it work, the only reference is System.
I checked the Make assembly COM-Visible flag on the Assembly Information and my project is signed (seams required for codebase).
It compiling fine, after that, I called RegAsm.exe, giving it my dll, I added /codebase and /tlb, the command is successful.
When I go to my VBA project, I can add my new tlb file to the references, working fine. After, I can use it in my code, the autocomplete is working and I can compile with no errors.
Then, when I execute, I got this:
Run-time error '430':
Class does not support Automation or does not support expected interface
Here is my code sample in the VBA:
Private Sub Button1_Click()
'With CreateObject("PolygonSl.Config")
With New PolygonSl.Config
MessBox .GetCompany, MB_OK, "Test"
End With
End Sub
I tried late binding and my code is running fine with it but I'd like to be able to use the autocomplete.
Anyone have a suggestion on what I could try to make it work?
Edit (Adding some details on my environment)
I work on VS2008 for projects related to Dynamics SL (one of the Microsoft ERPs)
I'm on Windows Server 2008 R8 Standard, running from VMWare
Compiling on Framework 3.5, Release, x86, Dynamics SL client is 32 bits
I tried my dll on Dynamics but also on Excel to be sure that the problem was not Dynamics ;)
I think you need to define an interface to be able to see getcompany.
using System;
using System.Runtime.InteropServices;
namespace PolygonSl
{
[Guid("6DC1808F-81BA-4DE0-9F7C-42EA11621B7E")]
[System.Runtime.InteropServices.ComVisible(true)]
[System.Runtime.InteropServices.InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IConfig
{
string GetCompany();
}
[Guid("434C844C-9FA2-4EC6-AB75-45D3013D75BE")]
[System.Runtime.InteropServices.ComVisible(true)]
[System.Runtime.InteropServices.ClassInterface(ClassInterfaceType.None)]
public class Config : IConfig
{
public string GetCompany()
{
return "POL";
}
}
}
You can generate the interface automatically by placing the cursor in the class definition and using Edit.Refactor.ExtractInterface.
I'd have to admit that I'm at the absolute edge of my abilities here and the above is put together based on examples I've seen elsewhere.
Edit
The following test code works fine on my PC
Option Explicit
Sub polygontest()
Dim my_polygon As SOPolygon.Config
Set my_polygon = New SOPolygon.Config
Debug.Print my_polygon.GetCompany
End Sub
Where SOPolygon is the project name.
I have the purpose to create a com-visible class with UI elements which I can execute/access via Lotus Notes. This is no problem using Visual Studio 2017. My com-visible class is correctly registered in Windows GAC and I'm able to call the available/visible functions supplied by a com-visible class:
[Guid("AD2C59FF-7B27-458E-9745-CB27092BAC9E")]
[ClassInterface(ClassInterfaceType.None)]
public class LotusNotesIntegrator
{
public void OpenDocumentUI(string filePath, string label, string password)
{
try
{
SingeltonUtils.Instance.MainForm.Show();
}
catch (Exception exception)
{
throw;
}
}
public void SetFocus()
{
}
}
I get in trouble when it comes down to usability for the user. Lotus Notes always 'steals' the shortcuts when I'm inside of the UI of my C# com-visible dll which displays a form with a simple text box. As soon as I try to copy the input text of the text box using 'Crtl + C' the shortcut is executed in the underlaying Lotus Notes client. This is a strange behavior as the UI of the com-visible dll is currently with focus and I'm able to type into the textbox field right after the form.Show() method was executed. But the shortcuts are still referenced to the Lotus Notes client which is the host/origin of the com-visible dll.
Has anyone of you experience a similar or the same issue? I hope you guys have an idea or solution for this problem.
Thanks in advance for your effort!
// Martin
i'm trying to create a User Defined Function for MS Excel in C#.
But no matter what I try, when I try to add the Add-in to Excel I always get the infamous "The file you have selected does not contain a new automation server, or you do not have sufficient privileges to register the automation server" error.
Here's the code that I took from and online example just to try it out:
// C#
using System;
using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace AutomationAddin
{
[ClassInterface(ClassInterfaceType.AutoDual)]
public class MyUdf
{
public MyUdf()
{
}
public double addMeTest(double x, double y)
{
return x + y;
}
[ComRegisterFunctionAttribute]
public static void RegisterFunction(Type t)
{
Microsoft.Win32.Registry.ClassesRoot.CreateSubKey(
"CLSID\\{" + t.GUID.ToString().ToUpper() +
"}\\Programmable");
}
[ComUnregisterFunctionAttribute]
public static void UnregisterFunction(Type t)
{
Microsoft.Win32.Registry.ClassesRoot.DeleteSubKey(
"CLSID\\{" + t.GUID.ToString().ToUpper() +
"}\\Programmable");
}
}
}
I tried this with MS Visual Studio 2012 on Excel 2013 x64 and Excel 2010 x86
SolutionsI've found and tried with no success:
[ClassInterface(ClassInterfaceType.AutoDual)] as seen in the code
[ComRegisterFunctionAttribute] AND [ComUnregisterFunctionAttribute] as seen in the code
regasm /codebase did nothing as well
Turning on/off "Register COM interop" (VS running as admin when building)
[assembly: ComVisible(true)] set to true
Tried different code examples from the web
Read this on stackoverflow: How to get COM Server for Excel written in VB.NET installed and registered in Automation Servers list?
I've also tried all of the above together - no luck here
Ran Excel in admin mode
So please guys, if you can tell me what am I missing here and maybe even tell me what should I do to make it work I would be so grateful! Thanks in advance!
I will gladly provide any additional info if needed.
P.S. Haven't had any sleep for two nights now so I might be screwing something up in a really stupid way. If someone could test this code if it works and tell me their project setup it just might help.
You can try this library https://exceldna.codeplex.com, it simplifies creation of UDFs a lot.
I have written a managed OpenXML file converter in c#, but I'm having trouble with the deployment. For deployment, I am using a VS Setup Project.
I guess my first question is, I see some people using a Class Library and others using a Windows Application as the COM server. Is there a preference on either one? My converter has dependencies on libraries not in the GAC.
When it comes to registering the COM server, the following post: http://blogs.msdn.com/b/speront/archive/2009/04/17/9553717.aspx
suggests adding this to the Main() of a managed EXE:
Application.OleRequired();
MyConverter converter = new MyConverter();
Application.Run();
Which would not work for a setup project. This does work though if I manually run the EXE first.
I've tried running regasm:
regasm MyConverter.dll, which succeeds, but when Microsoft Word tries to use the converter, I get the error "Word cannot start the converter MyConverter Document"
Next, I tried creating a Windows Application and using:
public static void Main(string[] args)
{
Guid guid = new Guid("EFADDB5B-933E-49FE-B3C8-F6FD7FB1B788");
RegistrationServices regSrv = new RegistrationServices();
regSrv.RegisterTypeForComClients(typeof(MyConverter), ref guid);
}
Lastly, I tried:
regasm /regfile:test.reg MyConverter.dll
and then importing the registry file.
All of these give the error: "Word cannot start the converter MyConverter Document"
I have the correct registry entries for my converter in Office\12.0\Word\Text Converters\OOXML Converters\Import
The converter has successfully worked. It's just that deployment does not work under any instance.
If you set up the converter correctly it might be that it throws an unhandled exception when Word tries to start it. To figure out what the exception is it is probably a good idea to wrap all of your interface methods with a try/catch block and log the exception stack trace:
public void HrImport(
string bstrSourcePath,
string bstrDestPath,
IConverterApplicationPreferences pcap,
out IConverterPreferences ppcp,
IConverterUICallback pcuic)
{
try
{
// code to import document
}
catch (Exception ex)
{
// log the exception
//
System.Diagnostics.Trace(ex.ToString());
}
}
I have created a simple class library project in visual studio 2008 that has one class as shown below. I am trying to get this class to register for COM interop so that I can use in via unmanaged scripts like vbscript or jscript.
In my project build properties I have checked the box that says "Register for COM Interop".
In the Assembly Settings I have checked "Make this assembly COM Visible" and I have confirmed that the [assembly: ComVisible(true)] attribute is present in the assembly.cs file.
Every time I build this project I get an error that reads "projectname.dll does not contain any types that can be registered for COM Interop. Also, I have not been able to successfully create an instance of class 1 using a vbscript. Does anyone know that this is not registering properly?
My vbscript fails to create activex object at this line... Set F = CreateObject("64BitCLTest.Class1").
Finally, how do I get VS to register this in the 64bit area of the registry instead of the 32 bit area so that 64bit processes can use it?
-- The Test Class--
namespace _64BitCLTest
{
[Guid("BBAA06EF-CA4C-4fe2-97CD-9B1D85ADA656")]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
[ProgId("64BitCLTest.Class1")]
public class Class1
{
Class1()
{
// do nothing
}
public string Method1()
{
return "This is a return string from method 1";
}
public int Property1
{
get {return 777;}
}
}
}
you need to mark the constructor public:
-- The Test Class--
namespace _64BitCLTest
{
[Guid("BBAA06EF-CA4C-4fe2-97CD-9B1D85ADA656")]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
[ProgId("64BitCLTest.Class1")]
public class Class1
{
public Class1()
{
// do nothing
}
public string Method1()
{
return "This is a return string from method 1";
}
public int Property1
{
get {return 777;}
}
}
}
There are two parts to this answer. The first, problem as consultutah said was that I did not have the constructor marked as public.
The second answer is that there is a bug (I believe) in VS2008 that causes assemblies to never be registered in the 64-bit section of the registry, even if the setup project is configured for a target platform of x64.
I installed VS2010, rebuilt the exact same project and ran the Install. The assembly registered perfectly and I was able to successfully access it through COM using a 64bit process. I still have not found a solution for this in VS2008.