使用 InfoPath 2003 物件模型在 InfoPath 專案中支援執行緒
透過 Microsoft.Office.Interop.InfoPath.dll、Microsoft.Office.Interop.InfoPath.SemiTrust.dll 及 Microsoft.Office.Interop.InfoPath.Xml.dll interop 組件 (由 Microsoft InfoPath 所安裝) 來存取的 COM 物件,並不支援多執行緒的呼叫。 這包括 Microsoft XML Core Services (MSXML) 物件的介面,這些介面是由 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)。 此表單必須安裝為完全信任的表單,才能夠執行。 如需偵錯完全信任窗體範本的資訊,請參閱 需要完全信任的預覽和偵錯窗體範本。 如需部署完全信任表單範本的資訊,請參閱 使用程式碼部署 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='http://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);
}
}
}