open specific word doc. depending on user selection c# - c#

i currently have a word doc. file merging program and am attempting to open a specific word doc. depending on user selection.
// sample of code used:
string outputFolder = null;
...
// file selection
...
string outcomeFolder = outputFolder;
string outputFile = "Combined Folder " + fileDate + " # " + fileTime + ".docx";
string outputFileName = Path.Combine(outcomeFolder, outputFile);
in the program, outputFolder is selected by the user via a fileBrowserDialog
currently, the program runs correctly and merges the files in the folder selected by the user however it fails to open Microsoft Word as well as the outcome document merged.
i've attempted to use:
Microsoft.Office.Interop.Word.Application officeApp =
new Microsoft.Office.Interop.Word.Application();
...
// merging code
...
Document documentTest = officeApp.Documents.Open(outputFileName);
i've noticed that though the program fails to launch Word, Task Manager continues to create a new instance of Word. The merged document formed also cannot be deleted as it claims the file is currently in use. It's as if program it's opening in the background however not physically launching. The Task Manager instance of Word must then be killed before the merged file can be edited / deleted
Any suggestions as to remedy this? Am i missing something simplistic or is the issue due to the non-static file path? - if any additional information is required please ask. thank you
Update 1:
Since implementing the officeApp.Visible = true; the program now launches the file created which can then be edited / re-saved etc. However if i immediately run the program again, attempting to create another merged file within the same folder etc. I am presented with "RPC server is unavailable. (Exception from HRESULT: 0x800706BA)"
Update 2:
As listed above, I was getting a generic HRESULT error code which I have now since remedied. I moved the "new officeApp" into the "Merge" handler which seems to be allowing multiple merges in quick succession without throwing errors.
Update 3:
To make things more simplistic, i've experimented with implementing Process.Start(outputFileName); to open the document. This is due to the additional check box I am now introducing which allows the user to decide whether the merged doc. will be launched / presented once created. This new code also prevents the additional Word.exe's from being created if the file visibility is set to false.
thank you all for your suggestions and help.

Have you tried making Word visible?
officeApp.Visible = true;

Related

C# OpenFileDialog multiple filename filters including exclude

I have a requirement to allow users to open a specific file for processing. The open file dialog is currently
OpenFileDialog ofg = new OpenFileDialog
{
FileName = "BaseFileName*",
Filter = "CSV File (*.CSV)|*.csv",
Multiselect = false,
InitialDirectory = #"N:\Downloads"
};
However the process adds a suffix of _Processed along with timestamp data to the filename and I want to exclude these renamed files the next time the OpenFileDialog is used to prevent the user trying to reprocess the same file.
I have to leave the original files where they are for internal audit reasons.
So I need an additional filename filter of not equal to "_Processed".
Is there any way to do this with OpenFileDialog or does anyone know of a custom c#/.net component that can do this?
You are asking to omit specific items from the file dialog view.
According to MSDN, this is no longer possible as of Windows 7, but was possible previously.
The C# file dialogs (both WPF and WinForms) use the IFileDialog API.
Here is the function that could have made this work, but is no longer supported:
https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-ifiledialog-setfilter
As it is, you are stuck with checking the file for correctness after the user has already selected it and confirmed it with OK.
You can help the situation a little bit: If you enjoy pain, then you can copy the whole IFileDialog COM interop code from the .NET source code, and implement IFileDialogEvents. This way, when the user clicks "OK", you can deny the selection and display an error before the dialog closes, leaving the dialog open so the user can select a different file.
If you are sane and you don't want to do that, then you'll have to open the dialog again after the verification fails.
The easy way is just saving the processed data with another extension e.g. "BaseFileName_Processed_20105640640.cvs1", that way you keep the data and your file dialog will not show this file.
Another way could be to call the OpenFileDialog() in an if statement (and compare the return to DialogResult.OK), then split the file name for {'_','.'}, then run a loop to count the occurrences of the word Processed( >0), and possibly as a safety check determine whether a timestamp is present in one of the split strings. Finally, reload the FileOpenDialog in the same folder when the wrong file was selected.

How to create multiple files in design automation api for revit and download result as one zip file

I am working on a project where I am required to create multiple revit files, zip them all together and download the zip file as the output in design automation API for Revit.
My project is completely working as expected on my local machine, but when I upload my appbundle and execute my workitem, I get a "failedInstructions" status.
I am not aware whether it is possible to create multiple revit files in design automation API
Following is what I have tried:
This is my workitem json, you see I am passing a json array with sample data for the wall.
"arguments":{
"ElementParams":{
"url":"{'elementdata':[[{'Keys':'Sytème','Value':'Wall_1'},{'Keys':'Thickness','Value':'120.00'},{'Keys':'Length','Value':'2500.00'},{'Keys':'Height','Value':'1200.00'}],[{'Keys':'Sytème','Value':'Wall_2'},{'Keys':'Thickness','Value':'120.00'},{'Keys':'Length','Value':'2500.00'},{'Keys':'Height','Value':'1200.00'}],[{'Keys':'Sytème','Value':'Wall_3'},{'Keys':'Thickness','Value':'120.00'},{'Keys':'Length','Value':'2500.00'},{'Keys':'Height','Value':'1200.00'}],[{'Keys':'Sytème','Value':'Wall_4'},{'Keys':'Thickness','Value':'120.00'},{'Keys':'Length','Value':'2500.00'},{'Keys':'Height','Value':'1200.00'}]]}"
},
"resultFamily":{
"verb":"put",
"url":"https://storage.googleapis.com/bucketname/RevitObjects.zip?XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"headers": {
"Authorization": "",
"Content-Type": "application/octet-stream"
}
}
}
In my code, I create a new document in a loop.
Document doc = app.NewProjectDocument(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\" + "DefaultTemplates.rte");
and save and close the current document
SaveAsOptions options = new SaveAsOptions();
options.OverwriteExistingFile = true;
doc.SaveAs(Assembly.GetExecutingAssembly().Location) + "\\" + fileName, options);
doc.Close(); //Closing the document
List<string> files = Directory.GetFiles(Assembly.GetExecutingAssembly().Location) + "\\").Where(a => a.Contains(Path.GetFileNameWithoutExtension(fileName)) && a.Split('.').Count() > 2).ToList();
foreach (var fl in files)
{
if (File.Exists(fl))
File.Delete(fl);
}
byte[] filebytes = File.ReadAllBytes(GlobalData.TemplatePath + "\\" + GlobalData.DestinationFile);
GlobalData.FileList.Add(GlobalData.DestinationFile, filebytes);
Here fileName is Wall_1, Wall_2, Wall_3 and Wall_4 which will appear in a loop
Here what I am doing is saving the created revit file example Wall_1
After closing the document, there is a copy of the file created example Wall_1.0001.rvt. I delete all the additional files created and keep one final version and add it to file bytes.
The data added in byte[] filebytes is then used to create a zip file of name "RevitObjects.zip"
After which I delete all the files.
This process works perfect on my local machine, but when I execute the workitem the log created states the following:
[07/03/2019 13:47:38] Error: An unexpected error happened during phase CoreEngineExecution of job.
[07/03/2019 13:47:38] Job finished with result FailedExecution
[07/03/2019 13:47:38] Job Status:
{
"status": "failedInstructions",
No other error message is stated in the log.
Let me know if multiple revit document creation is possible in design automation api for revit
Are we not allowed to perform delete operation in the working directory.
I tried by creating a folder and performing the same operation mentioned above, but I got an access denied message.
Let me know where I have gone wrong. Also any guidance to achieve the task will be appreciated
Thank you
First of all, Yes, multiple revit file output is supported by Design Automation system, it's very easy that you just need to set the parameter zip to "true" of your output, and within your plugin, save all your output file to a folder as you named in your output parameter of "localName", please check my blog post at https://forge.autodesk.com/blog/how-generate-dynamic-number-output-design-automation-revit-v3 for all the details.
You are not allowed to access any other folders except the current working folder, you can create subfolder under current working folder and put all your files there.
Hope it helps.
If the json argument is very large, you may provide a "inputParameters.json" as an input file, instead of passing everything in the WorkItem payload

Is it possible to save a word document by bypassing the Save or SaveAs methods c#

I have a MS Word AddIn that launches a winform which allows the user to specify some additional metadata which is then saved as an xml file along with a copy of the document in a specified location.
This all works fine when run from a standalone Word document, however one of the areas this will be used is where a Word document is launched inside an application (EMIS WEB). It launches a copy of Word from the local machine which is fine as it allows the AddIn to be run.
When I try to save the document I get a Command Failed. error. The XML file saves no problem: xml.Save(path + docName + ".xml");.
The application prompts with it's own 'save' like dialog.
At first I thought it was the application removing focus from the document therefore this.Application.ActiveDocument.SaveAs failing because it wasn't the Active Document. So I tried getting the Document object when it was active and passing it through to the saveDoc method so that I could set it as the Active Document like so:
public void saveDoc(string doc, Word.Document wd)
{
string path = #"\\servername\folder\subfolder\";
object filename = path + doc + ".docx";
try
{
wd.Activate();
this.Application.ActiveDocument.SaveAs(ref filename);
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
However this made no difference, the application's dialog still pops up, and regardless of whether I click OK or Cancel to the dialog it does not process the SaveAs command.
I have come to the conclusion that the application is intercepting the Save/SaveAs command and doing its own thing instead.
So is it possible to save a word document by bypassing the Save or SaveAs methods? Is there a way round this?
Figured it out, fortunately there was not a strict requirement to save it as a .doc or .docx so I have opted for .pdf. I have got round the application intercepting the Save commands by using the Document.ExportAsFixedFormat Method with wdExportFormatPDF to save it as a PDF.
So the final code looks like this, and it works a treat:
public void saveDoc(string doc)
{
string path = #"\\servername\folder\sub-folder\";
string filename = path + doc + ".pdf";
try
{
this.Application.ActiveDocument.ExportAsFixedFormat(filename, WdExportFormat.wdExportFormatPDF);
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}

OpenSharedItem for opening .MSG files showing Error in Outlook C#

I am using the following code to open the signed/unsigned
Outlook messages and I display the content in WebBrowser control.
Microsoft.Office.Interop.Outlook.Application app = new Microsoft.Office.Interop.Outlook.Application();
var item = app.Session.OpenSharedItem(msgfile) as Microsoft.Office.Interop.Outlook.MailItem;
string message = item.HTMLBody;
app.Session.Logoff();
It is working fine for the first time the file is opening, but after
closing the Outlook file trying to reopen the file it showing the
following error:
"Cannot open file: C:\tion.msg. The file may not exist, you may not
have permission to open it, or it may be open in another program.
Right-click the folder that contains the file, and then click
Properties to check your permissions for the folder."
After some time later it is opening fine. For this strange behavior
what could be the reason and how to rectify the the error message?
Outlook manages its own cache of items when you are opening and closing messages. Your best bet would be to use a randomly generated filename (i.e. Path.GetRandomFilename) when opening via OpenSharedItem so that you don't get issues. I would also use a temporary path instead of root c:\ (i.e. Path.GetTempPath).
You can try and free the MailItem reference (i.e. setting it to null), but there is no guarantee when Outlook will release the item from its cache.
Would any combination of the Quit[1], Close[2] or ReleaseComObject[3] methods work for you? My code worked better but not perfect after I used them.[4]
using Outlook = Microsoft.Office.Interop.Outlook;
.
.
.
var app = new Outlook.Application();
var item = app.Session.OpenSharedItem(msgfile) as Outlook.MailItem;
//Do stuff with the mail.
item.Close(OlInspectorClose.olDiscard);
app.Quit();
Marshal.ReleaseComObject(item);
Another solution, according to Microsoft - Help and Support[5], is to delay the opening of the file. However, it doesn't sound like a good solution to me since, like #SliverNinja also said, you'll never know when Outlook releases its lock of the file.
Notes and references
http://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook._application.quit.aspx, read 2014-10-14, 16:19.
http://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook._mailitem.close%28v=office.15%29.aspx, read 2014-10-14, 16:19.
http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.releasecomobject.aspx, read 2014-10-14, 16:19.
For example, if I had opened Outlook for som regular work, the Quit-method would close that window as well.
http://support2.microsoft.com/kb/2633737, read 2014-10-08, 16:19.
Hello you have two options .
set the Read-only attribute to the msg file
or
disable the following permissions for the users or usergroups to the parent folder:
Write Attributes
Write Extended Attributes
the msg file can now open multiple times but is write protect
I had this problem, in my case it was the space in the file name
import win32com.client
import os
path = 'C:/testes/mail'
files = [f for f in os.listdir(path) if '.msg' in f]
for file in files:
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
msg = outlook.OpenSharedItem(os.path.join(path, file))
att=msg.Attachments
for i in att:
i.SaveAsFile(os.path.join('C:/testes/email_download', i.FileName))
I don't know if in your case the OpenSharedItem method can help ...
Firstly, try to release the message as soon as you are done with it using Marshal.ReleaseComObject(). This may or may not help since Outlook likes to cache its last opened item.
Secondly, you are logging off from Outlook while it might still be running and visible to the user - Outlook is a singleton, so you will end up with the existing instance if it was already running. Either don't call Logoff at all, or check that there are no open inspectors and explorers (Application.Explorers.Count == 0 && Application.Inspectors.Count == 0).
Thirdly, reading HTMLBody alone won't work properly if there are embedded images - they are stored as regular attachments. You can save the message as an MHTML file (which most browsers would be happy to show) using MailItem.SaveAs(..., olMHTML).
You can also use Redemption (I am its author) for that - call RDOSession.GetMessageFromMsgFile.
If you need to release the message immediately after you are done, call Marshal.ReleaseComObject()
In case of Redemption, you can also cast RDOMail object to the IDisposable interface and call IDisposable.Dispose(). In addition to the MHTML format, Redemption can also save in the HTML format with image attachments converted into embedded images- use RDOMail.SaveAs(..., olHTMLEmbeddedImages) (olHTMLEmbeddedImages == 1033).

Selection.InsertFile() not finding file despite it being in directory

I am experimenting with the Microsoft.Office.Interop.Word namespace to do some manipulation of docx files, specifically programmatically merging them.
I created a simple test harness to try out some of the functionality and I am getting a file not found error despite the file being in the executing directory.
All I am trying to do is merge two docx files, doc1.docx and doc2.docx respectively. Again I am just playing around with this functionality at this point so I created a simple C# console app and have the following:
using Word = Microsoft.Office.Interop.Word;
//and in my method:
object defaultTemplate = #"Normal.dotm";
object missing = System.Type.Missing;
object outputFile = "out.docx";
Word.Application wordApplication = new Word.Application();
//using the default Word template
Word._Document wordDocument = wordApplication.Documents.Add(defaultTemplate);
Word.Selection selection = wordApplication.Selection;
//add files manually. THIS is where things are failing
selection.InsertFile("doc1.docx");
selection.InsertFile("doc2.docx");
I get an exception with the message "This file could not be found." in my first call to InsertFile(). I am certain the files exist in my debug directory, which is where this program is running. MSDN explicitly states that if you don't provide a path with your parameter it uses the current directory. It finds the template Normal.dotm fine. I feel like I am missing something simple here but have been messing with it for over a half hour with no luck. Does anyone have any suggestions on what I should be doing here? Thanks for reading!
Make sure for your path is available. use GetCurrentDirectory() to be sure your current directory is what you want. else use full path.
You also might need to set the default file path.
MyWordApp.Application.Options.set_DefaultFilePath()

Categories

Resources