使用Windows本机库扩展用于ESSO AccessProfile的IBM Security Access Manager

在本文中,了解有关在企业级单点登录(ISAM ESSO)8.2 AccessProfile的IBM Security Access Manager中开发和嵌入Windows本机库的信息。 根据样本库逐步完成组件对象模型(COM)组件注册的步骤。 开发和部署ISAM ESSO产品解决方案的业务合作伙伴和顾问可能会发现本文特别有用。

您可以下载本文中使用的代码示例。

ISAM ESSO访问配置文件

ISAM ESSO为包括Windows本机GUI和控制台可执行文件在内的各种应用程序提供了单点登录(SSO)支持。 ISAM ESSO的主要目标是响应对用户凭据(用户名/密码)的请求。

响应流在AccessProfile中定义,类似于流程图。 ISAM ESSO AccessProfile是结构成XML文件的一组指令,该文件定义了应用程序的自动SSO或签核机制。 每个AccessProfile包含一组定义和状态。 每个状态代表一种特定情况,其中状态机等待某些事件发生并触发触发器。 状态机模型表示一系列步骤,例如登录/注销,进入/退出应用程序,更改密码等。

图1显示了ISAM ESSO AccessProfile的示例。 第一个椭圆形(开始状态)激活触发器以激活主窗口。 主窗口激活触发器以在大型机中搜索文本,然后该文本进入等待用户输入的状态。

图1. ISAM ESSO AccessProfile
ISAM ESSO访问配置文件

AccessProfile由ISAM ESSO观察者模块解释。 Observer模块是Windows库,使用Windows钩子机制注入到各种应用程序集中,然后再咨询适当的AccessProfile来执行必要的登录/注销操作。 Observer代理还侦听并捕获操作系统级别的Windows消息,从而充当应用程序和OS之间的中间层。

例如,当应用程序创建对话框窗口时,操作系统会向该对话框过程发送一条消息。 观察者代理拦截该消息,并在为此应用程序分配的AccessProfile中查找对话框标题。 如果找到匹配项,则专用的AccessProfile通过Observer代理根据分配的状态机控制其余应用程序流。

AccessProfile是在AccessStudio(ISAM ESSO组件套件中的工具之一)中创建和维护的。 AccessStudio要求将AccessAgent安装在同一台计算机上。 尽管AccessStudio允许您控制许多OS消息和属性,但有时仍需要更高级的功能。 一些客户可能需要利用现有的ISAM ESSO功能,而不是使用标准配置文件组件和方法提供的功能。 当为Windows命令行和IBM Personal Communications编写基于控制台的应用程序概要文件时,可能会出现这种要求。

根据设计,ISAM ESSO不会公开任何配置机制来监视Windows剪贴板缓冲区接口和消息。 当用户在控制台窗口中注入一些文本时,AccessProfile没有标准方法来拦截此操作。 为什么这很重要? 许多用户习惯于从另一个来源(例如文本文档)复制/粘贴凭据。 在这种情况下,通过设计,ISAM ESSO在支持基于控制台的应用程序时将无法正确捕获那些凭据。

先决条件

要跟随本文中的示例,您需要准备以下环境。 (基本安装和配置步骤不在本文讨论范围之内。)在Windows系统上,安装和配置:

  • 版本8.1或更高版本的Tivoli Access Manager Enterprise单点登录(TAM E-SSO)AccessAgent
  • 版本8.1或更高版本的Tivoli Access Manager Enterprise单点登录(TAM E-SSO)AccessStudio
  • Microsoft Visual Studio 2010(可选,用于重写PCOMMHelper库)

在禁用用户帐户控制的Windows XP和Windows 7上测试了示例实现。 如果启用了“用户帐户控制”,则在初始COM组件注册过程中可能会出现一些问题,因为此过程需要将预定义的条目写入Windows注册表。 COM组件的注册方法与Regsvr32 Windows命令的注册方法相同,并且需要相同的管理权限。

样例代码

您可以下载本文中使用的样本文件,以使用IBM Personal Communications进行捕获粘贴文本缓冲区(例如用户凭证)的真实测试。 testPcomm.eas文件包含AccessProfile,可以将其上载到IMS服务器中。 也可以在AccessStudio测试模式下使用。 示例AccessProfile已经在VBScript示例代码中嵌入了PCOMMHelper库,因此不需要进行初始更改。

超越标准的ISAM ESSO分析技术

如前所述,有时标准配置机制需要其他技巧。 ISAM ESSO缺乏直接的方法来监视和捕获Windows剪贴板缓冲区中的用户凭据。 尽管用户通常使用击键输入凭据,但是您希望同时支持两种输入凭据技术。 使用Windows本机库将是克服编写ISAM ESSO AccessProfiles时遇到的问题的一种技巧。 (本文后面将介绍用于IBM Personal Communications(PCOMM)应用程序的AccessProfile解决方案。)

要解决的第一个问题是:如何使用Windows库而不使用单独的传递方法来扩展现有的AccessProfile? 请记住,ISAM ESSO的主要优势之一是在一组用户和IMS服务器(用户身份,AccessProfile和身份验证策略的集中数据库)之间的配置文件平滑无缝地同步,而无需用户事先干预。 如果一组用户往往很大,那么单独交付此类库文件可能会变得困难且耗时。 作为另一种方法,请考虑将库文件直接嵌入到配置文件中。 显而易见的容器似乎是VBScript代码。

增强标准配置技术的一种方法是使用VBScript或JavaScript代码,这些代码执行AccessProfile内部工作流操作的一部分所需的自定义操作。 这样的脚本可以直接调用Windows操作系统来执行规定的任务。

对于示例情况,您想使用VBScript代码扩展:

  • 作为库文件的静态容器
  • 将库文件解码并解压缩到Windows文件系统中
  • 要将解压缩的库注册为COM接口
  • 要将库文件加载到预期的过程对象空间中

图2显示了VBScript的示例,准备在激活PCOMM Window之后立即执行。

图2. VBScript
该屏幕在“脚本编辑器”窗口的“语言”字段中显示VBScript。

库文件部分已分配给本Native变量。 当然,您不能直接在VBScript代码中包含二进制文件,这就是为什么需要使用某些编码技术的原因。 在这种情况下,二进制文件使用十六进制表示法编码为字节字符串。 该解决方案使您可以将输出自由地存储在任何ASCII文本文件中。 清单1使用PCOMMHelper.cab.hex文件作为临时存储,必须将其复制到AccessProfile VBScript代码中。 清单1中的外部VBScript代码还使用MakeCab命令将库文件最初压缩为cabinet(.cab)文件。

清单1.外部VBScript代码
Const ForReading = 1, ForWriting = 2, adTypeBinary = 1
Dim bin, bBytes

Set bin = CreateObject("ADODB.Stream")
Set fso = CreateObject("Scripting.FileSystemObject")
Set objShell = CreateObject("WScript.Shell")

If  (fso.FileExists ("PCOMMHelper.dll")) Then 
	Set objExec = objShell.Exec ("MakeCab PCOMMHelper.dll PCOMMHelper.cab")
else
	Wscript.Quit(0)
end if

Do While objExec.Status = 0
	WScript.Sleep 250
Loop 

Set OutFile = fso.OpenTextFile("PCOMMHelper.cab.hex", ForWriting, true)
bin.Type = adTypeBinary
bin.Open
bin.LoadFromFile "PCOMMHelper.cab"
size = bin.Size
Binary = bin.Read()

ReDim byteArray(LenB(Binary))
For i = 1 To LenB(Binary)
	znak = AscB(MidB(Binary, i, 1))
	if (znak < 16) Then 
		OutFile.Write "0"
	End If
	OutFile.Write hex(znak)
Next
	
For x = 1 To size 
	OutFile.Write byteArray(x)
Next
OutFile.Close

Windows数据压缩技术用于在真正的编码过程开始之前节省一些空间-您希望尽可能有效地使用AccessProfile存储。

清单2中的相反过程只是将这个十六进制字符串(本native变量)读取到数组中,并作为压缩的库文件写回到文件系统中。

清单2.逆向过程
Sub WriteBinary(FileName)
On Error Resume Next
        Dim Buf()
        Dim I, aBuf, Size, bStream
        ReDim Buf(Len (native)/2)

        For I = 0 To Len(native)-1 Step 2
                Buf(I\2) = Clng("&h"&Mid(native, I+1, 2))
        Next

        Size = UBound(Buf): ReDim aBuf(Size)
        For I = 0 To Size-1 Step 2
                aBuf(I \ 2) = ChrW(Buf(I + 1) * 256 + Buf(I))
        Next
        If I = Size Then aBuf(I \ 2) = ChrW(Buf(I))
        aBuf = Join(aBuf, "")
        
        Set bStream = CreateObject("ADODB.Stream")
        bStream.Type = 1
        bStream.Open
        With CreateObject("ADODB.Stream")
                .Type = 2 : .Open: .WriteText aBuf
                .Position = 2: .CopyTo bStream: .Close
        End With
        bStream.SaveToFile FileName, 2
        bStream.Close
        Set bStream = Nothing
End Sub

在这两个脚本中,都使用ADODB.Stream对象在二进制数据流和文本流之间进行无缝转换。

现在是时候使用Expand命令解压缩cabinet(.cab)文件了,如清单3所示。

清单3. Cabinet文件解压缩
Function ExpandDll()
tempPath = objShell.ExpandEnvironmentStrings("%USERPROFILE%") & "\"
statusFail = 0
fCabName = "PCOMMHelper.dll.cab"
fDLLName = "PCOMMHelper.dll"
 Do While (True)
	WriteBinary (tempPath&fCabName)
	If  (fso.FileExists (tempPath&fCabName)) Then 
		Set objExec = objShell.Exec ("EXPAND " & """" & tempPath&fCabName 
           & """" & " " & """" & tempPath&fDLLName & """")
	else
		statusFail=1
		Exit Do
	end if

	Do While objExec.Status = 0
		runtime.Sleep(250)
	Loop 

	If  (fso.FileExists (tempPath&fDLLName) =0 ) Then
		pc.SetPropValue "PCOMMHelper Error: ", "EXPAND failed"
		statusFail=1
	end if
 Loop
End Function

库文件的目标目录是由%USERPROFILE%环境变量定义的用户的主目录。 使用该目录可确保不会出现“拒绝访问”问题。

此时,您可以得出以下结论:Windows库文件已就位,可以注册为COM接口。 您可能想知道为什么需要使用这种复杂的本机代码调用方法。 有没有更简单的方法来做这些事情? 问题是:AccessProfile无法直接调用Windows库。 这样做的唯一方法是通过VBScript代码,并且按照设计,大多数这些脚本语言都不允许您将本机库加载到流程对象空间中。 现在的最初目标是在应用程序本身中嵌入并执行一些代码。

COM组件

在本部分中,您将在操作系统中注册Windows库(以模仿真实的COM组件的行为),以便可以使用CreateObject函数从AccessProfile VBScript代码直接调用它。

基本上,在调用CreateObject时,Windows将查找注册表以查找应如何实例化该对象。 然后,它尝试加载相应的库并从中创建对象。 此注册表查找过程完成了两次。 首先,给定一些标识符,在HKEY CLASSES ROOT条目下进行检查(在此示例中,该标识符为PCOMMHelper)。 如果找到了这样的标识符,则将拾取相应的CLSID值并将其用于第二次检查-这次是在HKEY CLASSES ROOT \ CLSID项下。

如果第二个检查也匹配,则InprocServer32子项默认值用于掌握Windows库已安装的完整路径。 通过考虑实际的生产代码COM组件注册过程,可以大大简化此过程,该过程应满足示例的基本要求。 下一步是将PCOMMHelper标识符绑定到库文件。

首先,检查COM组件是否已经注册,如清单4所示。

清单4. COM组件
Function testDLL()
On Error Resume Next
	gPimsCurVer = ReadRegistry("HKCR\" & fDLLObject & "\CurVer\")
	gPimsCLSID  = ReadRegistry("HKCR\" & fDLLObject & "\CLSID\")
	dllLocation = ReadRegistry("HKCR\CLSID\" & gPimsCLSID & "\InprocServer32\")

	If Left (gPimsCurVer, Len ("Invalid")) = "Invalid"  Or Left (gPimsCurVer, 
       Len ("Unable")) = "Unable" Or Left (gPimsCLSID, Len ("Invalid")) = "Invalid" Or 
    Left (gPimsCLSID, Len ("Unable")) = "Unable" Or Left (dllLocation, 
       Len ("Invalid")) = "Invalid" Or Left (dllLocation, Len ("Unable")) = "Unable" Then
		WriteCOMToRegistry
	End If

 	Err.Clear
	Set PCOMMHelperAgain = CreateObject("PCOMMHelper")
       If Err = -2147221231 Or Err = 0 Then
            pc.SetPropValue "PCOMMHelper ", "Enabled"
	else
            pc.SetPropValue "PCOMMHelper ", "Disabled"
	End If
End Function

清单4模仿了COM组件查找过程的步骤。 如果其中任何一个未通过注册,则需要完成该过程。 如果满足注册条件,则可以再次使用CreateObject函数来检查是否可以加载PCOMMHelper.dll库。 (清单4中检查的确切错误值-2147221231与COM组件的不完全初始化有关。示例中的目标是仅将库加载到进程对象空间中,而不使用COM接口。)

清单5显示了COM组件注册过程。

清单5. COM组件注册过程
Function WriteCOMToRegistry ()
   tempPath 	= objShell.ExpandEnvironmentStrings("%USERPROFILE%") & "\"
   fDLLName 	= "PCOMMHelper.dll"
   fDLLObject 	= "PCOMMHelper"

   For i=1 To Len (TypeLib.Guid)
	Char = mid (TypeLib.Guid , i, 1)
	if Char <> "}" Then
		CLSID = CLSID & Char
	else
		CLSID = CLSID & "}"
		Exit For
	End If
   Next
   
   ret = WriteRegistry ("HKEY_CLASSES_ROOT\" & fDLLObject & "\" , "PCOMMHelper Class", 
      "REG_SZ")
   ret = WriteRegistry ("HKEY_CLASSES_ROOT\" & fDLLObject & "\CurVer\", fDLLObject & 
      ".1", "REG_SZ")
   ret = WriteRegistry ("HKEY_CLASSES_ROOT\" & fDLLObject & "\CLSID\", CLSID, "REG_SZ")
   ret = WriteRegistry ("HKEY_CLASSES_ROOT\CLSID\" & CLSID & "\" , "PCOMMHelper Class", 
      "REG_SZ")
   ret = WriteRegistry ("HKEY_CLASSES_ROOT\CLSID\" & CLSID & "\InprocServer32\" , 
      tempPath & fDLLName, "REG_SZ")
   ret = WriteRegistry ("HKEY_CLASSES_ROOT\CLSID\" & CLSID & 
      "\InprocServer32\ThreadingModel" , "Apartment", "REG_SZ")
   ret = WriteRegistry ("HKEY_CLASSES_ROOT\CLSID\" & CLSID & "\ProgID\" , fDLLObject & 
      ".1" , "REG_SZ")
   ret = WriteRegistry ("HKEY_CLASSES_ROOT\CLSID\" & CLSID & "\Programmable\" , "" , 
      "REG_SZ")
   ret = WriteRegistry ("HKEY_CLASSES_ROOT\CLSID\" & CLSID & "\VersionIndependentProgID\" 
      , fDLLObject , "REG_SZ")
End Function

WriteCOMToRegistry函数的前半部分生成新的唯一CLSID值(以十六进制表示的全局唯一类标识符,括在一对花括号中)。 CLSID是一个16字节(128位)的数组,其中填充有唯一的一系列字节。 从理论上讲,再次生成时,它永远不能具有相同的字节序列。 在COM世界中, CLSID值(也称为GUID )用于唯一地区分不同的软件组件接口。

乍一看,此过程可能没有多大意义。 您可能想知道为什么不一次生成CLSID并在脚本中预先分配它。 这不是编写COM组件时的典型过程吗? 简单的答案是:它在脚本中,用于测试和疑难解答。 您可以根据自己的目标随意更换这部分。

此处还要注意的是,通常,每个COM对象都必须具有QueryInterface函数,在该函数中检查预分配的CLSID值。 在该示例中,Windows库满足了非常基本的条件,足以将其加载到流程对象空间中-绝对不满足成熟的COM组件要求。

如前所述,概念验证的一个目标是有效使​​用AccessProfile存储。 在此,保持库的初始大小尽可能小至关重要(使用COM接口开发会偏离目的)。 就COM组件实现而言,示例库仅包含两个函数:

  • DllGetClassObject
  • DllCanUnloadNow

WriteCOMToRegistry函数的WriteCOMToRegistry用于模仿Regsvr32 Windows命令(用于注册或注销COM组件)功能,并覆盖上面概述的查找过程的步骤。 Regsvr32工具的作用不大。 它加载在命令行参数中传递的库文件,然后在该库中调用一些COM注册函数。 从那时起,将由COM组件实现自行注册。 以最简单的形式,此注册过程仅在HKEY CLASSES ROOT条目下添加适当的注册表项。

如果您有兴趣进一步调查,建议您使用Process Monitor工具(请参阅参考资料 )。 它使您可以准确查看在COM注册过程中Regsvr32 Windows命令使用了哪些Windows注册表项。

IBM Personal Communications的AccessProfile方案

PCOMMHelper库的主要目的是从Windows剪贴板缓冲区捕获用户凭据,并将其提供给标准ISAM ESSO AccessProfile触发器。 以下方案模拟了IBM Personal Communications(PCOMM)应用程序的AccessProfile。 (对于Windows命令行,使用情况完全相同)。

  • 用户运行该应用程序,然后等待命令输入出现在屏幕上。
  • 在Edit下拉菜单上,用户选择Paste ,如图3所示,然后按CTRL / Enter键进行确认。
图3.将Windows剪贴板缓冲区与IBM Personal Communications一起使用
一个PCOMM窗口,其中显示“编辑”下拉菜单,并突出显示“粘贴”选项。

图4显示了该用例的AccessProfile方案。

图4. AccessProfile
屏幕上显示帐户数据袋ID,添加类型字段,并填写帐户数据项模板ID。

选择CTRL / Enter键后,概要文件应该能够捕获粘贴到命令输入中的内容。 不幸的是,用于监视键盘输入的标准触发器将无法捕获粘贴到屏幕中的任何文本,除非通过模拟击键以某种方式再次注入了该文本。 这正是PCOMMHelper库所做的。

实施PCOMMHelper

在本节中,我们尝试描述执行CreateObject ("PCOMMHelper")时的序列流。 请记住,PCOMMHelper库包含一个COM组件的非常基本的实现,因此不会有OS调用标准的COM初始化方法。 注册表查找过程从用户的主目录中提取PCOMMHelper.dll库并将其加载到PCOMM过程对象空间后,将DllMain入口点函数DllMain 。 这是处理Windows本机库的标准WINAPI过程(系统使用DLL_PROCESS_ATTACH值作为调用原因来调用DllMain函数)。

清单6显示了PCOMMHelper库中的DllMain代码段。

清单6. DllMain代码片段
BOOL WINAPI DllMain(HINSTANCE instance, DWORD fdwReason, LPVOID lpvReserved)
{
    switch (fdwReason)
    {
    case DLL_PROCESS_ATTACH:
        {
            DisableThreadLibraryCalls(instance);
            EnumWindows ((WNDENUMPROC)EnumWindowsProc, GetCurrentProcessId());
            if (PCOMMhwnd)
                lpfnOldLoginWndProc = (WNDPROC) SetWindowLong ((HWND)PCOMMhwnd, 
                GWL_WNDPROC, (LONG)LoginWndProc);
            break;
        }
    case DLL_PROCESS_DETACH:
        {
            if (lpfnOldLoginWndProc)
                SetWindowLong ((HWND)PCOMMhwnd, GWL_WNDPROC, (LONG)lpfnOldLoginWndProc);
        }
    }
    return(TRUE);
}

第一步是获取PCOMM进程窗口句柄。 您需要枚举屏幕上所有可见的窗口,寻找创建该窗口的进程的标识符。 该进程标识符将与您从以下位置调用的PCOMMHelper库的标识符进行比较:pcsws.exe(IBM Personal Communications-PCOMM)。 如果这有点朦胧,请记住您是从由概要文件执行的VBScript代码调用CreateObject ("PCOMMHelper")的,该概要文件是由最初由ISAM ESSO引擎注入到过程对象空间的ISAM ESSO Observer模块解释的。

图5显示了属于PCOMM应用程序的所有控件(使用Winspector捕获)。

图5.控件
一个PCOMM窗口,其控件在左侧列出。

大多数情况下,会有一个以上的窗口(控件)属于PCOMM进程,因此您需要查找由PCSWS:Main:00400000PCSWS:Main:00400000的父窗口。

清单7显示了PCOMMHelper库中的EnumWindowsProc片段。

清单7. EnumWindowsProc
BOOL CALLBACK EnumWindowsProc (HWND hwnd, LPARAM ProcID)
{
    DWORD      dwID=0 ;
    HWND        testHwnd=NULL;
    char             wBuffer[256]={0};

    GetWindowThreadProcessId(hwnd, &dwID) ;
    if(dwID == ProcID)
    {
        if (GetWindowLong(hwnd, GWL_HWNDPARENT) == 0)
        {
            if(GetClassName (hwnd, wBuffer, sizeof (wBuffer))>0)
            {
                if (_stricmp(wBuffer, "PCSWS:Main:00400000")==0)
                    PCOMMhwnd = hwnd;
            }
        }
    }
    return TRUE ;
}

现在,您已经获得了窗口句柄,是时候执行主要任务了:使用SetWindowLong函数将PCOMM进程主窗口的实例子类化。 您将劫持该特定应用程序窗口的控件,从而可以监视和评估在该进程和OS之间传递的所有内部消息。 乍一看,这似乎很危险,但这实际上正是ISAM ESSO Observer模块的工作-侦听和捕获OS级Windows消息。 就本示例而言,您将只是“扩展” Observer模块功能。

尽管您可以对发送到该窗口的每条消息做出React,但是您只关心WM_COMMAND消息,当用户从菜单中选择一个项目时发送该消息。 对于PCOMM应用程序,此菜单项(粘贴)的ID以十六进制表示的值为0x414。 在这种使用情况下,假定用户确实从下拉菜单中选择“ 粘贴”命令。 为了确保一切顺利,请为此关键部分创建一个单独的线程( SendWindowText ),并将控制权交还给监视过程。

监视过程的最后一部分负责将消息传递回原始PCOMM进程(使用CallWindowProc函数),从而确保几乎不引起您的干扰。

清单8显示了PCOMMHelper库中的LoginWndProc片段。

清单8. LoginWndProc
LRESULT CALLBACK LoginWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    WORD        wID = 0;
    HANDLE    hThread = NULL; 
    DWORD     dwThread; 

    switch (message)
    {
    case WM_COMMAND:
        wID = LOWORD(wParam);	
        if (0x414 == wID)
        {
            hThread = CreateThread(NULL, NULL,(LPTHREAD_START_ROUTINE) SendWindowText,
hwnd, NULL, &dwThread);
            CloseHandle (hThread);
        }
    }	

    if (lpfnOldLoginWndProc)
        return CallWindowProc (lpfnOldLoginWndProc, hwnd, message, wParam, lParam) ;
}

现在是最后一个关键步骤的时候了:模拟击键,以便监视键盘输入的标准触发器能够捕获用户刚刚粘贴的内容。 基本上,整个剪贴板文本缓冲区都是使用SendMessage函数调用一次发送到PCOMM进程窗口的。 总而言之,该示例拦截了在用户下拉菜单选择时发送的WM_COMMAND消息,并在稍加修改后又发送了另一条实质上模拟用户按键的消息。

清单9所示的代码片段SendWindowText从PCOMMHelper库。

清单9. SendWindowText
void SendWindowText (HWND hwnd)
{
    char *buffer                  = NULL;
    HANDLE hData            = NULL;
    BOOL ClipboardOpened = FALSE;

    ClipboardOpened = OpenClipboard(hwnd);
    if (ClipboardOpened)
    {
        hData = GetClipboardData(CF_TEXT);
        if (hData)
            buffer = (char*)GlobalLock( hData );
    }

    if (buffer && strlen(buffer)<128)
    {
        int i = 0;
        for (i=0; i<strlen(buffer); i++)
        {
            if (isprint_ (buffer[i]))
                 SendMessage (hwnd, WM_CHAR, buffer[i], 1L);
        }
    }else
        MessageBox (NULL, "No support for Clipboard buffer bigger than 128 characters", 
           "PCOMMHelper", NULL);

    if (hData)
        GlobalUnlock(hData);
    if (ClipboardOpened)
        CloseClipboard();
}

生成PCOMMHelper.dll

本节介绍了一些使PCOMMHelper.dll库的大小最小化的技术,以便以最有效的方式使用AccessProfile存储。 压缩COM组件实现是有效的,但是仍然需要从平均库文件中消除很多空间。

该示例实现了4KB的大小,大约有1KB的空白空间,可以通过MakeCab Windows命令轻松压缩。 从理论上讲,可以通过合并文件的某些部分(例如代码和数据)来切断1KB的空间,但是这样的过程存在风险,操作系统可能会拒绝该库。 (通常,大多数可执行文件和库文件都有多个部分,每个部分在512字节边界上对齐。)

表1显示了在编译和链接阶段使用的设置。

设置 笔记
禁用运行时类型信息 这将禁用检查和存储有关对象数据类型的信息。
不产生清单 您不想让Visual Studio将XML清单资源嵌入到库文件中。 清单资源是一种XML文件,描述了可执行文件的属性。 尽管在Windows 7上处理用户帐户控制时可能很有用,但您不能为此浪费宝贵的空间。
不要使用Unicode字符集 只需使用所有Windows功能的ANSI版本。
不生成调试信息 不言自明。

结论

ISAM ESSO提供了本机技术来支持广泛的应用程序。 对于大多数应用程序而言,标准配置文件组件和方法绰绰有余。 但是,当您需要将范围扩展到当前限制之外时,使用Windows本机库可能会帮助解决问题。 本文中的示例解决方案在一个内部IBM项目上进行了测试。


翻译自: https://www.ibm.com/developerworks/security/library/se-extendesso/index.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值