다음을 통해 공유


XGameSaveReadBlobDataAsync

XGameSaveContainer에서 XGameSaveBlob을 비동기적으로 읽습니다.

구문

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

매개 변수

container _In_
형식: XGameSaveContainerHandle

게임 저장 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
게임 저장 오류