gpt4 book ai didi

c# - 多个 InfoPath 互操作自动化实例

转载 作者:太空狗 更新时间:2023-10-29 20:37:17 25 4
gpt4 key购买 nike

我正在尝试通过 Windows 服务自动执行 Office InfoPath 2010 的多个并行实例。我了解不支持通过服务自动化 Office,但这是我的客户的要求。

我可以以并行方式自动执行其他 Office 应用程序,但 InfoPath 的行为不同。

我发现,无论对 CreateObject("InfoPath.Application") 进行多少次并行调用,都只会创建一个 INFOPATH.EXE 进程实例。与此相反,可以通过类似的机制 CreateObject("Word.Application")

创建 WINWORD.EXE 的多个实例

要重现此问题,可以使用一个简单的控制台应用程序。

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

InfoPathTest 和 WordTest 类 (VB) 在另一个项目中。

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

互操作类只是创建自动化对象,休眠然后退出(尽管在 Word 的情况下,我已经完成了更复杂的测试)。

运行控制台应用程序时,我可以看到(通过任务管理器)并行创建了两个 WINWORD.EXE 进程,并且只创建了一个 INFOPATH.EXE 进程。事实上,当 InfoPathTest 的第一个实例调用 ip.Quit 时,INFOPATH.EXE 进程终止。当 InfoPathTest 的第二个实例调用 ip.Quit 时,将引发 DCOM 超时异常 - 看起来好像这两个实例共享相同的基础自动化对象,并且该对象在第一次调用 ip.Quit 后不再存在。

在这个阶段,我的想法是每个用户登录只支持一个 INFOPATH.EXE。我扩展了 Windows 服务以启动两个新进程(一个名为 InfoPathTest 的控制台应用程序),每个进程都在不同的用户帐户下运行。然后,这些新进程将尝试自动执行 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 实例有其他想法。

最佳答案

我猜如果您尝试对 Outlook 做同样的事情,您会得到类似的行为,这意味着 Microsoft 认为运行多个副本不是一个好主意。

如果是这样,我看到两个选项。

选项一是使您的 Infopath 自动化同步,一次运行一个实例。

选项二,我没有想知道它是否可行,就是看看您是否可以启动虚拟机来完成您的 InfoPath 工作。

我希望这至少可以激发一些新的思路,从而走向成功。

关于c# - 多个 InfoPath 互操作自动化实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10423375/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com