Example #1
0
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;
}
Example #2
0
/// @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;
	}
}
Example #3
0
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);
}
Example #4
0
/// 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);
	}
}
Example #5
0
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;
}
Example #6
0
/// @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;
	}
}
Example #7
0
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;
	}
}
Example #8
0
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);
	}
}
Example #9
0
/// 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);
	}
}
Example #10
0
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;
}