问题描述
我想在Outlook 2010(或2007)的待办事项栏"中添加一个新部分.我找到了一些代码来创建一个新的可折叠任务窗格,有人声称您不能修改待办事项栏,但我还发现了一个名为Add-In Express的产品声称可以做到(尽管349美元的价格不值得)一次性项目).
I would like to add a new section to the To-Do Bar in Outlook 2010 (or 2007). I found some code to create a new collapsible task pane and someone claiming you can't modify the To-Do bar, but I also found a product called Add-In Express that claims it can do it (although at $349 it's not worth it for a one-off project).
可以这样做吗?
推荐答案
经过一番研究(并查看了Add-in Express的产品文档),我发现可以在Outlook中自定义待办事项栏2007年.
After some research (and after having seen the product documentation of Add-in Express), I figured that it is possible to customize the To-Do Bar in Outlook 2007.
在CodeProject上有一个证明概念,该概念将自定义"(自读的)窗格嵌入到Outlooks主窗口中.该文章由Lukas Neumann撰写,可以在这里找到:
There is a proof-poof-concept on CodeProject that embeds a "custom" (read self-written) pane into Outlooks main window. The article has been written by Lukas Neumann and is available here:
原理如下:
- 在Outlook窗口中搜索要放置自己的窗口(即待办事项栏"子窗口)的子窗口
- 调整该窗口的内容大小以为控件留出一些空间
- 添加自己的窗口作为孩子
- 将待办事项栏"窗口子类化,以挂接到该窗口的消息循环中
基本上只需要进行两次修改即可调整示例代码:
There is basically only two modifications that need to be done to adjust the sample code:
- 获取正确的子窗口句柄:待办事项栏的窗口类称为"WUNDERBAR".此类用于多个子窗口,因此请确保还检查正确的窗口标题("ToDoBar")或仅按窗口标题进行搜索.
- 正确调整面板的大小(简单但并不总是容易;-).
(如果未找到待办事项栏等,并添加一些适当的错误处理).
(And add some proper error handling if the To-Do Bar is not found etc).
如果您熟悉Spy ++,这是一个不错的选择,因为它需要找出Outlook子窗口的类名和窗口标题.
It's a strong plus if you are familiar with Spy++ as it is needed to find out the class names and window titles of Outlook's child windows.
我建议您下载示例代码并进行以下修改:
I suggest you to download the sample code and apply the following modifications:
在Connect.cs中:
In Connect.cs:
private const string SIBLING_WINDOW_CLASS = "NetUINativeHWNDHost";
public delegate bool EnumChildCallback(IntPtr hwnd, ref IntPtr lParam);
[DllImport("User32.dll")]
public static extern bool EnumChildWindows(IntPtr hWndParent, EnumChildCallback lpEnumFunc, ref IntPtr lParam);
[DllImport("User32.dll")]
public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int GetWindowTextLength(IntPtr hWnd);
public static bool EnumChildProc(IntPtr hwndChild, ref IntPtr lParam)
{
StringBuilder className = new StringBuilder(128);
GetClassName(hwndChild, className, 128);
int length = GetWindowTextLength(hwndChild);
StringBuilder windowText = new StringBuilder(length + 1);
GetWindowText(hwndChild, windowText, windowText.Capacity);
if (className.ToString() == "WUNDERBAR" && windowText.ToString() == "ToDoBar")
{
lParam = hwndChild;
return false;
}
return true;
}
public void OnStartupComplete(ref System.Array custom)
{
if (_outlookApplication == null)
return; //We were not loaded into Outlook, so do nothing
//Get the instance of Outlook active explorer (= the main window) and start capturing selection changes
_outlookExplorer = _outlookApplication.ActiveExplorer();
_outlookExplorer.SelectionChange += new ExplorerEvents_10_SelectionChangeEventHandler(outlookExplorer_SelectionChange);
//Find Outlook window handle (HWND)
IntPtr outlookWindow = FindOutlookWindow();
if (outlookWindow == IntPtr.Zero)
return;
// Find ToDoBar window handle
IntPtr todoBarWindow = IntPtr.Zero;
EnumChildCallback cb = new EnumChildCallback(EnumChildProc);
EnumChildWindows(outlookWindow, cb, ref todoBarWindow);
if (todoBarWindow == IntPtr.Zero)
return;
//Find sibling window handle (HWND)
//Sibling window is the window which we are going to "cut" to make space for our own window
IntPtr siblingWindow = SafeNativeMethods.FindWindowEx(todoBarWindow, IntPtr.Zero, SIBLING_WINDOW_CLASS, null);
if (siblingWindow == IntPtr.Zero)
return;
//Initialise PanelManager and assign own panel to it
_panelManager = new PanelManager(outlookWindow, siblingWindow);
_customPanel = new MyPanel();
_panelManager.ShowBarControl(_customPanel);
}
在PanelManager.cs中:
In PanelManager.cs:
private void ResizePanels()
{
if (_changingSize)
return; //Prevent infinite loops
_changingSize = true;
try
{
//Get size of the sibling window and main parent window
Rectangle siblingRect = SafeNativeMethods.GetWindowRectangle(this.SiblingWindow);
Rectangle parentRect = SafeNativeMethods.GetWindowRectangle(this.ParentWindow);
//Calculate position of sibling window in screen coordinates
SafeNativeMethods.POINT topLeft = new SafeNativeMethods.POINT(siblingRect.Left, siblingRect.Top);
SafeNativeMethods.ScreenToClient(this.ParentWindow, ref topLeft);
//Decrease size of the sibling window
int newHeight = parentRect.Height - topLeft.Y - _panelContainer.Height;
SafeNativeMethods.SetWindowPos(this.SiblingWindow, IntPtr.Zero, 0, 0, siblingRect.Width, newHeight, SafeNativeMethods.SWP_NOMOVE | SafeNativeMethods.SWP_NOZORDER);
//Move the bar to correct position
_panelContainer.Left = topLeft.X;
_panelContainer.Top = topLeft.Y + newHeight;
//Set correct height of the panel container
_panelContainer.Width = siblingRect.Width;
}
finally
{
_changingSize = false;
}
}
概念验证是一个托管的COM加载项,并且不使用VSTO,但是非常相似的方法也适用于VSTO.如果您需要进一步的帮助,请告诉我,因为概念验证已经需要有关子类化和Office加载项体系结构(IDTExtensibility2)的知识.
The proof-of-concept is a managed COM Add-in and not using VSTO, but a very similar approach should also work for VSTO. Let me know in case you need any further help, as the proof-of-concept already requires some knowledge about subclassing and the Office add-in architecture (IDTExtensibility2).
也请考虑这只是概念验证,它显示了如何自定义Outlook UI的基本技术.而且我的编辑远非精美的代码;-)
Please also consider that this is just a proof-of-concept showing the basic technique how to customize the Outlook UI. And my edits are far from beautiful code ;-)
这篇关于是否在Outlook 2007/2010的“待办事项"栏中添加了部分?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!