extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD fdwReason, LPVOID) { char procname[PROCNAMEFILEPATH_EXTENDED_BUFFER_BUFLEN]; GetModuleFileNameA(NULL, procname, ARRAY_NUM_ELEMENTS(procname)); // Fix for windows XP; on length nSize does not include null-termination // @see http://msdn.microsoft.com/en-us/library/windows/desktop/ms683197%28v=vs.85%29.aspx procname[ARRAY_NUM_ELEMENTS(procname) - 1] = '\0'; switch (fdwReason) { case DLL_PROCESS_ATTACH: ods("Lib: ProcAttach: %s", procname); dllmainProcAttach(procname); break; case DLL_PROCESS_DETACH: ods("Lib: ProcDetach: %s", procname); dllmainProcDetach(); break; case DLL_THREAD_ATTACH: ods("Lib: ThreadAttach: %s", procname); dllmainThreadAttach(); break; default: break; } return TRUE; }
/// @param hDXGI must be a valid module handle. void hookDXGI(HMODULE hDXGI, bool preonly) { wchar_t modulename[MODULEFILEPATH_BUFLEN]; GetModuleFileNameW(NULL, modulename, ARRAY_NUM_ELEMENTS(modulename)); ods("DXGI: hookDXGI in App '%ls'", modulename); // Add a ref to ourselves; we do NOT want to get unloaded directly from this process. HMODULE hTempSelf = NULL; GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast<LPCTSTR>(&hookDXGI), &hTempSelf); bHooked = true; // Can we use the prepatch data? GetModuleFileNameW(hDXGI, modulename, ARRAY_NUM_ELEMENTS(modulename)); if (_wcsicmp(dxgi->wcFileName, modulename) == 0) { // The module seems to match the one we prepared d3dd for. unsigned char *raw = (unsigned char *) hDXGI; HookPresentRaw((voidFunc)(raw + dxgi->offsetPresent)); HookResizeRaw((voidFunc)(raw + dxgi->offsetResize)); } else if (! preonly) { ods("DXGI: Interface changed, can't rawpatch. Current: %ls ; Previously: %ls", modulename, dxgi->wcFileName); } else { bHooked = false; } }
int GetFnOffsetInModule(voidFunc fnptr, wchar_t *refmodulepath, unsigned int refmodulepathLen, const std::string &logPrefix, const std::string &fnName) { HMODULE hModule = NULL; if (! GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (char *) fnptr, &hModule)) { ods((logPrefix + ": Failed to get module for " + fnName).c_str()); return -1; } const bool bInit = refmodulepath[0] == '\0'; if (bInit) { GetModuleFileNameW(hModule, refmodulepath, refmodulepathLen); } else { wchar_t modulename[MODULEFILEPATH_BUFLEN]; GetModuleFileNameW(hModule, modulename, ARRAY_NUM_ELEMENTS(modulename)); if (_wcsicmp(modulename, refmodulepath) != 0) { ods((logPrefix + ": " + fnName + " functions module path does not match previously found. Now: '%ls', Previously: '%ls'").c_str(), modulename, refmodulepath); return -2; } } unsigned char *fn = reinterpret_cast<unsigned char *>(fnptr); unsigned char *base = reinterpret_cast<unsigned char *>(hModule); unsigned long off = static_cast<unsigned long>(fn - base); // XXX: convert this function to use something other than int. // Issue mumble-voip/mumble#1924. if (off > static_cast<unsigned long>(std::numeric_limits<int>::max())) { ods("Internal overlay error: GetFnOffsetInModule() offset greater than return type can hold."); return -1; } return static_cast<int>(off); }
/// This function is called by the Mumble client in Mumble's scope /// mainly to extract the offsets of various functions in the IDXGISwapChain /// and IDXGIObject interfaces that need to be hooked in target /// applications. The data is stored in the dxgi shared memory structure. extern "C" __declspec(dllexport) void __cdecl PrepareDXGI() { if (! dxgi) return; ods("DXGI: Preparing static data for DXGI Injection"); dxgi->wcFileName[0] = 0; dxgi->offsetPresent = 0; dxgi->offsetResize = 0; // Make sure this is Vista or greater as quite a number of <=WinXP users have fake DX10 libs installed OSVERSIONINFOEXW ovi; memset(&ovi, 0, sizeof(ovi)); ovi.dwOSVersionInfoSize = sizeof(ovi); GetVersionExW(reinterpret_cast<OSVERSIONINFOW *>(&ovi)); if (ovi.dwMajorVersion < 6 || (ovi.dwMajorVersion == 6 && ovi.dwBuildNumber < 6001)) { ods("DXGI: No DXGI pre-Vista - skipping prepare"); return; } HMODULE hDXGI = LoadLibrary("DXGI.DLL"); if (hDXGI != NULL) { GetModuleFileNameW(hDXGI, dxgi->wcFileName, ARRAY_NUM_ELEMENTS(dxgi->wcFileName)); CreateDXGIFactory1Type pCreateDXGIFactory1 = reinterpret_cast<CreateDXGIFactory1Type>(GetProcAddress(hDXGI, "CreateDXGIFactory1")); ods("DXGI: Got CreateDXGIFactory1 at %p", pCreateDXGIFactory1); if (pCreateDXGIFactory1) { IDXGIFactory1 * pFactory; HRESULT hr = pCreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)(&pFactory)); if (FAILED(hr)) ods("DXGI: Call to pCreateDXGIFactory1 failed!"); if (pFactory) { IDXGIAdapter1 *pAdapter = NULL; pFactory->EnumAdapters1(0, &pAdapter); /// Offsets have to be identified and initialized only once. bool initializeDXGIData = !dxgi->offsetPresent && !dxgi->offsetResize; PrepareDXGI10(pAdapter, initializeDXGIData); initializeDXGIData = !dxgi->offsetPresent && !dxgi->offsetResize; PrepareDXGI11(pAdapter, initializeDXGIData); pFactory->Release(); } else { FreeLibrary(hDXGI); } } else { FreeLibrary(hDXGI); } } else { FreeLibrary(hDXGI); } }
bool IsFnInModule(voidFunc fnptr, wchar_t *refmodulepath, const std::string &logPrefix, const std::string &fnName) { HMODULE hModule = NULL; BOOL success = GetModuleHandleEx( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, reinterpret_cast<LPCSTR>(fnptr), &hModule); if (!success) { ods((logPrefix + ": Failed to get module for " + fnName).c_str()); } else { wchar_t modulename[MODULEFILEPATH_BUFLEN]; GetModuleFileNameW(hModule, modulename, ARRAY_NUM_ELEMENTS(modulename)); return _wcsicmp(modulename, refmodulepath) == 0; } return false; }
/// @param hD3D10 must be a valid module handle void hookD3D10(HMODULE hD3D10, bool preonly) { // Add a ref to ourselves; we do NOT want to get unloaded directly from this process. HMODULE hTempSelf = NULL; GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast<char *>(&hookD3D10), &hTempSelf); bHooked = true; wchar_t modulename[MODULEFILEPATH_BUFLEN]; GetModuleFileNameW(hD3D10, modulename, ARRAY_NUM_ELEMENTS(modulename)); if (_wcsicmp(d3d10->wcFileName, modulename) == 0) { unsigned char *raw = (unsigned char *) hD3D10; HookAddRelease((voidFunc)(raw + d3d10->iOffsetAddRef), (voidFunc)(raw + d3d10->iOffsetRelease)); } else if (! preonly) { ods("D3D10: Interface changed, can't rawpatch. Current: %ls ; Previously: %ls", modulename, d3d10->wcFileName); } else { bHooked = false; } }
static void hookD3D9(HMODULE hD3D, bool preonly) { char procname[MODULEFILEPATH_BUFLEN]; GetModuleFileName(NULL, procname, ARRAY_NUM_ELEMENTS(procname)); ods("D3D9: hookD3D9 in App '%s'", procname); // Add a ref to ourselves; we do NOT want to get unloaded directly from this process. HMODULE hTempSelf = NULL; GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast<char *>(&hookD3D9), &hTempSelf); bHooked = true; // Can we use the prepatch data? wchar_t modulename[MODULEFILEPATH_BUFLEN]; GetModuleFileNameW(hD3D, modulename, ARRAY_NUM_ELEMENTS(modulename)); if (_wcsicmp(d3dd->wcFileName, modulename) == 0) { // The module seems to match the one we prepared d3dd for. unsigned char *raw = (unsigned char *) hD3D; HookCreateRaw((voidFunc)(raw + d3dd->iOffsetCreate)); if (d3dd->iOffsetCreateEx) { HookCreateRawEx((voidFunc)(raw + d3dd->iOffsetCreateEx)); } } else if (! preonly) { ods("D3D9: Interface changed, can't rawpatch. Current: %ls ; Previously: %ls", modulename, d3dd->wcFileName); pDirect3DCreate9 d3dcreate9 = reinterpret_cast<pDirect3DCreate9>(GetProcAddress(hD3D, "Direct3DCreate9")); if (d3dcreate9) { ods("D3D9: Got %p for Direct3DCreate9", d3dcreate9); IDirect3D9 *id3d9 = d3dcreate9(D3D_SDK_VERSION); if (id3d9) { HookCreate(id3d9); id3d9->Release(); } else { ods("D3D9: Failed call to Direct3DCreate9"); } } else { ods("D3D9: Library without Direct3DCreate9?"); } pDirect3DCreate9Ex d3dcreate9ex = reinterpret_cast<pDirect3DCreate9Ex>(GetProcAddress(hD3D, "Direct3DCreate9Ex")); if (d3dcreate9ex) { ods("D3D9: Got %p for Direct3DCreate9Ex", d3dcreate9ex); IDirect3D9Ex** id3d9ex = 0; HRESULT hr = d3dcreate9ex(D3D_SDK_VERSION, id3d9ex); if (SUCCEEDED(hr)) { HookCreateEx(*id3d9ex); (*id3d9ex)->Release(); } else { switch (hr) { case D3DERR_OUTOFVIDEOMEMORY: ods("D3D11: Direct3DCreate9Ex returned with out of memory error."); break; case D3DERR_NOTAVAILABLE: ods("D3D11: Direct3DCreate9Ex is not available."); break; default: ods("D3D11: Unexpected return result from Direct3DCreate9Ex"); break; } } } } else { bHooked = false; } }
extern "C" __declspec(dllexport) void __cdecl PrepareD3D9() { if (! d3dd) return; ods("D3D9: Preparing static data for D3D9 Injection"); HMODULE hD3D = LoadLibrary("D3D9.DLL"); if (hD3D != NULL) { GetModuleFileNameW(hD3D, d3dd->wcFileName, ARRAY_NUM_ELEMENTS(d3dd->wcFileName)); std::string d3d9FnName("Direct3DCreate9"); pDirect3DCreate9 d3dcreate9 = reinterpret_cast<pDirect3DCreate9>(GetProcAddress(hD3D, d3d9FnName.c_str())); if (! d3dcreate9) { ods(("D3D9: Library without " + d3d9FnName).c_str()); } else { if (!IsFnInModule(reinterpret_cast<voidFunc>(d3dcreate9), d3dd->wcFileName, "D3D9", d3d9FnName)) { ods(("D3D9: " + d3d9FnName + " is not in D3D9 library").c_str()); } else { IDirect3D9 *id3d9 = d3dcreate9(D3D_SDK_VERSION); if (id3d9) { void ***vtbl = (void ***) id3d9; void *pCreate = (*vtbl)[VTABLE_OFFSET_ID3D_CREATEDEVICE]; if (!IsFnInModule(reinterpret_cast<voidFunc>(pCreate), d3dd->wcFileName, "D3D9", "CreateDevice")) { ods("D3D9: CreateDevice is not in D3D9 library"); } else { unsigned char *fn = reinterpret_cast<unsigned char *>(pCreate); unsigned char *base = reinterpret_cast<unsigned char *>(hD3D); d3dd->iOffsetCreate = fn - base; ods("D3D9: Successfully found prepatch offset: %p %p %p: %d", hD3D, d3dcreate9, pCreate, d3dd->iOffsetCreate); } id3d9->Release(); } } } std::string d3d9exFnName("Direct3DCreate9Ex"); pDirect3DCreate9Ex d3dcreate9ex = reinterpret_cast<pDirect3DCreate9Ex>(GetProcAddress(hD3D, d3d9exFnName.c_str())); if (! d3dcreate9ex) { ods(("D3D9: Library without " + d3d9exFnName).c_str()); } else { if (!IsFnInModule(reinterpret_cast<voidFunc>(d3dcreate9ex), d3dd->wcFileName, "D3D9", d3d9exFnName)) { ods(("D3D9: " + d3d9exFnName + " is not in D3D9 library").c_str()); } else { IDirect3D9Ex *id3d9 = NULL; d3dcreate9ex(D3D_SDK_VERSION, &id3d9); if (id3d9) { void ***vtbl = (void ***) id3d9; void *pCreateEx = (*vtbl)[VTABLE_OFFSET_ID3D_CREATEDEVICE_EX]; if (!IsFnInModule(reinterpret_cast<voidFunc>(pCreateEx), d3dd->wcFileName, "D3D9", "CreateDeviceEx")) { ods("D3D9: CreateDeviceEx is not in D3D9 library"); } else { unsigned char *fn = reinterpret_cast<unsigned char *>(pCreateEx); unsigned char *base = reinterpret_cast<unsigned char *>(hD3D); d3dd->iOffsetCreateEx = fn - base; ods("D3D9: Successfully found prepatch ex offset: %p %p %p: %d", hD3D, d3dcreate9ex, pCreateEx, d3dd->iOffsetCreateEx); } id3d9->Release(); } } } FreeLibrary(hD3D); } }
/// Prepares DXGI and D3D10 data by trying to determining the module filepath /// and function offsets in memory. /// (This data can later be used for hooking / code injection. /// /// Adjusts the data behind the global variables dxgi and d3d10. void PrepareDXGI10(IDXGIAdapter1 *pAdapter, bool initializeDXGIData) { if (!dxgi || !d3d10 || !pAdapter) return; ods("D3D10: Preparing static data for DXGI and D3D10 Injection"); d3d10->wcFileName[0] = 0; d3d10->iOffsetAddRef = 0; d3d10->iOffsetRelease = 0; HMODULE hD3D10 = LoadLibrary("D3D10.DLL"); if (hD3D10 != NULL) { HWND hwnd = CreateWindowW(L"STATIC", L"Mumble DXGI Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, 0, NULL, NULL, 0); D3D10CreateDeviceAndSwapChainType pD3D10CreateDeviceAndSwapChain = reinterpret_cast<D3D10CreateDeviceAndSwapChainType>(GetProcAddress(hD3D10, "D3D10CreateDeviceAndSwapChain")); DXGI_SWAP_CHAIN_DESC desc; ZeroMemory(&desc, sizeof(desc)); RECT rcWnd; GetClientRect(hwnd, &rcWnd); desc.BufferDesc.Width = rcWnd.right - rcWnd.left; desc.BufferDesc.Height = rcWnd.bottom - rcWnd.top; ods("D3D10: Got ClientRect W %d H %d", desc.BufferDesc.Width, desc.BufferDesc.Height); desc.BufferDesc.RefreshRate.Numerator = 60; desc.BufferDesc.RefreshRate.Denominator = 1; desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; desc.BufferDesc.Scaling = DXGI_MODE_SCALING_CENTERED; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; desc.BufferCount = 2; desc.OutputWindow = hwnd; desc.Windowed = true; desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; IDXGISwapChain *pSwapChain = NULL; ID3D10Device *pDevice = NULL; HRESULT hr = pD3D10CreateDeviceAndSwapChain(pAdapter, D3D10_DRIVER_TYPE_HARDWARE, NULL, 0, D3D10_SDK_VERSION, &desc, &pSwapChain, &pDevice); if (FAILED(hr)) ods("D3D10: pD3D10CreateDeviceAndSwapChain failure!"); if (pDevice && pSwapChain) { // For VC++ the vtable is located at the base addr. of the object and each function entry is a single pointer. Since p.e. the base classes // of IDXGISwapChain have a total of 8 functions the 8+Xth entry points to the Xth added function in the derived interface. void ***vtbl = (void ***) pSwapChain; void *pPresent = (*vtbl)[8]; int offset = GetFnOffsetInModule(reinterpret_cast<voidFunc>(pPresent), dxgi->wcFileName, ARRAY_NUM_ELEMENTS(dxgi->wcFileName), "D3D10", "Present"); if (offset >= 0) { if (initializeDXGIData) { dxgi->iOffsetPresent = offset; ods("D3D10: Successfully found Present offset: %ls: %d", dxgi->wcFileName, dxgi->iOffsetPresent); } else { if (dxgi->iOffsetPresent == offset) { ods("D3D10: Successfully verified Present offset: %ls: %d", dxgi->wcFileName, dxgi->iOffsetPresent); } else { ods("D3D10: Failed to verify Present offset for %ls. Found %d, but previously found %d.", dxgi->wcFileName, offset, dxgi->iOffsetPresent); } } } void *pResize = (*vtbl)[13]; offset = GetFnOffsetInModule(reinterpret_cast<voidFunc>(pResize), dxgi->wcFileName, ARRAY_NUM_ELEMENTS(dxgi->wcFileName), "D3D10", "ResizeBuffers"); if (offset >= 0) { if (initializeDXGIData) { dxgi->iOffsetResize = offset; ods("D3D10: Successfully found ResizeBuffers offset: %ls: %d", dxgi->wcFileName, dxgi->iOffsetResize); } else { if (dxgi->iOffsetResize == offset) { ods("D3D10: Successfully verified ResizeBuffers offset: %ls: %d", dxgi->wcFileName, dxgi->iOffsetResize); } else { ods("D3D10: Failed to verify ResizeBuffers offset for %ls. Found %d, but previously found %d.", dxgi->wcFileName, offset, dxgi->iOffsetResize); } } } vtbl = (void ***) pDevice; void *pAddRef = (*vtbl)[1]; offset = GetFnOffsetInModule(reinterpret_cast<voidFunc>(pAddRef), d3d10->wcFileName, ARRAY_NUM_ELEMENTS(d3d10->wcFileName), "D3D10", "AddRef"); if (offset >= 0) { d3d10->iOffsetAddRef = offset; ods("D3D10: Successfully found AddRef offset: %ls: %d", d3d10->wcFileName, d3d10->iOffsetAddRef); } void *pRelease = (*vtbl)[2]; offset = GetFnOffsetInModule(reinterpret_cast<voidFunc>(pRelease), d3d10->wcFileName, ARRAY_NUM_ELEMENTS(d3d10->wcFileName), "D3D10", "Release"); if (offset >= 0) { d3d10->iOffsetRelease = offset; ods("D3D10: Successfully found Release offset: %ls: %d", d3d10->wcFileName, d3d10->iOffsetRelease); } } if (pDevice) pDevice->Release(); if (pSwapChain) pSwapChain->Release(); DestroyWindow(hwnd); } else { FreeLibrary(hD3D10); } }
bool D11State::init() { HRESULT hr; ID3D11Texture2D* pBackBuffer = NULL; hr = pSwapChain->GetBuffer(0, __uuidof(*pBackBuffer), (LPVOID*)&pBackBuffer); if (FAILED(hr)) { ods("D3D11: pSwapChain->GetBuffer failure!"); return false; } hr = pDevice->CreateDeferredContext(0, &pDeviceContext); // Depending on the device settings a deferred context may not be createable // for example if it is a SINGLETHREADED device. // (See http://msdn.microsoft.com/en-us/library/windows/desktop/ff476505%28v=vs.85%29.aspx) // We handle the expected failure and failure fallback in the same way - // by trying to use an immediate context. if (FAILED(hr) || !pDeviceContext) { ods("D3D11: Failed to create DeferredContext (0x%x). Getting ImmediateContext", hr); pDevice->GetImmediateContext(&pDeviceContext); D11CreateStateBlock(pDeviceContext, &pOrigStateBlock); D11CreateStateBlock(pDeviceContext, &pMyStateBlock); pOrigStateBlock->Capture(); bDeferredContext = false; } else { bDeferredContext = true; } D3D11_TEXTURE2D_DESC backBufferSurfaceDesc; pBackBuffer->GetDesc(&backBufferSurfaceDesc); ZeroMemory(&vp, sizeof(vp)); vp.Width = static_cast<float>(backBufferSurfaceDesc.Width); vp.Height = static_cast<float>(backBufferSurfaceDesc.Height); vp.MinDepth = 0; vp.MaxDepth = 1; vp.TopLeftX = 0; vp.TopLeftY = 0; pDeviceContext->RSSetViewports(1, &vp); hr = pDevice->CreateRenderTargetView(pBackBuffer, NULL, &pRTV); if (FAILED(hr)) { ods("D3D11: pDevice->CreateRenderTargetView failed!"); return false; } pDeviceContext->OMSetRenderTargets(1, &pRTV, NULL); // Settings for an "over" operation. // https://en.wikipedia.org/w/index.php?title=Alpha_compositing&oldid=580659153#Description D3D11_BLEND_DESC blend; ZeroMemory(&blend, sizeof(blend)); blend.RenderTarget[0].BlendEnable = TRUE; blend.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; blend.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; blend.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; blend.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; blend.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; blend.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; blend.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; pDevice->CreateBlendState(&blend, &pBlendState); if (FAILED(hr)) { ods("D3D11: pDevice->CreateBlendState failed!"); return false; } pDeviceContext->OMSetBlendState(pBlendState, NULL, 0xffffffff); hr = pDevice->CreateVertexShader(g_vertex_shader, sizeof(g_vertex_shader), NULL, &pVertexShader); if (FAILED(hr)) { ods("D3D11: Failed to create vertex shader."); return false; } hr = pDevice->CreatePixelShader(g_pixel_shader, sizeof(g_pixel_shader), NULL, &pPixelShader); if (FAILED(hr)) { ods("D3D11: Failed to create pixel shader."); return false; } pTexture = NULL; pSRView = NULL; // Define the input layout D3D11_INPUT_ELEMENT_DESC layout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; hr = pDevice->CreateInputLayout(layout, ARRAY_NUM_ELEMENTS(layout), g_vertex_shader, sizeof(g_vertex_shader), &pVertexLayout); if (FAILED(hr)) { ods("D3D11: pDevice->CreateInputLayout failure!"); return false; } pDeviceContext->IASetInputLayout(pVertexLayout); D3D11_BUFFER_DESC bd; ZeroMemory(&bd, sizeof(bd)); bd.Usage = D3D11_USAGE_DYNAMIC; bd.ByteWidth = VERTEXBUFFER_SIZE; bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; bd.MiscFlags = 0; hr = pDevice->CreateBuffer(&bd, NULL, &pVertexBuffer); if (FAILED(hr)) { ods("D3D11: pDevice->CreateBuffer failure!"); return false; } DWORD indices[] = { 0,1,3, 1,2,3, }; ZeroMemory(&bd, sizeof(bd)); bd.Usage = D3D11_USAGE_IMMUTABLE; bd.ByteWidth = sizeof(DWORD) * 6; bd.BindFlags = D3D11_BIND_INDEX_BUFFER; bd.CPUAccessFlags = 0; bd.MiscFlags = 0; D3D11_SUBRESOURCE_DATA InitData; ZeroMemory(&InitData, sizeof(InitData)); InitData.pSysMem = indices; hr = pDevice->CreateBuffer(&bd, &InitData, &pIndexBuffer); if (FAILED(hr)) { ods("D3D11: pDevice->CreateBuffer failure!"); return false; } // Set index buffer pDeviceContext->IASetIndexBuffer(pIndexBuffer, DXGI_FORMAT_R32_UINT, 0); // Set primitive topology pDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); if (!bDeferredContext) { pMyStateBlock->Capture(); pOrigStateBlock->Apply(); } pBackBuffer->Release(); return true; }