從檔案工作中獲得閱讀。下面的解釋和代碼,但在這一點上真的只是一個破解,看看它是否可能。我只是不斷修改東西,直到我找到工作。這僅僅是一個有效的例子,決不是一個生產質量代碼(它不能重新開始)。毫無疑問,很多事情是不好的/不必要的/跆拳道,所以隨時用評論來幫助清理。
如前所述,將路徑傳遞到庫是不夠的 - 除非文件位於KnownFolders(文檔,家庭,媒體,音樂,圖片,可移動或視頻)之一中,否則「訪問是否認「信息。相反,庫必須能夠接受從FileOpenPicker返回的StorageFile ^。至少我還沒有找到任何其他的方式去做,也許有人知道更好?
MiniZip通過iowin32.h/.c爲zlib提供Windows文件系統訪問層。這仍舊適用於舊式應用程序的桌面模式,但對於Metro應用程序不起作用,因爲它使用不推薦的API並依賴於路徑。要使MiniZip在Windows 8上運行,需要完整重寫iowin32。
爲了重新開始工作,首先要找到一種方法將StorageFile ^一直傳遞到iowinrt(Windows 8 for iowin32的替代品)。幸運的是,這不是一個問題,因爲MiniZip提供了兩種類型的開放文件函數 - 接受指向char的指針,其他接受指向void的指針。由於^仍然只是一個指針,因此將StorageFile ^轉換爲void *並返回到StorageFile ^工作正常。
現在我已經能夠將StorageFile ^傳遞給我的新iowinrt,接下來的問題是如何使用Zlib創建新的異步C++文件訪問API。爲了支持非常古老的C編譯器,Zlib使用舊式的K & R風格編寫。VisualStudio編譯器將拒絕將其編譯爲C++,它必須編譯爲C,並且新的Iowinrt必須編譯爲C++ - 在創建項目時請記住這一點。關於VS項目的其他注意事項是我做了Visual C++ Windows Metro風格的靜態庫,儘管DLL也應該可以工作,但是你還必須定義宏來導出MiniZip API(我還沒有試過這個,不知道哪個宏你必須使用)。我想我還必須設置「消耗Windows運行時擴展」(/ ZW),設置「不使用預編譯頭」,並將_CRT_SECURE_NO_WARNINGS和_CRT_NONSTDC_NO_WARNINGS添加到預處理器定義中。
至於iowinrt本身,我把它分成兩個文件。一個擁有兩個密封的ref類 - 讀寫器對象;他們接受StorageFile ^。 Reader實現了Read,Tell,SeekFromBeginning,SeekFromCurrent和SeekFromEnd(3 Seek方法的原因是因爲ref密封類必須堅持使用RT類型,並且顯然不包括枚舉,所以我只是採取了簡單的路線)。 Writer實現只寫了,還沒有使用它。
這是的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庫而言,您的方法是正確和直接的。您將路徑傳遞給minizip,然後使用I/O回調在內部重新創建StorageFile對象。你看過Process Monitor並檢查了I/O調用和相關的錯誤嗎? –
@Nathan謝謝你的建議 - 沒有嘗試過,會放棄它。不過,我現在基本上放棄了Win8 C++。在WinRT C++文檔趕上C#/ JS文檔之前,將進一步的努力投入到WinRT C++編程中是浪費時間。由於MS不認爲C++文檔很重要(請參閱這裏的評論:http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/04cbe02b-700f-4be5-b6e9-fe98f3f2cd2e/)我想我'等一兩年後再給它一次。 –
這太糟糕了。它看起來像你在那裏的大部分。 –