次の方法で共有


XGameSaveReadBlobDataAsync

XGameSaveContainer から XGameSaveBlob データを非同期に読み取ります。

構文

HRESULT XGameSaveReadBlobDataAsync(  
         XGameSaveContainerHandle container,  
         const char** blobNames,  
         uint32_t countOfBlobs,  
         XAsyncBlock* async  
)  

パラメーター

container _In_
型: XGameSaveContainerHandle

gamesave BLOB データを保持するコンテナー。

blobNames_In_opt_z_count_(countOfBlobs)
型: char**

XGameSaveBlob の名前を表す文字列の配列へのポインター。

countOfBlobs_In_
型: uint32_t

読み取る BLOB の数。

async _In_
型: XAsyncBlock*

XGameSaveReadBlobDataAsync の呼び出しに対するコンテキストとコールバック関数が格納されている AsyncBlock。

戻り値

型: HRESULT

関数の結果です。

解説

結果とデータは、XGameSaveReadBlobDataResult 関数でキャプチャされます。 XGameSaveReadBlobDataResult では、コンテナー内の BLOB の数と BLOB データ自体が返されます。 この関数には、XGameSaveReadBlobData という名前の同期バージョンがあります。

// ASYNC Read - can be kicked off from a time sensitive thread 
//              actual work and completion will be scheduled based upon  
//              the configuration of the async_queue tied to the XAsyncBlock 
void Sample::_ReadContainerBlobsAsync(const XGameSaveContainerInfo* container) 
{ 
    const char* blobNames[] = { 
        "WorldState", 
        "PlayerState", 
        "PlayerInventory" 
    }; 
  
    struct LoadContext 
    { 
        LoadContext(Sample* s) : container(nullptr), self(s) {} 
        ~LoadContext() 
        { 
            XGameSaveCloseContainer(container); 
        } 
        XAsyncBlock async; 
        XGameSaveContainerHandle container; 
        Sample* self; 
    }; 
    HRESULT hr; 
    LoadContext* loadContext = new LoadContext(this); 
    if (loadContext == nullptr) 
    { 
        hr = E_OUTOFMEMORY; 
    } 
  
    auto completionCallback = [](XAsyncBlock* async) 
    { 
        auto ctx = reinterpret_cast<LoadContext*>(async->context); 
        auto self = ctx->self; 
        size_t allocatedSize; 
        XGameSaveBlob* blobData = nullptr; 
        uint32_t blobCount = 0; 
  
        HRESULT hr = GetAsyncStatus(async, false); 
  
        if (SUCCEEDED(hr)) 
        { 
            // use local wrapper for GetAsyncResultSize to give strongly typed alloc 
            XGameSaveBlob* blobData = _AllocAsyncResult<XGameSaveBlob>(async, &allocatedSize); 
            if (blobData == nullptr) 
            { 
                hr = E_OUTOFMEMORY; 
            } 
        } 
  
        if (SUCCEEDED(hr)) 
        { 
            // now that we have allocated the required buffers 
            // ask XGameSave to populate them 
            hr = XGameSaveReadBlobDataResult(async, allocatedSize, blobData, &blobCount); 
        } 
        if (SUCCEEDED(hr)) 
        { 
            if (blobCount == _countof(blobNames)) 
            { 
                for (uint32_t i = 0; i < blobCount; i++) 
                { 
                    XGameSaveBlob* currentBlob = blobData + i; 
                    if (strcmp(currentBlob->info.name, "WorldState") == 0) 
                    { 
                        hr = self->_LoadSaveBlob(currentBlob, self->_worldState); 
                    } 
                    else if (strcmp(currentBlob->info.name, "PlayerState") == 0) 
                    { 
                        hr = self->_LoadSaveBlob(currentBlob, self->_playerState); 
                    } 
                    else if (strcmp(currentBlob->info.name, "PlayerInventory") == 0) 
                    { 
                        hr = self->_LoadSaveBlob(currentBlob, self->_playerInventory); 
                    } 
                    if (FAILED(hr)) 
                    { 
                        break; 
                    } 
                } 
            } 
            else 
            { 
                // what containers are missing? Can we get by without XXX? 
                hr = E_UNEXPECTED; 
            } 
        } 
  
        self->_HandleContainerBlobErrors(hr); 
  
        if (blobData != nullptr) 
        { 
            // we own the buffer so better kill it 
            free(blobData); 
        } 
        // be sure to clear this since it will be no longer valid after we exit 
        self->_asyncLoad = nullptr; 
        // kill the temp context tracking the async op 
        delete ctx; 
    }; 
  
    if (SUCCEEDED(hr)) 
    { 
        loadContext->async.context = loadContext; 
        // set the XTaskQueueHandle so the completion will be done on our thread 
        // and then we can allocate the larger buffers with less lock contention 
        loadContext->async.queue = _asyncCompleteQueue; 
        loadContext->async.callback = completionCallback; 
    } 
  
    hr = XGameSaveCreateContainer(_provider, container->name, &loadContext->container); 
    if (SUCCEEDED(hr)) 
    { 
        hr = XGameSaveReadBlobDataAsync(loadContext->container, blobNames, _countof(blobNames), &loadContext->async); 
    } 
    if (SUCCEEDED(hr)) 
    { 
        // keep a reference to this so we can Cancel later if needed 
        _asyncLoad = &loadContext->async;  
        // hand over ownership to the async callback 
        loadContext = nullptr;  
    } 
  
    if (loadContext) 
    { 
        delete loadContext; 
    } 
    if (FAILED(hr)) 
    { 
        _HandleContainerBlobErrors(hr); 
    } 
} 
 
// Allocate a strongly typed portion from an Async Result 
template<typename T> 
static T* _AllocAsyncResult(XAsyncBlock* async, size_t* allocatedSize) 
{ 
    *allocatedSize = 0; 
    size_t allocSize = 0; 
    HRESULT hr = XAsyncGetResultSize(async, &allocSize); 
    if (SUCCEEDED(hr) && allocSize > 0) 
    { 
        *allocatedSize = allocSize; 
        return reinterpret_cast<T*>(malloc(allocSize)); 
    } 
    return nullptr; 
} 
  
/*static*/ 
DWORD Sample::_CompleteThreadProc(PVOID context) 
{ 
    auto self = reinterpret_cast<Sample*>(context); 
  
    while (DWORD wait = WaitForSingleObjectEx(self->_shutdownEvent, INFINITE, TRUE) == WAIT_IO_COMPLETION) 
    { 
        // loop waiting for APC, any other return should exit the thread 
    } 
} 
  
// Init thread and async queue 
HRESULT Sample::_InitQueueThread() 
{ 
    HRESULT hr = S_OK; 
    _shutdownEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr); 
    if (_shutdownEvent == nullptr) 
    { 
        hr = HRESULT_FROM_WIN32(GetLastError()); 
    } 
     
    if (SUCCEEDED(hr)) 
    { 
        _completeThread = CreateThread(nullptr, 0, _CompleteThreadProc, this, 0, &_completeThreadId); 
        if (_completeThread == nullptr) 
        { 
            hr = HRESULT_FROM_WIN32(GetLastError()); 
        } 
    } 
    if (SUCCEEDED(hr)) 
    { 
        hr = XTaskQueueCreate(XTaskQueueDispatchMode::ThreadPool, XTaskQueueDispatchMode::Manual, &_asyncCompleteQueue); 
    } 
    return hr; 
} 
  
void Sample::_CancelReadContainerBlobsAsync() 
{ 
    if (_asyncLoad) 
    { 
        XAsyncCancel(_asyncLoad); 
    } 
}

要件

ヘッダー: XGameSave.h

ライブラリ: xgameruntime.lib

サポートされているプラットフォーム: Windows、Xbox One ファミリー本体、Xbox Series 本体

関連項目

XGameSave
XGameSaveBlobInfo
XGameSaveReadBlobDataResult
XGameSaveReadBlobData
ゲームのセーブ エラー