I did a prototype some time ago, using VSTO and exposing its methods to an other project.
Now I tried to implement my then successful use to a project I am currently working on, but it doesn't work.
I get an Exception Message "System.__ComObject enthält keine Definition für Open.", which in English means as much, as there is no definition in that ComObject.
What am I doing wrong here?
I checked for missspellings, references and if I forgot to implement something I did with the prototype, without success.
Originally I got pointed to the way I am implementing in this answer:
https://stackoverflow.com/a/35555413/3664953
While the containing link is awsome and does help with working at VSTO, I don't see a solution for my particular problem here. Also I checked for problems, this answer pointed out:
https://stackoverflow.com/a/3690214/3664953
I tried using x86-compiled binaries and switched the Framework from 4.5.2 back to 4.5 without change.
€: Well, ok there are changes in behaviour, with the x64-compiled bins (I usually use "Any CPU") there is a null in the ComAddIn's Object ...
I don't really know where this behaviour is orginating, but maybe you do.
Lastly, what is a already bad question, which probably only got created because I am too close up and don't see the mistake, without the broken code.
So here it is, I start with the working Prototype and also include the new code. I cut a little, so now there is only the Open-method in both solutions.
I did this, since I am aware this question is already extremely long and I don't want to kill too much of your time.
The prototype looks like this:
Controler:
static void Main(string[] args)
{
Microsoft.Office.Interop.Word.Application wd =
new Microsoft.Office.Interop.Word.Application();
wd.Visible = false;
object addinName = "Worker_AddIn";
foreach (Microsoft.Office.Core.COMAddIn comaddin in wd.COMAddIns)
{
if (comaddin.ProgId.Equals(addinName.ToString(),
StringComparison.InvariantCultureIgnoreCase))
{
object addinObj = comaddin.Object;
object[] invokeArgs = { "Dummy" };
object retVal =
addinObj.
GetType().
InvokeMember("Open", System.Reflection.BindingFlags.InvokeMethod,
null, addinObj, invokeArgs);
//dynamics ...
var t1 = comaddin.Object.Open("Dummy");
var t2 = comaddin.Object.GetCustomProperties();
var t3 = comaddin.Object.SetCustomProperty("Test",
PropertyTypes.msoPropertyTypeBoolean, 42);
}
}
//Properly close Word
wd.Quit();
}
AddIn:
PropertyReaderWriter with its Interface:
public enum WordBuiltinProperties
{
//some enums
}
public enum PropertyTypes
{
//more enums
}
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IPropertyReadWriter
{
bool Open(string Path);
//There are more methods, but this one is already causing problems,
//also the others don't work either, so I kept the simplest one ;)
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class PropertyReaderWriter : StandardOleMarshalObject, IPropertyReadWriter
{
public bool Open(string Path)
{
return false;
//This was a test, if I could actually use those methods outside of VSTO,
//so I didn't implement logic, since I know the stuff I need works in VSTO.
}
}
The AddIn override of RequestComAddInAutomationService():
private IPropertyReadWriter rw;
protected override object RequestComAddInAutomationService()
{
if (rw == null)
rw = new PropertyReaderWriter();
return rw;
}
The Program class:
Microsoft.Office.Interop.Word.Application wd =
new Microsoft.Office.Interop.Word.Application();
wd.Visible = false;
object addinName = "Worker_AddIn";
foreach (Microsoft.Office.Core.COMAddIn comaddin in wd.COMAddIns)
{
if (comaddin.ProgId.Equals(addinName.ToString(),
StringComparison.InvariantCultureIgnoreCase))
{
object addinObj = comaddin.Object;
object[] invokeArgs = { "Dummy" };
object retVal = addinObj.
GetType().
InvokeMember("Open", System.Reflection.BindingFlags.InvokeMethod,
null, addinObj, invokeArgs);
//dynamics ...
var t1 = comaddin.Object.Open("Dummy");
var t2 = comaddin.Object.GetCustomProperties();
var t3 = comaddin.Object.SetCustomProperty("Test", PropertyTypes.msoPropertyTypeBoolean,
42);
}
}
//Properly close Word
wd.Quit();
The implementation in my project looks like this.
With the interface I have a derived interface, called IPropertyReadWrite_Word, where I add some more methods, I don't override. Also I use IPropertyReadWrite_Word for my final implementation, but since it is this interface, that defines "Open" I only post this to shorten the extremely long post.
Interface:
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IPropertyReadWrite_Common
{
/// <summary>
/// Soll die Datei am entsprechenden Pfad öffnen.
/// </summary>
/// <param name="Path">Pfad zur Datei</param>
/// <returns>Gibt Erfolg/true oder Misserfolg/false zurück.</returns>
bool Open(string Path);
}
The implementation in the AddIn:
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class Word_PropertyReadWrite : StandardOleMarshalObject, IPropertyReadWrite_Word
{
internal static Word.Document Document;
internal ThisAddIn home;
/// <summary>
/// Erzeugt die Klasseninstanz.
/// </summary>
/// <param name="home">Übergibt das ThisAddIn-Objekt,
/// um die Funktionen von Word verwenden zu können.</param>
public Word_PropertyReadWrite(ThisAddIn home)
{
this.home = home;
}
/// <summary>
/// Öffnet die Datei am entsprechenden Pfad.
/// </summary>
/// <param name="Path">Pfad zur Datei</param>
/// <returns>Gibt bei Erfolg true zurück.</returns>
public bool Open(string Path)
{
try
{
Document = home.Application.Documents.OpenNoRepairDialog(FileName: Path,
ConfirmConversions: false, ReadOnly: false, AddToRecentFiles: false,
Revert: false, Visible: false, OpenAndRepair: true, NoEncodingDialog: false);
return true;
}
catch
{
//TODO: Logging
//Rethrow der entstandenden Exception.
throw;
}
}
}
The override of RequestComAddInAutomationService():
private Word_PropertyReadWrite PropertyReadWrite;
protected override object RequestComAddInAutomationService()
{
//System.Diagnostics.Debugger.Break();
if (PropertyReadWrite == null)
PropertyReadWrite = new Word_PropertyReadWrite(this);
return PropertyReadWrite;
}
And lastly, this is my testclass so far:
static void Main(string[] args)
{
Microsoft.Office.Interop.Word.Application wd =
new Microsoft.Office.Interop.Word.Application();
wd.Visible = false;
object addinName = "Dokumentenvorbereitung_Word_AddIn";
try
{
Microsoft.Office.Core.COMAddIn addin =
wd.COMAddIns.Item(ref addinName);
foreach (Microsoft.Office.Core.COMAddIn comaddin in wd.COMAddIns)
{
if (comaddin.ProgId.Equals(addinName.ToString(),
StringComparison.InvariantCultureIgnoreCase))
{
var test = (comaddin).Object.Open(@"Path to some valid .docx");
}
}
}
catch(Exception e)
{
//...
}
finally
{
wd.Quit();
}
}