示例#1
0
CEffectCreator::CEffectCreator (void) : m_pDamage(NULL)

//	CEffectCreator constructor

	{
	utlMemSet(m_CachedEvents, sizeof(m_CachedEvents), 0);
	}
示例#2
0
ALERROR CGenericWnd::Create (CNodeEditor *pEditor, HWND hParent, RECT *pRect)

//	Create
//
//	Create the new window

	{
	DWORD dwStyle;

	//	Register the class, if we haven't already

	if (!g_bRegistered)
		{
		WNDCLASS  wc;

		//	Register the class

		utlMemSet(&wc, sizeof(wc), 0);
		wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
		wc.lpfnWndProc = (WNDPROC)GenericWndProc;
		wc.hInstance = pEditor->GetTF()->GetInstance();
		wc.hCursor = LoadCursor(NULL, IDC_ARROW);
		wc.hbrBackground = GetStockObject(BLACK_BRUSH);
		wc.lpszClassName = g_szClassName;

		if (!RegisterClass(&wc))
			return ERR_FAIL;
		}

	//	Initialize this right away

	m_pEditor = pEditor;

	//	Now create the window

	dwStyle = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE;

	m_hWnd = CreateWindow(
			g_szClassName,
			"",
			dwStyle,
			pRect->left, pRect->top, RectWidth(pRect), RectHeight(pRect),
			hParent,
			(HMENU)1,
			pEditor->GetTF()->GetInstance(),
			this);
	if (m_hWnd == NULL)
		return ERR_FAIL;

	return NOERROR;
	}
示例#3
0
ALERROR CGroupOfGenerators::LoadFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc)

//	LoadFromXML
//
//	Load from XML

	{
	int i;
	ALERROR error;

	m_iCount = pDesc->GetContentElementCount();
	if (m_iCount > 0)
		{
		m_Table = new SEntry [m_iCount];
		utlMemSet(m_Table, sizeof(SEntry) * m_iCount, 0);

		for (i = 0; i < m_iCount; i++)
			{
			CXMLElement *pEntry = pDesc->GetContentElement(i);
			
			m_Table[i].iChance = pEntry->GetAttributeInteger(CHANCE_ATTRIB);
			if (m_Table[i].iChance == 0)
				m_Table[i].iChance = 100;

			CString sCount = pEntry->GetAttribute(COUNT_ATTRIB);
			if (sCount.IsBlank())
				m_Table[i].Count = DiceRange(0, 0, 1);
			else
				m_Table[i].Count.LoadFromXML(sCount);

			if (error = IItemGenerator::CreateFromXML(Ctx, pEntry, &m_Table[i].pItem))
				return error;
			}
		}
	else
		m_Table = NULL;

	return NOERROR;
	}
示例#4
0
bool IIOCPEntry::BeginWrite (const CString &sData, CString *retsError)

//	BeginWrite
//
//	Overlapped write on the given handle. Returns FALSE if we get an error.

	{
	//	Must be in the proper state

	HANDLE hHandle = GetCompletionHandle();
	if (hHandle == INVALID_HANDLE_VALUE
			|| m_iCurrentOp != opNone)
		{
		if (retsError) *retsError = ERR_INVALID_STATE;
		return false;
		}

	m_iCurrentOp = opWrite;
	m_dwOpStartTime = sysGetTickCount64();

	//	If we don't have a buffer, then we're done.

	IMemoryBlock *pBuffer = GetBuffer();
	if (pBuffer == NULL)
		{
		m_iCurrentOp = opNone;
		if (retsError) *retsError = ERR_INVALID_STATE;
		return false;
		}

	//	Initialize operation

	utlMemSet(&m_Overlapped, sizeof(m_Overlapped));

	//	Let our subclasses know (this also initializes the buffer)

	OnBeginWrite(sData);

	//	Write into the buffer

	DWORD lasterror = 0;
	if (!::WriteFile(hHandle,
			pBuffer->GetPointer(),
			pBuffer->GetLength(),
			NULL,
			&m_Overlapped))
		lasterror = GetLastError();

	//	If IO is pending or we succeeded, then nothing to do--we will get an
	//	event on the completion port.

	if (lasterror == ERROR_IO_PENDING
			|| lasterror == 0)
		return true;

	//	If another error or 0 bytes read, then we fail

	else
		{
		m_iCurrentOp = opNone;

		if (retsError)
			*retsError = strPattern(ERR_FILE_ERROR, lasterror);

		return false;
		}
	}
示例#5
0
bool IIOCPEntry::BeginConnection (const CString &sAddress, DWORD dwPort, CString *retsError)

//	BeginConnection
//
//	Overlapped connection to the given address.

	{
	//	Must be in the proper state

	HANDLE hHandle = GetCompletionHandle();
	if (hHandle == INVALID_HANDLE_VALUE
			|| m_iCurrentOp != opNone)
		{
		if (retsError) *retsError = ERR_INVALID_STATE;
		return false;
		}

	m_iCurrentOp = opConnect;
	m_dwOpStartTime = sysGetTickCount64();

	//	Bind the socket before passing to ConnectEx. For some reason the API
	//	does not do its own bind (probably so you can reuse sockets).

	SOCKADDR_IN LocalAddress;
	utlMemSet(&LocalAddress, sizeof(LocalAddress), 0);
	LocalAddress.sin_family = AF_INET;
	LocalAddress.sin_addr.s_addr = INADDR_ANY;
	LocalAddress.sin_port = 0;
	if (::bind((SOCKET)hHandle, (SOCKADDR *)&LocalAddress, sizeof(LocalAddress)) != 0)
		{
		m_iCurrentOp = opNone;
		if (retsError) *retsError = ERR_CANNOT_BIND;
		return false;
		}

	//	Get the ConnectEx pointer

	GUID guidConnectEx = WSAID_CONNECTEX;
	LPFN_CONNECTEX pfnConnectEx = NULL;
	DWORD dwBytes;
	if (::WSAIoctl((SOCKET)hHandle,
			SIO_GET_EXTENSION_FUNCTION_POINTER,
			&guidConnectEx,
			sizeof(guidConnectEx),
			&pfnConnectEx,
			sizeof(pfnConnectEx),
			&dwBytes,
			NULL,
			NULL) == SOCKET_ERROR)
		{
		m_iCurrentOp = opNone;
		if (retsError) *retsError = ERR_NOT_SUPPORTED;
		return false;
		}

	//	Compose the destination address

	SOCKADDR_IN Address;
	if (!CSocket::ComposeAddress(sAddress, dwPort, &Address))
		{
		m_iCurrentOp = opNone;
		if (retsError) *retsError = strPattern(ERR_INVALID_ADDRESS, sAddress, dwPort);
		return false;
		}

	//	Initialize operation

	utlMemSet(&m_Overlapped, sizeof(m_Overlapped));

	//	Connect

	DWORD lasterror = 0;
	if (!pfnConnectEx((SOCKET)hHandle,
			(SOCKADDR *)&Address,
			sizeof(Address),
			NULL,
			0,
			NULL,
			&m_Overlapped))
		lasterror = ::WSAGetLastError();

	//	If IO is pending or we succeeded, then nothing to do--we will get an
	//	event on the completion port.

	if (lasterror == ERROR_IO_PENDING 
			|| lasterror == 0)
		return true;

	//	If another error or 0 bytes read, then we fail

	else
		{
		m_iCurrentOp = opNone;

		if (retsError)
			*retsError = strPattern(ERR_FILE_ERROR, lasterror);

		return false;
		}
	}
示例#6
0
ALERROR CDataFile::Flush (void)

//	Flush
//
//	Flush the entry table and header

	{
	ALERROR error;

	//	If we're already flushing, don't bother. This can happens since
	//	We're using the normal WriteEntry call to write out the entry table.

	if (m_fFlushing)
		return NOERROR;

	m_fFlushing = TRUE;

	//	Write out the entry table, if necessary

	if (m_fEntryTableModified)
		{
		int i, iEntryTableSize;

		//	Make sure there's at least one free entry in the entry table
		//	Otherwise we might have to grow the entry table while trying to
		//	save it.

		for (i = 0; i < m_iEntryTableCount; i++)
			if (m_pEntryTable[i].dwBlock == FREE_ENTRY)
				break;

		if (i == m_iEntryTableCount)
			if (error = GrowEntryTable(NULL))
				goto Fail;

		//	Figure out how many blocks we need to hold the entry

		iEntryTableSize = m_iEntryTableCount * sizeof(ENTRYSTRUCT);

		//	Write out the entry table. Note that the act of writing the
		//	entry table may modify the entry table, so we first resize
		//	the entry.

		if (error = ResizeEntry(0, iEntryTableSize, NULL))
			goto Fail;

		//	Write the stuff

		if (error = WriteBlockChain(m_pEntryTable[0].dwBlock, (char *)m_pEntryTable, iEntryTableSize))
			goto Fail;

		m_fEntryTableModified = FALSE;
		m_fHeaderModified = TRUE;
		}

	//	Write out the header

	if (m_fHeaderModified)
		{
		HEADERSTRUCT header;
		DWORD dwWritten;

		utlMemSet(&header, sizeof(header), 0);
		header.dwSignature = DATAFILE_SIGNATURE;
		header.dwVersion = DATAFILE_VERSION;
		header.dwBlockCount = (DWORD)m_iBlockCount;
		header.dwBlockSize = (DWORD)m_iBlockSize;
		header.dwEntryTableCount = (DWORD)m_iEntryTableCount;
		header.dwEntryTablePos = sizeof(HEADERSTRUCT) + (m_pEntryTable[0].dwBlock * m_iBlockSize);
		header.dwDefaultEntry = (DWORD)m_iDefaultEntry;

		//	Position the file pointer

		if (SetFilePointer(m_hFile, 0, NULL, FILE_BEGIN) == 0xFFFFFFFF)
			{
			error = ERR_FAIL;
			goto Fail;
			}

		//	Write the header

		if (!WriteFile(m_hFile, &header, sizeof(header), &dwWritten, NULL) || dwWritten != sizeof(header))
			{
			error = ERR_FAIL;
			goto Fail;
			}

		m_fHeaderModified = FALSE;
		}

	m_fFlushing = FALSE;

	return NOERROR;

Fail:

	m_fFlushing = FALSE;

	return error;
	}
示例#7
0
ALERROR CDataFile::Create (const CString &sFilename,
							int iBlockSize,
							int iInitialEntries)

//	Create
//
//	Creates a new data file

	{
	ALERROR error;
	HEADERSTRUCT header;
	HANDLE hFile;
	DWORD dwWritten;
	int iEntryTableSize;
	ENTRYSTRUCT entry;
	int i;

	if (iBlockSize < DATAFILE_MINBLOCKSIZE)
		iBlockSize = DATAFILE_MINBLOCKSIZE;

	//	Create the file

	hFile = CreateFile(sFilename.GetASCIIZPointer(),
			GENERIC_READ | GENERIC_WRITE,
			FILE_SHARE_READ,
			NULL,
			CREATE_ALWAYS,
			FILE_ATTRIBUTE_NORMAL,
			NULL);
	if (hFile == INVALID_HANDLE_VALUE)
		{
		error = ERR_FAIL;
		goto Fail;
		}

	//	Figure out how big the entry table will be

	iEntryTableSize = (iInitialEntries + 1) * sizeof(ENTRYSTRUCT);

	//	Prepare the header

	utlMemSet(&header, sizeof(header), 0);
	header.dwSignature = DATAFILE_SIGNATURE;
	header.dwVersion = DATAFILE_VERSION;
	header.dwBlockCount = (iEntryTableSize / iBlockSize) + 1;
	header.dwBlockSize = (DWORD)iBlockSize;
	header.dwEntryTableCount = (DWORD)iInitialEntries + 1;
	header.dwEntryTablePos = sizeof(header);

	//	Write the header

	if (!WriteFile(hFile, &header, sizeof(header), &dwWritten, NULL) || dwWritten != sizeof(header))
		{
		error = ERR_FAIL;
		goto Fail;
		}

	//	Prepare the single entry that describes the entry table

	entry.dwBlock = 0;
	entry.dwBlockCount = header.dwBlockCount;
	entry.dwSize = (DWORD)iEntryTableSize;
	entry.dwVersion = 1;
	entry.dwPrevEntry = (DWORD)INVALID_ENTRY;
	entry.dwLatestEntry = (DWORD)INVALID_ENTRY;
	entry.dwFlags = 0;

	//	Write the entry

	if (!WriteFile(hFile, &entry, sizeof(entry), &dwWritten, NULL) || dwWritten != sizeof(entry))
		{
		error = ERR_FAIL;
		goto Fail;
		}

	//	Write the rest of the entries

	entry.dwBlock = FREE_ENTRY;
	entry.dwBlockCount = 0;
	entry.dwSize = 0;
	entry.dwVersion = 1;
	entry.dwPrevEntry = (DWORD)INVALID_ENTRY;
	entry.dwLatestEntry = (DWORD)INVALID_ENTRY;
	entry.dwFlags = 0;

	for (i = 0; i < iInitialEntries; i++)
		if (!WriteFile(hFile, &entry, sizeof(entry), &dwWritten, NULL) || dwWritten != sizeof(entry))
			{
			error = ERR_FAIL;
			goto Fail;
			}

	//	Done

	CloseHandle(hFile);

	return NOERROR;

Fail:

	if (hFile)
		{
		CloseHandle(hFile);
		DeleteFile(sFilename.GetASCIIZPointer());
		}

	return error;
	}
示例#8
0
ALERROR CGImageCache::ConvertToChannel (HBITMAP hTransparency, CGChannelStruct **retpTrans)

//	ConvertToChannel
//
//	Converts an 8-bit grayscale bitmap to a channel format

	{
	BITMAP bm;
	CGChannelStruct *pTrans;
	HDC hDC;
	BYTE bmibuffer[sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD)];
	BITMAPINFO *bmi = (BITMAPINFO *)bmibuffer;
	RGBQUAD *pColors = (RGBQUAD *)&bmi[1];

	//	Get some basic info about the bitmap

	GetObject(hTransparency, sizeof(BITMAP), &bm);

	//	Allocate a buffer

	pTrans = (CGChannelStruct *)MemAlloc(sizeof(CGChannelStruct) + bm.bmWidthBytes * bm.bmHeight);
	if (pTrans == NULL)
		return ERR_MEMORY;

	//	Initialize some stuff

	pTrans->cxWidthBytes = bm.bmWidthBytes;
	pTrans->cxWidth = bm.bmWidth;
	pTrans->cyHeight = bm.bmHeight;
	pTrans->pMap = (BYTE *)&pTrans[1];

	//	Create a BITMAPINFO structure describing how we want the bits
	//	to be returned to us

	utlMemSet(bmi, sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD), 0);
	bmi->bmiHeader.biSize = sizeof(BITMAPINFO);
	bmi->bmiHeader.biWidth = bm.bmWidth;
	bmi->bmiHeader.biHeight = -bm.bmHeight;	//	negative means top-down
	bmi->bmiHeader.biPlanes = 1;
	bmi->bmiHeader.biBitCount = 8;
	bmi->bmiHeader.biCompression = BI_RGB;

	hDC = CreateCompatibleDC(NULL);
	GetDIBits(hDC, hTransparency, 0, bm.bmHeight, pTrans->pMap, bmi, DIB_RGB_COLORS);
	DeleteDC(hDC);

	//	Color table

#if 0
	int i;
	for (i = 0; i < 256; i++)
		kernelDebugLogMessage("TEST: Color %d = %d,%d,%d",
				i,
				pColors[i].rgbRed,
				pColors[i].rgbGreen,
				pColors[i].rgbBlue);

	//	Convert from palette indeces to grayscale values

	for (i = 0; i < pTrans->cxWidthBytes * pTrans->cyHeight; i++)
		{
		if ((i % pTrans->cxWidthBytes) == 32)
			kernelDebugLogMessage("TEST: Color index %d", pTrans->pMap[i]);

		pTrans->pMap[i] = pColors[pTrans->pMap[i]].rgbBlue;
		}
#endif

	//	Done

	*retpTrans = pTrans;

	return NOERROR;
	}
示例#9
0
ALERROR CGImageCache::LoadBitmapImage (DWORD dwImageUNID, DWORD dwTransparencyUNID, DWORD dwDepthUNID, int *retiIndex)

//	LoadBitmapImage
//
//	Loads an image into the cache. This should only be called once
//	when the cache is initialized or when an image is first requested.

	{
	ALERROR error;
	HRESULT result;
	HBITMAP hBitmap;
	DDSURFACEDESC ddsd;
	BITMAP bm;
	LPDIRECTDRAWSURFACE7 pSurface;
	HDC hDC, hBitmapDC;
	HBITMAP hOldBitmap;
	HBITMAP hDepth;
	CGChannelStruct *pTrans = NULL;

	//	Load the bitmap from the image db

	if (error = m_pMediaDb->LoadBitmap(dwImageUNID, &hBitmap))
		return error;

	//	Get some info from bitmap

	GetObject(hBitmap, sizeof(bm), &bm);

	//	Create a surface of the proper size

	utlMemSet(&ddsd, sizeof(ddsd), 0);
	ddsd.dwSize = sizeof(ddsd);
	ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
	ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
	ddsd.dwWidth = bm.bmWidth;
	ddsd.dwHeight = bm.bmHeight;

	if (m_pScreen->GetDD()->CreateSurface(&ddsd, &pSurface, NULL) != DD_OK)
		{
		DeleteObject(hBitmap);
		return ERR_FAIL;
		}

	if (result = pSurface->GetDC(&hDC) != DD_OK)
		{
		pSurface->Release();
		DeleteObject(hBitmap);
		return ERR_FAIL;
		}

	//	Blt the bitmap onto the surface

	hBitmapDC = CreateCompatibleDC(NULL);
	hOldBitmap = (HBITMAP)SelectObject(hBitmapDC, hBitmap);

	BitBlt(hDC,
			0,
			0,
			bm.bmWidth,
			bm.bmHeight,
			hBitmapDC,
			0,
			0,
			SRCCOPY);

	SelectObject(hBitmapDC, hOldBitmap);
	DeleteDC(hBitmapDC);
	DeleteObject(hBitmap);

	pSurface->ReleaseDC(hDC);

	//	Load the transparency bitmap

	if (dwTransparencyUNID)
		{
		HBITMAP hTransparency;

		if (error = m_pMediaDb->LoadBitmap(dwTransparencyUNID, &hTransparency))
			{
			pSurface->Release();
			return error;
			}

		//	Convert this bitmap into an 8-bit map

		error = ConvertToChannel(hTransparency, &pTrans);
		DeleteObject(hTransparency);
		if (error)
			{
			pSurface->Release();
			return error;
			}
		}

	//	Load the depth bitmap

	if (dwDepthUNID)
		{
		if (error = m_pMediaDb->LoadBitmap(dwDepthUNID, &hDepth))
			{
			if (pTrans)
				MemFree(pTrans);
			pSurface->Release();
			return error;
			}
		}
	else
		hDepth = NULL;

	//	Add the surface to our cache

	if (error = AddImage(dwImageUNID, pSurface, pTrans, hDepth, retiIndex))
		{
		if (hDepth)
			DeleteObject(hDepth);
		if (pTrans)
			MemFree(pTrans);
		pSurface->Release();
		return ERR_FAIL;
		}

	return NOERROR;
	}
示例#10
0
ALERROR CUWindow::Boot (void)

//	Boot
//
//	Must be called after the window object is created

	{
	ALERROR error;
	DWORD dwStyle;
	int xPos, yPos, cxWidth, cyHeight;

	ASSERT(m_hWnd == NULL);

	//	Register the class, if we haven't already

	if (!g_bRegistered)
		{
		WNDCLASS  wc;

		//	Register the class

		utlMemSet(&wc, sizeof(wc), 0);
		wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
		wc.lpfnWndProc = (WNDPROC)CUWindowWndProc;
		wc.hInstance = m_pApp->GetInstance();
		wc.hIcon = LoadIcon(m_pApp->GetInstance(), m_pApp->GetIconRes());
		wc.hCursor = LoadCursor(NULL, IDC_ARROW);
		wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
		wc.lpszClassName = g_szClassName;

		if (!RegisterClass(&wc))
			return ERR_FAIL;
		}

	//	Figure out some initial parameters

	if (IsFullScreen())
		{
		dwStyle = WS_POPUP | WS_CLIPSIBLINGS;
		xPos = 0;
		yPos = 0;
		cxWidth = GetSystemMetrics(SM_CXSCREEN);
		cyHeight = GetSystemMetrics(SM_CYSCREEN);
		}
	else
		{
		dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS;
		xPos = CW_USEDEFAULT;
		yPos = 0;
		cxWidth = CW_USEDEFAULT;
		cyHeight = 0;
		}

	//	Create the actual window

	m_hWnd = CreateWindow(
			g_szClassName,
			"",
			dwStyle,
			xPos,
			yPos,
			cxWidth,
			cyHeight,
			NULL,
			(HMENU)NULL,
			m_pApp->GetInstance(),
			this);
	if (m_hWnd == NULL)
		return ERR_MEMORY;

	//	The main frame covers the entire

	if (error = CreateFrame(NULL, 0, 0, NULL, NULL))
		return error;

	return NOERROR;
	}
示例#11
0
ALERROR dibCreate16bitDIB (int cxWidth, int cyHeight, HBITMAP *rethBitmap, WORD **retpPixel)

//	dibCreate16bitDIB
//
//	Creates a DIB and returns a handle to it and a pointer to the bits.
//    
//	The format of the bits is an array of WORDs, one WORD for each pixel. 
//	The RGB values are stored as 5-6-5 bits. A single scan line is DWORD aligned.
//	The DIB is always top-down

	{
	ALERROR error;
	HBITMAP hBitmap = NULL;
	BITMAPINFO *pInfo = NULL;
	DWORD *pRGBMask;
	void *pBits;
	HDC hDC = NULL;
	BYTE Buffer[sizeof(BITMAPINFO) + 2 * sizeof(DWORD)];

	//	First we allocate a bitmapinfo structure, which consists
	//	of a structure followed by an array of color values. We need to allocate
	//	three color values, but we ask for 2 because BITMAPINFO includes the first

	pInfo = (BITMAPINFO *)Buffer;
	utlMemSet(pInfo, sizeof(BITMAPINFO), 0);

	pInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	pInfo->bmiHeader.biWidth = cxWidth;
	pInfo->bmiHeader.biHeight = cyHeight;
	pInfo->bmiHeader.biPlanes = 1;
	pInfo->bmiHeader.biBitCount = 16;
	pInfo->bmiHeader.biCompression = BI_BITFIELDS;

	//	Set up the masks that describe the RGB arrangement

	pRGBMask = (DWORD *)&pInfo->bmiColors[0];
	pRGBMask[0] = 0xF800;				//	red component
	pRGBMask[1] = 0x07E0;				//	green component
	pRGBMask[2] = 0x001F;				//	blue component

	hDC = CreateCompatibleDC(NULL);
	hBitmap = CreateDIBSection(hDC,
			pInfo,
			DIB_RGB_COLORS,
			&pBits,
			NULL,
			0);
	if (hBitmap == NULL)
		{
		error = GetLastError();
		goto Fail;
		}

	DeleteDC(hDC);
	hDC = NULL;

	if (retpPixel)
		*retpPixel = (WORD *)pBits;

	*rethBitmap = hBitmap;

	return NOERROR;

Fail:

	if (hBitmap)
		DeleteObject(hBitmap);

	if (hDC)
		DeleteDC(hDC);

	return error;
    }
示例#12
0
ALERROR dibCreate32bitDIB (int cxWidth, int cyHeight, DWORD dwFlags, HBITMAP *rethBitmap, DWORD **retpPixel)

//	dibCreate32bitDIB
//
//	Creates a DIB and returns a handle to it and a pointer to the bits.
//    
//	The format of the bits is an array of DWORDs, one DWORD for each pixel. 
//	The RGB values are stored as 8-8-8 bits. A single scan line is DWORD aligned.
//	The DIB is always bottom-up

	{
	ALERROR error;
	HBITMAP hBitmap = NULL;
	BITMAPINFO *pInfo = NULL;
	void *pBits;
	HDC hDC = NULL;
	BYTE Buffer[sizeof(BITMAPINFO) + 2 * sizeof(DWORD)];

	//	First we allocate a bitmapinfo structure, which consists
	//	of a structure followed by an array of color values. We need to allocate
	//	three color values, but we ask for 2 because BITMAPINFO includes the first

	pInfo = (BITMAPINFO *)Buffer;
	utlMemSet(pInfo, sizeof(BITMAPINFO), 0);

	pInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	pInfo->bmiHeader.biWidth = cxWidth;
	pInfo->bmiHeader.biHeight = cyHeight;
	pInfo->bmiHeader.biPlanes = 1;
	pInfo->bmiHeader.biBitCount = 32;
	pInfo->bmiHeader.biCompression = BI_RGB;

	//	Create the DIB section

	hDC = CreateCompatibleDC(NULL);
	hBitmap = CreateDIBSection(hDC,
			pInfo,
			DIB_RGB_COLORS,
			&pBits,
			NULL,
			0);
	if (hBitmap == NULL)
		{
		error = GetLastError();
		goto Fail;
		}

	DeleteDC(hDC);
	hDC = NULL;

	*retpPixel = (DWORD *)pBits;
	*rethBitmap = hBitmap;

	return NOERROR;

Fail:

	if (hBitmap)
		DeleteObject(hBitmap);

	if (hDC)
		DeleteDC(hDC);

	return error;
    }