Prevent termination of Word Application when user closes last document - c#

I have a simple Win Forms application that consists of a Button control, an OpenFileDialog component and a Microsoft.Office.Interop.Word.Application object:
using System;
using System.Windows.Forms;
namespace WordInterop
{
public partial class Form1 : Form
{
// From Form1.Designer.cs:
//Button openButton;
//FileOpenDialog openFileDialog;
private Microsoft.Office.Interop.Word.Application _wordApp;
public Form1()
{
InitializeComponent();
_wordApp = new Microsoft.Office.Interop.Word.Application();
}
protected override void OnClosed(EventArgs e)
{
_wordApp.Quit();
base.OnClosed(e);
}
private void _openButton_Click(object sender, EventArgs e)
{
DialogResult result = openFileDialog.ShowDialog();
if (result == DialogResult.OK) {
// Throws COMException if Word app is not longer running
_wordApp.Documents.Open(openFileDialog.FileName);
_wordApp.Visible = true;
}
}
}
}
When the user clicks the Open button, they can selected a Word document via the OpenFileDialog. The filename of the selected document is used to open the Word Document using the Microsoft.Office.Interop.Word.Application object.
It appears that the Word application is terminated when the user closes the last document: If the user clicks the Open button, selects a document, closes the document, clicks the Open button and selects a document a second time, a COMException occurs with the message The RPC server is unavailable. If there is at least one document open, the user can open documents without a COMException occurring.
Is there a way I can prevent Word application from terminating when the user closes the last document?
I tried creating a hidden blank document by changing the Form1 constructor to the following:
public Form1()
{
InitializeComponent();
_wordApp = new Microsoft.Office.Interop.Word.Application();
_wordApp.Documents.Add(Visible: false);
}
However the blank document becomes visible when the user opens a document meaning it is still possible for user terminate the Word application.

Create a new instance of Microsoft.Office.Interop.Word.Application() on the button click.
private void _openButton_Click(object sender, EventArgs e)
{
DialogResult result = openFileDialog.ShowDialog();
if (result == DialogResult.OK) {
_wordApp = new Microsoft.Office.Interop.Word.Application();
_wordApp.Documents.Open(openFileDialog.FileName);
_wordApp.Visible = true;
}
}

Related

How to run a macro from C#?

I have a macro (.docm) that opens an rtf file and saves it in .doc format. This macro needs to be run from a C# application. How to do it?
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// Создание экземпляра Word
Word.Application app = new Word.Application();
app.Visible = true;
Word.Documents doc = app.Documents;
// Открытие файлов
MessageBox.Show("add file (.docm)");
OpenFileDialog macroFile = new OpenFileDialog();
if (macroFile.ShowDialog() != DialogResult.OK)
{
MessageBox.Show("Error");
return;
}
}
}
After you have got a file name you can use the Documents.Open method which opens the specified document and adds it to the Documents collection. The Document.SaveAs2 method allows saving the specified document with a new name or format. Some of the arguments for this method correspond to the options in the Save As dialog box (File tab). The format in which the document is saved. Can be any WdSaveFormat constant. It seems you are interested in the wdFormatDocument value.

Handle WebBrowser.ShowPrintDialog() close event without "SHDocVw"

To print document I have created separate WindowsApplication and each time I want to print any document I call that application with path as parameter and Print application have below code:
public static void Print(string path)
{
WebBrowser wb = new WebBrowser();
wb.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser_DocumentCompleted);
wb.Navigate(path);
}
public static void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser wb = (WebBrowser)sender;
if (wb.ReadyState.Equals(WebBrowserReadyState.Complete))
{
((SHDocVw.WebBrowser)wb.ActiveXInstance).PrintTemplateTeardown += Print_PrintTemplateTeardown;
wb.ShowPrintDialog();
}
}
void Print_PrintTemplateTeardown(object pDisp)
{
_Application.Exit();
}
When I call Print aaplication, using "WebBrowser" control it loads document and show Print Dialog using "wb.ShowPrintDialog();".
On Print Dialog when I click Print or Cancel I got PrintTemplateTeardown event where I asks Application to Exit (To close application).
Now I want to remove "SHDocVw" dependency from my Print Application due to some security issue while installing on client's machine through Internet.
If I remove "SHDocVw", is there any alternate event or solution available that achknowledge me that PrintDialog is closed?

To store the key in a same directory and validate it at the start up of the application

I have 2 Windows application forms. In the first form I have a button and in the second form a button and a textbox.
When I click on the button in the first form the program should check if the product is already activated or not. If it's activated, then it should continue with form1, otherwise it should call form2 asking to input the product key.
Once the product key is inputted into form2 the program should validate it and store it in a text file in the same directory.
When I run the program the next time, after clicking on the button in form1, it should not ask to activate it again.
I have the below code, but I am not getting this full functionality. Please help me with this and also please help with exception while reading or writing the text file.
// FIRST FORM
private void fixButton_Click(object sender, EventArgs e)
{
TextReader tr = new StreamReader("Product-Key.txt");
if ( (tr.ToString() == "TGR2W2") || (tr.ToString() == "8DTT9M") )
{
MessageBox.Show ( "product is already activated ");
}
else
{
Form2 secondForm = new Form2();
secondForm.Show();
}
}
// ACTIVATION BUTTON IN SECOND FORM
private void activateButton_Click(object sender, EventArgs e)
{
if ((productkeyTextBox.Text == "TGR2W2") || (productkeyTextBox.Text == "8DTT9M") )
{
// to store the inputted product key in a tex file of the same directory
keyStore ((productkeyTextbOX.Text).ToString());
this.Close();
MessageBox.Show(" The product has been succesfully activated");
// NEED HELP HERE IN LOADING THE FORM 1 BACK AFTER STORING THE PRODUCT KEY
}
else
{
MessageBox.Show("Please enter a valid 16 digit product key!!");
}
}
public void keyStore(string key)
{
try
{
// create a writer and open the file
TextWriter tw = new StreamWriter("Product-Key.txt");
// write a line of text to the file
tw.WriteLine(key);
// close the stream
tw.Close();
}
catch (IOException)
{
}
}

How to use a method from the Startup form to enable its controls when called through a child form?

I am trying to enable admin privileges on my startup form. For this I've created an admin toolstrip login which would cause a password form to launch. I am however unable to update the startup form through the password form. I've seen a similar article over here [Why the controls not update, when call method from other form but this hasn't helped me solve my problem. My code is as below and what I have achieved so far is as below:
// Code for startup form...
public partial class StartupForm : Form {
private void adminToolStripMenuItem_Click(object sender, EventArgs e) {
FrmAdminPassword frmAdminPassword = new FrmAdminPassword();
frmAdminPassword.Show();
//this.Close();
//AdminLogin();
}
public void AdminLogin() {
loginToolStripMenuItem.Enabled = false;
logoutToolStripMenuItem.Enabled = true;
cmb1.Enabled = true;
btn1.Enabled = true;
tab1.Enabled = true;
tab2.Enabled = true;
tabControl1.TabPages.Add(tabAdminTasks);
MessageBox.Show("Admin Logged In");
}
}
// Code for password form
public partial class FrmAdminPassword : Form {
private void btnLoginAdmin_Click(object sender, EventArgs e) {
if (mskAdminPassword.Text == "password") {
StartupForm frm = new StartupForm();
frm.Show();
frm.AdminLogin();
this.Close();
}
else {
MessageBox.Show("Not a valid password");
this.Close();
}
}
}
If I implement it this way, what happens is that the original instance of the startup form is still present as a duplicate instance with all tabs and controls disabled and a new form is launched with all controls enabled.
What I actually want to achieve is:
Click on the adminToolStripMenuItem.
Launch the FrmAdminPassword.
Enter the password and hit Login on FrmAdminPassword.
After hitting Login, close the FrmAdminPassword and enable the controls on StartupForm.
Could someone please help on this? Thanks.
Use ShowDialog() to show your login form. This will stop the execution of code in the startup form until the login form closes
private void adminToolStripMenuItem_Click(object sender, EventArgs e)
{
// Putting the creation of the form inside a using block allows
// the automatic closing and disposing of the form when the code
// reaches the closing brace of the using block.
using(FrmAdminPassword frmAdminPassword = new FrmAdminPassword())
{
// This opens the frmAdminPassword form in modal mode, no
// code is executed after the call until you close the
// form with DialogResult.OK, DialogResult.Cancel or whatever
if(DialogResult.OK == frmAdminPassword.ShowDialog())
{
MessageBox.Show("Login executed with success!");
}
else
{
// Mo password given or form cancelled
// put here the logic to exit or disable things
}
}
}
Now in the Login form OK button click you could execute your logic to validate the password and to allow the closing of the form if the password match
public partial class FrmAdminPassword : Form
{
private void btnLoginAdmin_Click(object sender, EventArgs e)
{
if (mskAdminPassword.Text == "password")
this.DialogResult = DialogResult.OK;
else
{
MessageBox.Show("Not a valid password");
this.DialogResult = DialogResult.None;
}
}
}
To make this work you need to set the DialogResult property of the Login Form to something different from DialogResult.None. This Will force the Login form to automatically hide (not close) so you can read the DialogResult property on the initial instance of the startup form and decide what to do next. You should also provide some method to exit from the login form with DialogResult.Cancel and stop further processing because the user decided to not give a password.
Try this...
FrmAdminPassword
private void btnLoginAdmin_Click(object sender, EventArgs e)
{
if (mskAdminPassword.Text == "password")
{
this.DialogResult = System.Windows.Forms.DialogResult.OK;
}
else
{
MessageBox.Show("Not a valid password");
this.Close();
}
}
StartupForm
private void adminToolStripMenuItem_Click(object sender, EventArgs e)
{
FrmAdminPassword frmAdminPassword = new FrmAdminPassword();
using(frmAdminPassword)
{
if(frmAdminPassword.Show() == System.Windows.Forms.DialogResult.OK)
{
AdminLogin();
}
}
}
What is happening is that you have two separate copies of the form instantiated. At launch, the startup form is instantiated. During login, you are instantiating a totally new copy. Your login needs to reference the existing startup form.

Windows Form wont close properly

I am developing an add-in for outlook 2010.
Basically, I have a button on my ribbon that takes the selected email, and saves it to a text file. If the email contains a certain subject then the save is done automatically to a hard coded file path. If not, a windows form is opened asking the user to enter a filepath.
When the user has selected a path, and clicked 'OK' the save takes place and then the form closes... but then it re-opens... it seems to be creating a new instance of it or something... if I click 'Cancel' or 'X' it closes, but I can't see why it's not closing properly the first time.
Below is my code
//This is myRibbon.cs
private void btn_SaveFile_Click(object sender, RibbonControlEventArgs e)
{
//other code
if (subject = "xyz")
{
//other code
textFile.Save();
}
else
{
MyPopup popup = new MyPopup();
popup.ShowDialog();
}
}
//This is MyPopup.cs
private void btnOK_Click(object sender, EventArgs e)
{
var filePath = txtFilePath.Text;
if (!string.IsNullOrWhiteSpace(filePath))
{
SaveEmailToText(filePath);
this.Close();
}
else
{ //show message box with error }
this.Close();
}
private static void SaveEmailToText(string filePath)
{
//other code
textFile.Save();
}
I have simplified this quite a bit so its easier to read.
Any help would be greatly appreciated.
Consider to use OpenFileDialog instead of your popup form
Use your popup (or file dialog) only for getting file name
Keep email saving code in one place (otherwise you will have duplicated code)
Verify DialogResult of dialog form, before processing further
Forms are disposable - using statement will dispose them automatically
Do not close dialog form - set it's DialogResult property instead
Here is refactored code:
private void btn_SaveFile_Click(object sender, RibbonControlEventArgs e)
{
string filePath = defaultPath;
if (subject != "xyz")
{
using(MyPopup popup = new MyPopup())
{
// user can close popup - handle this case
if (popup.ShowDialog() != DialogResult.OK)
return;
filePath = popup.FilePath;
}
}
SaveEmailToText(filePath);
}
private void SaveEmailToText(string filePath)
{
//other code
textFile.Save();
}
And your popup, which should be replaced with OpenFileDialog:
private void btnOK_Click(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(FilePath))
{
//show message box with error
DialogResult = DialogResult.Cancel;
return;
}
// you can assign default dialog result to btnOK in designer
DialogResult = DialogResult.OK;
}
public string FilePath
{
get { return txtFilePath.Text; }
}

Categories

Resources