Outlook 2003 Word as Editor and .NET forms

  • Thread starter Thread starter rob_tt08
  • Start date Start date
R

rob_tt08

Our company has been working on an Outlook AddIn using VSTO which has a
number of issues which we have not been able to resolve yet.

We would appreciate any insight or assistance you can offer.

Our .NET AddIn includes support for using Word as editor in Outlook 2003. On
the editor window we add a custom command bar button that launches a .NET
form. The problem is that the .NET form does not always appear in front of
the inspector when Word is being used as the editor.

I have attempted to use the .NET methods and properties available on the
Form (TopLevel, TopMost, BringToFront) to make it appear above the Outlook
window but none of them were consistently working.

Is there any way I can ensure the .NET form comes out on top as our users
are becoming frustrated with this?

Thanks.

The code fragment is as follows:

private void OnSendAndLogClick(Office.CommandBarButton Ctrl, ref bool
CancelDefault)
{

// Other code

using (FrmRegisterDMSEmail registerscreen = new
FrmRegisterDMSEmail(_registerEmail))
{
if (registerscreen.ShowDialog() == DialogResult.OK)
{
...
}
}
// Other code
}
 
About the only way I know of to do that is to get the hWnd of the WordMail
window and make that window the parent window of your dialog. You can use
the Win32 API function FindWindow() to get the WordMail window (class =
"OpusApp" and caption is the Inspector caption) and the returned hWnd as the
value for the parent of your dialog. You might have to use SetParent() which
is another Win32 API call.
 
Ken,

I have found the window handle and set the parent window using the API calls
you suggested.

This makes the .NET form appear in front of the WordMail window but it
causes both the .NET form and the WordMail window to lock up and refuse user
input.

The documentation on the SetParent API notes that Windows 2000 and XP should
have the UISTATE of both windows synchronised, so I have also done that, but
it made no difference.

Can you offer further advice?

My amended code is as follows:

using (FrmRegisterDMSEmail registerscreen = new
FrmRegisterDMSEmail(_registerEmail))
{
if (_isWordEditor)
{
IntPtr hWnd = WindowHelper.GetWordEditorWindowHandle(_inspector.Caption);
WindowHelper.SetParentWithMessage(registerscreen.Handle, hWnd);
}

if (registerscreen.ShowDialog() == DialogResult.OK)
{
...
}
}

public static IntPtr GetWordEditorWindowHandle(string caption)
{
try
{
IntPtr hWnd = FindWindow("OpusApp", caption);

return hWnd;
}
catch (Exception ex)
{
...
}
}

public static bool SetParentWithMessage(IntPtr hWndChild, IntPtr
hWndNewParent)
{
SetParent(hWndChild, hWndNewParent);

SendMessage(hWndNewParent, WM_CHANGEUISTATE, UIS_INITIALIZE, IntPtr.Zero);

return true;
}
 
I'm wondering if the problem is that WordMail is running on a different
thread than Outlook in the case of Outlook 2003 WordMail. When I've
displayed forms with browser controls on them I've run into the threading
problem and have had to set up thread synchronization with the main Outlook
thread.

In those cases I've gotten the Outlook thread in NewInspector (Outlook has
to have a UI for this to work) like this:

// class level
private static System.Threading.SynchronizationContext _syncContext;

// in NewInspector
if (_syncContext == null)
{
System.Windows.Forms.Application.DoEvents(); //needed to start the
message pump
if (System.Threading.SynchronizationContext.Current != null)
{
_syncContext = System.Threading.SynchronizationContext.Current ;
}
}

Then when I need to work in that thread context I use a callback using
Threading.SendOrPostCallback.

Another approach might be to call ShowDialog on your form using
IWin32Window, which would be the window of the WordMail window.
 
Ken,

I have been able to use the FindWindow API call to get the window handle and
use that with a wrapper class that implements the IWin32Window interface,
allowing me to pass it to ShowDialog.

This has resolved the problem on the development machine, so we will release
a new version with this change.

I will repost if any further issues occur on the user machines.

Thank you for your help.

I wonder if you could also offer any advice with the other issue I posted on
11/09/2008 - MailItem User Properties not updating?
 
Ken,

My other issue is as follows (you can find the original thread by looking at
my recent posts if you need to):

MailItem User Properties not updating

Our company has been working on an Outlook AddIn using VSTO which has a
number of issues which we have not been able to resolve yet.

In our .NET addin we have created a couple of custom fields specific to our
application on the Inbox folder. These link to user properties we create on
the mail items. In code when we set the values for these user properties, we
are calling mailItem.Save() both before and after to ensure the values get
persisted.

We are noticing that sometimes the field value in the Inbox is not updating.
Yet if we manually go into the mail item afterwards and save it from the GUI,
it then updates properly. But closing Outlook and re-opening it or changing
folders doesn't make it update. This appears to happen most often on mail
items which have just been forwarded or replied to. We are unsure why the
custom fields don't update sometimes and how to fix this.

Any help you can give would be much appreciated.
 
I don't have access to older posts I've already marked, so your previous
post doesn't help me. Can you show the code you're using for that? Are you
sure that you've released all references to the objects you're concerned
with? How are you adding the user properties to the folder?
 
Ken,

Here is the code we are using to set the User Properties. The variable
_emails is a class level List<Outlook.MailItem>. It is being cleared and set
to null when we are finished with it.

I have previously tried changing the code to avoid using the list in case
the mailitems being in a .NET collection was interfering somehow, but this
did not help.

The user properties are being added to the folder using the parameter on
UserProperties.Add which tells it to add the property to the folder if
required (except for SetIDProperty as these are not meant to be available as
folder columns), but the problem is happening even after the properties have
been added for other mail items successfully.

When I check the value of a property immediately after adding it, it is
correct. It just doesn't show up in the folder unless the user opens an
inspector and saves it manually.

Thank you for your assistance with this.

// Loop through the mail items
foreach (Outlook.MailItem mailItem in _emails)
{
// Other code
...
// Check save first
mailItem.Save();

if (_emailIn)
EmailTRACERManager.Manager.MAPIHelper.SetIDProperty(mailItem,
EmailTRACERManager.UPReceivedID, matterID);

//We are logging an item with Register Only and need all properties

EmailTRACERManager.Manager.MAPIHelper.SetBooleanProperty(mailItem,
EmailTRACERManager.UPLogged, true);
EmailTRACERManager.Manager.MAPIHelper.SetTextProperty(mailItem,
EmailTRACERManager.UPProject, this.MatterName);

//We have to save the email if the properties are to stay.
mailItem.Save();
}

public void SetBooleanProperty(Outlook.MailItem mailItem, string
propertyName, bool boolValue)
{
try
{
Outlook.UserProperty prop = null;

// Attempt to get the property, if it exists.
if (mailItem.UserProperties[propertyName] == null)
{
//The property did not exist, add it.
prop = mailItem.UserProperties.Add(propertyName,
Microsoft.Office.Interop.Outlook.OlUserPropertyType.olYesNo, true,
System.Reflection.Missing.Value);
}

mailItem.UserProperties[propertyName].Value = boolValue;
}
catch (Exception ex)
{
EmailTRACERManager.Manager.LogError(ex.Message + " " + ex.StackTrace);
}
}

public void SetIDProperty(Outlook.MailItem mailItem, string propertyName,
Int64 idValue)
{
try
{
Outlook.UserProperty prop = null;

// Attempt to get the property, if it exists.
if (mailItem.UserProperties[propertyName] == null)
{
//The property did not exist, add it.
prop = mailItem.UserProperties.Add(propertyName,

Microsoft.Office.Interop.Outlook.OlUserPropertyType.olText, false,

Microsoft.Office.Interop.Outlook.OlUserPropertyType.olText);
}
mailItem.UserProperties[propertyName].Value =
idValue.ToString();
}
catch (Exception ex)
{
EmailTRACERManager.Manager.LogError(ex.Message + " " +
ex.StackTrace);
}
}

public void SetTextProperty(Outlook.MailItem mailItem, string propertyName,
string textValue)
{
try
{
Outlook.UserProperty prop = null;

// Attempt to get the property, if it exists.
if (mailItem.UserProperties[propertyName] == null)
{
//The property did not exist, add it.
prop = mailItem.UserProperties.Add(propertyName,

Microsoft.Office.Interop.Outlook.OlUserPropertyType.olText, true,

Microsoft.Office.Interop.Outlook.OlUserPropertyType.olText);
}
mailItem.UserProperties[propertyName].Value = textValue;
}
catch (Exception ex)
{
EmailTRACERManager.Manager.LogError(ex.Message + " " +
ex.StackTrace);
}
}
 
Offhand I'm not sure but I'd try 2 different things. First see if setting
the DisplayFormat argument instead of setting it to missing helps. Second,
see if passing the email item object by reference makes any difference.




rob_tt08 said:
Ken,

Here is the code we are using to set the User Properties. The variable
_emails is a class level List<Outlook.MailItem>. It is being cleared and
set
to null when we are finished with it.

I have previously tried changing the code to avoid using the list in case
the mailitems being in a .NET collection was interfering somehow, but this
did not help.

The user properties are being added to the folder using the parameter on
UserProperties.Add which tells it to add the property to the folder if
required (except for SetIDProperty as these are not meant to be available
as
folder columns), but the problem is happening even after the properties
have
been added for other mail items successfully.

When I check the value of a property immediately after adding it, it is
correct. It just doesn't show up in the folder unless the user opens an
inspector and saves it manually.

Thank you for your assistance with this.

// Loop through the mail items
foreach (Outlook.MailItem mailItem in _emails)
{
// Other code
...
// Check save first
mailItem.Save();

if (_emailIn)
EmailTRACERManager.Manager.MAPIHelper.SetIDProperty(mailItem,
EmailTRACERManager.UPReceivedID, matterID);

//We are logging an item with Register Only and need all properties

EmailTRACERManager.Manager.MAPIHelper.SetBooleanProperty(mailItem,
EmailTRACERManager.UPLogged, true);
EmailTRACERManager.Manager.MAPIHelper.SetTextProperty(mailItem,
EmailTRACERManager.UPProject, this.MatterName);

//We have to save the email if the properties are to stay.
mailItem.Save();
}

public void SetBooleanProperty(Outlook.MailItem mailItem, string
propertyName, bool boolValue)
{
try
{
Outlook.UserProperty prop = null;

// Attempt to get the property, if it exists.
if (mailItem.UserProperties[propertyName] == null)
{
//The property did not exist, add it.
prop = mailItem.UserProperties.Add(propertyName,
Microsoft.Office.Interop.Outlook.OlUserPropertyType.olYesNo, true,
System.Reflection.Missing.Value);
}

mailItem.UserProperties[propertyName].Value = boolValue;
}
catch (Exception ex)
{
EmailTRACERManager.Manager.LogError(ex.Message + " " + ex.StackTrace);
}
}

public void SetIDProperty(Outlook.MailItem mailItem, string propertyName,
Int64 idValue)
{
try
{
Outlook.UserProperty prop = null;

// Attempt to get the property, if it exists.
if (mailItem.UserProperties[propertyName] == null)
{
//The property did not exist, add it.
prop = mailItem.UserProperties.Add(propertyName,

Microsoft.Office.Interop.Outlook.OlUserPropertyType.olText, false,

Microsoft.Office.Interop.Outlook.OlUserPropertyType.olText);
}
mailItem.UserProperties[propertyName].Value =
idValue.ToString();
}
catch (Exception ex)
{
EmailTRACERManager.Manager.LogError(ex.Message + " " +
ex.StackTrace);
}
}

public void SetTextProperty(Outlook.MailItem mailItem, string
propertyName,
string textValue)
{
try
{
Outlook.UserProperty prop = null;

// Attempt to get the property, if it exists.
if (mailItem.UserProperties[propertyName] == null)
{
//The property did not exist, add it.
prop = mailItem.UserProperties.Add(propertyName,

Microsoft.Office.Interop.Outlook.OlUserPropertyType.olText, true,

Microsoft.Office.Interop.Outlook.OlUserPropertyType.olText);
}
mailItem.UserProperties[propertyName].Value = textValue;
}
catch (Exception ex)
{
EmailTRACERManager.Manager.LogError(ex.Message + " " +
ex.StackTrace);
}
}
 
Hi Ken,

Sorry I did not get back to you sooner but I have only just had time to test
these two suggestions. Unfortunately I can still reproduce the problem with
them implemented.

Is there a way we could force the screen to update in code? The fact that
the values are present and correct on the mail item after being set and that
they can be made to appear on the screen by opening the inspector and
manually saving suggests that it may be a refresh issue but the Refresh
option on the menu is disabled so I cannot test with that and restarting
Outlook does not cause them to appear.

Could Outlook be changing a different instance of the mailItem to the one it
originally gave us and overwriting our changes?

Ken Slovak - said:
Offhand I'm not sure but I'd try 2 different things. First see if setting
the DisplayFormat argument instead of setting it to missing helps. Second,
see if passing the email item object by reference makes any difference.




rob_tt08 said:
Ken,

Here is the code we are using to set the User Properties. The variable
_emails is a class level List<Outlook.MailItem>. It is being cleared and
set
to null when we are finished with it.

I have previously tried changing the code to avoid using the list in case
the mailitems being in a .NET collection was interfering somehow, but this
did not help.

The user properties are being added to the folder using the parameter on
UserProperties.Add which tells it to add the property to the folder if
required (except for SetIDProperty as these are not meant to be available
as
folder columns), but the problem is happening even after the properties
have
been added for other mail items successfully.

When I check the value of a property immediately after adding it, it is
correct. It just doesn't show up in the folder unless the user opens an
inspector and saves it manually.

Thank you for your assistance with this.

// Loop through the mail items
foreach (Outlook.MailItem mailItem in _emails)
{
// Other code
...
// Check save first
mailItem.Save();

if (_emailIn)
EmailTRACERManager.Manager.MAPIHelper.SetIDProperty(mailItem,
EmailTRACERManager.UPReceivedID, matterID);

//We are logging an item with Register Only and need all properties

EmailTRACERManager.Manager.MAPIHelper.SetBooleanProperty(mailItem,
EmailTRACERManager.UPLogged, true);
EmailTRACERManager.Manager.MAPIHelper.SetTextProperty(mailItem,
EmailTRACERManager.UPProject, this.MatterName);

//We have to save the email if the properties are to stay.
mailItem.Save();
}

public void SetBooleanProperty(Outlook.MailItem mailItem, string
propertyName, bool boolValue)
{
try
{
Outlook.UserProperty prop = null;

// Attempt to get the property, if it exists.
if (mailItem.UserProperties[propertyName] == null)
{
//The property did not exist, add it.
prop = mailItem.UserProperties.Add(propertyName,
Microsoft.Office.Interop.Outlook.OlUserPropertyType.olYesNo, true,
System.Reflection.Missing.Value);
}

mailItem.UserProperties[propertyName].Value = boolValue;
}
catch (Exception ex)
{
EmailTRACERManager.Manager.LogError(ex.Message + " " + ex.StackTrace);
}
}

public void SetIDProperty(Outlook.MailItem mailItem, string propertyName,
Int64 idValue)
{
try
{
Outlook.UserProperty prop = null;

// Attempt to get the property, if it exists.
if (mailItem.UserProperties[propertyName] == null)
{
//The property did not exist, add it.
prop = mailItem.UserProperties.Add(propertyName,

Microsoft.Office.Interop.Outlook.OlUserPropertyType.olText, false,

Microsoft.Office.Interop.Outlook.OlUserPropertyType.olText);
}
mailItem.UserProperties[propertyName].Value =
idValue.ToString();
}
catch (Exception ex)
{
EmailTRACERManager.Manager.LogError(ex.Message + " " +
ex.StackTrace);
}
}

public void SetTextProperty(Outlook.MailItem mailItem, string
propertyName,
string textValue)
{
try
{
Outlook.UserProperty prop = null;

// Attempt to get the property, if it exists.
if (mailItem.UserProperties[propertyName] == null)
{
//The property did not exist, add it.
prop = mailItem.UserProperties.Add(propertyName,

Microsoft.Office.Interop.Outlook.OlUserPropertyType.olText, true,

Microsoft.Office.Interop.Outlook.OlUserPropertyType.olText);
}
mailItem.UserProperties[propertyName].Value = textValue;
}
catch (Exception ex)
{
EmailTRACERManager.Manager.LogError(ex.Message + " " +
ex.StackTrace);
}
}
 
Outlook can certainly overwrite changes made in code if the changes aren't
saved, and especially if you use a different API such as Redemption and
don't save, but otherwise no overwriting should happen. There is no way to
refresh what's shown unless you switch to a different folder and back again,
which will produce an annoying flash.
 
Back
Top