65.9K
CodeProject 正在变化。 阅读更多。
Home

从 C++/CLI MSSQL 存储过程直接访问 C++ 原生代码

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.61/5 (11投票s)

2013年10月28日

CPOL

3分钟阅读

viewsIcon

31252

downloadIcon

518

在存储过程中读取硬件信息。

一些 MS SQL 开发者希望保护他们的独特产品,并希望将自制代码链接到独特的硬件参数。最好的方法是读取 HDD 序列号和型号数据,以及可选的网络 MAC 地址。

我找到的唯一能够获取此类信息的代码来自最受欢迎的源代码,即 Sysinternals 的代码以及一些用于读取 Windows 序列号的 C++/CLI 变体。

当前项目代表 C++/CLI 存储过程,这是提供从存储过程访问原生 C++ 代码的最佳解决方案。

创建 C++/CLI 过程

要创建 C++/CLI 过程,开发人员必须遵循以下流程:

添加新项目 -> Visual C++ -> CLR -> 类库。最简洁的工作代码如下:

public ref class StoredProcedures
{
  [SqlFunction(DataAccess = DataAccessKind::Read)]
    static SqlString MyFunction( SqlString buffer )
  {
    return buffer;
  }
  [SqlProcedure]
    static void GetHelloWorld()
  {
    SqlPipe^ spPipe = Microsoft::SqlServer::Server::SqlContext::Pipe;
    spPipe->Send( L"Hello World" );
  }
 } 

目前没有必要制作 x86 版本,我的示例仅支持 x64 WinNT 平台,但添加 x86 平台也不难。在编译实际程序集之前,请确保在项目属性中设置了以下选项:

  • 通用语言运行时支持:纯 MSIL 通用语言运行时支持 (/clr:pure);
  • C/C++ -> 预处理器定义 -> Win64
  • 链接器 -> 目标计算机 -> /MACHINE:X64;

现在是棘手的部分 - Microsoft 没有提供设置 .NET 平台版本的选项。我找到的唯一方法是:将项目文件打开为 XML 文档,然后更改为要支持的平台。如果您使用原生 C++ 代码,则 2.0 版本绰绰有余,您需要安装 VS2008。(但您可以使用任何工具集(它会为最终程序集添加更多无用的 Microsoft 代码)。

<TargetFrameworkVersion>v2.0</TargetFrameworkVersion> 

从此刻起,一切都已准备好构建一个用于 MS SQL Server 的程序集。

  • 选择配置为“发布”,平台为“x64”,然后构建项目。
  • 将程序集 [ClrDiskId.dll] 复制到 SQL Server 的 BINN 文件夹(必须是 64 位实例!)。在我的情况下,MSSQL2008R 的默认实例路径是:[c:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\Binn]
  • 注册程序集。

注册程序集

在此之前,您必须让 MSSQL 服务器准备好使用 UNSAFE 程序集。

CREATE DATABASE myTestDb
GO
USE master
GO
EXEC sp_configure 'show advanced options', 1
RECONFIGURE
EXEC sp_configure 'clr enabled', 1
RECONFIGURE
GO
USE myTestDb
GO
ALTER DATABASE myTestDb SET TRUSTWORTHY ON
GO 

现在我们可以注册我们的程序集了。

CREATE ASSEMBLY CLIESP from 'c:\Program Files\Microsoft SQL 
   Server\MSSQL10_50.MSSQLSERVER\MSSQL\Binn\ClrDiskId.dll' WITH PERMISSION_SET = UNSAFE;

将所需的存储过程注册为 CLR 存储过程。

CREATE PROCEDURE dbo.GetHelloWorld
    WITH EXECUTE AS CALLER AS EXTERNAL NAME CLIESP.StoredProcedures.GetHelloWorld;
GO 

最后运行。

EXEC dbo.GetHelloWorld 

现在我们知道了如何使用 C++/CLI 存储过程,就可以添加 C++ 代码并直接从我们的存储过程中调用它了。

让我们做一些更复杂的事情,首先从显示我们计算机上的当前硬盘开始。我使用代码从 WinSim 读取硬盘制造信息。这段代码在我看来不太安全,我添加了单元测试,并使代码在如此关键的应用程序(如 MS SQL Server)中更加安全——没有人想让服务器崩溃。

附加的解决方案包含 3 个项目:

  • EspDiskId - 扩展存储过程 xp_DiskId 显示硬盘列表(MS 建议停止使用它)
  • ClrDiskId - CLR 存储过程 GetDiskID 显示硬盘列表
  • mainDiskIdTest - 几个单元测试,以确保原始 C++ 代码大致安全。

执行后

EXEC dbo.GetDiskID

我在我的电脑上得到了以下结果:

ID 模型 串口 供应商 大小 [Gb] UUID
0 HDS723020BLA642 MN1220F32AJ4PD Hitachi 1863 -5791026690894825696
1 WD3000HLHX-01JJPV0 WD-WXW1E31HHMV5 WD 279 4862279922329562629 

最终代码包含几个有用的函数:

  • GetWinSerial - 显示 Windows 序列号 { select dbo.GetWinSerial() as Serial }
  • crc64 - 计算 crc64 { select dbo.crc64( 'Time it takes time' ) }
  • GetNetworkMAC - 显示已安装的网络适配器列表 {select dbo.GetComputerId() as ComputerUUID }
  • GetComputerId - 计算计算机的唯一标识符。
© . All rights reserved.