Класс для использования библиотеки UNRAR.DLL

<!--StartFragment -->

Класс для использования библиотеки UNRAR.DLL

Часто в программах перед использованием каких-либо данных требуется разархивация файлов. Ставший уже почти стандартом RAR предлагает для этих целей библиотеку UNRAR.DLL.

Данный класс использует динамическую загрузку библиотеки, что позволяет программам выполнять основную часть своей работы без ее наличия.

Пример использования:

Unrar m_Unrar;
m_Unrar.Extract("c:\\arch\\*.rar", "c:\\arch\\out", "pass");

Вместе с исходниками поставляется текстовый файл UNRARDLL.TXT, который содержит описания всех структур и функций библиотеки. Скачать >> (rar-архив, 7k)

Наиболее свежую версию UNRAR.DLL можно скачать с Web-сайта WinRAR (раздел Extras).

Примечание. Использование кода, поставляемого разработчиками WinRAR-а вместе с библиотекой является довольно проблематичным в связи с периодическим изменением формата архивных файлов. Что приведет не к простой замене DLL-ки у пользователей, а Вашего программного кода.

А теперь сам класс:

//-------------------- Unrar.h ----------------------------------------------

#ifndef UNRAR_H
#define UNRAR_H

class Unrar
{
private:

    // структуры и описания функций поставляются вместе с UNRAR.DLL
    struct RAROpenArchiveData
    {
      char         *ArcName;
      unsigned int OpenMode;
      unsigned int OpenResult;
      char         *CmtBuf;
      unsigned int CmtBufSize;
      unsigned int CmtSize;
      unsigned int CmtState;
    };

    struct RARHeaderData
    {
      char         ArcName[260];
      char         FileName[260];
      unsigned int Flags;
      unsigned int PackSize;
      unsigned int UnpSize;
      unsigned int HostOS;
      unsigned int FileCRC;
      unsigned int FileTime;
      unsigned int UnpVer;
      unsigned int Method;
      unsigned int FileAttr;
      char         *CmtBuf;
      unsigned int CmtBufSize;
      unsigned int CmtSize;
      unsigned int CmtState;
    };

    struct RARHeaderDataEx
    {
      char         ArcName[1024];
      wchar_t      ArcNameW[1024];
      char         FileName[1024];
      wchar_t      FileNameW[1024];
      unsigned int Flags;
      unsigned int PackSize;
      unsigned int PackSizeHigh;
      unsigned int UnpSize;
      unsigned int UnpSizeHigh;
      unsigned int HostOS;
      unsigned int FileCRC;
      unsigned int FileTime;
      unsigned int UnpVer;
      unsigned int Method;
      unsigned int FileAttr;
      char         *CmtBuf;
      unsigned int CmtBufSize;
      unsigned int CmtSize;
      unsigned int CmtState;
      unsigned int Reserved[1024];
    };

    struct RAROpenArchiveDataEx
    {
      char         *ArcName;
      wchar_t      *ArcNameW;
      unsigned int OpenMode;
      unsigned int OpenResult;
      char         *CmtBuf;
      unsigned int CmtBufSize;
      unsigned int CmtSize;
      unsigned int CmtState;
      unsigned int Flags;
      unsigned int Reserved[32];
    };

    typedef HANDLE (PASCAL *RAROPENARCHIVE)(
        struct RAROpenArchiveData *ArchiveData
        );
    typedef HANDLE (PASCAL *RAROPENARCHIVEEX)(
        struct RAROpenArchiveDataEx *ArchiveData
        );
    typedef int (PASCAL *RARCLOSEARCHIVE)(
        HANDLE hArcData
        );
    typedef int (PASCAL *RARREADHEADER)(
        HANDLE hArcData,
        struct RARHeaderData *HeaderData
        );
    typedef int (PASCAL *RARREADHEADEREX)(
        HANDLE hArcData,
        struct RARHeaderDataEx *HeaderData
        );
    typedef int (PASCAL *RARPROCESSFILE)(
        HANDLE hArcData,
        int Operation,
        char *DestPath,
        char *DestName
        );
    typedef int (PASCAL *RARPROCESSFILEW)(
        HANDLE hArcData,
        int Operation,
        wchar_t *DestPath,
        wchar_t *DestName
        );

    // сообщения в CALLBACK - функции
    enum UNRARCALLBACK_MESSAGES {
            UCM_CHANGEVOLUME,
            UCM_PROCESSDATA,
            UCM_NEEDPASSWORD   // требуется пароль
        };
    typedef int (CALLBACK *UNRARCALLBACK)(
        UINT msg, LONG UserData, LONG P1, LONG P2
        );
    typedef void (PASCAL *RARSETCALLBACK)(
        HANDLE hArcData,
        UNRARCALLBACK Callback,
        LONG UserData
        );

    typedef int (PASCAL *CHANGEVOLPROC)(char *ArcName,int Mode);
    typedef void (PASCAL *RARSETCHANGEVOLPROC)(
        HANDLE hArcData,
        CHANGEVOLPROC ChangeVolProc
        );

    typedef int (PASCAL *PROCESSDATAPROC)(unsigned char *Addr,int Size);
    typedef void (PASCAL *RARSETPROCESSDATAPROC)(
        HANDLE hArcData,
        PROCESSDATAPROC ProcessDataProc
        );
    typedef void (PASCAL *RARSETPASSWORD)(
        HANDLE hArcData,
        char *Password
        );

    HINSTANCE m_hLib;
    RAROPENARCHIVEEX RAROpenArchiveEx;
    RARREADHEADER RARReadHeader;
    RARPROCESSFILE RARProcessFile;
    RARCLOSEARCHIVE RARCloseArchive;
    RARSETPASSWORD RARSetPassword;
    RARSETCALLBACK RARSetCallback;

    char m_sOutDir[MAX_PATH];

    void Init();
    void SetOutDir(const char *sDir);
    static int CALLBACK CallBackProc(UINT msg, LONG UserData, LONG P1, LONG P2);

public:
    Unrar();
    virtual ~Unrar();

    void Extract(const char *sArchive, const char *sDir = NULL, const char *sPass = NULL);

};

#endif

//-------------------- End Unrar.h ------------------------------------------

//-------------------- Unrar.cpp --------------------------------------------
/*
*
*    Автор: Алимов Рустем
*    mailto:rus_tem@mail333.com
*
*/

#include 
#include "Unrar.h"

//---------------------------------------------------------------------------

namespace
{
    #define ERAR_END_ARCHIVE     10
    #define ERAR_NO_MEMORY       11
    #define ERAR_BAD_DATA        12
    #define ERAR_BAD_ARCHIVE     13
    #define ERAR_UNKNOWN_FORMAT  14
    #define ERAR_EOPEN           15
    #define ERAR_ECREATE         16
    #define ERAR_ECLOSE          17
    #define ERAR_EREAD           18
    #define ERAR_EWRITE          19
    #define ERAR_SMALL_BUF       20
    #define ERAR_UNKNOWN         21

    #define RAR_OM_LIST           0
    #define RAR_OM_EXTRACT        1

    #define RAR_SKIP              0
    #define RAR_TEST              1
    #define RAR_EXTRACT           2

    #define RAR_VOL_ASK           0
    #define RAR_VOL_NOTIFY        1

    const char RAROpenArchiveExName[] = "RAROpenArchiveEx";
    const char RARReadHeaderName[]    = "RARReadHeader";
    const char RARProcessFileName[]   = "RARProcessFile";
    const char RARCloseArchiveName[]  = "RARCloseArchive";
    const char RARSetPasswordName[]   = "RARSetPassword";
    const char RARSetCallbackName[]   = "RARSetCallback";
}
//---------------------------------------------------------------------------

Unrar::Unrar() : RAROpenArchiveEx(NULL), RARReadHeader(NULL),
                 RARProcessFile(NULL), RARCloseArchive(NULL),
                 RARSetPassword(NULL), 
                 m_hLib(NULL)
{
    Init();
}
//---------------------------------------------------------------------------

Unrar::~Unrar()
{
    if(m_hLib)
        FreeLibrary(m_hLib);
}
//---------------------------------------------------------------------------
//
// IN: sArchive - маска файлов, sDir - каталог извлечения, sPass - пароль
void Unrar::Extract(const char *sArchive, const char *sDir, const char *sPass)
{
    if(!m_hLib)
        return;

    char str[MAX_PATH], tmp[MAX_PATH];

    // здесь будет каталог расположения архивов
    lstrcpy(tmp, sArchive);
    int i;
    for(i = lstrlen(tmp) - 1; i >=0; i--)
        if(tmp[i] == '\\')
        {
            tmp[i + 1] = 0;
            break;
        }
    if(i < 0)
        tmp[0] = 0;

    SetOutDir(sDir);

    WIN32_FIND_DATA FindData;
    HANDLE hFind = FindFirstFile(sArchive, &FindData);
    if(hFind != INVALID_HANDLE_VALUE)
    {
        HANDLE hArcData;
        int RHCode, PFCode;
        struct RARHeaderData HeaderData;
        struct RAROpenArchiveDataEx OpenArchiveData;
        char sCmtBuf[16*1024];

        do
        {
            wsprintf(str, "%s%s", tmp, FindData.cFileName);

            ZeroMemory(&OpenArchiveData, sizeof(OpenArchiveData));
            OpenArchiveData.ArcName = str;
            OpenArchiveData.CmtBuf  = sCmtBuf;
            OpenArchiveData.CmtBufSize = sizeof(sCmtBuf);
            OpenArchiveData.OpenMode = RAR_OM_EXTRACT;

            hArcData = RAROpenArchiveEx(&OpenArchiveData);

            if( !OpenArchiveData.OpenResult )
            {
                // передаем параметром в Callback пароль
                RARSetCallback(hArcData, CallBackProc, (LONG)sPass);
                HeaderData.CmtBuf = NULL;

                while( (RHCode = RARReadHeader(hArcData, &HeaderData)) == 0 )
                {
                    PFCode = RARProcessFile(hArcData, RAR_EXTRACT, m_sOutDir, NULL);
                    if(PFCode)
                        break;
                }

//
//                if(RHCode == ERAR_BAD_DATA)
//                {
//                    wsprintf(str, "Ошибка архива: %s", FindData.cFileName);
//                    MessageBox(GetActiveWindow(), str, "Unrar", MB_OK|MB_ICONERROR);
//                }

                RARCloseArchive(hArcData);
            }
        } while( FindNextFile(hFind, &FindData) );
        FindClose(hFind);
    }
}
//---------------------------------------------------------------------------

// библиотека UNRAR требует имена каталогов в OEM кодировке
void Unrar::SetOutDir(const char *sDir)
{
    CharToOem(sDir, m_sOutDir);
}
//---------------------------------------------------------------------------

// загружаем библиотеку и инициализируем функции
void Unrar::Init()
{
    m_hLib = LoadLibrary("UNRAR.DLL");
    if(m_hLib)
    {
        RAROpenArchiveEx = (RAROPENARCHIVEEX) GetProcAddress(m_hLib, RAROpenArchiveExName);
        RARReadHeader    = (RARREADHEADER) GetProcAddress(m_hLib, RARReadHeaderName);
        RARProcessFile   = (RARPROCESSFILE) GetProcAddress(m_hLib, RARProcessFileName);
        RARCloseArchive  = (RARCLOSEARCHIVE) GetProcAddress(m_hLib, RARCloseArchiveName);
        RARSetCallback   = (RARSETCALLBACK) GetProcAddress(m_hLib, RARSetCallbackName);

        RARSetPassword   = (RARSETPASSWORD) GetProcAddress(m_hLib, RARSetPasswordName);

        // проверка на инициализацию необходимых функций
        if( !RAROpenArchiveEx || !RARReadHeader || 
            !RARProcessFile || !RARCloseArchive || !RARSetCallback )
        {
            FreeLibrary(m_hLib);
            m_hLib = NULL;
        }
    }
}
//---------------------------------------------------------------------------

int CALLBACK Unrar::CallBackProc(UINT msg, LONG UserData, LONG P1, LONG P2)
{
    switch(msg)
    {
    case UCM_NEEDPASSWORD:
        // в UserData переданные параметром в CallBack данные
        // в нашем случае - пароль
        lstrcpyn((char *)P1, (char *)UserData, P2);
        return 0;
    }
    return 0;
}

//-------------------- End Unrar.cpp ----------------------------------------
© Copyright 2004 Алимов Рустем
rus_tem@mail333.com


Опубликовал admin
26 Апр, Понедельник 2004г.



Программирование для чайников.