मैं विंडोज़ सेवा के माध्यम से 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 उदाहरणों को स्वचालित करने के तरीके पर अन्य विचार हैं।
हमारा वर्तमान स्वचालन दृष्टिकोण तुल्यकालिक है, हालांकि प्रदर्शन कारणों से हम समांतर प्रक्रियाओं को अनुमति देने की कोशिश कर रहे हैं। – user1369371