Installing OpenXML File Converter - c#

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());
}
}

Related

Does the Visual Studio OneClick publisher change the byte array needed for RSA encryption?

I'm trying to publish a COM add-in for Word and need to have a license file. I'm using Rhino Licensing and the file has no issues during debugging, but when using OneClick to publish the add-in the license is reported as no longer valid. Here is the code for the class I'm using to check the license:
using System;
using System.IO;
using Rhino.Licensing;
namespace Services.Licensing
{
public class LicenseChecker
{
private static string PublicKeyPath;
private static string LicensePath;
public static bool LicenseIsValid(string licPath)
{
bool result = false;
Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
String Root = Directory.GetCurrentDirectory();
PublicKeyPath = Root + #"\Licensing\publicKey.xml";
LicensePath = Root + #"\Licensing\license.xml"; //licPath;
// not working on INSTALL, runs fine in debug
try
{
var publicKey = File.ReadAllText(PublicKeyPath);
//Throws an exception if license has been modified
LicenseValidator validator = new LicenseValidator(publicKey, LicensePath);
validator.AssertValidLicense();
if (validator.ExpirationDate > DateTime.Now)
{
result = true;
}
}
catch
{ }
return result;
}
}
}
I'm trying to bundle the license with the exe I'll be giving to a small testing group to save the testers unnecessary trouble managing the license and public key. Currently I have the (valid) license file and public key as embedded resources, set to "copy always."
I'm having the same issue when the license is not bundled with the published exe, but the public key is. When both files are left outside of the solution, there seems to be no problem. Could publishing the solution be changing the byte array of the public key or the license?
I'm using .Net Framework 4.7.2 and Visual Studio 2019.
After a lot of toying, the broad answer seems to be no, ClickOnce publishing does not affect the byte array.
The error seems to be occurring because the ClickOnce is not copying XML files into the Application Files folder it creates at all.
After pulling the licenses into a desktop folder and having the program call them from there, another class that uses XML files to load list items would not initialize, leading me to put Try{} around all functions that use pre-made XML files in my program. Each of these functions returned the Catch{}. I'm assuming that ClickOnce is too simplistic an installer to be used if you are trying to include many/any resource files, especially if they are XML.

LaunchAdvancedAssociationUI in C# -> Element not found on Windows 8

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!

Issue with COM References : System.Runtime.InteropServices.COMException: Creating an instance of the COM component with CLSID

I am a French intern and I got a really big issue so can you help me please :
The goal of my project is to automatize some tests from a .dll coded in VB6 in a C# programs.
In fact I use some classes from my VB project which will allow us to prevent regressions in the code. The .dll is in x86 so my C# project.
Here is an example of how I use the dll
using E2S_Equipment;
…
public void verifyEquipmentTextProperty(string eqpCode, bool equipmentIsDynamic, string textPropertyCode, bool textPropertyIsDynamic, string propValue)
{
//Class from E2S_Equipment dll
claEQPSRVReadString readStrService = new claEQPSRVReadString();
readStrService.LoadByKey(eqpCode);
…
}
All my test are in success when I launch them in Visual Studio but when I launch them with Command Line with MSTest the first test is in success and the others are in failure. My error is :
System.Runtime.InteropServices.COMException: Creating an instance of the COM component with CLSID {987C190C-8CFD-4E41-882B-3BAE73768066} from the IClassFactory failed due to the following error: 800a005b Exception from HRESULT: 0x800A005B.
My problem concern the declaration of claEQPSRVReadString
My first thought was that my code created for each test a new instance of the COM Object and so I created a Singleton pattern to have only one instance of my COM component like this:
public static class SrvReadTextPropertySingleton
{
private static claEQPSRVReadString mEqpSrvReadTextProperty;
public static claEQPSRVReadString EqpSrvReadTextProperty
{
get
{
if (mEqpSrvReadTextProperty == null)
{
mEqpSrvReadTextProperty = new claEQPSRVReadString();
}
return mEqpSrvReadTextProperty;
}
}
}
And now I get this error SrvReadTextPropertySingleton. EqpSrvReadTextProperty.LoadByKey(eqpCode);.
System.Runtime.InteropServices.InvalidComObjectException: COM object that has been separated from its underlying RCW cannot be used.
So, do you have any idea?
Thanks you in advance !
Are you 100% sure that your project settings are correct. Your Platform Target should be x86 and the Prefer 32-bit check box should be ticked. Also are you running the Debug version or the release version from the command line. You need to set your 32 bit settings for both environments.
For the command line version print out the following to ensure your environment is correct.
Console.WriteLine("OS {0}, Process {1}", System.Environment.Is64BitOperatingSystem, System.Environment.Is64BitProcess);
It may also be useful to keep a reference to the object you are using so that you create it before you use it and then assign it's output value.
var instance = new claEQPSRVReadString();
mEqpSrvReadTextProperty = instance.Value;
Once of course that's possible to access the value that was read from the instance. It looks like it's doing all it's work during the construction phase in the VB6 component, which is a some what an unusual way of doing it. Do you have any other methods to use on the instance that is created.
I Found the problem. It's was due link to the Thread Execution.
In the .testsettings file we add :
<Execution>
<ExecutionThread apartmentState="MTA"/>
</Execution>
</TestSettings>
http://ralessi.wordpress.com/2013/09/11/mta-testing-on-vs2012/

What does "Unhandled Exception: GLib.GException: Unhandled tag: 'requires'" mean?

I'm trying to get my linux Gtk# application working on Windows. When I try to run it, I get this error message:
Unhandled Exception: GLib.GException:
Unhandled tag: 'requires'
at Gtk.Builder.AddFromFile(String
filename)
at Interface.MainWindow..ctor()
at [My Project Name].MainClass.Main(String[]
args) in c:\Path\To\Main.cs:line 10
It seems to be happening when trying to build the interface from my Glade file. I've checked and the path to the glade file is correct. What might be going wrong?
Here is some code to reproduce the problem:
using System;
using Gtk;
namespace TestGtk {
class MainClass {
public static void Main (string[] args)
{
Application.Init();
string gladefile = #"C:\path\to\gladefile.glade";
Builder builder = new Builder();
builder.AddFromFile(gladefile);
Application.Run();
}
}
}
Strange... I don't know why on windows GTK# does not support requires. Anyway I'd try to remove the <requires ... /> tag from gladefile.glade.
This most likely means that your Glade file is corrupt or has got some weirdness in it.
You're using GtkBuilder to load GladeXML files. GtkBuilder has different XML format, incompatible with GladeXML (it more generic). If you use glade-3 to design your UI, you have an option to save as GtkBuilder XML or GladeXML. Also, glade has utility called gtk-builder-convert that you can use to convert GladeXML to GtkBuilder XML.
So, there are two options:
Use glade-3 and save your UI in GtkBuilder format
Use gtk-builder-convert utility
Glade is for GTK 3.x and your system is probably on GTK 4.x.
I had a similar issue when the version was not specified in a Python app using a .glade file, and upon running it would show:
Use gi.require_version('Gtk', '4.0') before import to ensure that the right version gets loaded.
It worked prior to an Ubuntu update last I ran if. After adding
import gi
gi.require_version("Gtk", "3.0")
It works.
A similar issue was noted in a Haskell app. I am not sure how one changes the reference to GTK3 on C#.

Exception details lost when thrown from C++ to C# through COM interop?

I am consuming a cpp COM object from c# code.
My c# code looks like this:
try
{
var res = myComServer.GetSomething();
}
catch (Exception e) { }
However the exception never contains any of the details I set in cpp, in particular my error message.
In my cpp side I have followed several examples I have found on the web:
...
ICreateErrorInfo *pcerrinfo;
IErrorInfo *perrinfo;
HRESULT hr;
hr = CreateErrorInfo(&pcerrinfo);
pcerrinfo->SetDescription(L"C++ Exception");
hr = pcerrinfo->QueryInterface(IID_IErrorInfo, (LPVOID FAR*) &perrinfo);
if (SUCCEEDED(hr))
{
SetErrorInfo(0, perrinfo);
perrinfo->Release();
}
pcerrinfo->Release();
return E_FAIL; // E_FAIL or other appropriate failure code
...
Am I missing anything?
Is there anything else that could affect this, like marshaling, the interop creation or attributes of the com server itself?
Does your COM class support ISupportErrorInfo ?
Assuming that your class does implement ISupportErrorInfo, did you by any chance add the support AFTER you imported the library into your C# project from Visual Studio?
Visual Studio generates the gunk that it needs to talk to a COM library only once, when you import the library. For this purpose, it builds a special translation DLL called "originalDllName.Interop.dll", based on the information available in the TypeLib of the DLL at the time of the import.
You can make implementation changes as often as you want without trouble; but if you changed the library in any way (added new classes, changed the interface definitions, changed the iterfaces implemented by your classes...), you will have to remove the COM DLL from your References, and then re-import it, for the Interop DLL to be refreshed.
I was facing the exact same issue. I had implemented ISupportErrorInfo and the InterfaceSupportsErrorInfo method in my COM module.Still, In C# exception I was not getting the error description I had set in perrorinfo on the C++ side. In my case, the entry of COM_INTERFACE_ENTRY(ISupportErrorInfo) was missing in the header file.
Instead of catching the Exception type, catch COMException type like this ...
try
{
// COM call
}
catch( COMException cEx )
{
// Check HRESULT here
}

Categories

Resources