2012-06-07 28 views
8

以前にアーカイブを解凍するためにMiniZip(zlibラッパー)を使用しました。 MiniZipは、 "iowin32.c"で廃止予定のAPI(CreateFile()およびSetFilePointer()を使用するため、Metroアプリケーションには使用できません。Windows 8でアーカイブを解凍する

私は簡単な修正であり、CreateFile()とSetFilePointer()をCreateFile2()とSetFilePointerEx()に置き換えて "iowinrt.c"を作成したと思っていました。このようにして、私は、承認されたWin8 APIしか使用しないミニジップを入手しましたが、それはまだ役に立たないと判明しました - 私はサンドボックスを忘れていました。 FileOpenPicker()を使用してファイルを選択し、そのパスを変更したMiniZipに渡しても、それを開くことはできません - CreateFile2()は "Access is denied"で失敗します。メッセージ。

ファイルアクセスのための古いC APIが今ではほとんど役に立ちません。これを修正するには、新しい非同期ファイルアクセスを使用してC++/CXで私の "iowinrt"を再実装する必要があると私は理解しています。他のオプションはありますか?私は、WinRTが圧縮/解凍機能を持っていても、アーカイブではなく個々のファイルでしか動作しない場所を見たと思います。

追加の要件は、私がこれをメモリで動作させるために必要とすることです。

  1. 私はC++/CXから使用することができます.NETクラスを作成する方法についての情報のこの作品が見つかりました:: http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/3ff383d0-0c9f-4a30-8987-ff2b23957f01私は、.NET Frameworkの4.5を経由して解決策を持っていたと思った瞬間のために

  2. の.NET Framework 4.5は、System.IO.CompressionでZIPARCHIVEとZipArchiveEntryクラスが含まれています: http://msdn.microsoft.com/en-us/library/system.io.compression.ziparchive%28v=vs.110%29.aspx#Y0 http://msdn.microsoft.com/en-us/library/system.io.compression.ziparchiveentry%28v= vs.110%29.aspx#Y0

WinMD出力タイプでZipArchiveとZipArchiveEntryを公開してC#/ CXプロジェクトでC#Metroクラスライブラリを作成できたと思っていました。しかし、それが働いてもメモリ内では動作しません。 ZipArchiveとZipArchiveEntryはファイルのみで動作するようです。

+0

あなたのアプローチは、ミニクリップが行く限り、正確で簡単です。 minizipへのパスを渡してから、I/OコールバックでStorageFileオブジェクトを内部的に再作成します。あなたはProcess Monitorを見て、I/O呼び出しと関連するエラーを調べましたか? –

+0

@Nathanあなたの提案をありがとう - それを試していない、それを行ってくれます。しかし、私は基本的にWin8 C++をあきらめました。 WinRT C++のドキュメントがWinRT C++プログラミングにさらに力を入れているC#/ JSのドキュメントに追いつくまで、時間の無駄です。 MSはC++のドキュメントを重要視していないので(ここのコメントを参照してください:http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/04cbe02b-700f-4be5-b6e9-fe98f3f2cd2e/) 1年か2年待ってからもう一度行ってください。 –

+0

それはあまりにも悪い人です。そこにはほとんどの道があるようです。 –

答えて

5

アーカイブ作業から読み込みました。以下の説明とコードですが、実際にはこの点ではちょうどハックで、それが可能かどうかを確認することができます。私は何かが働くまで事を修正し続けました。これは、動作するものと決して生産品質のコードではない(開始には再入可能ではない)ものの単なる例です。間違いなく多くのものが悪い/不必要な/ wtfですので、クリーンアップに役立つコメントを自由に使用してください。

前述のように、ファイルがKnownFolders(ドキュメント、ホーム、メディア、音楽、写真、リムーバブルまたはビデオ)のいずれかにある場合を除いて、「アクセスは拒否されました。代わりに、FileOpenPickerから返されたように、ライブラリはStorageFile ^を受け入れることができる必要があります。少なくとも私はそれを行うための他の方法を見つけていない、誰かがよく知っている?

ミニジップはiowin32.h/.c経由でzlib用のWindowsファイルシステムアクセス層を提供します。これは旧式のアプリのデスクトップモードでも機能しますが、廃止予定のAPIを使用し、パスに依存しているMetroアプリでは機能しません。 Windows 8でMiniZipを使用するには、iowin32の完全な書き換えが必要です。

物事をもう一度やり直すには、最初にStorageFile ^をiowinrt(Windows 8のiowin32の置き換え)に引き渡す方法を見つけることでした。幸いにも、それは問題ではありませんでした。なぜなら、MiniZipはオープンファイル関数の2つのスタイル(charへのポインタを受け入れるメソッドとvoidへのポインタを受け入れる他のもの)を提供するからです。^はまだ単なるポインタなので、StorageFile ^をvoid *にキャストし、StorageFile ^に戻すとうまく動作します。

私は新しいiowinrtにStorageFile ^を渡すことができました。次の問題は、新しい非同期C++ファイルアクセスAPIをZlibで動作させる方法でした。非常に古いCコンパイラをサポートするために、Zlibは古いK & Rスタイルで書かれています。C. Visual StudioのコンパイラはこれをC++としてコンパイルすることを拒否し、Cとしてコンパイルしなければならず、新しいiowinrtをC++としてコンパイルする必要があります。プロジェクトを作成するときはそれを覚えておいてください。 VSプロジェクトについての注意点は、Visual C++のWindows Metroスタイルの静的ライブラリですが、DLLも機能するはずですが、MiniZip APIをエクスポートするマクロを定義する必要があります(これを試したことはありません。どのマクロあなたが使用する必要があります)。私は、 "Consumption Windows Runtime Extension"(/ ZW)を "プリコンパイル済みヘッダーを使用しない"に設定し、_CRT_SECURE_NO_WARNINGSと_CRT_NONSTDC_NO_WARNINGSをプリプロセッサ定義に追加する必要もあったと思います。

iowinrt自体については、私は2つのファイルに分割しました。 1つはリーダとライターオブジェクトの2つの密封されたrefクラスを保持しています。彼らはStorageFile ^を受け入れます。 ReaderはRead、Tell、SeekFromBeginning、SeekFromCurrent、SeekFromEndを実装しています(3つのSeekメソッドの理由は、ref密封クラスはRT型に固執していて、簡単にenumを除外しているからです)。ライターはまだ瞬時に書き込みを実装し、まだ使用していません。

これはFileReaderのコードである:

#include "pch.h" 
    #include "FileAccess.h" // FileReader and FileWriter 

    using namespace Concurrency; 
    using namespace Windows::Security::Cryptography; 
    using namespace CFileAccess; 

    FileReader::FileReader(StorageFile^ archive) 
    { 
     if (nullptr != archive) 
     { 
      create_task(archive->OpenReadAsync()).then([this](IRandomAccessStreamWithContentType^ archiveStream) 
      { 
       if (nullptr != archiveStream) 
       { 
        _readStream = archiveStream; 
       } 
      }).wait(); 
     } 
    } // end of constructor 

    int32 FileReader::Read(WriteOnlyArray<byte>^ fileData) 
    { 
     int32 bytesRead = 0; 

     if ((nullptr != _readStream) && (fileData->Length > 0)) 
     { 
      try 
      { 
       auto inputStreamReader = ref new DataReader(_readStream); 
       create_task(inputStreamReader->LoadAsync(fileData->Length)).then([&](task<unsigned int> dataRead) 
       { 
        try 
        { 
         bytesRead = dataRead.get(); 
         if (bytesRead) 
         { 
          inputStreamReader->ReadBytes(fileData); 
         } 
        } 
        catch (Exception^ e) 
        { 
         bytesRead = -1; 
        } 

        inputStreamReader->DetachStream(); 
       }).wait(); 
      } 
      catch (Exception^ e) 
      { 
       bytesRead = -1; 
      } 
     } 

     return (bytesRead); 
    } // end of method Read() 

    int64 FileReader::Tell(void) 
    { 
     int64 ret = -1; 

     if (nullptr != _readStream) 
     { 
      ret = _readStream->Position; 
     } 

     return (ret); 
    } // end of method Tell() 

    int64 FileReader::SeekFromBeginning(uint64 offset) 
    { 
     int64 ret = -1; 

     if ((nullptr != _readStream) && (offset < _readStream->Size)) 
     { 
      _readStream->Seek(offset); 
      ret = 0; 
     } 

     return (ret); 
    } // end of method SeekFromBeginning() 

    int64 FileReader::SeekFromCurrent(uint64 offset) 
    { 
     int64 ret = -1; 

     if ((nullptr != _readStream) && ((_readStream->Position + offset) < _readStream->Size)) 
     { 
      _readStream->Seek(_readStream->Position + offset); 
      ret = 0; 
     } 

     return (ret); 
    } // end of method SeekFromCurrent() 

    int64 FileReader::SeekFromEnd(uint64 offset) 
    { 
     int64 ret = -1; 

     if ((nullptr != _readStream) && ((_readStream->Size - offset) >= 0)) 
     { 
      _readStream->Seek(_readStream->Size - offset); 
      ret = 0; 
     } 

     return (ret); 
    } // end of method SeekFromEnd() 

iowinrtはMiniZipとFileReaderの(及びてFileWriter)の間に位置します。それはここにすべてを与えるためには長すぎるのですが、これは、それは別の関数名と同じの大部分は、単により多くのだから、残りを再構築するのに十分であるべきで、プラス明白ですfill_winRT_filefuncxxxの束():

#include "zlib.h" 
    #include "ioapi.h" 
    #include "iowinrt.h" 
    #include "FileAccess.h" 

    using namespace Windows::Security::Cryptography; 
    using namespace Platform; 
    using namespace CFileAccess; 

    static FileReader^ g_fileReader = nullptr; 
    static FileWriter^ g_fileWriter = nullptr; 
    static StorageFile^ g_storageFile = nullptr; 

    [...] 

    static voidpf winRT_translate_open_mode(int mode) 
    { 
     if (nullptr != g_storageFile) 
     { 
      if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) 
      { 
       g_fileWriter = nullptr; 
       g_fileReader = ref new FileReader(g_storageFile); 
      } 
      else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) 
      { 
       g_fileReader = nullptr; 
       g_fileWriter = ref new FileWriter(g_storageFile); 
      } 
      else if (mode & ZLIB_FILEFUNC_MODE_CREATE) 
      { 
       g_fileReader = nullptr; 
       g_fileWriter = ref new FileWriter(g_storageFile); 
      } 
     } 
     return (nullptr != g_fileReader ? reinterpret_cast<voidpf>(g_fileReader) : reinterpret_cast<voidpf>(g_fileWriter)); 
    } 


    voidpf ZCALLBACK winRT_open64_file_func (voidpf opaque,const void* storageFile,int mode) 
    { 
     g_storageFile = reinterpret_cast<StorageFile^>(const_cast<void*>(storageFile)); 
     return (winRT_translate_open_mode(mode)); 
    } 

    [...] 

    Long ZCALLBACK winRT_read_file_func (voidpf opaque, voidpf stream, void* buf,uLong size) 
    { 
     uLong bytesRead = 0; 
     if (nullptr != g_fileReader) 
     { 
      auto fileData = ref new Platform::Array<byte>(size); 
      bytesRead = g_fileReader->Read(fileData); 
      memcpy(buf, fileData->Data, fileData->Length); 
     } 
     return (bytesRead); 
    } 


    uLong ZCALLBACK winRT_write_file_func (voidpf opaque,voidpf stream,const void* buf,uLong size) 
    { 
     uLong bytesWritten = 0; 
     if (nullptr != g_fileWriter) 
     { 
      auto bytes = ref new Array<uint8>(reinterpret_cast<uint8*>(const_cast<void*>(buf)), size); 
      IBuffer ^writeBuffer = CryptographicBuffer::CreateFromByteArray(bytes); 
      bytesWritten = g_fileWriter->Write(writeBuffer); 
     } 
     return (bytesWritten); 
    } 

    long ZCALLBACK winRT_tell_file_func (voidpf opaque,voidpf stream) 
    { 
     long long ret = 0; 
     if (nullptr != g_fileReader) 
     { 
      ret = g_fileReader->Tell(); 
     } 
     return (static_cast<long>(ret)); 
    } 

    ZPOS64_T ZCALLBACK winRT_tell64_file_func (voidpf opaque, voidpf stream) 
    { 
     ZPOS64_T ret = 0; 
     if (nullptr != g_fileReader) 
     { 
      ret = g_fileReader->Tell(); 
     } 
     return (ret); 
    } 

    [...] 

    long ZCALLBACK winRT_seek64_file_func (voidpf opaque, voidpf stream,ZPOS64_T offset,int origin) 
    { 
     long long ret = -1; 
     if (nullptr != g_fileReader) 
     { 
      switch (origin) 
      { 
      case ZLIB_FILEFUNC_SEEK_CUR : 
       ret = g_fileReader->SeekFromCurrent(offset); 
       break; 
      case ZLIB_FILEFUNC_SEEK_END : 
       ret = g_fileReader->SeekFromEnd(offset); 
       break; 
      case ZLIB_FILEFUNC_SEEK_SET : 
       ret = g_fileReader->SeekFromBeginning(offset); 
       break; 
      default: 
       // should never happen! 
       ret = -1; 
       break; 
      } 
     } 
     return (static_cast<long>(ret)); 
    } 

    int ZCALLBACK winRT_close_file_func (voidpf opaque, voidpf stream) 
    { 
     g_fileWriter = nullptr; 
     g_fileReader = nullptr; 
     return (0); 
    } 

    int ZCALLBACK winRT_error_file_func (voidpf opaque,voidpf stream) 
    { 
     /// @todo Get errors from FileAccess 
     return (0); 
    } 

これで十分ですMiniZipを入手するには(少なくとも読むために)、MiniZip関数をどのように呼び出すか注意しなければなりません。Metroはすべて非同期で、UIスレッドのブロックは例外で終了するため、タスクでのアクセスをラップする必要があります。

FileOpenPicker^ openPicker = ref new FileOpenPicker(); 
    openPicker->ViewMode = PickerViewMode::List; 
    openPicker->SuggestedStartLocation = PickerLocationId::ComputerFolder; 
    openPicker->FileTypeFilter->Append(".zip"); 
    task<IVectorView<StorageFile^>^>(openPicker->PickMultipleFilesAsync()).then([this](IVectorView<StorageFile^>^ files) 
    { 
     if (files->Size > 0) 
     { 
      std::for_each(begin(files), end(files), [this](StorageFile ^file) 
      { // open selected zip archives 
       create_task([this, file]() 
       { 
        OpenArchive(file); 
        [...] 
       }); 
      }); 
     } 
     else 
     { 
      rootPage->NotifyUserBackgroundThread("No files were returned.", NotifyType::ErrorMessage); 
     } 
    }); 

    [...] 

    bool OpenArchive(StorageFile^ archive) 
    { 
     bool isArchiveOpened = false; 

     if (nullptr != archive) 
     { // open ZIP archive 
      zlib_filefunc64_def ffunc; 
      fill_winRT_filefunc64(&ffunc); 

      unzFile archiveObject = NULL; 
      create_task([this, &ffunc, archive]() 
      { 
       archiveObject = unzOpen2_64(reinterpret_cast<const void*>(archive), &ffunc); 
      }).wait(); 

      if (NULL != archiveObject) 
      { 
       [...] 
+0

そしてありがとう。あなたは私の考えを、既存の* nix OSSプロジェクト、zlibをWindows Storeに変換しようと奨励した最初の人です。私はあなたのアイデアを拡張し、最終的に[Windows Store x86、x64、ARM archtecturesのzlibstat.libをコンパイルする]ことができました(http://stackoverflow.com/q/13900749/1712065)。必要に応じて、変換プロセスを改善するための手順を実行することができます。 – Annie

関連する問題