Outlook addin forward issue - c#

I have an Outlook addin for encryption and decryption that supports Outlook 2010 to 2013.
I am trying encrypt email to decrypt and display.
I am using open mail through mailItem_Open function
wrappedMailItem.Open += new MailItemInspectorOpenDelegate(mailItem_Open);
through this function i just decrypt email and content updated using
mailItem.HTMLBody = decryptString
Then the inspector window open and showing decrypt mail. Its working fine. I close the inspector window
mailItem_close function call
void mailItem_Close(Outlook.MailItem mailItem, ref bool Cancel)
{
try
{
if (mailItem == null)
return;
if (mailItem.Sent != false)
{
var signProperty = GetProperty(mailItem, "App.Decrypted");
// NOTE: Cannot call mailItem.Close from Close event handler
// instead we will start a timer and call it after we
// return. There is a small race condition, but 250
// milliseconds should be enough even on slow machines.
if ((bool)signProperty)
{
var timer = new System.Windows.Forms.Timer { Interval = 250};
timer.Tick += new EventHandler((o, e) =>
{
timer.Stop();
((Outlook._MailItem)mailItem).Close(Outlook.OlInspectorClose.olDiscard);
mailItem = null;
});
Cancel = true;
timer.Start();
}
}
}
catch
{
// Ignore random COM errors
}
Marshal.ReleaseComObject(mailItem);
}
The issue is
But am not closing the inspector window (Showing decrypt message) i just click the forward button its open new inspector window by out look and forward email and close it. Then i close the inspector window ,but the parent mailItem (Ie. inbox mail) showing in decrypt mode . In mailItem_close function i just discard all changes but its not working
This issue is not happening in Reply procedure in same steps, only happens forward case
Please help me

Instead of modifying the message contents on the fly, you'd be better off creating your own form that shows the decrypted data without setting and potentially saving the decrypted data on the original message.

Related

How do I create an Outlook add-in that alerts the user when they attempt to reply to senders that are outside of their domain?

I am new to coding in c#. I am currently trying to create an Outlook add-in to prompt and alert users if they are to attempt to reply to anyone that is not from "#abc.com". For example if 'ben#abc.com' is to trying to reply to 'jack#def.com', a window to alert Ben will be prompted warning him "You are about to reply to someone that is not from '#abc.com'." with the options of 'ok' and 'cancel'.
I referred online for the code below but this add-in only allows me to edit the field values of the email I am trying to send. I am unable to even figure out how to address and implement the code to deal with replying. I have tried researching online and have seen methods like .reply() but I am confused as to how to apply them.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Outlook = Microsoft.Office.Interop.Outlook;
using Office = Microsoft.Office.Core;
namespace FirstOutlookAddIn
{
public partial class ThisAddIn
{
Outlook.Inspectors inspectors;
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
inspectors = this.Application.Inspectors;
inspectors.NewInspector +=
new Microsoft.Office.Interop.Outlook.InspectorsEvents_NewInspectorEventHandler(Inspectors_NewInspector);
}
void Inspectors_NewInspector(Microsoft.Office.Interop.Outlook.Inspector Inspector)
{
Outlook.MailItem mailItem = Inspector.CurrentItem as Outlook.MailItem;
if (mailItem != null)
{
if (mailItem.EntryID == null)
{
mailItem.To = "Testing for Recipient.";
mailItem.Subject = "Currently testing add-in for Subject.";
mailItem.Body = "Currently testing add-in for Body.";
mailItem.CC = "Testing for CC.";
}
}
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
// Note: Outlook no longer raises this event. If you have code that
// must run when Outlook shuts down, see https://go.microsoft.com/fwlink/?LinkId=506785
}
#region VSTO generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InternalStartup()
{
this.Startup += new System.EventHandler(ThisAddIn_Startup);
this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
}
#endregion
}
}
Firstly, you are only tracking Inspectors.NewInspector event. But in most cases replies will be inline - you also need Explorer.InlineResponse event (where Explorer comes from Application.ActiveExplorer, which can be null on startup, so you'd also need Application.Explorers.NewExplorer event).
Secondly, you will need to loop through all recipients in the mailItem.Recipients collection, and for each Recipient, check the Recipient.Address property (which you can test for the match).
Listen to send event, as it will be triggered irrespective of inline replies or inspector level replies.
this.Application.ItemSend += new Outlook.ApplicationEvents_11_ItemSendEventHandler(Application_ItemSend);
then implementation of this can be done as below,
/// param : item -> mail item to be sent
/// param : cancel -> allows you to cancel sending mail in outlook. By default value is false.
private void Application_ItemSend(object item, ref bool cancel){
Outlook.MailItem mail = (Outlook.MailItem)item;
// read "mail.To" and check for your logic;
// if To list has other domains, then show the warning prompt maybe like below,
var result = MessageBox.Show("yourmessage","title",MessageBoxButtons.YesNo);
if(result == DialogResult.No)
cancel = true; // setting this to `true` will stop sending an email out.
}
you can read on this event in MS blog here Item_Send

SendKeys.Send() does not send or react as I expect

I have a problem using Sendkeys.Send in my C# application and I really cannot understand why. When using it then it does not send what I expect to the active application. I am using it together with the global hotkey manager, https://github.com/thomaslevesque/NHotkey
I have created this simple PoC that, for my part at least, will be able to reproduce my problem. Just launch Wordpad and press the hotkey, ALT + O:
using System.Windows.Forms;
using System.Diagnostics;
using NHotkey.WindowsForms;
namespace WindowsFormsApp5
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// Convert string to keys
string hotkey = "Alt + O";
KeysConverter cvt;
Keys key;
cvt = new KeysConverter();
key = (Keys)cvt.ConvertFrom(hotkey);
// Setup the hotkey
HotkeyManager.Current.AddOrReplace("MyID", key, HotkeyAction);
// Copy some text to the clipboard that I want to paste to the active application
Clipboard.SetText("My String");
}
private void HotkeyAction(object sender, NHotkey.HotkeyEventArgs e)
{
Debug.WriteLine("Pressed the hotkey");
SendKeys.Send("^v");
// SendKeys.Send("Test string");
e.Handled = true;
}
}
}
When I do this in Wordpad, then instead of pasting the clipboard (^v equals CTRL + V) then it tries to "Paste Special":
Even if I do the most simple thing and then just put some text in SendKeys.Send, then it seems to be messing with the menus in Wordpad? SendKeys.SendWait is not any different.
I have been trying to figure this out for quite some time now but I simply do not understand why it does that. Basically, I need to paste the clipboard on a hotkey though it doesn't need to be with this exact method so if anyone knows another way of doing it then I would appreciate some hints.
MY IMPLEMENTED SOLUTION
Based on the accepted answer then I did change my implementation slightly as I could not get it working with just a timer. I may have missed something(?) but this is working.
In basic then I change focus to my application as soon as the hotkey is detected, to avoid conflict with modifier keys (ALT etc) in the active application. I then create an invisible form and when I detect a KeyUp event, then I check for modifier keys and if none is pressed down then I enable a timer and immediately switch focus back to the originating application. After 50ms the clipboard will be pasted to the active application.
Something like this:
// Somewhere else in code but nice to know
// IntPtr activeApp = GetForegroundWindow(); // get HWnd for active application
// SetForegroundWindow(this.Handle); // switch to my application
private System.Timers.Timer timerPasteOnHotkey = new System.Timers.Timer();
// Main
public PasteOnHotkey()
{
InitializeComponent();
// Define the timer
timerPasteOnHotkey.Elapsed += new ElapsedEventHandler(OnTimedEvent);
timerPasteOnHotkey.Interval = 50;
timerPasteOnHotkey.Enabled = false;
// Make the form invisble
this.Size = new System.Drawing.Size(0, 0);
this.Opacity = 0.0;
}
private void PasteOnHotkey_KeyUp(object sender, KeyEventArgs e)
{
// Check if modifier keys are pressed
bool isShift = e.Shift;
bool isAlt = e.Alt;
bool isControl = e.Control;
// Proceed if no modifier keys are pressed down
if (!isShift && !isAlt && !isControl)
{
Hide();
// Start the timer and change focus to the active application
timerPasteOnHotkey.Enabled = true;
SetForegroundWindow(activeApp);
}
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
timerPasteOnHotkey.Enabled = false;
SendKeys.SendWait("^v"); // send "CTRL + v" (paste from clipboard)
}
When you use SendKeys.Send in a response to a key press then the keys you send may be combined with the physical keys you’re holding at that moment. In this case you’re holding Alt, so Wordpad assumes you pressed Alt-Ctrl-V instead of just Ctrl-V. Also Alt opens menu, so sending other keys may relate to hotkeys there.
Adding a delay will remove this issue, and usually when sending key presses it would be done as not relating to other key presses so it won’t be a problem.

Unable To Write to a text box from a method

Im currently trying to create a messaging application from client to server. When the server sends the client a message it will open up an new form and add the text to a text box inside the form.
However the client is defiantly reviving the message, I tested this with a message box displaying the message before trying to update the text box. The text box is displaying the message perfectly.
However, when i try to edit the textboxt nothing happens. However my other method on a button click works perfectly. really unsure why this is happening.
I've also written an invoke method to check if the textbox need's to be invoked as i am using differen't threads for some methods.
Below is an example of my code with some screenshots the method below is being opened from another form "MAIN" i have reference to it in the code. Not sure if that is causing an issue perhaps?
public ChatWindow()
{
InitializeComponent();
Thread timerThread = new Thread(Main.ReceiveLoop);
timerThread.Start();
}
private void txtChatLog_TextChanged(object sender, EventArgs e)
{
}
private void btnSendMessage_Click(object sender, EventArgs e)
{
string clientReply = txtReply.Text;
string Message = "ClientMsg§" + clientReply;
var time = DateTime.Now;
txtChatWindow.AppendText($"{time} client: {clientReply}");
txtChatWindow.AppendText(Environment.NewLine);
Main main = new Main();
main.ChatResponse(Message);
txtReply.Text = "";
}
delegate void setTextCallBack(string message);
public void UpdateChatLog(string message)
{
if (txtChatWindow.InvokeRequired)
{
setTextCallBack d = new setTextCallBack(UpdateChatLog);
this.Invoke(d, new object[] { message });
}
else
{
var time = DateTime.Now;
string newMessage = message.Split('$')[1];
string messageToDisplay = $"{time} Server: {newMessage}";
MessageBox.Show(messageToDisplay);
this.txtChatWindow.AppendText(messageToDisplay);
this.txtChatWindow.AppendText(Environment.NewLine);
}
}
Below are some images of my server and the code running on the client:
as you can see the server is recieving what the client replies with, the textbox is also being appended for when the client presses the SEND button. However it isn't being changed when the method is called. You know the method is being called because the MessageBox.Show is being called and displaying what should be in the text box.
Really unsure what the issue is here. If anyone could help me It would be very appreciated! This is a project for my university degree that is due in soon!
Thankyou in advance!

killing a thread from within in a form

my application calls crystal reports viewer to display a report. I run the report viewer in a separate thread. It works just fine. it displays the report properly. my problem is i want to kill the report while it is processing if it is taking too long to run. While the report is processing the busy indicator is spinning and it seems to block any UI on the report viewer form. My report viewer form has a crystal reports viewer on it along with a close button at the bottom of the form itself. i would like to be able to click the close button and have it stop the processing. Here is my code to run the viewer in a single apartment thread
public void RunReportStep1(UAReport report)
{
UAReportService service = new UAReportService(report);
service.RunReport();
var reportDocument = service.ReportDocument;
Thread staThread = new Thread(r => { RunReportStep2((ReportDocument) r); });
staThread.SetApartmentState(ApartmentState.STA);
staThread.Start(reportDocument);
staThread.Join();
}
public void RunReportStep2(ReportDocument reportDocument)
{
ReportViewerForm form = new ReportViewerForm(reportDocument);
form.BringToFront();
form.ShowDialog();
if (form.DialogResult == DialogResult.OK)
{
}
what is the best way to kill the thread from within the report viewer form while the processing is going on. Once the processing completes and the report is destroyed closing the report is no problem. It's only a problem while the processing is going on before the report is displayed. While the report is processing the close button is not responsive. sometimes if i click it repeatedly i can get a response and the report cancels. but it is not consistent and i have to click it repeatedly. that is not acceptable for my clients to have to do.
Call the service.RunReport() from another thread and wait for that thread to finish or for a certain amount of time to pass. I didn't write all the code for this, but anything I didn't write I a least described.
// Global so it can be reached from both threads
UAReportService service;
// Global variable that is written to when the report doc is ready:
ReportDocType reportDoc; //Can't use var here unfortunately
public void RunReportStep1(UAReport report)
{
service = new UAReportService(report);
Thread staThread = new Thread(r => { RunReportStep2((UAReportService)r); });
staThread.SetApartmentState(ApartmentState.STA);
staThread.Start(service);
// Save time the thread started:
DateTime start = DateTime.Now;
// Display a loading box (label or something, up to you).
// Then this function will end and your user can do stuff in the UI again (like press Cancel).
myLoadingBox.Visible = true;
}
public void RunReportStep2(UAReportService service)
{
service.RunReport();
reportDocument = service.ReportDocument;
}
// Call this new function periodically to see if the service thread finished, maybe once every second.
public checkAndDisplay()
{
// If thread is finished or 30 seconds have passed.
if (staThread.IsAlive == false || (DateTime.Now - start).TotalSeconds > 30)
{
// Show a message saying report failed to run
}
else // Else you can now show your report viewer
{
ReportViewerForm form = new ReportViewerForm(reportDocument);
form.BringToFront();
form.ShowDialog();
if (form.DialogResult == DialogResult.OK)
{
}
}
}
// Code for cancelling the report service call if user presses cancel button.
private void CancelButton_Click(object sender, EventArgs e)
{
// Terminate the report service thread.
staThread.Abort();
// Abort() isn't the nicest way to do this so if you can set a timeout on the UAReportService object (where it quits running after so long) that would be better.
// Or have it periodically check a variable to see if it should quit (see link below)
}
MSDN example of gracefully closing a thread.

VSTO Outlook 2013 Addin Quit

I have a VSTO addin that displays a a dialog box with buttons yes no and cancel. I want the form to close anytime cancel or the X are clicked. I also want the application to quit when the form is closed. Here is my code:
var frm = new Form1();
DialogResult res = frm.ShowDialog();
if (client != null)
{
if (res == DialogResult.Yes)
{
path = DRIVE_LETTER + ":/Clients/" + client + "/Correspondence/";
}
else if (res == DialogResult.No)
{
path = DRIVE_LETTER + ":/Clients Project History/" + client + "/Correspondence/";
}
else if (res == DialogResult.Cancel)
{
frm.Close();
}
else
{
frm.Close();
}
And then my form closing event handler:
private void Form1_Closing(object sender, CancelEventArgs e)
{
Application.Exit();
}
But it doesn't seem to work. Microsoft.Office.Interop.Outlook.Application doesn't have an Exit method. How can I do the equivalent from within VSTO? I want my application to stop executing completely when those forms are canceled/closed.
Thanks
EDIT: can anyone provide an example of quitting the addin. Or stopping all execution if a certain condition is met, like Pyton's sys.exit(). I don't want outlook to close, just the addin to stop execution. Not even unload, just stop.
If you need to shut down Outlook you may use the Quit method of the Application class. The associated Outlook session will be closed completely; the user will be logged out of the messaging system and any changes to items not already saved will be discarded.
But if you need to shut down the add-in (not the host application) you can:
Disable all event handlers and UI controls. To get the job done you may check out the global boolean variable which can indicate the state of the add-in (allowed to run or not).
The Connect property of the ComAddIn class allows to set the state of the connection for the specified COMAddIn object. The property returns true if the add-in is active; it returns false if the add-in is inactive. An active add-in is registered and connected; an inactive add-in is registered but not currently connected.
Outlook.Application outlook = new Outlook.Application();
if (outlook.Application.COMAddIns.Item("OutlookAddIn").Connect)
{
outlook.Application.COMAddIns.Item("OutlookAddIn").Connect = false;
}
else
{
outlook.Application.COMAddIns.Item("OutlookAddIn").Connect = true;
}

Categories