2008年12月24日

SetupAPIでcabファイル展開

Win2000Pro以降であればSetupAPIを使って、外部のDLL等を必要せず、cabファイルが展開できる

MSDN SetupIterateCabinet
http://msdn.microsoft.com/en-us/library/aa377404(VS.85).aspx
サンプルもある
http://support.microsoft.com/kb/189085/en-us

ちょっとサンプルわかりにくいので、自前で書くとこんなもんかな。
#include <windows.h>
#include <setupapi.h>
#include <string>

#pragma comment (lib, "setupapi.lib")

using namespace std;

LRESULT WINAPI CabinetCallback( IN PVOID pMyInstallData, 
                                IN UINT Notification, 
                                IN UINT_PTR Param1, 
                                IN UINT_PTR Param2 );

//-------------------------------------------------------------------
//! キャビネットファイルの展開(SetupAPI版)
/*! 
    @param[in] cabinet_fname : キャビネットファイル名
    @param[in] extract_dir   : 展開先ディレクトリ名(末尾'\\'付き)
    @remarks 動作環境は SetupIterateCabinet APIの動作環境に依存する
*/
bool extract_cabinet3( std::string cabinet_fname, std::string extract_dir )
{
    // 参考情報
    // SetupIterateCabinet cabファイル展開サンプル
    //   http://support.microsoft.com/kb/189085/en-us
    // MSDN SetupIterateCabinet
    //   http://msdn.microsoft.com/en-us/library/aa377404(VS.85).aspx
    BOOL r = SetupIterateCabinet(cabinet_fname.c_str(), 
                                 0, 
                                 (PSP_FILE_CALLBACK)CabinetCallback, 
                                 (void *)extract_dir.c_str()         );
    return (r == TRUE);
}

//-----------------------------------------------------------------------------
LRESULT WINAPI CabinetCallback ( IN PVOID pMyInstallData, 
                                 IN UINT Notification, 
                                 IN UINT_PTR Param1, 
                                 IN UINT_PTR /*Param2*/ )
{
    LRESULT lRetVal = NO_ERROR;
    string out_dir = (char *)pMyInstallData;    // ユーザーデータ
                                                // (SetupIterateCabinetの第4パラメータ)

    switch(Notification) {
      case SPFILENOTIFY_FILEINCABINET:
          {
              string full_target_name;
              FILE_IN_CABINET_INFO *pInfo = (FILE_IN_CABINET_INFO *)Param1;
              full_target_name = out_dir + pInfo->NameInCabinet;
              lstrcpyn(pInfo->FullTargetName, 
                       full_target_name.c_str(), 
                       sizeof(pInfo->FullTargetName)/sizeof(pInfo->FullTargetName[0])-1 );
              lRetVal = FILEOP_DOIT;  // Extract the file.
          }
          break;

      case SPFILENOTIFY_FILEEXTRACTED:
          {
#ifdef _DEBUG
              FILEPATHS *pFilePaths = (FILEPATHS *)Param1;
              OutputDebugString( pFilePaths->Target );
#endif
              lRetVal = NO_ERROR;
          }
          break;

      case SPFILENOTIFY_NEEDNEWCABINET: // Unexpected.
          lRetVal = NO_ERROR;
          break;
    }

    return lRetVal;
}
追記:2019/04/28
Param1とParam2の型が間違っていたので修正
(MSのサンプルが間違っている)


posted by sanahi at 02:41| 滋賀 ☀| Comment(0) | TrackBack(0) | Develop | 更新情報をチェックする
この記事へのコメント
コメントを書く
コチラをクリックしてください

この記事へのトラックバック
×

この広告は180日以上新しい記事の投稿がないブログに表示されております。