アーカイブ作業から読み込みました。以下の説明とコードですが、実際にはこの点ではちょうどハックで、それが可能かどうかを確認することができます。私は何かが働くまで事を修正し続けました。これは、動作するものと決して生産品質のコードではない(開始には再入可能ではない)ものの単なる例です。間違いなく多くのものが悪い/不必要な/ 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)
{
[...]
あなたのアプローチは、ミニクリップが行く限り、正確で簡単です。 minizipへのパスを渡してから、I/OコールバックでStorageFileオブジェクトを内部的に再作成します。あなたはProcess Monitorを見て、I/O呼び出しと関連するエラーを調べましたか? –
@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年待ってからもう一度行ってください。 –
それはあまりにも悪い人です。そこにはほとんどの道があるようです。 –