InfoPath 專案中使用 InfoPath 2003 物件模型的執行緒支援
透過 Microsoft.Office.Interop.InfoPath.dll、Microsoft.Office.Interop.InfoPath.SemiTrust.dll 及 Microsoft.Office.Interop.InfoPath.Xml.dll interop 組件 (由 Microsoft Office InfoPath 2007 所安裝) 來存取的 COM 物件,並不支援多執行緒的呼叫。這包括適用 Office 物件之 Microsoft XML Core Services (MSXML) 5.0 的介面,這些物件是由 Microsoft.Office.Interop.InfoPath.SemiTrust 命名空間 (其中大多數都具有以 IXMLDOM 字元開頭的名稱) 所包裝的,而且所有的介面都由 Microsoft.Office.Interop.InfoPath.Xml 命名空間公開,這些介面都不是安全執行緒。
對這些 COM 物件所做出的呼叫必須是在單一的執行緒上發出。在 InfoPath 專案中的 Managed 程式碼可以建立其他的執行緒以執行背景工作,但是在非主要執行緒以外的執行緒上所執行的程式碼則無法呼叫 InfoPath 物件模型。
如果您的 InfoPath Managed 程式碼專案使用多個執行緒,則在執行緒間共用物件必須非常小心。您不能在執行緒間共用「XML 文件物件模型」(DOM) 的參照或 InfoPath 物件的參照。
對 InfoPath 物件模型進行非同步呼叫
至於需要在程序中呼叫的情況,例如在個別執行緒執行的計時器,想要解決 InfoPath 物件模型不支援此種呼叫的狀況是有可能的。
下列範例會在表單的 _Startup 方法中建立 System.Timers.Timer 執行個體,並將非同步的回呼連結至計時器。此外,還會建立一個隱藏的視窗表單 (System.Windows.Forms.Form) 執行個體。計時器每經過一秒,回呼函數也會執行一次,它會呼叫 Win32 PostMessage 函數,將訊息貼至隱藏的視窗。這個隱藏視窗含有一個 WndProc 函數,以便處理從計時器回呼函數收到的訊息,並更新表單的 XML 文件物件模型 (DOM)。此表單必須安裝為完全信任的表單,才能夠執行。如需偵錯完全信任之表單範本的詳細資訊,請參閱操作方法:預覽及偵錯需要完全信任的 Managed 程式碼表單範本。如需部署完全信任之表單範本的詳細資訊,請參閱操作方法:部署 InfoPath 專案。
using System;
using Microsoft.Office.Interop.InfoPath.SemiTrust;
using System.Timers;
using System.Runtime.InteropServices;
// Office integration attribute. Identifies the startup class for the
// form. Do not modify.
[assembly: System.ComponentModel.DescriptionAttribute("InfoPathStartupClass, Version=1.0, Class=AsyncUpdate.AsyncUpdate")]
namespace AsyncUpdate
{
public class User32
{
[DllImport("User32.dll")]
public static extern Int32 PostMessage(
IntPtr hWnd, int Msg, int wParam, int lParam);
public User32()
{
}
~User32()
{
}
}
public class MyWindow : System.Windows.Forms.Form
{
private XDocument thisXDocument;
private AsyncUpdate thisProcess ;
// Private message for internal class.
public const int WM_MYNOTIFY = 0x400;
public MyWindow(XDocument doc, AsyncUpdate process)
{
thisXDocument = doc;
thisProcess = process;
this.Text = "MyWindow";
// Force HWND to get created in Win32
IntPtr hwnd = this.Handle;
}
[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name="FullTrust")]
protected override void WndProc(
ref System.Windows.Forms.Message m)
{
switch (m.Msg)
{
case WM_MYNOTIFY:
IXMLDOMNode xml = thisXDocument.DOM.selectSingleNode(
"/my:myFields/my:field1");
xml.text = thisProcess.counter.ToString();
break;
}
base.WndProc(ref m);
}
}
// The namespace prefixes defined in this attribute must remain
// synchronized with those in the form definition file (.xsf).
[InfoPathNamespace("xmlns:my='https://schemas.microsoft.com/office/infopath/2003/myXSD/2004-02-11T23-29-59'")]
public class AsyncUpdate
{
private XDocument thisXDocument;
private Application thisApplication;
public int counter;
private System.Timers.Timer myTimer;
private MyWindow myWnd;
public void _Startup(Application app, XDocument doc)
{
thisXDocument = doc;
thisApplication = app;
// init the counter
counter = 0;
// Start a timer on another thread
myTimer = new System.Timers.Timer(1000);
myTimer.Elapsed += new ElapsedEventHandler(
myTimer_Elapsed);
myTimer.Start();
// create hidden window to receive notifications
// back on the main thread
myWnd = new MyWindow(thisXDocument, this);
}
public void _Shutdown()
{
myWnd.Dispose();
myTimer.Stop();
myTimer.Dispose();
}
private void myTimer_Elapsed(object sender, ElapsedEventArgs e)
{
// This method is called on a second thread
counter ++;
// Post message back to main thread
User32.PostMessage(
myWnd.Handle, MyWindow.WM_MYNOTIFY, 0, 0);
}
}
}