Threadunterstützung in InfoPath-Projekten mit dem InfoPath 2003-Objektmodell

Die COM-Objekte, auf die über die von Microsoft Office InfoPath 2007 installierten Interop-Assemblys "Microsoft.Office.Interop.InfoPath.dll", "Microsoft.Office.Interop.InfoPath.SemiTrust.dll" und "Microsoft.Office.Interop.InfoPath.Xml.dll" zugegriffen wird, unterstützen keine Aufrufe auf mehreren Threads. Dazu gehören die Schnittstellen für Microsoft XML Core Services (MSXML) 5.0 für Office-Objekte, die vom Microsoft.Office.Interop.InfoPath.SemiTrust-Namespace gepackt werden (und deren Namen meistens IXMLDOM vorangestellt ist) sowie alle Schnittstellen, die vom Microsoft.Office.Interop.InfoPath.Xml-Namespace verfügbar gemacht werden und von denen keine Thread-sicher ist.

Alle Aufrufe dieser COM-Objekte müssen auf einem einzigen Thread ausgegeben werden. Mit verwaltetem Code in einem InfoPath-Projekt können weitere Threads für die Ausführung von Hintergrundarbeiten erstellt werden. Code, der auf anderen Threads als dem Hauptthread ausgeführt wird, kann jedoch keine InfoPath-Objektmodelle aufrufen.

Wenn das InfoPath-Projekt mit verwaltetem Code mehrere Threads verwendet, müssen Sie bei der gemeinsamen Nutzung von Objekten zwischen Threads vorsichtig sein. Es sollten keine Verweise auf das XML-DOM (Document Object Model) oder Verweise auf InfoPath-Objekte zwischen Threads gemeinsam genutzt werden.

Senden von asynchronen Aufrufen an das InfoPath-Objektmodell

In Situationen, in denen ein Prozess, wie z. B. ein auf einem separaten Thread ausgeführter Zeitgeber, aufgerufen werden muss, lässt sich die Tatsache umgehen, dass das InfoPath-Objektmodell keine derartigen Aufrufe unterstützt.

Im folgenden Beispiel wird eine System.Timers.Timer-Instanz in der _Startup-Methode des Formulars erstellt und mit einem asynchronen Rückruf an den Zeitgeber verbunden. Darüber hinaus wird eine unsichtbare Instanz des Windows Forms (System.Windows.Forms.Form) erstellt. Bei Ablauf des Zeitgebers wird die Rückruffunktion einmal pro Sekunde ausgeführt. Sie ruft die Win32-Funktion PostMessage auf, um eine Nachricht für das unsichtbare Fenster bereitzustellen. Dieses verfügt über eine WndProc-Funktion, mit der die von der Zeitgeber-Rückruffunktion empfangene Nachricht verarbeitet und das XML-DOM (Document Object Model) des Formulars verarbeitet wird. Damit dieses Formular ausgeführt werden kann, muss es als vollständig vertrauenswürdig installiert werden. Weitere Informationen zum Debuggen einer vollständig vertrauenswürdigen Formularvorlage finden Sie unter Vorgehensweise: Anzeigen einer Vorschau und Debuggen von Formularvorlagen mit verwaltetem Code, die vollständig vertrauenswürdig sein müssen. Weitere Informationen zum Bereitstellen einer vollständig vertrauenswürdigen Formularvorlage finden Sie unter Vorgehensweise: Bereitstellen von InfoPath-Projekten.

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);
        }
    }
}