知识大全 6)编写资源DLL
Posted 资源
篇首语:出门莫恨无人随,书中车马多如簇。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 6)编写资源DLL相关的知识,希望对你有一定的参考价值。
Windows群集开发:6)编写资源DLL 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
编写资源DLL
开始
可以使用MS Visual C++开发系统或其它C/C++开发工具编写自定义资源DLL 本文中例子使用的是
Microsoft Visual C++ version b 包含Unicode MFC库
MIDL编译器 版本 (该MIDL编译器可在SDK中找到)
活动模板库(ATL)版本 (扩展例子代码和资源类型生成向导产生的代码需要它)
建立编译环境时 请参考平台SDK 特别是 Preparing a Build Environment 和 Developer Notes 章节
在平台SDK的例子中也可找到完整的资源DLL参考实现(参见SMBsmp)
创建新资源类型
要创建新的资源类型 必须写一个资源DLL和一个群集管理器扩展DLL 简单的方法是运行资源类型生成向导来创建资源DLL 该向导将箭竹一个资源DLL框架和/或包含入口点定义 申明 导出的群集管理器扩展DLL
创建资源DLL的完整步骤 请参考SDK文档的 Creating a Custom Resource Type Using the Resource Type AppWizard 和 Customizing a Resource DLL 等章节
生成的资源DLL框架仅包含最基本的故障转移和故障恢复功能 要使用群集环境的全部功能和允许DLL提供资源的特定信息 需要编写自己的代码 注意由向导生成的框架代码中包含TODO 和ADDPARAM:注释以指明哪里需要添加资源的特定信息 像下面所描述的那样 你需要使用资源API完成大部分的自定义功能
自定义资源DLL
如前所述 资源API包含几个入口点函数 这些函数在资源DLL内实现 资源监视器使用这些入口点函数管理DLL提供的资源 另外 资源监视器实现少数几个回调函数 资源DLL使用这些回调函数向群集服务报告状态或为系统管理员记录事件日志
大部分入口点函数是所有资源必需的 两个特别的API入口点函数-Arbitrate和Release-仅在编写仲裁资源时需要 本文不讨论这两个函数 其余的入口点函数在下面列出 本文将讨论它们的细节 Startup Open Online LooksAlive IsAlive Offline Close Terminate ResourceControl ResourceTypeControl
每个由群集软件支持的资源DLL应该遵从下面的指引
在某个例外情况下 对于给定的资源实例 资源DLL是不可重入的 该情况是Terminate入口点函数 Terminate应该在任何时候都能被调用 即使资源DLL中线程处于等待Online或Offline调用完成的阻塞状态
资源DLL对于其它资源ID是可重入的 如果资源DLL拥有超过 个资源ID 就必须为DLL内所有共享的全局数据进行同步
在资源DLL内 一个入口点函数完成操作所花费的时间不应该超过 毫秒 如果一个入口点函数-特别是Online Offline LooksAlive或isAlive-超出了这个限制 就应该派生线程来处理耗时的操作 (注意当前向导会为Online生成线程 未来版本也应该为Offline生成一个线程 )
在资源DLL初始化期间 DLL的入口点函数(系统加载DLL后的标准的DLL入口)以DLL_PROCESS_ATTACH标志被调用 接着资源监视器开始调用资源API入口点函数
Startup例程
当资源DLL被加载后 资源监视器就调用Startup例程 注意仅有Startup入口点函数被导出 所有在资源DLL内实现的其它入口点函数通过Startup返回的函数表来访问
下面是Startup例程的定义 DWORD WINAPI Startup ( LPCWSTR ResourceType DWORD MinVersionSupported DWORD MaxVersionSupported PSET_RESOURCE_STATUS_ROUTINE SetResourceStatus PLOG_EVENT_ROUTINE LogEvent PCLRES_FUNCTION_TABLE * FunctionTable );
ResourceType参数标识被启动的资源的类型
SetResourceStatus和LogEvent是由资源监视器实现的回调函数 (本文后面章节将讨论这些回调函数 )在Online或Offline入口点函数被调用后 如果它们要花费超过 毫秒 资源DLL应该调用SetResourceStatus向群集告知资源状态 资源DLL也应该使用LogEvent报告事件和错误 (SetResourceStatus应该仅由Online或Offline调用 并且仅在Online或Offline返回ERROR_IO_PENDING的情况 更多的信息 请参考Online和Offline的讨论 )
FunctionTable结构包含了资源DLL其余入口点的函数地址
注意 Startup入口点函数资源DLL保存回调函数LogEvent和SetResourceStatus的仅有的地方
Startup返回以下值
如果请求成功 返回ERROR_SUCCESS
如果资源不支持在MinVersionSupported和MaxVersionSupported之间的版本 返回ERROR_REVISION_MISMATCH
如果操作不成功 返回Win ?编程接口的错误值
出于对资源操作的优化 要确保实现的Startup能够在 毫秒内完成
Open例程
一旦Startup成功返回 典型地 资源监视器会为由资源DLL管理的每个资源调用Open入口点函数
Open例程的下定义如下 RESID WINAPI Open ( LPCWSTR ResourceName HKEY ResourceKey RESOURCE_HANDLE ResourceHandle );
ResourceName参数标识指定了被打开的资源(一个资源DLL能够提供给定类型的多个资源) ResourceKey参数是关于资源的特定信息 是私有属性 并且 位于群集数据库中 该键值在Open返回时关闭 因此 如果该资源在其它入口点函数中访问一个键值 DLL应该调用ClusterRegOpenKey或ClusterRegCreateKey ResourceHandle参数在SetResourceStatus和LogEvent回调函数中使用
Open使用群集API打开群集数据库并取得资源参数和私有属性 一个重要的事情是资源DLL应该在Open入口检查资源当前是否脱机(一个资源不能同时在超过一个节点上处于联机状态) 如果资源当前正联机 DLL应该尝试将其脱机 (注意 在这种情况下 online和offline指明了应用程序或服务的状态 而不是给定的群集节点-资源必须是真正脱机并且没有被节点所拥有 )另外 在Open例程中 资源DLL应该为资源创建专属的数据结构
注意 如果资源为仲裁资源 则群集API在Open例程中是不可用的
Open返回以下值
如果操作成功 返回资源标识(RESID)
如果操作不成功 返回NULL 应该调用SetLastError指明发生的错误
如果Open返回错误(返回NULL) 资源将是不可管理的 因此 Open应该仅在相当稀有的情况返回错误(例如 不能为资源分配内存)
出于对资源的优化操作 确保实现的Open将在 毫秒内完成
Online例程
当资源被打开 资源监视器调用Online入口点函数将资源联机
Online例程定义如下 DWORD WINAPI Online ( RESID ResourceId PHANDLE EventHandle );
ResourceId参数被传递给该入口函数 是资源的唯一标识(与Open入口函数返回的值是同一个) 资源DLL能够将EventHandle参数传回给资源监视器以便异步通知资源监视器自身状态 如果EventHandle参数不是能够被信号激发(singal) 的有效句柄 那么资源监视器将周期性的调用资源DLL的LooksAlive入口函数以检查资源状态 如果不想资源被这种方法烦扰 DLL应该在EventHandle参数中返回有效的句柄 通过返回有效的EventHandle 资源DLL可以向资源监视器通知任何状态改变
每个资源类型必须有自己的Online入口函数实现 这种不同实现是必须的 因为不同类型的资源有不同的需要 例如 将磁盘联机与将普通应用程序联机是完全不同的 将磁盘联机涉及到装载磁盘 校验磁盘签名 等等 而将应用程序联机只需简单的调用CreateProcess
Online返回以下值
如果操作成功并且资源现在联机 返回ERROR_SUCCESS
如果资源被某些其它系统独占 并且这些其它系统之一拥有独占权 返回ERROR_RESOURCE_NOT_AVAILABLE
如果请求正处于等待状态 并且一个线程已经被激活以处理该请求 则返回ERROR_IO_PENDING
如果操作不成功 Online返回Win 错误值
出于对资源操作的优化 确保Online例程的实现能够在 毫秒完成处理 如果做不到 应该在派生一个将资源联机的工作线程后立即返回ERROR_IO_PENDING给资源监视器 SetResourceStatus回调函数(该函数地址保存在Startup入口函数中)应该被周期性的调用 以指示资源状态 一旦资源联机 工作线程应该被跟中止或挂起以留待未来使用
如果出于任何原因资源在联机时失败了 资源DLL应该使用LogEvent回调函数记录事件日志 并且应该调用SetResourceStatus函数 SetResourceStatus使用RESOURCE_STATUS结构来指示资源的联机或脱机状态 群集资源可以是下述状态之一
联机—状态代码ClusterResourceOnline
脱机—状态代码ClusterResourceOffline
失败—状态代码ClusterResourceFailed
等待联机—状态代码ClusterResourceOnlinePending
等待脱机—状态代码ClusterResourceOfflinePending
SDK 关于SetResourceStatus的更多信息 请参考平台SDK
如果 在 分钟后 资源仍没有联机 资源监视器将调用Terminate入口函数放弃操作 如果一个资源需要花费超过 分钟才能联机 使用群集API的群集管理器 Cluster exe 或者其它管理工具可以使用ClusterResourceControl通过控制代码CLUSCTL_RESOUCE_SET_M_PROPERTIES修改PendingTimeout公用属性 (更多关于群集控制代码 公用属性 私有属性等的信息 请参考平台SDK文档
LooksAlive和IsAlive例程
一旦资源联机 资源监视器将周期性检查资源状态 资源监视器使用LooksAlive和IsAlive入口函数来完成这个操作 资源监视器使用LooksAlive进行临时检查 IsAlive则做通透的检查
LooksAlive例程定义如下 BOOL WINAPI LooksAlive ( RESID ResourceId );
IsAlive例程定义如下 BOOL WINAPI IsAlive ( RESID ResourceId );
在这两个例程中 ResourceId参数唯一标识了被检查的资源实例 典型情况下 LooksAlive用于进行简单检查(例如检测进程是否仍在运行 文件共享是否仍存在 等等) 并且资源管理器可以经常性的调用LooksAlive 如果不想资源DLL被其打断 可以在Online例程中返回有效EventHandle(如前面所述) 然后使用这个句柄向资源监视器通知资源状态
IsAlive入口函数对资源状态进行更详细的计算 并且由资源监视器进行(不能被阻止) 资源DLL应该对资源做一个彻底的检查看看它是否工作正常 例如 数据库资源应该检查数据库是否能够写入到磁盘 执行查询和更新到磁盘 等等
LooksAlive返回以下值
如果资源可能联机并可用 返回TRUE
如果资源不能正常工作 LooksAlive返回FALSE
IsAlive返回以下值
如果资源联机并且工作正常 返回TRUE
如果资源不能正常工作 返回FALSE
出于优化目的 IsAlive入口函数应该在 毫秒完成 如前所述 应该创建一个分离的工作线程来完成对资源的检查工作 该工作线程其后将状态进行投递以便于IsAlive能够获取并返回给资源管理器
注意LooksAlive在任何情况下不能超出 毫秒 大多数情况下 应该不超过 毫秒 IsAlive稍长一些 不过即使它是个异步调用 资源监视器在同一线程中管理的其它资源入口函数将等待直接IsAlive返回 派生线程并不能改善这种状况 因此 IsAlive也应该在不超过 毫秒的时间内完成
Offline例程
入口函数的讨论到目前为止都是关于从核心开始定制一个表现良好的资源DLL 下面入口函数为资源提供收尾和卸载机制 第一个是Offline函数
Offline函数定义如下 DWORD WINAPI Offline ( RESID ResourceId );
ResourceId参数唯一标识了资源 在使资源脱机时 资源监视器调用这个入口函数 一旦脱机 对于群集客户端该资源就不再可用
Offline返回以下值
如果成功的完成了资源脱机请求 返回ERROR_SUCCESS
如果请求仍在等待并且一个线程已激活以处理脱机请求 则返回ERROR_IO_PENDING
如果由于其它原因 操作无法完成 应该返回Win 错误代码
资源DLL应该在 毫秒内优雅的关闭资源并从该入口返回 如果Offline例程的实现超出了这个限制 应该返回ERROR_IO_PENDING 并派生一个线程来完成脱机请求 该线程应该使用SetResourceStatus回调持续的向资源监视器更新资源状态 直到资源状态为ClusterResourceOffline
如果资源没有在PendingTimeout时间内优雅的关闭或Offline函数返回Win 错误代码 资源监视器将调用Terminate入口函数来强制终止资源
Close例程
Close入口函数用于关闭资源 并且对于一个资源 只能调用一次 应该使用Close翻译由Open Offline ResourceControl或ResourceTypeControl入口函数分配的结构 如果要关闭的资源仍没有脱机 调用Terminate强制使之脱机
Close例程定义如下 VOID WINAPI Close ( RESID ResourceId );
ResourcdId参数是被关闭资源的唯一标识
Close没有返回值
资源DLL应该在 毫秒内关闭资源 不过 如果超出了这个限制 群集服务将以正当的方式处理
例程
Terminate入口函数立即终止一个在调用Offline时没有优雅关闭的进程
Terminate例程定义如下 VOID WINAPI Terminate ( RESID ResourceId );
ResourceId是被强制脱机的资源的唯一标识 如果资源DLL有线程正等待资源脱机或优雅的将资源脱机 将放弃线程的脱机操作 并强制使资源脱机
Terminate没有返回值
ResourceControl和ResourceTypeControl例程
ResourceControl和ResourceTypeControl入口函数是可选的 但是 微软建议实现这两个函数以支持群集资源控制代码 管理工具 如群集管理器和Cluster Exe 以及群集可感知应用程序使用ClusterResourceControl和ClusterResourceTypeControl函数与资源进行独占的信息通信 例如 这些可用于设置属性(公用和私有的) 请求操作 等等 当管理器或群集可感知应用程序调用任一ClusterResourceXXXXControl函数 资源管理器将分别调用ResourceControl或ResourceTypeControl 将正确的控制代码传入 实现了这两个例程的资源DLL将根据控制代码执行控制请求或设置资源属性 对于没有处理的控制代码 资源DLL应该向资源监视器返回正确的状态(ERROR_INVALID_FUNCTION状态) 在这种情况下 如果有默认的处理动作 资源监视器将执行之
ResourceControl例程定义如下 DWORD WINAPI ResourceControl ( RESID ResourceId DWORD ControlCode LPVOID InBuffer DWORD InBufferSize LPVOID OutBuffer DWORD OutBufferSize LPDWORD BytesReturned );
ResourceId参数是受影响资源的标识 ControlCode代表要执行的操作的控制代码 该参数的有效值列表 请参见平台SDK的 Control Codes for Resources 章节
InBuffer是该操作用到的传入数据的缓冲区指针 InBufferSize是它的大小 以字节为单位 OutBuffer是操作返回数据的缓冲区指针 OutBufferSize是它的大小 以字节为单位 注意如果操作不需要数据或不返回数据 InBuffer和OutBuffer可以为NULL
BytesReturned是OutBuffer中实际数据的字节数
ResourceControl返回以下值
如果ControlCode指定的操作成功完成 返回ERROR_SUCCESS(不过实际返回有赖于控制代码)
如果资源DLL不支持ControlCode指示的操作 或者请求必须由资源监视器来处理 则返回ERROR_INVALID_FUNCTION
如果操作不成功 返回Win 错误代码
ResourceTypeControl例程定义如下 DWORD WINAPI ResourceTypeControl ( LPCWSTR ResourceTypeName DWORD ControlCode LPVOID InBuffer DWORD InBufferSize LPVOID OutBuffer DWORD OutBufferSize LPDWORD BytesReturned );
ResourceTypeName是操作所影响的资源类型的标识 ControlCode为要执行的操作的控制代码 关于ControlCode参数有效值列表 请参考平台SDK的 Control Codes for Resources
InBuffer是该操作用到的传入数据的缓冲区指针 InBufferSize是它的大小 以字节为单位 OutBuffer是操作返回数据的缓冲区指针 OutBufferSize是它的大小 以字节为单位 注意如果操作不需要数据或不返回数据 InBuffer和OutBuffer可以为NULL
BytesReturned是在OutBuffer缓冲区中返回的结果数据的实际尺寸
ResourceTypeControl返回以下值
如果由ControlCode指示的操作成功完成 ResourceTypeControl返回ERROR_SUCCESS(虽然实际的返回值有赖于控制代码)
如果资源DLL不支持ControlCode指定的操作 或者该请求必须由资源监视器来处理 则返回ERROR_INVALID_FUNCTION
cha138/Article/program/net/201311/13753相关参考
怎样在MFC中调用C#编写的DLL 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 一使用/clr
知识大全 如何在Delphi中调用.Net编写的DLL中的函数
如何在Delphi中调用.Net编写的DLL中的函数 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
1984年,固始县渔业区划编写组根据多年的渔业经济管理经验和积累编制了《固始县渔业区划》,记录了该县各种水生生物资源的概况如下:1)浮游植物各水域常见的浮游植物共6门34属。其中绿藻门居首,共计有16
1984年,固始县渔业区划编写组根据多年的渔业经济管理经验和积累编制了《固始县渔业区划》,记录了该县各种水生生物资源的概况如下:1)浮游植物各水域常见的浮游植物共6门34属。其中绿藻门居首,共计有16
Eclipse工具开发:编写代码生成器[6] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!&nbs
知识大全 我是一名C语言初学者,请各位大虾帮帮忙,用C语言编写一个程序,求1+2+3+4+5+6·····+100
我是一名C语言初学者,请各位大虾帮帮忙,用C语言编写一个程序,求1+2+3+4+5+6·····+100 以下文字资料是由(本站网www.cha138.com)小编为大
dll文件有什么方法可以查看源代码?有几个dll文件别人给的,想看看里面代码是具体怎么写的?大神啊!DLL变成高级语言的过程叫反编译(不是反汇编...两者区别很大)....C/C++DLL别想了...
Dll中导出类--Delphi实战[1] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 从Dll
怎么检视dll函式vs20101.开启命令列视窗CMD2.执行vcvarsall.batVS2010里vcvarsall.bat是在右键VS开启档案位置,D:\\MicrosoftVisualStud
Dotnet动态加载和卸载dll 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 案例在Dotne