SQLCLR 似乎没有启动 Windows 应用程序

SQLCLR does not appear to start Windows Application

我正在尝试使用 SQLCLR 从 SQL 服务器启动一个 Windows 程序。调用的程序没有报错,但是程序好像没有启动。

知道我做错了什么吗?

这是我的程序的 .NET 代码:

using System;
using Microsoft.SqlServer.Server;
using System.Diagnostics;

namespace MyUtility
{
    public class StoredProcedures
    {
        [Microsoft.SqlServer.Server.SqlProcedure]
        public static void MyUtilityExecute()
        {
            string result;

            try
            {
                Process myProcess = new Process();
                myProcess.StartInfo.FileName = "C:\Windows\System32\notepad.exe";
                myProcess.StartInfo.UseShellExecute = false;
                myProcess.StartInfo.CreateNoWindow = false;
                myProcess.Start();

                result = "Success! Time = "
                        + DateTime.Now.ToString("dddd, dd MMMM yyyy HH:mm:ss");
                SqlContext.Pipe.Send(result);
            }
            catch
            {
                result = "There was an error!";
                SqlContext.Pipe.Send(result);
            }
        }
    }
}

这是我的 T-SQL 代码,用于创建程序集和包装器对象:

USE [MyDatabase]
GO

CREATE ASSEMBLY MyUtility
AUTHORIZATION [dbo]
FROM 'C:\MyPath\MyUtility\bin\Debug\MyUtility.dll'
WITH PERMISSION_SET = UNSAFE
GO

CREATE PROCEDURE usp_MyUtilityExecute
AS EXTERNAL NAME 
    MyUtility.[MyUtility.StoredProcedures].MyUtilityExecute
GO

EXECUTE usp_MyUtilityExecute;

您是否检查了任务管理器、进程资源管理器或任何其他查看本地进程的方式以确定程序是否真正启动?我敢打赌它做到了。问题是 SQL 服务器是一个完全独立于您的 (Windows) 用户会话的后台进程,并且无法访问您的桌面(即使 SQL 服务器是 运行在您登录的同一台计算机上,通常它实际上是 运行 在另一台计算机上,您只是向其发送请求,就像网站是远程的一样)。如果您使用 SQL Server Express LocalDB,您会看到 GUI 应用程序或 window 的唯一方法,因为这是一个在您的会话中作为后台运行的用户模式进程进程,并且它确实可以访问您的桌面。所以,记事本应该是运行,你就是看不到而已。如果你继续执行这个存储过程,你可能每次都会产生一个新的、单独的 notepad 进程。你可能想杀死那些 ;-).

如果您想测试 SQL 服务器是否真的可以生成基于 OS 的进程/应用程序,只需在 C:\temp 中创建一个简单的 .cmd 脚本执行以下操作:

ECHO %TIME% >> C:\TEMP\_SQLCLR_test.txt

然后将第一个 StartInfo 行更改为:

myProcess.StartInfo.FileName = @"C:\TEMP\_SQLCLR_test.cmd";

也许还有:

myProcess.StartInfo.CreateNoWindow = true;

这将测试整体概念而不需要 UI 交互(假设登录帐户 运行 SQL 服务器进程有权访问和写入/修改 C:\TEMP 目录).

!!重要提示!!

Process 是一次性对象,因此需要在 using() 构造中创建,或者您需要实现 try / finally 来管理它不管发生什么,都调用 Dispose()。在您当前的设置中,如果有异常,您将拥有一个孤立的外部资源,它将保留在内存/文件系统句柄/等上,直到垃圾被收集,并且不确定何时会发生,因为我不相信 SQL 服务器经常调用它。