Outlook 2010 插件错误 32770 window
Outlook 2010 plugin wrong 32770 window
我正在按照此处发布的 Helmut Oberdan 示例开发适用于 Outlook 2010 的自定义地址对话框
http://www.codeproject.com/Articles/21288/Customize-the-built-in-Outlook-Select-Names-dialog
我已经将项目迁移到框架 4.5 的 VS2015,但是
我在使用 findwindow 函数时遇到了麻烦
IntPtr hBuiltInDialog = WinApiProvider.FindWindow("#32770", "");
在某些计算机(我的)上运行良好,而在其他一些计算机(客户)上则不能。
该函数似乎找到了另一个不是 Outlook 的 32770 window,我试图枚举所有 32770 windows 但是当 InspectorWrapper_Deactivate 函数启动时,我的 32770 window 不在列表中。
一个奇怪的行为发生了,如果我在停用函数中放置一个消息框,它会弹出两次,在第二次之后正确的 window 被捕获并且我的自定义对话框打开。
这里是InspectorWrapper_Deactivate函数
</p>
<pre><code>void InspectorWrapper_Deactivate()
{
_showOwnDialogOnActivate = false;
// If there is an invisible ghost Window out there - close it
if (_hWndInvisibleWindow != IntPtr.Zero) WinApiProvider.SendMessage(_hWndInvisibleWindow, WinApiProvider.WM_SYSCOMMAND, WinApiProvider.SC_CLOSE, 0);
IntPtr hBuiltInDialog = WinApiProvider.FindWindow("#32770", "");
if (hBuiltInDialog != IntPtr.Zero)
{
// ok, found one
// let's see what childwindows are there
List<IntPtr> childWindows = WinApiProvider.EnumChildWindows(hBuiltInDialog);
// Let's get a list of captions for the child windows
List<string> childWindowNames = WinApiProvider.GetWindowNames(childWindows);
//MessageBox.Show("Contact");
// now check some criteria to identify the build in dialog..
int languageId = Inspector.Application.LanguageSettings.get_LanguageID(Microsoft.Office.Core.MsoAppLanguageID.msoLanguageIDUI);
switch (languageId)
{
case 1031:
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// !!! This part is only valid for German Outlook 2007 Version !!!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
if (!childWindowNames.Contains("Nur N&ame")) return;
if (!childWindowNames.Contains("&Mehr Spalten")) return;
if (!childWindowNames.Contains("A&dressbuch")) return;
// you can even check more criteria
break;
case 1033:
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// !!! This part is only valid for english Outlook 2007 Version !!!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
if (!childWindowNames.Contains("&Name only")) return;
if (!childWindowNames.Contains("Mo&re columns")) return;
if (!childWindowNames.Contains("A&ddress Book")) return;
break;
case 1040:
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// !!! This part is only valid for italian Outlook 2007 Version !!!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
if (!childWindowNames.Contains("Solo n&ome")) return;
if (!childWindowNames.Contains("Altre &colonne")) return;
if (!childWindowNames.Contains("R&ubrica")) return;
break;
// TODO: place your language here....
default:
return;
}
// OK - we have the built in Recipient Dialog
// Create a new invisible window
_hWndInvisibleWindow = WinApiProvider.CreateWindowEx(0, "Static", "BriaSOFT", 0, 0, 0, 0, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
// use this window as new Parent for the original Dialog
WinApiProvider.SetParent(hBuiltInDialog, _hWndInvisibleWindow);
WinApiProvider.SendMessage(hBuiltInDialog, WinApiProvider.WM_SYSCOMMAND, WinApiProvider.SC_CLOSE, 0);
// When our INspector becomes active again, we should show our own Dialog
_showOwnDialogOnActivate = true;
}
}
如有任何建议,我们将不胜感激。
谢谢
弗拉维奥
遵循德米特里的建议
但仍然无法找到 32770 window,因为它的 window 名称为空(即使它存在)
</p>
<pre><code> string windowName;
IntPtr outlookHandle = (IntPtr)0;
IOleWindow window = Inspector as IOleWindow;
if (window != null)
{
window.GetWindow(out outlookHandle);
List<IntPtr> subWindows = WinApiProvider.EnumChildWindows(outlookHandle);
foreach (IntPtr hand in subWindows)
{
StringBuilder ClassName = new StringBuilder(256);
int nRet = WinApiProvider.GetClassName(hand, ClassName, ClassName.Capacity);
if (nRet != 0)
{
if (ClassName.ToString().Contains("#32770"))
{
windowName = WinApiProvider.GetWindowName(hand);
if (windowName.Contains("Seleziona nomi"))
{
hBuiltInDialog = hand;
break;
}
}
}
}
}
而不是使用 FindWindow
,您将需要找到托管该控件的 Outlook window(为 IOleWindow
和 cal lIOelWindow.GetWindow
转换 Inspector
),然后使用给定的 class 名称/标题/等查找 window (EnumChildWindows
) 的 child。如果有多个 windows class 名称,您可能需要使用 parent / child / peer windows 的唯一组合以确保您拥有正确的名称。
经过几天的测试和尝试,解决方案(Microsoft 建议)是插入一个单独的线程,从检查器启动并在找到 window 时自动终止。
里面inspector_deactivate
</p>
<pre><code> if (workerThread.ThreadState == ThreadState.Unstarted)
{
// Start the worker thread.
workerThread.Start();
while (!workerThread.IsAlive) ;
// Put the main thread to sleep for 1 millisecond to
// allow the worker thread to do some work:
Thread.Sleep(1);
}
else if (!workerThread.IsAlive)
{
workerObject = new Worker(Inspector);
workerThread = new Thread(workerObject.DoWork);
workerThread.Start();
}
和线程内
</p>
<pre><code> public Worker(Outlook.Inspector insp)
{
Inspector = insp;
_shouldStop = false;
}
public void DoWork()
{
while (!_shouldStop)
{
SubstituteWindow();
}
}
我正在按照此处发布的 Helmut Oberdan 示例开发适用于 Outlook 2010 的自定义地址对话框
http://www.codeproject.com/Articles/21288/Customize-the-built-in-Outlook-Select-Names-dialog
我已经将项目迁移到框架 4.5 的 VS2015,但是 我在使用 findwindow 函数时遇到了麻烦
IntPtr hBuiltInDialog = WinApiProvider.FindWindow("#32770", "");
在某些计算机(我的)上运行良好,而在其他一些计算机(客户)上则不能。 该函数似乎找到了另一个不是 Outlook 的 32770 window,我试图枚举所有 32770 windows 但是当 InspectorWrapper_Deactivate 函数启动时,我的 32770 window 不在列表中。 一个奇怪的行为发生了,如果我在停用函数中放置一个消息框,它会弹出两次,在第二次之后正确的 window 被捕获并且我的自定义对话框打开。
这里是InspectorWrapper_Deactivate函数
</p>
<pre><code>void InspectorWrapper_Deactivate()
{
_showOwnDialogOnActivate = false;
// If there is an invisible ghost Window out there - close it
if (_hWndInvisibleWindow != IntPtr.Zero) WinApiProvider.SendMessage(_hWndInvisibleWindow, WinApiProvider.WM_SYSCOMMAND, WinApiProvider.SC_CLOSE, 0);
IntPtr hBuiltInDialog = WinApiProvider.FindWindow("#32770", "");
if (hBuiltInDialog != IntPtr.Zero)
{
// ok, found one
// let's see what childwindows are there
List<IntPtr> childWindows = WinApiProvider.EnumChildWindows(hBuiltInDialog);
// Let's get a list of captions for the child windows
List<string> childWindowNames = WinApiProvider.GetWindowNames(childWindows);
//MessageBox.Show("Contact");
// now check some criteria to identify the build in dialog..
int languageId = Inspector.Application.LanguageSettings.get_LanguageID(Microsoft.Office.Core.MsoAppLanguageID.msoLanguageIDUI);
switch (languageId)
{
case 1031:
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// !!! This part is only valid for German Outlook 2007 Version !!!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
if (!childWindowNames.Contains("Nur N&ame")) return;
if (!childWindowNames.Contains("&Mehr Spalten")) return;
if (!childWindowNames.Contains("A&dressbuch")) return;
// you can even check more criteria
break;
case 1033:
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// !!! This part is only valid for english Outlook 2007 Version !!!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
if (!childWindowNames.Contains("&Name only")) return;
if (!childWindowNames.Contains("Mo&re columns")) return;
if (!childWindowNames.Contains("A&ddress Book")) return;
break;
case 1040:
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// !!! This part is only valid for italian Outlook 2007 Version !!!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
if (!childWindowNames.Contains("Solo n&ome")) return;
if (!childWindowNames.Contains("Altre &colonne")) return;
if (!childWindowNames.Contains("R&ubrica")) return;
break;
// TODO: place your language here....
default:
return;
}
// OK - we have the built in Recipient Dialog
// Create a new invisible window
_hWndInvisibleWindow = WinApiProvider.CreateWindowEx(0, "Static", "BriaSOFT", 0, 0, 0, 0, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
// use this window as new Parent for the original Dialog
WinApiProvider.SetParent(hBuiltInDialog, _hWndInvisibleWindow);
WinApiProvider.SendMessage(hBuiltInDialog, WinApiProvider.WM_SYSCOMMAND, WinApiProvider.SC_CLOSE, 0);
// When our INspector becomes active again, we should show our own Dialog
_showOwnDialogOnActivate = true;
}
}
如有任何建议,我们将不胜感激。 谢谢 弗拉维奥
遵循德米特里的建议 但仍然无法找到 32770 window,因为它的 window 名称为空(即使它存在)
</p>
<pre><code> string windowName;
IntPtr outlookHandle = (IntPtr)0;
IOleWindow window = Inspector as IOleWindow;
if (window != null)
{
window.GetWindow(out outlookHandle);
List<IntPtr> subWindows = WinApiProvider.EnumChildWindows(outlookHandle);
foreach (IntPtr hand in subWindows)
{
StringBuilder ClassName = new StringBuilder(256);
int nRet = WinApiProvider.GetClassName(hand, ClassName, ClassName.Capacity);
if (nRet != 0)
{
if (ClassName.ToString().Contains("#32770"))
{
windowName = WinApiProvider.GetWindowName(hand);
if (windowName.Contains("Seleziona nomi"))
{
hBuiltInDialog = hand;
break;
}
}
}
}
}
而不是使用 FindWindow
,您将需要找到托管该控件的 Outlook window(为 IOleWindow
和 cal lIOelWindow.GetWindow
转换 Inspector
),然后使用给定的 class 名称/标题/等查找 window (EnumChildWindows
) 的 child。如果有多个 windows class 名称,您可能需要使用 parent / child / peer windows 的唯一组合以确保您拥有正确的名称。
经过几天的测试和尝试,解决方案(Microsoft 建议)是插入一个单独的线程,从检查器启动并在找到 window 时自动终止。
里面inspector_deactivate
</p>
<pre><code> if (workerThread.ThreadState == ThreadState.Unstarted)
{
// Start the worker thread.
workerThread.Start();
while (!workerThread.IsAlive) ;
// Put the main thread to sleep for 1 millisecond to
// allow the worker thread to do some work:
Thread.Sleep(1);
}
else if (!workerThread.IsAlive)
{
workerObject = new Worker(Inspector);
workerThread = new Thread(workerObject.DoWork);
workerThread.Start();
}
和线程内
</p>
<pre><code> public Worker(Outlook.Inspector insp)
{
Inspector = insp;
_shouldStop = false;
}
public void DoWork()
{
while (!_shouldStop)
{
SubstituteWindow();
}
}