MS Access数据库用于在服务器上进行处理。当前的过程是人们使用RDP登录服务器,然后在MDB文件中运行宏。这些宏有时需要几天才能执行。
开发了一个Web应用程序,它在MDB文件中运行代码。当MS Access显示“禁用宏”这样的对话框时,您信任此文件吗? (由于服务器更新)或任何未正确处理的错误,进程不会退出,而是等待MS Access完成。
由于IIS,此MS Access进程在会话0中运行,无法向用户显示。我想要做的是能够让用户连接RDP会话,请参阅MS Access应用程序并调试VBA代码。
理想情况下,我会创建一个新的用户会话并在其中运行MDB应用程序,但这似乎是不可能的;由于安全风险,Microsoft已禁用此功能。
处理这种情况的最佳方法是什么?
欢迎任何使MS Access应用程序出现在RDP会话中的解决方案。
我目前的想法是这样的:(但我很想听听更方便的解决方案)
我通过使用托管自身的Windows窗体应用程序解决了这个问题,以便可以从Web服务调用它,与Interop Access库一起启动MS Access和TestStack.White库来监视MS Access正在执行的操作。最终结果是用户可以从Web应用程序启动远程计算机上的MS Access。然后,当它正常运行时,生成的消息将返回到Web客户端。如果出现问题,用户将收到一条消息,表明他们必须通过RDP会话登录才能查看/调试MS Access。如果Forms应用程序未运行(它位于用户的Startup文件夹中),则会显示一条消息,说明必须启动RDP会话才能在远程计算机上执行MS Access文件。错误也会记录在Forms应用程序中,因此用户可以记录先前运行期间计算机上发生的情况。
免责声明:这段代码绝不是完整的,它是我认为重要的代码片段的一般化摘录。 (整套应用程序是巨大的)应该可以将它们融合在一起,使它们可行。如果有要求,我会提出一个完整的解决方案并发布。我想给别人可能正在寻找类似的东西开始。
使用TCP的服务主机:
var host = new ServiceHost(typeof(MyService),
new Uri("net.tcp://localhost:9001"));
host.AddServiceEndpoint(typeof(IMyService),
new NetTcpBinding(), "MyService");
host.Open();
然后在服务中我在新线程中实例化MS Access:
Thread t = new Thread(() => { result = RunMdb(pathToMdbFile, "MyFunction", true); });
t.Start();
实例化MS Access的功能:
private string RunMdb(string path, string functionToRun, bool visible)
{
string result;
try
{
Directory.SetCurrentDirectory(newDir);
// get the MS Access process, we need it later
var before = Process.GetProcessesByName("MSACCESS");
MsAccessApp = new Microsoft.Office.Interop.Access.Application { Visible = visible };
var after = Process.GetProcessesByName("MSACCESS");
var process = after.Single(p => !before.Select(p1 => p1.Id).Contains(p.Id));
MsAccessProc = process;
MsAccessApp.OpenCurrentDatabase(newDbPath, false);
result = MsAccessApp.Run(functionToRun);
}
catch (Exception e)
{
result = $"MS Access Error: {e.Message}";
log.Log("MS Access Error:", e);
}
finally
{
if (IsFunctionRunning)
{
try
{
MsAccessApp.CloseCurrentDatabase();
}
catch
{
// ignored
}
try
{
MsAccessApp.Quit(Microsoft.Office.Interop.Access.AcQuitOption.acQuitSaveNone);
}
catch
{
// ignored
}
}
}
MsAccessApp = null;
MsAccessProc = null;
IsFunctionRunning = false;
return result;
}
然后在主线程中我开始使用TestStack.White轮询MS Access:
result = TrackMsAccessPopups(log, result);
private string TrackMsAccessPopups(ILogger log, string result)
{
while (IsFunctionRunning)
{
Thread.Sleep(1000);
if (MsAccessProc != null)
{
if (WhiteApplication == null)
{
WhiteApplication = TestStack.White.Application.Attach(MsAccessProc);
}
log.Log(LogLevel.Info, "GetWindows.");
WhiteWindows = WhiteApplication.GetWindows();
log.Log(LogLevel.Info, "GetWindows done.");
if (WhiteWindows.Count > (MsAccessApp.Visible ? 1 : 0))
{
IsFunctionRunning= false;
log.Log(LogLevel.Error, "MS Access has created a popup.");
result = $"MS Access has created a popup. Log in on {Environment.MachineName} to view the message.";
}
}
}
WhiteApplication = null;
return result;
}
生成的字符串通过服务回调返回给Web应用程序。