您现在的位置:首页 >> API >> API >> 内容

Delphi版OCX制作CAB

时间:2011/9/3 15:45:14 点击:

  核心提示:unit UnitMakeCAB;interface uses ActiveX , SysUtils , Classes , Windows;//.inf文件模板const Templete = ';...

unit UnitMakeCAB;

interface
  uses
      ActiveX
    , SysUtils
    , Classes
    , Windows;

//.inf文件模板
const
  Templete =
    '; %Title%'#13#10+
    '; File Name %DLLName%  File Version= %DllVersion%'#13#10+
    '; ProgId= %ProgId% ClassId= %DLLClsid%'#13#10#13#10+
    '[version]'#13#10+
    'signature="$CHICAGO$"'#13#10+
    'AdvancedINF=2.0'#13#10#13#10+
    '[Add.Code]'#13#10+
    '%DLLName%=%DLLName%'#13#10#13#10+
    '[%DLLName%]'#13#10+
    'file-win32-x86=thiscab'#13#10+
    'RegisterServer=yes'#13#10+
    'clsid=%DLLClsid%'#13#10+
    'DestDir='#13#10+
    'FileVersion=%DLLVersion%'#13#10#13#10+
    '[Setup Hooks]'#13#10+
    'AddToRegHook=AddToRegHook'#13#10#13#10+
    '[AddToRegHook]'#13#10+
    'InfSection=DefaultInstall'#13#10#13#10+
    '[DefaultInstall]'#13#10+
    'AddReg=AddToRegistry'#13#10#13#10+
    '[AddToRegistry]'#13#10+
    'HKLM,"SOFTWAREClassesCLSID%DLLClsid%Implemented Categories{7DD95801-9882-11CF-9FA9-00AA006C42C4}"'#13#10+
    'HKLM,"SOFTWAREClassesCLSID%DLLClsid%Implemented Categories{7DD95802-9882-11CF-9FA9-00AA006C42C4}"';

//MackCab 用的中间文件模板,文件附加在后面,不能带路径(估计可以支持8.3短路径)
  MakeCabDirective =
    '.OPTION EXPLICIT     ; Generate errors'#13#10+
    '.Set CabinetNameTemplate=%CABFile%'#13#10+
    '.set DiskDirectoryTemplate=CDROM ; All cabinets go in a single  directory'#13#10+
    '.Set CompressionType=MSZIP;** All files are compressed in cabinet files'#13#10+
    '.Set UniqueFiles="OFF"'#13#10+
    '.Set Cabinet=on'#13#10+
    '.Set DiskDirectory1=%CABFilePath%'#13#10;

//取得CoClass的ClassID
function GetCLSID(FileName: String): WideString;
//取得ProgID
function GetProgID(FileName: String): String;
//制作用于发布的CAB包
procedure MakeCAB(FileName: String);

implementation

//取得CoClass的ClassID
function GetCLSID(FileName: String): WideString;
var
  spTypeLib: ITypeLib;
  spTypeInfo: ITypeInfo;
  pta: PTypeAttr;
  hr: HRESULT;
  Count, I: UINT;

begin
  Result := '{00000000-0000-0000-0000-000000000000}';
  hr := LoadTypeLib(PWideChar(WideString(FileName)),spTypeLib);
  if Failed(hr) then Exit;
  Count := spTypeLib.GetTypeInfoCount;
  I := 0;
  while I < Count do begin
    hr := spTypeLib.GetTypeInfo(I, spTypeInfo);
    if Failed(hr) then Exit;
    hr := spTypeInfo.GetTypeAttr(pta);
    if Failed(hr) then Exit;
    if TKIND_COCLASS = pta.typekind then begin
      StringFromGUID2(pta.guid, PWideChar(Result), Length(Result)* sizeof(WideChar));
      spTypeInfo.ReleaseTypeAttr(pta);
      pta := Nil;
      Exit;
    end;
    spTypeInfo.ReleaseTypeAttr(pta);
    pta := Nil;
    Inc(I);
  end;
end;

//取得ProgID
function GetProgID(FileName: String): String;
var
  spTypeLib: ITypeLib;
  spTypeInfo: ITypeInfo;
  pta: PTypeAttr;
  hr: HRESULT;
  Count, I: UINT;
  bstrName0, bstrName: WideString;
begin
  Result := '';
  hr := LoadTypeLib(PWideChar(WideString(FileName)),spTypeLib);
  if Failed(hr) then Exit;
  Count := spTypeLib.GetTypeInfoCount;
  hr := spTypeLib.GetDocumentation(   -1
                                    , @bstrName0
                                    , Nil
                                    , 0
                                    , Nil
                                    );
  if Failed(hr) then Exit;
  I := 0;
  while I < Count do begin
    hr := spTypeLib.GetTypeInfo(I, spTypeInfo);
    if Failed(hr) then Exit;
    hr := spTypeInfo.GetDocumentation(  -1
                                      , @bstrName
                                      , Nil
                                      , 0
                                      , Nil
                                      );
    if Failed(hr) then Exit;
    hr := spTypeInfo.GetTypeAttr(pta);
    if Failed(hr) then Exit;
    if TKIND_COCLASS = pta.typekind then begin
      Result := WideString(bstrName0) + '.' + WideString(bstrName);
      spTypeInfo.ReleaseTypeAttr(pta);
      pta := Nil;
      Exit;
    end;
    spTypeInfo.ReleaseTypeAttr(pta);
    pta := Nil;
    Inc(I);
  end;
end;

//取得文件版本
function GetVersion(FileName: String): String;
var
    dwHandle: DWORD ;
    m_szVersion: array[0..255] of char;
    dwVerSize: DWORD;
    pbBuffer: PChar;
    lpVSInfo: PVSFixedFileInfo;
    uiVerSize: UINT;
begin
  Result := '0,0,0,0';
  uiVerSize := 0;
  dwVerSize  := GetFileVersionInfoSize(PChar(FileName), &dwHandle);
  lpVSInfo := Nil;
  pbBuffer := AllocMem( dwVerSize);
    if (pbBuffer = Nil) then Exit;
    if (GetFileVersionInfo(PChar(FileName), 0, dwVerSize, pbBuffer)) then begin
        if (VerQueryValue(pbBuffer, '', Pointer(lpVSInfo), uiVerSize)) then begin
            Result := Format( '%d,%d,%d,%d',
                                    [ (lpVSInfo^.dwFileVersionMS shr 16) and $FFFF,
                                      lpVSInfo^.dwFileVersionMS and $FFFF,
                                      (lpVSInfo^.dwFileVersionLS shr 16) and $FFFF,
                                      lpVSInfo^.dwFileVersionLS and $FFFF
                        ]
                                  );
    end;
  end;

    FreeMem(pbBuffer);
end;

//制作用于发布的CAB包
procedure MakeCAB(FileName: String);
var
  CABFileName, DDFFileName, InfFileName: String;
  F: TFileStream;
  P: PChar;
  iLen, iWrote: Integer;

  Title, DLLName, ProgID, ClsID, FileVer: String;

  CABDirective, Inffile: String;

  _hfile: HFILE;
    mCreationTime, mLastAccessTime, mLastWriteTime: FILETIME;

    StartInfo: STARTUPINFO ; // name structure
    ProcInfo: PROCESS_INFORMATION ; // name structure
begin
  CoInitialize(Nil);
  try
    FileVer := GetVersion(FileName);
    ClsID := GetCLSID(FileName);
    DLLName := ExtractFileName(FileName);
    ProgID := GetProgID(FileName);
    Title := 'Ocx Inf file Maker';
    InfFileName := ChangeFileExt(FileName, '.inf');
    CabFileName := ChangeFileExt(FileName, '.cab');
    DDFFileName := ChangeFileExt(FileName, '.ddf');

    CABDirective :=    StringReplace(    MakeCabDirective,
                                    '%CABFile%',
                                    ExtractFileName(CabFileName),
                                    [rfReplaceAll, rfIgnoreCase]
                                    );
    CABDirective :=    StringReplace(    CABDirective,
                                    '%CABFilePath%',
                                    ExtractFilePath(CabFileName),
                                    [rfReplaceAll, rfIgnoreCase]
                                    )
                    + '"' + FileName + '"'
                    +    #13#10'"' + InfFileName + '"';

    //如果还有其它附加文件需要打包请在这里增加一个CallBack
    //直接按每文件一行往上附加

    InfFile := StringReplace(  Templete,
                              '%Title%',
                              Title,
                              [rfReplaceAll, rfIgnoreCase]
                              );
    InfFile := StringReplace(    InfFile,
                              '%DLLName%',
                              DLLName,
                              [rfReplaceAll, rfIgnoreCase]
                              );
    InfFile := StringReplace(    InfFile,
                              '%DllVersion%',
                              FileVer,
                              [rfReplaceAll, rfIgnoreCase]
                              );
    InfFile := StringReplace(    InfFile,
                              '%ProgId%',
                              ProgID,
                              [rfReplaceAll, rfIgnoreCase]
                              );
    InfFile := StringReplace(    InfFile,
                              '%DLLClsid%',
                              ClsID,
                              [rfReplaceAll, rfIgnoreCase]
                              );

    //写入INF文件
    f := TFileStream.Create(InfFileName,fmCreate);
    try
      p := PChar(InfFile);
      iLen := Length(InfFile);
      while (iLen > 0) do begin
        iWrote := f.Write(p^, iLen);
        Inc(p, iWrote);
        Dec(iLen, iWrote);
      end;
    finally
      f.Free;
    end;

    //如果还有其它附加文件请在这里增加一个CallBack
    //文件通常有两类:1.需要注册的;2.不需要注册的.
    //另外就是文件可能安装目录有两种:1.当前目录(即随机目录);2.特定目录(可以使用环境变量)
    //写Inf文件请按照.Ini格式,比如TIniFile类或者API来操作等


    //更新.INF的文件时间为.OCX的时间
    _hFile := _lopen(PChar(FileName), OF_READWRITE);
    GetFileTime(  THANDLE(_hFile),
                  @mCreationTime,
                  @mLastAccessTime,
                  @mLastWriteTime
                  );
    _lclose(_hFile);

    _hFile := _lopen(PChar(InfFile), OF_READWRITE);
    SetFileTime(    THANDLE(_hFile),
                  @mCreationTime,
                  @mLastAccessTime,
                  @mLastWriteTime
                  );
    _lclose(_hFile);

    //写入DDF文件,供工具程序MakeCab.exe使用
    f := TFileStream.Create(DDFFileName,fmCreate);
    try
      p := PChar(CABDirective);
      iLen := Length(CABDirective);
      while (iLen > 0) do begin
        iWrote := f.Write(p^, iLen);
        Inc(p, iWrote);
        Dec(iLen, iWrote);
      end;
    finally
      f.Free;
    end;

    //执行MakeCAB创建CAB包

    fillchar(ProcInfo, sizeof(ProcInfo), 0); // Set up memory block
    fillchar(StartInfo, sizeof(StartInfo), 0); // Set up memory block
    StartInfo.cb := sizeof(StartInfo); // Set structure size
    if Not CreateProcess( Nil,
                          PChar('makecab /f "' + DDFFileName + '"'),
                          Nil,
                          Nil,
                          False,
                          0,
                          Nil,
                          PChar(ExtractFilePath(FileName)),
                          StartInfo,
                          ProcInfo) then
      Exit;

    WaitForSingleObject(ProcInfo.hProcess, INFINITE);
    CloseHandle(ProcInfo.hThread);
    CloseHandle(ProcInfo.hProcess);

    //更新CAB的文件时间为.OCX的时间
    _hFile := _lopen(PChar(FileName), OF_READWRITE);
    GetFileTime(  THANDLE(_hFile),
                  @mCreationTime,
                  @mLastAccessTime,
                  @mLastWriteTime
                  );
    _lclose(_hFile);

    _hFile := _lopen(PChar(CabFileName), OF_READWRITE);
    SetFileTime(    THANDLE(_hFile),
                  @mCreationTime,
                  @mLastAccessTime,
                  @mLastWriteTime
                  );
    _lclose(_hFile);
  finally
    CoUninitialize;
  end;

end;
end.

 

示例代码

uses
    UnitMakeCAB;
procedure TForm3.Button1Click(Sender: TObject);
var
  FileName: String;
begin
  if OpenDialog1.Execute then begin
    FileName := OpenDialog1.FileName;
    if SameText(ExtractFileExt(FileName), '.ocx') then begin
      MakeCAB(FileName);
    end;
  end;
end;

Tags:制作 
作者:unsigned 来源:转载
共有评论 0相关评论
发表我的评论
  • 大名:
  • 内容:
本类推荐
  • 没有
本类固顶
  • 没有
  • 盒子文章(www.2ccc.com) © 2024 版权所有 All Rights Reserved.
  • 沪ICP备05001939号