Поддержка потоков в проектах InfoPath, использующих объектную модель InfoPath 2003
COM-объекты, доступ к которым предоставляется через сборки взаимодействия Microsoft.Office.Interop.InfoPath.dll, Microsoft.Office.Interop.InfoPath.SemiTrust.dll и Microsoft.Office.Interop.InfoPath.Xml.dll, установленные приложением Microsoft Office InfoPath 2007, не поддерживают вызовы в нескольких потоках. В число таковых входят интерфейсы MSXML 5.0 для объектов Office, реализуемых пространством имен Microsoft.Office.Interop.InfoPath.SemiTrust (в именах большинства которых используется префикс IXMLDOM), а также все интерфейсы, предоставляемые пространством имен Microsoft.Office.Interop.InfoPath.Xml, которые не обеспечивают точную синхронизацию потоков.
Все вызовы этих COM-объектов необходимо выполнять в одном потоке. Управляемый код в проекте InfoPath может создавать другие потоки для фоновой работы, но вызовы объектной модели может осуществлять только главный поток.
Если в проекте InfoPath с управляемым кодом используется несколько потоков, то следует осторожно распределять объекты между потоками. Нельзя распределять между потоками ссылки на модель XML DOM и ссылки на объекты InfoPath.
Осуществление асинхронных вызовов объектной модели InfoPath
В случаях, когда необходимо вызвать процесс, например таймер, запущенный в отдельном потоке, можно проигнорировать тот факт, что объектная модель InfoPath не поддерживает подобных вызовов.
В следующем примере создается экземпляр System.Timers.Timer метода _Startup для формы и обрабатывается асинхронный обратный вызов к таймеру. Кроме того, создается невидимый экземпляр формы Window (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='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);
}
}
}