I have a program that does batch processing on some drawings. One of the drawings throws an exception "Error Decrypting Data" when I try to open it. This drawing in particular was generated by a third-party tool other than AutoCAD. In addition, this problem only occurs in AutoCAD 2011. In AutoCAD 2010 it prompts the user that the file was generated outside of AutoCAD but they can click and the batch will continue. I've tried opening it using both the managed .NET API and the COM Interop API but both give the same error.
Here is a post from the AutoCAD formus though it didn't provide me with a solution:
http://forums.autodesk.com/t5/NET/Error-Decrypting-Data-Acad-2011/td-p/2661762/highlight/true
Managed API
string drawingFilePath = #"C:\Drawings\MyDrawing.dwg";
Application.DocumentManager.Open(drawingFilePath, false);
COM Interop
string drawingFilePath = #"C:\Drawings\MyDrawing.dwg";
Object comAutoCAD = Application.AcadApplication;
Object comDocuments = comAutoCAD.GetType().InvokeMember("Documents", BindingFlags.GetProperty, null, comAutoCAD, new object[] { });
Object comDocument = comDocuments.GetType().InvokeMember("Open", BindingFlags.InvokeMethod, null, comDocuments,
new object[] { drawingFilePath, false, Type.Missing });
Document.FromAcadDocument(comDocument);
Someone from the AutoCAD forums posted an answer that works for me.
http://forums.autodesk.com/t5/NET/Error-Decrypting-Data-Acad-2011/td-p/2661762/page/2
Here is an example:
const string systemVar_DwgCheck = "DWGCHECK";
Int16 dwgCheckPrevious = (Int16)Application.GetSystemVariable(systemVar_DwgCheck);
Application.SetSystemVariable(systemVar_DwgCheck, 2);
Document document = Application.DocumentManager.Open(#"C:\Drawings\MyDrawing.dwg", false);
// Do stuff...
Application.SetSystemVariable(systemVar_DwgCheck, dwgCheckPrevious);
Related
I'm trying to create a custom Ribbon with a button that triggers a VBA Macro in Outlook 2010. Creation of the ribbon itself works fine but the button doesnt trigger the VBA.
I've tried these solutions: 1) How-to: Run existing Word VBA Macros from C# Ribbon Addin but it throws an error since AFAIK Outlook.Application doesn't have a Run() method, contrary to Excel or Word.
public void RunMacro(object otApp, object[] oRunArgs){
otApp.GetType().InvokeMember("Run",
System.Reflection.BindingFlags.Default |
System.Reflection.BindingFlags.InvokeMethod,
null, oApp, oRunArgs);
}
public void RunChronosMacro(Office.IRibbonControl control)
{
RunMacro(oApp, new object[] { "TestMacro" })
}
2) The third answer of this question Call Outlook VBA code from c# but it also throws an exception {"Unknow name. ( RESULT : 0x80020006 (DISP_E_UNKNOWNNAME))"}. Maybe this was working in Outlook 2007 but it doesn't in my environnement. As this answer is inspired from Python code, I've also tried it in Python but without success.
public void RunChronosMacro(Office.IRibbonControl control)
{
try
{
otApp.GetType().InvokeMember("TestMacro",
System.Reflection.BindingFlags.Default |
System.Reflection.BindingFlags.InvokeMethod,
null, otApp, arFunctionParameters);
System.Runtime.InteropServices.Marshal.ReleaseComObject(otApp);
otApp = null;
GC.Collect();
}
catch (Exception e)
{
MessageBox.Show(e.GetType().ToString());
}
}
I'm quite hard-stuck on this and as I'm not very familiar with C# and Offices add-ins, I don't know what to try next. Thanks in advance for any help.
Please try the code below:
using Outlook = Microsoft.Office.Interop.Outlook;
object oMissing = System.Reflection.Missing.Value;
// create outlook object
Outlook.Application otApp = new Outlook.Application();
string[] functionParameters =
{
sTo,
sCC,
sBCC,
sSubject,
sBody
};
// Run the macro
otApp.GetType().InvokeMember("YourVBA",
System.Reflection.BindingFlags.Default |
System.Reflection.BindingFlags.InvokeMethod,
null, otApp, functionParameters);
For more information, Please refer the link below:
Need to run/invoke macro from c# code for Outlook Addin
How can I run a macro from a VBE add-in, without Application.Run?
Hopefully it helps you!
I'm referring this thread to refresh the windows explorer, I want to refresh some windows only, which means I want to filter the opened windows according to their title or path. Let me copy the code from that thread for more clarification:
Guid CLSID_ShellApplication = new Guid("13709620-C279-11CE-A49E-444553540000");
Type shellApplicationType = Type.GetTypeFromCLSID(CLSID_ShellApplication, true);
object shellApplication = Activator.CreateInstance(shellApplicationType);
object windows = shellApplicationType.InvokeMember("Windows", System.Reflection.BindingFlags.InvokeMethod, null, shellApplication, new object[] { });
Type windowsType = windows.GetType();
object count = windowsType.InvokeMember("Count", System.Reflection.BindingFlags.GetProperty, null, windows, null);
for (int i = 0; i < (int)count; i++)
{
object item = windowsType.InvokeMember("Item", System.Reflection.BindingFlags.InvokeMethod, null, windows, new object[] { i });
Type itemType = item.GetType();
string itemName = (string)itemType.InvokeMember("Name", System.Reflection.BindingFlags.GetProperty, null, item, null);
if (itemName == "Windows Explorer")
{
// Here I want to check whether this window need to be refreshed
// based on the opened path in that window
// or with the title of that window
// How do I check that here
itemType.InvokeMember("Refresh", System.Reflection.BindingFlags.InvokeMethod, null, item, null);
}
}
What I understood from the above code is: By using this line windowsType.InvokeMember("Item", System.Reflection.BindingFlags.InvokeMethod, null, windows, new object[] { i }); we will get the current window object, and then we are using .InvokeMember("Name".. to get the name of that object, like wise what should I pass to InvokeMember method to get the path of that object or the title of that window? or can anyone tell me the possible alternative values for "Name" in the above statement?
What I'm expecting is some code like the following:
string itemPath = (string)itemType.InvokeMember("Something here", System.Reflection.BindingFlags.GetProperty, null, item, null);
OR
string itemTitle = (string)itemType.InvokeMember("Something here", System.Reflection.BindingFlags.GetProperty, null, item, null);
I can give you more information if you need, expecting expert's suggestion to solve this issue,
Thanks in advance
This is the way you had to write late-bound COM client code in the Bad Old Days. Considerable pain and suffering to get it going, what is in the snippet is not close yet. I'll first propose a very different way to do this, there just isn't any point in doing it late-bound since these COM objects are available on any Windows version and are never going to change anymore. The "Embed Interop Types" feature supported since VS2010 removes any good reason to avoid it.
Project > Add Reference > COM tab. Tick "Microsoft Internet Controls" and "Microsoft Shell Controls and Automation". Now you can write it early-bound, nice and compact with all the benefits of IntelliSense to help you find the correct members and avoid typos:
var shl = new Shell32.Shell();
foreach (SHDocVw.InternetExplorer win in shl.Windows()) {
var path = win.LocationURL;
if (!path.StartsWith("file:///")) continue;
path = System.IO.Path.GetFullPath(path.Substring(8));
if (path.StartsWith("C")) win.Refresh();
}
A slightly silly example, it refreshes any Explorer window who's displayed path is located on the C drive. Note how the Path property is not useful to discover what is displayed, LocationURL is needed. You might have to find the distinction between Internet Explorer and Windows Explorer windows (aka "File Explorer"), albeit that IE can also display directory content so I think this is the most correct version.
If you really want to do this late-bound then use the dynamic keyword to minimize the suffering. In this case almost identical:
dynamic shl = Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application"));
foreach (var win in shl.Windows()) {
string path = win.LocationURL;
if (!path.StartsWith("file:///")) continue;
path = System.IO.Path.GetFullPath(path.Substring(8));
if (path.StartsWith("C")) win.Refresh();
}
Answering your question explicitly, use "LocationURL".
I have the following code being used with Word 2016 installed, referencing Microsoft Word 16.0 Object Library:
private void RefreshFootnoteNumbering(FileManagement.FileManager FileManager)
{
Console.WriteLine(DateTime.Now.ToString() + " Refreshing footnotes DOCX");
// Opening and saving in word generates the required element
var Word = GetWordApp();
try
{
var DocxPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, Path.ChangeExtension(FileManager.HtmlFileLocation, "docx"));
Console.WriteLine(DateTime.Now.ToString() + "\tOpening document");
var Doc = GetWordDoc(Word, DocxPath);
try
{
// Fails on these lines below (both cause the same exception)
Doc.Footnotes.NumberingRule = InteropWord.WdNumberingRule.wdRestartPage;
Doc.Footnotes.Location = InteropWord.WdFootnoteLocation.wdBottomOfPage;
Doc.SaveAs2(DocxPath, InteropWord.WdSaveFormat.wdFormatXMLDocument, AddToRecentFiles: false, EmbedTrueTypeFonts: true);
}
finally
{
Doc.Close();
Doc = null;
}
}
finally
{
Word.Quit();
Word = null;
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
This works for most documents, however for some I get the following exception:
System.Runtime.InteropServices.COMException was unhandled
ErrorCode=-2146823680
HResult=-2146823680
HelpLink=wdmain11.chm#37376
Message=Value out of range
Source=Microsoft Word
StackTrace:
at Microsoft.Office.Interop.Word.Footnotes.set_NumberingRule(WdNumberingRule prop)
Other interop functions (iterating/manipulating fields, sections etc) work fine, it seems to be just altering footnotes in this way that have an issue. Altering them from within Word itself works fine.
Has anyone encountered this issue before? Any work arounds or alternatives?
I've tried recording a macro, and it gave this VBA code:
With ActiveDocument.Range(Start:=ActiveDocument.Content.Start, End:= _
ActiveDocument.Content.End).FootnoteOptions
.Location = wdBottomOfPage
.NumberingRule = wdRestartContinuous
.StartingNumber = 1
.NumberStyle = wdNoteNumberStyleArabic
.NumberingRule = wdRestartPage
.LayoutColumns = 0
End With
If I run this macro, I get the same error (value out of range, error number 4608) on the .Location line, whether I run from the debugger, or just view macros -> run.
I've also tried to translate that VBA into C# code:
var Options = Doc.Range(Doc.Content.Start, Doc.Content.End).FootnoteOptions;
Options.Location = InteropWord.WdFootnoteLocation.wdBottomOfPage;
Options.NumberingRule = InteropWord.WdNumberingRule.wdRestartPage;
However, this gives the same error.
Still not sure of the exact cause (possibly something further up in my code creating different sections); still not clear on why it worked when word recorded the macro, but not when running it.
Anyway, I managed to alter the C# code to the below, which seems to do the job and actually works!
foreach(InteropWord.Footnote FootNote in Doc.Footnotes)
{
FootNote.Reference.FootnoteOptions.NumberingRule = InteropWord.WdNumberingRule.wdRestartPage;
FootNote.Reference.FootnoteOptions.Location = InteropWord.WdFootnoteLocation.wdBottomOfPage;
}
The below code is used to get the custom document properties for Excel workbook.
var xlApp = Globals.ThisAddIn.Application; // This works in VSTO Excel Add-in
var xlApp = new global::Microsoft.Office.Interop.Excel.Application(); // This doesn't work anywhere
xlApp.Visible = true;
global::Microsoft.Office.Interop.Excel.Workbook workbook = xlApp.Workbooks.Open(file, false, true, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, false, Type.Missing, Type.Missing);
global::Microsoft.Office.Core.DocumentProperties properties = workbook.CustomDocumentProperties; // Exception occurs here
global::Microsoft.Office.Core.DocumentProperty property = properties["propertyname"];
The first 2 lines are references to the Excel Application. One obtain the reference from VSTO add-in internals, the other is a regular new Application().
When using the Application from VSTO internals, the code run fines without any problems. But when using new Application(), the workbook.CustomDocumentProperties line throws InvalidCastException:
Unable to cast COM object of type 'System.__ComObject' to interface
type 'Microsoft.Office.Core.DocumentProperties'. This operation failed
because the QueryInterface call on the COM component for the interface
with IID '{2DF8D04D-5BFA-101B-BDE5-00AA0044DE52}' failed due to the
following error: No such interface supported (Exception from HRESULT:
0x80004002 (E_NOINTERFACE)).
I am trying to make it to work on a C# winforms project without VSTO. A lot of examples and tutorials use new Application() for Excel interop, but I noticed that Microsoft.Office.Interop.Excel.Application is an interface, so using new on interface is actually strange to me. How can I create a proper Application that can get the CustomDocumentProperties?
Reference Assemblies I am using:
Microsoft.Office.Interop.Excel v2.0.50727 Version 14.0.0.0
Microsoft.CSharp v4.0.30319 Version 4.0.0.0
I noticed that Microsoft.Office.Interop.Excel.Application is an interface, so using new on interface is actually strange to me.
That is strange indeed, but by design. The Excel.Application interface is decorated with the CoClass attribute telling the actual class to instantiate on 'instantiating' the interface. More about it here.
But when using new Application(), the workbook.CustomDocumentProperties line throws InvalidCastException:
Strange indeed again. I have experienced some issues myself using document properties. It seems that the actual class returned differs from the spec, so I moved to use dynamic in order to prevent type casting issues.
So instead of this:
Microsoft.Office.Core.DocumentProperties properties = workbook.CustomDocumentProperties;
Use:
dynamic properties = workbook.CustomDocumentProperties;
How can I create a proper Application that can get the CustomDocumentProperties?
There is no need to create a new Excel Application instance if you develop an add-in. You should use the Application property provided by the VSTO runtime:
var xlApp = Globals.ThisAddIn.Application; // This works in VSTO Excel Add-in
But if you develop a standalone application which automates Excel, in that case you need to create a new Application instance by using the new operator:
var xlApp = new global::Microsoft.Office.Interop.Excel.Application();
Use the late binding technology (Type.InvokeMember) for getting or setting document property as the How To Use Automation to Get and to Set Office Document Properties with Visual C# .NET article suggests.
I've had a same problem. Today it has been resolved. There is a different approach to derive the results. The question and its' answer is at
How can I read excel custom document property using c# excel interop
Here is my implementation.
public string CheckDocProp(string propName, object props)
{
Excel.Workbook workBk = Globals.ThisAddIn.Application.ActiveWorkbook;
object customProperties = workBk.CustomDocumentProperties;
Type docPropsType = customProperties.GetType();
object nrProps;
object itemProp = null;
object oPropName;
object oPropVal = null;
nrProps = docPropsType.InvokeMember("Count",
BindingFlags.GetProperty | BindingFlags.Default,
null, props, new object[] { });
int iProps = (int)nrProps;
for (int counter = 1; counter <= ((int)nrProps); counter++)
{
itemProp = docPropsType.InvokeMember("Item",
BindingFlags.GetProperty | BindingFlags.Default,
null, props, new object[] { counter });
oPropName = docPropsType.InvokeMember("Name",
BindingFlags.GetProperty | BindingFlags.Default,
null, itemProp, new object[] { });
if (propName == oPropName.ToString())
{
oPropVal = docPropsType.InvokeMember("Value",
BindingFlags.GetProperty | BindingFlags.Default,
null, itemProp, new object[] { });
return oPropVal.ToString();
break;
}
else
{
return "Not Found.";
}
}
return "Not Found.";
}
Usage:
object docProps = wb.CustomDocumentProperties;
string prop1 = ExistsDocProp("<CustomProperty>", docProps);
I created a new email-message using Redemption-Data-Objects in C#. After calling Display(), the window is opened - all looks great.
When I try to send the message, by clicking the "send"-button, I get one of the following messages (translated from german...): "The messaging-interface returned an unknown error. try to restart outlook if the problem...." or "The element cannot be sent!"
When I use the Send-Method, all works fine, the email will be sent.
I tried OutlookSpy to find a solution - when i try to send the message i get return code 0x80020009.
Here is the sample-code:
Redemption.RDOSession session = new Redemption.RDOSession();
session.Logon(null, null, false, null, null, null);
Redemption.RDOFolder folder = session.GetDefaultFolder(Redemption.rdoDefaultFolders.olFolderOutbox);
Redemption.RDOMail newMail = folder.Items.Add(Redemption.rdoItemType.olMailItem);
// no difference when using .Add
newMail.Recipients.AddEx("a.b#blabla.com","a.b#blabla.com", "SMTP", Redemption.rdoMailRecipientType.olTo);
newMail.Recipients.ResolveAll();
newMail.Subject = "Testmail-Subject";
newMail.HTMLBody = "Test";
newMail.Display(false, Type.Missing);
Does anybody know a solution for that problem?
regards Martin
PS: I am using office 2010 (german) an Visual Studio 2010 (english) with target framework 2.0 in my project) on Windows 7 (english).
OK...
I found the "error".
Because my session ran out of scope, the context was lost and so the error occurred.
Here is the solution:
// Event object to wait for
System.Threading.ManualResetEvent _manualEvent = new ManualResetEvent(false);
private void DisplayMail() {
...
// register an eventhandler for the close event
_newMail.OnClose += new Redemption.IRDOMailEvents_OnCloseEventHandler(_newMail_OnClose);
_newMail.Recipients.Add(txtTo);
_newMail.Recipients.ResolveAll();
_newMail.Subject = subject;
_newMail.HTMLBody = body;
_newMail.Display(false, null);
// wait here until the message-window is closed...
_manualEvent.WaitOne();
}
private void _newMail_OnClose()
{
_manualEvent.Set();
}