다음을 통해 공유


InfoPath 2003 개체 모델을 사용하는 InfoPath 프로젝트의 스레딩 지원

Microsoft InfoPath 2010에서 설치한 Microsoft.Office.Interop.InfoPath.dll, Microsoft.Office.Interop.InfoPath.SemiTrust.dll 및 Microsoft.Office.Interop.InfoPath.Xml.dll interop 어셈블리를 통해 액세스하는 COM 개체는 다중 스레드 호출을 지원하지 않습니다. 여기에는 Microsoft.Office.Interop.InfoPath.SemiTrust 네임스페이스(대부분 이름 앞에 IXMLDOM이 붙음)에 의해 래핑되는 Microsoft XML Core Services(MSXML) 개체에 대한 인터페이스와 Microsoft.Office.Interop.InfoPath.Xml 네임스페이스에 의해 노출되는 모든 인터페이스가 포함되며, 모두 스레드로부터 안전하지 않습니다.

이러한 COM 개체에 만들어진 모든 호출은 단일 스레드로 발급되어야 합니다. InfoPath 프로젝트의 관리 코드는 다른 스레드를 만들어 백그라운드 작업을 수행할 수 있지만 기본 스레드가 아닌 다른 스레드에서 실행하는 코드는 InfoPath 개체 모델로 호출할 수 없습니다.

InfoPath 관리 코드 프로젝트가 여러 스레드를 사용하면 스레드 간에 개체를 공유할 때 주의해야 합니다. 스레드 간에 XML DOM(문서 개체 모델)에 대한 참조나 InfoPath 개체에 대한 참조를 공유하면 안 됩니다.

InfoPath 개체 모델에 대한 비동기 호출 만들기

다른 스레드에서 실행하는 타이머와 같은 프로세스로 호출해야 하는 상황에서 InfoPath 개체 모델이 그러한 호출을 지원하지 않더라도 작업할 수 있습니다.

다음 예제에서는 양식의 _Startup 메서드로 System.Timers.Timer 인스턴스를 만들고 타이머에 비동기 콜백을 후크합니다. 또한 창 양식(System.Windows.Forms.Form)의 표시되지 않는 인스턴스가 만들어집니다. 타이머 경과 콜백 함수가 초당 한 번씩 실행되면 Win32 PostMessage 함수를 호출하여 표시되지 않는 창에 메시지를 게시합니다. 표시되지 않는 창에는 타이머 콜백 함수로부터 받은 메시지를 처리하여 양식의 XML DOM(문서 개체 모델)을 업데이트하는 WndProc 함수가 있습니다. 이 양식은 완전히 신뢰할 수 있는 양식 서식 파일을 실행할 때 설치해야 합니다. 완전히 신뢰할 수 있는 양식 서식 파일의 디버깅에 대한 자세한 내용은 방법: 전체 신뢰가 필요한 관리 코드 양식 서식 파일 디버깅 및 미리 보기를 참조하십시오. 완전히 신뢰할 수 있는 양식 서식 파일의 배포에 대한 자세한 내용은 방법: 코드가 포함된 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);
        }
    }
}