![]() |
... dll.func("build", ReportFilename); dll.func("SetSource", "reportdata/datacenter.do?pa1=23"); dll.func("calc", ""); dll.func("callfunc", "105\r\n type=htm;filename=" + TempFilename); ...如果您熟悉硕正客户端的开发,看到这段代码肯定不会感到陌生,其函数名、参数形式和浏览器 js 的书写方法几乎一致, 连最外层 "func" 都一样。
HANDLE APIENTRY OpenReportService(LPCTSTR para); void APIENTRY CloseService(HANDLE h); int APIENTRY GetActiveServices(); LPCTSTR APIENTRY func(HANDLE h, LPCTSTR funcname, LPCTSTR para);简单地说,这个接口所要做的就是打开报表服务、调用报表服务、关闭报表服务这几个简单的事情.
public class DllInvoke { //操作系统函数 [DllImport("kernel32.dll")] private extern static IntPtr LoadLibrary(String path); [DllImport("kernel32.dll")] private extern static IntPtr GetProcAddress(IntPtr lib, String funcName); [DllImport("kernel32.dll")] private extern static bool FreeLibrary(IntPtr lib); //4个API的委托声明 private delegate int DllGetActiveServices( ); private delegate IntPtr DllOpenReportService(IntPtr CreatePara); private delegate void DllCloseService(IntPtr h); private delegate IntPtr Dllfunc(IntPtr h, IntPtr funcname, IntPtr para); //构建函数, 参数DLLPath: 为winface.dll的全文件名 public DllInvoke(String DLLPath) { //加载dll m_hService = IntPtr.Zero; m_hLib = LoadLibrary(DLLPath); if(m_hLib == IntPtr.Zero) return; //定位入口函数地址 m_getactiveservices = (DllGetActiveServices)GetInvoke("GetActiveServices", typeof(DllGetActiveServices)); m_openservice = (DllOpenReportService)GetInvoke("OpenReportService", typeof(DllOpenReportService)); m_closeservice = (DllCloseService)GetInvoke("CloseService", typeof(DllCloseService)); m_func = (Dllfunc)GetInvoke("func", typeof(Dllfunc)); if(m_getactiveservices==null || m_openservice==null || m_closeservice==null || m_func==null) { //定位失败 FreeLibrary(m_hLib); m_hLib = IntPtr.Zero; } } ~DllInvoke() { CloseService( ); if(m_hLib != IntPtr.Zero) FreeLibrary(m_hLib); } //DLL句柄 public IntPtr m_hLib; //函数:取得当前活动的服务数量 public int GetActiveServices() { return m_getactiveservices(); } //函数:打开服务 public bool OpenReportService(string CreatePara) { if(m_hService != IntPtr.Zero) return true; //已经打开着 if(m_hLib == IntPtr.Zero) return false; IntPtr h1 = Marshal.StringToHGlobalUni(CreatePara); m_hService = m_openservice(h1); Marshal.FreeHGlobal(h1); return (m_hService == IntPtr.Zero) ? false : true; } //函数:关闭服务 public void CloseService() { if(m_hService != IntPtr.Zero) { m_closeservice(m_hService); m_hService = IntPtr.Zero; } } //函数:调用服务中的方法 public string func(string funcname, string para) { if(m_hService == IntPtr.Zero) return ""; //参数 ==> Unicode串指针地址 IntPtr h1 = Marshal.StringToHGlobalUni(funcname); IntPtr h2 = Marshal.StringToHGlobalUni(para); //调用 IntPtr nRet = m_func(m_hService, h1, h2); //释放参数内存 Marshal.FreeHGlobal(h1); Marshal.FreeHGlobal(h2); return Marshal.PtrToStringUni(nRet); } //private==================== private Delegate GetInvoke(String APIName,Type t) { IntPtr api = GetProcAddress(m_hLib, APIName); return (Delegate)Marshal.GetDelegateForFunctionPointer(api,t); } //入口函数地址 private DllGetActiveServices m_getactiveservices; private DllOpenReportService m_openservice; private DllCloseService m_closeservice; private Dllfunc m_func; //服务句柄 private IntPtr m_hService; };浏览这个类,它在创建时就加载winface.dll了,如果加载失败,其成员变量 m_hLib 为零,报表服务也就不可用。
... DllInvoke dll = new DllInvoke(WinFacePathname); if(dll.m_hLib == IntPtr.Zero) { Response.Write("winface.dll加载失败"); Response.End(); return; } ...并都以该类的4个同名封装函数为准,不再深究 winface.dll 的原始API。
函数 int GetActiveServices( ) | |
用途 | 取得当前进程中活动的服务数量 |
返回值 | 整数, 大于等于零 |
函数 bool OpenReportService(string CreatePara) | |
用途 | 打开报表服务 |
参数 | ";"分隔的 名-值对 串, 例如: LogSize=1000; LogLevel=2; TempDir=c:\\website\\temp;BaseDir=http://localhost/supcan 可用属性及其解释说明如下: TempDir - 临时目录的全名, 非常重要。因为硕正报表服务在运行过程中会产生一些临时缓存文件,而Web服务器对目录的写权限有很严格的控制,为此您必须提供一个匿名访问者都能写的物理目录; BaseDir - 为后继的函数中可能出现的相对URL提供统一的参考路径。在浏览器端的开发中,"相对URL" 通常是相对于页面的,而在后端开发中,这个相对URL的参考点就必须指定,因为报表服务根本不知道当前aspx的实际URL; LogLevel - 日志级别, 为0/1/2, 默认是0, 0表示不需要日志,1表示需要简单的日志, 2需要更详细的日志. 日志文件名为 @Log.txt, 会自动产生于临时目录中; LogSize - 日志文件最大尺寸, 单位为kb. 防止日志文件无限膨胀. |
返回值 | true/false, 失败的原因通常为DLL文件位置不正确 |
函数 string func(string funcname, string para) | |
用途 | 调用报表服务 |
参数 | 和硕正套件常规的用法完全一致,请参考硕正常规的开发文档 |
返回值 | 串, 也和套件的常规的用法一致 |
函数 void CloseService( ) | |
用途 | 关闭报表服务 |
返回值 | 无 |
~DllInvoke() { CloseService( ); if(m_hLib != IntPtr.Zero) FreeLibrary(m_hLib); }但我们发现,这个 CloseService( )不一定会被执行到,可能和非托管有关,最终结果就是应用程序池资源耗尽,导致http请求响应异常,产生大量 httpStatusCode 为 503 的错误,甚至IIS重启都困难. 切记!