7

मैं विंडोज़ सेवा के माध्यम से Office InfoPath 2010 के कई समांतर उदाहरणों को स्वचालित करने की कोशिश कर रहा हूं। मैं समझता हूं कि एक सेवा से स्वचालित कार्यालय समर्थित नहीं है, हालांकि यह मेरे ग्राहक की आवश्यकता है।एकाधिक इन्फोपैथ इंटरऑप ऑटोमेशन उदाहरण

मैं समानांतर फैशन में अन्य कार्यालय अनुप्रयोगों को स्वचालित कर सकता हूं, हालांकि इन्फोपाथ अलग-अलग व्यवहार करता है।

मुझे जो मिला है वह यह है कि केवल INFOPATH.EXE प्रक्रिया का एक उदाहरण होगा, इससे कोई फर्क नहीं पड़ता कि CreateObject("InfoPath.Application") पर कितनी समानांतर कॉल की गई है। इसके विपरीत, WINWORD.EXE के कई उदाहरण इसी तरह के तंत्र के माध्यम से बनाया जा सकता है CreateObject("Word.Application")

इस समस्या को पुन: उत्पन्न करने के लिए, एक साधारण कंसोल एप्लिकेशन का उपयोग किया जा सकता है।

static void Main(string[] args) { 
    // Create two instances of word in parallel 
    ThreadPool.QueueUserWorkItem(Word1); 
    ThreadPool.QueueUserWorkItem(Word2); 

    System.Threading.Thread.Sleep(5000); 

    // Attempt to create two instances of infopath in parallel 
    ThreadPool.QueueUserWorkItem(InfoPath1); 
    ThreadPool.QueueUserWorkItem(InfoPath2); 
} 

static void Word1(object context) { 
    OfficeInterop.WordTest word = new OfficeInterop.WordTest(); 
    word.Test(); 
} 

static void Word2(object context) { 
    OfficeInterop.WordTest word = new OfficeInterop.WordTest(); 
    word.Test(); 
} 

static void InfoPath1(object context) { 
    OfficeInterop.InfoPathTest infoPath = new OfficeInterop.InfoPathTest(); 
    infoPath.Test(); 
} 

static void InfoPath2(object context) { 
    OfficeInterop.InfoPathTest infoPath = new OfficeInterop.InfoPathTest(); 
    infoPath.Test(); 
} 

इन्फोपाथटेस्ट और वर्डटेस्ट कक्षाएं (वीबी) एक और परियोजना में हैं।

Public Class InfoPathTest 
    Public Sub Test() 
     Dim ip As Microsoft.Office.Interop.InfoPath.Application 
     ip = CreateObject("InfoPath.Application") 
     System.Threading.Thread.Sleep(5000) 
     ip.Quit(False) 
    End Sub 
End Class 

Public Class WordTest 
    Public Sub Test() 
     Dim app As Microsoft.Office.Interop.Word.Application 
     app = CreateObject("Word.Application") 
     System.Threading.Thread.Sleep(5000) 
     app.Quit(False) 
    End Sub 
End Class 

इंटरॉप कक्षाओं बस स्वचालन वस्तुओं, नींद बनाने और उसके बाद छोड़ दिया (हालांकि पद के मामले में, मैं और अधिक जटिल परीक्षण पूरा कर लिया है)।

कंसोल ऐप चलाते समय, मैं (कार्य प्रबंधक के माध्यम से) समानांतर में बनाए गए दो WINWORD.EXE प्रक्रियाओं को देख सकता हूं, और केवल एक ही INFOPATH.EXE प्रक्रिया बनाई गई है। वास्तव में जब InfoPathTest का पहला उदाहरण ip.Quit कहते हैं, INFOPATH.EXE प्रक्रिया समाप्त हो जाती है। जब InfoPathTest का दूसरा उदाहरण ip.Quit को कॉल करता है, तो DCOM टाइमआउट अपवाद फेंक दिया जाता है - ऐसा प्रतीत होता है कि दो उदाहरण समान अंतर्निहित स्वचालन ऑब्जेक्ट साझा कर रहे थे, और यह ऑब्जेक्ट ip.Quit के पहले कॉल के बाद मौजूद नहीं है।

इस चरण में मेरे विचार केवल एक ही INFOPATH.EXE प्रति उपयोगकर्ता लॉगिन समर्थित है। मैंने दो नई प्रक्रियाओं (एक कंसोल एप्लिकेशन जिसे इन्फोपाथटेस्ट कहा जाता है) शुरू करने के लिए विंडोज सेवा का विस्तार किया, प्रत्येक एक अलग उपयोगकर्ता खाते के तहत चल रहा है। इन नई प्रक्रियाओं में INFOPATH.EXE

यहां यह दिलचस्प है, जहां यह दिलचस्प हो जाता है, यह वास्तव में काम करता है, लेकिन केवल कुछ मशीनों पर, और मैं यह नहीं समझ सकता कि ऐसा क्यों है।

और (AsproLock की मदद से) सेवा कोड:

public partial class InfoPathService : ServiceBase { 
    private Thread _mainThread; 
    private bool isStopping = false; 

    public InfoPathService() { 
     InitializeComponent(); 
    } 

    protected override void OnStart(string[] args) { 
     if (_mainThread == null || _mainThread.IsAlive == false) { 
      _mainThread = new Thread(ProcessController); 
      _mainThread.Start(); 
     } 
    } 

    protected override void OnStop() { 
     isStopping = true; 
    }   

    public void ProcessController() { 
     while (isStopping == false) { 
      try { 

       IntPtr hWinSta = GetProcessWindowStation(); 
       WindowStationSecurity ws = new WindowStationSecurity(hWinSta, System.Security.AccessControl.AccessControlSections.Access); 
       ws.AddAccessRule(new WindowStationAccessRule("user1", WindowStationRights.AllAccess, System.Security.AccessControl.AccessControlType.Allow)); 
       ws.AddAccessRule(new WindowStationAccessRule("user2", WindowStationRights.AllAccess, System.Security.AccessControl.AccessControlType.Allow)); 
       ws.AcceptChanges(); 

       IntPtr hDesk = GetThreadDesktop(GetCurrentThreadId()); 
       DesktopSecurity ds = new DesktopSecurity(hDesk, System.Security.AccessControl.AccessControlSections.Access); 
       ds.AddAccessRule(new DesktopAccessRule("user1", DesktopRights.AllAccess, System.Security.AccessControl.AccessControlType.Allow)); 
       ds.AddAccessRule(new DesktopAccessRule("user2", DesktopRights.AllAccess, System.Security.AccessControl.AccessControlType.Allow)); 
       ds.AcceptChanges(); 

       ThreadPool.QueueUserWorkItem(Process1); 
       ThreadPool.QueueUserWorkItem(Process2); 

      } catch (Exception ex) { 
       System.Diagnostics.Debug.WriteLine(String.Format("{0}: Process Controller Error {1}", System.Threading.Thread.CurrentThread.ManagedThreadId, ex.Message)); 
      } 

      Thread.Sleep(15000); 
     } 
    } 

    private static void Process1(object context) { 

     SecureString pwd2; 

     Process process2 = new Process(); 
     process2.StartInfo.FileName = @"c:\debug\InfoPathTest.exe"; 

     process2.StartInfo.UseShellExecute = false; 
     process2.StartInfo.LoadUserProfile = true; 
     process2.StartInfo.WorkingDirectory = @"C:\debug\"; 
     process2.StartInfo.Domain = "DEV01"; 
     pwd2 = new SecureString(); foreach (char c in "password") { pwd2.AppendChar(c); }; 
     process2.StartInfo.Password = pwd2; 
     process2.StartInfo.UserName = "user1"; 
     process2.Start(); 

     process2.WaitForExit(); 
    } 

    private static void Process2(object context) { 
     SecureString pwd2; 

     Process process2 = new Process(); 
     process2.StartInfo.FileName = @"c:\debug\InfoPathTest.exe"; 
     process2.StartInfo.UseShellExecute = false; 
     process2.StartInfo.LoadUserProfile = true; 
     process2.StartInfo.WorkingDirectory = @"C:\debug\"; 
     process2.StartInfo.Domain = "DEV01"; 
     pwd2 = new SecureString(); foreach (char c in "password") { pwd2.AppendChar(c); }; 
     process2.StartInfo.Password = pwd2; 
     process2.StartInfo.UserName = "user2"; 
     process2.Start(); 

     process2.WaitForExit(); 
    } 

    [DllImport("user32.dll", SetLastError = true)] 
    public static extern IntPtr GetProcessWindowStation(); 

    [DllImport("user32.dll", SetLastError = true)] 
    public static extern IntPtr GetThreadDesktop(int dwThreadId); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    public static extern int GetCurrentThreadId(); 

} 

InfoPathTest.exe प्रक्रिया बस InfoPathTest.Test() विधि ऊपर विस्तृत कहता है।

संक्षेप में, यह काम करता है, लेकिन केवल कुछ मशीनों पर। जब यह विफल हो जाता है, तो दूसरी INFOPATH.EXE प्रक्रिया वास्तव में बनाई जाती है, लेकिन तुरंत 0 के बाहर निकलने के साथ निकलती है। ईवेंट लॉग में कुछ भी नहीं है, न ही कोड में कोई अपवाद है।

मैंने काम करने/गैर-काम करने वाली मशीनों के बीच कोशिश करने और अंतर करने के लिए कई चीजों को देखा है, लेकिन अब मैं अटक गया हूं।

किसी भी पॉइंटर्स की सराहना की, विशेष रूप से यदि आपके पास समानांतर में एकाधिक InfoPath उदाहरणों को स्वचालित करने के तरीके पर अन्य विचार हैं।

उत्तर

1

मुझे लगता है कि यदि आप Outlook के साथ एक ही चीज़ करने की कोशिश करते हैं तो आपको समान व्यवहार मिल जाएगा, जिसका अर्थ है कि माइक्रोसॉफ्ट का मानना ​​है कि कई प्रतियां चलाने का बुरा विचार है।

यदि ऐसा है, तो मुझे दो विकल्प दिखाई देते हैं।

विकल्प एक है कि आपके इन्फोपैथ स्वचालन को एक समय में एक उदाहरण चलाना सिंक्रोनस बनाना है।

विकल्प दो, और मेरे पास नहीं विचार है कि यह भी काम करेगा, यह देखना होगा कि क्या आप InfoPath काम को पूरा करने के लिए वर्चुअल मशीन लॉन्च कर सकते हैं या नहीं।

मुझे उम्मीद है कि यह कम से कम कुछ नई ट्रेनों को स्पार्क कर सकता है हालांकि इससे सफलता मिल जाएगी।

+0

हमारा वर्तमान स्वचालन दृष्टिकोण तुल्यकालिक है, हालांकि प्रदर्शन कारणों से हम समांतर प्रक्रियाओं को अनुमति देने की कोशिश कर रहे हैं। – user1369371

1

मुझे Outlook के साथ एक बहुत ही समान समस्या का सामना करना पड़ा है। आवेदन के केवल एक ही उदाहरण को चलाने के लिए प्रतिबंध प्रति उपयोगकर्ता लागू नहीं होता है, बल्कि प्रति इंटरैक्टिव लॉगिन सत्र पर लागू होता है। आप इसके बारे में Investigating Outlook's Single-Instance Restriction:

आउटलुक यह निर्धारित कर रहा था कि इंटरैक्टिव लॉगिन सत्र में कोई अन्य उदाहरण पहले से चल रहा था या नहीं। [...] आउटलुक के प्रारंभिकरण के दौरान, यह देखने के लिए जांच करता है कि क्लास नाम "mspim_wnd32" नामक "माइक्रोसॉफ्ट आउटलुक" नामक एक विंडो मौजूद है, और यदि ऐसा है, तो यह मानता है कि एक और उदाहरण पहले से चल रहा है।

वहाँ उसके चारों ओर हैकिंग के तरीके हैं - वहाँ Hammer of God साइट (नीचे स्क्रॉल करें) पर एक से अधिक आउटलुक उदाहरणों की शुरूआत के लिए एक उपकरण है - लेकिन वे शायद बाधा उत्पन्न कर रहा Win32 कॉल शामिल होगी।

आपके कोड के लिए केवल कुछ मशीनों पर काम करना है: शायद यह दौड़ की स्थिति के कारण है। यदि दोनों प्रक्रियाएं एक साथ पर्याप्त तेज़ी से शुरू करने में कामयाब होती हैं, तो वे एक दूसरे की खिड़की का पता नहीं लगाएंगे, और मान लें कि वे एकमात्र उदाहरण चल रहे हैं। हालांकि, अगर मशीन धीमी है, तो एक प्रक्रिया दूसरी खिड़की से पहले अपनी खिड़की खुलती है, जिससे दूसरी प्रक्रिया पहली प्रक्रिया की खिड़की का पता लगाने और खुद को बंद कर देती है। पुन: पेश करने के लिए, पहली प्रक्रिया और दूसरी लॉन्च करने के बीच कई सेकंड की देरी शुरू करने का प्रयास करें - इस तरह, केवल पहली प्रक्रिया को सफल होना चाहिए।

+0

एक दौड़ की स्थिति कुछ है जिसे मैंने पहले ही माना है। प्रत्येक प्रक्रिया शुरू करने के बीच कृत्रिम देरी जोड़ना (10 सेकेंड तक की वृद्धि की कोशिश की गई) का कोई असर नहीं पड़ा, मशीनों पर जहां यह काम करता है, यह अभी भी काम करता है, अन्य मशीनों पर, यह अभी भी असफल रहा है। हालांकि जानकारी के लिए धन्यवाद, मैं प्रक्रियाओं को डीबग करने का प्रयास कर सकता हूं (आउटलुक जांच के अनुसार) और देखें कि क्या मैं कुछ भी लेकर आया हूं। – user1369371

संबंधित मुद्दे