I am having trouble setting the "default" page size for my document. I am using Visual C++ on Windows, with GDI calls (required for backward-compatibility).
So far my basic approach is to get a default DEVMODE, set the properties on it that I want, and then prompt the user if he wants to change it. But it seems to make no difference on the page size. It works on Orientation.
What am I doing wrong?
HDC GetPrinterDC () {
// Initialize device
PRINTDLG pd = {0};
pd.lStructSize = sizeof( pd );
pd.Flags = PD_RETURNDEFAULT;
PrintDlg(&pd);
// If device initialization failed, abort
if (pd.hDevMode == NULL) return NULL;
// Get the actual memory pointer
PDEVMODE dm = (PDEVMODE)GlobalLock(pd.hDevMode);
if (dm) {
// Set any properties that are specific for our document
if (dm->dmFields & DM_ORIENTATION)
dm->dmOrientation = DMORIENT_LANDSCAPE;
if (dm->dmFields & DM_PAPERSIZE)
dm->dmPaperSize = 0;
if (dm->dmFields & DM_PAPERLENGTH)
dm->dmPaperLength = 3302; // 13in
if (dm->dmFields & DM_PAPERWIDTH)
dm->dmPaperWidth = 4572; // 18in
GlobalUnlock(pd.hDevMode);
}
// Initialize a PRINTDLG structure.
pd.hwndOwner = GetForegroundWindow();
pd.Flags = PD_RETURNDC | PD_HIDEPRINTTOFILE | PD_DISABLEPRINTTOFILE | PD_NOPAGENUMS | PD_NOSELECTION | PD_USEDEVMODECOPIESANDCOLLATE ;
// Retrieve the printer DC
HDC hdc = NULL;
if (PrintDlg(&pd)) hdc = pd.hDC;
// Free the resources allocated
if (pd.hDevMode != NULL) GlobalFree(pd.hDevMode);
if (pd.hDevNames != NULL) GlobalFree(pd.hDevNames);
return hdc;
}
Apparently you can specify dmFields in the DEVMODE struct to be anything you want.
The code should look like this:
PDEVMODE dm = (PDEVMODE)GlobalLock(pd.hDevMode);
if (dm) {
// Set any properties that are specific for our document
dm->dmFields = dm->dmFields | DM_ORIENTATION | DM_PAPERSIZE
| DM_PAPERLENGTH | DM_PAPERWIDTH;
dm->dmOrientation = DMORIENT_LANDSCAPE;
dm->dmPaperSize = 0;
dm->dmPaperLength = 3302; // 13in
dm->dmPaperWidth = 4572; // 18in
GlobalUnlock(pd.hDevMode);
}
Related
In my app (MFC, C++) I have a button that creates a PDF file in a path.
Now I want to create another button that will print the pdf starting from the path and choosing some option like orientation and number of copies... but I'm not able to do that...
I saw that CPrintDialog shows the default dialog of the printer but I'm not able to attach the PDF file using the path.
I saw also the
ShellExecute(NULL, L"print", L"C:\\Documents\\1.pdf", NULL, NULL, SW_SHOWNORMAL);
that works but in this way I cannot choose any parameter...
How I can use the CPrintDialog to print an existing PDF that is in a path?
You have to use ShellExecuteEx and verb printto to get more control over printing:
SHELLEXECUTEINFO ShellInfo;
ZeroMemory(&ShellInfo, sizeof(SHELLEXECUTEINFO));
ShellInfo.cbSize = sizeof(SHELLEXECUTEINFO);
ShellInfo.lpVerb = L"printto";
ShellInfo.lpFile = L"C:\\Documents\\1.pdf";
ShellInfo.lpParameters = szPrinter;
ShellInfo.nShow = SW_SHOWNORMAL;
ShellInfo.fMask = SEE_MASK_FLAG_DDEWAIT | SEE_MASK_NOCLOSEPROCESS;
if(::ShellExecuteEx(&ShellInfo))
{
if((int)ShellInfo.hInstApp > 32)
{
if(ShellInfo.hProcess != NULL)
{
DWORD dwExitCode = STILL_ACTIVE;
while(dwExitCode == STILL_ACTIVE)
{
if(!::GetExitCodeProcess(ShellInfo.hProcess, &dwExitCode))
{
dwExitCode = 0;
}
}
::CloseHandle(ShellInfo.hProcess);
}
}
}
To get the printer name:
CPrintDialog dlg(TRUE);
if (dlg.DoModal() == IDOK)
{
CString sPrinterName = dlg.GetDeviceName();
}
I have solved with a workaround. Instead of use the ShellExecute, I draw all the thing that I want to print using a CDC object attached to the hDC of a CPrintDialog class. Rember to manage the size of the draw depending on printer DPI like here.
A snippet only to have an idea:
CPrintDialog printDialog(FALSE);
printDialog.GetDefaults();
printDialog.m_pd.Flags &= ~PD_RETURNDEFAULT;
DEVMODE* pDevMode = printDialog.GetDevMode();
pDevMode->dmFields = DM_ORIENTATION | DM_PAPERSIZE | DM_PRINTQUALITY ;
pDevMode->dmOrientation = DMORIENT_LANDSCAPE;
pDevMode->dmPaperSize = DMPAPER_A4;
::GlobalUnlock(printDialog.m_pd.hDevMode);
if (printDialog.DoModal() == IDOK)
{
CDC* pDC = new CDC;
pDC->Attach(printDialog.m_pd.hDC);
pDCPDF->StartDoc(_T(""));
pDCPDF->StartPage();
// ...
//draw what you want
// ...
pDCPDF->EndPage();
pDCPDF->EndDoc(); //this starts the printer
pDCPDF->DeleteDC();
}
Hope to reach soon the reputation of 15 to vote the answer of other questions.
Thanks to Andrew Komiagin answers.
INTRODUCTION AND RELEVANT INFORMATION:
I am trying to learn to print with XPS Document API.
For a simple start, I have decided to draw a rectangle, and some text below it.
After going through the official examples I was able to achieve my goal.
PROBLEM:
Basically, I have concatenated 2 code examples provided from the above link. Now I wanted to polish the code, mainly to use single brush to draw both rectangle and the text.
After rewriting the code, I get the following error:
First-chance exception at 0x7555D3CF in XPS printing.exe: Microsoft C++ exception: SplException::THResultException at memory location 0x002CEF9C.
If there is a handler for this exception, the program may be safely continued.
SSCCEE:
Below is the function I rewrote. I have marked the crashing point with the appropriate comments.
void XPS_TEST()
{
IXpsOMObjectFactory *xpsFactory;
HRESULT hr = S_OK;
// Init COM for this thread if it hasn't
// been initialized, yet.
hr = CoInitializeEx(0, COINIT_MULTITHREADED);
hr = CoCreateInstance(
__uuidof(XpsOMObjectFactory),
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IXpsOMObjectFactory),
reinterpret_cast<LPVOID*>(&xpsFactory));
if (SUCCEEDED(hr))
{
// Declare the variables used in this section.
IOpcPartUri *opcPartUri = NULL;
IXpsOMPackage *xpsPackage = NULL;
IXpsOMDocumentSequence *xpsFDS = NULL;
IXpsOMDocumentCollection *fixedDocuments = NULL;
IXpsOMDocument *xpsFD = NULL;
IXpsOMPage *xpsPage = NULL;
IXpsOMPageReferenceCollection *pageRefs = NULL;
IXpsOMPageReference *xpsPageRef = NULL;
// test size of the document
XPS_SIZE pageSize = { 200, 200 };
// Create the package.
hr = xpsFactory->CreatePackage(&xpsPackage);
// Create the URI for the fixed document sequence part and then
// create the fixed document sequence
hr = xpsFactory->CreatePartUri(
L"/FixedDocumentSequence.fdseq", &opcPartUri);
hr = xpsFactory->CreateDocumentSequence(opcPartUri, &xpsFDS);
// Release this URI to reuse the interface pointer.
if (NULL != opcPartUri) { opcPartUri->Release(); opcPartUri = NULL; }
// Create the URI for the document part and then create the document.
hr = xpsFactory->CreatePartUri(
L"/Documents/1/FixedDocument.fdoc", &opcPartUri);
hr = xpsFactory->CreateDocument(opcPartUri, &xpsFD);
// Release this URI to reuse the interface pointer.
if (NULL != opcPartUri) { opcPartUri->Release(); opcPartUri = NULL; }
// Create a blank page.
hr = xpsFactory->CreatePartUri(
L"/Documents/1/Pages/1.fpage", &opcPartUri);
hr = xpsFactory->CreatePage(
&pageSize, // Page size
L"en-US", // Page language
opcPartUri, // Page part name
&xpsPage);
// Release this URI to reuse the interface pointer.
if (NULL != opcPartUri) { opcPartUri->Release(); opcPartUri = NULL; }
// Create a page reference for the page.
hr = xpsFactory->CreatePageReference(&pageSize, &xpsPageRef);
// Add the fixed document sequence to the package.
hr = xpsPackage->SetDocumentSequence(xpsFDS);
// Get the document collection of the fixed document sequence
// and then add the document to the collection.
hr = xpsFDS->GetDocuments(&fixedDocuments);
hr = fixedDocuments->Append(xpsFD);
// Get the page reference collection from the document
// and add the page reference and blank page.
hr = xpsFD->GetPageReferences(&pageRefs);
hr = pageRefs->Append(xpsPageRef);
hr = xpsPageRef->SetPage(xpsPage);
//======================== draw rectangle ====================//
XPS_COLOR xpsColor;
IXpsOMSolidColorBrush *xpsFillBrush = NULL;
// the brush I want to reuse !!
IXpsOMSolidColorBrush *xpsStrokeBrush = NULL;
// Set the fill brush color to RED.
xpsColor.colorType = XPS_COLOR_TYPE_SRGB;
xpsColor.value.sRGB.alpha = 0xFF;
xpsColor.value.sRGB.red = 0xFF;
xpsColor.value.sRGB.green = 0x00;
xpsColor.value.sRGB.blue = 0x00;
// Use the object factory to create the brush.
hr = xpsFactory->CreateSolidColorBrush(
&xpsColor,
NULL, // color profile resource
&xpsFillBrush);
// The color profile resource parameter is NULL because
// this color type does not use a color profile resource.
// Set the stroke brush color to BLACK.
xpsColor.colorType = XPS_COLOR_TYPE_SRGB;
xpsColor.value.sRGB.alpha = 0xFF;
xpsColor.value.sRGB.red = 0x00;
xpsColor.value.sRGB.green = 0x00;
xpsColor.value.sRGB.blue = 0x00;
// Use the object factory to create the brush.
hr = xpsFactory->CreateSolidColorBrush(
&xpsColor,
NULL, // This color type does not use a color profile resource.
&xpsStrokeBrush);
// test rectangle
XPS_RECT rect = { 0, 0, 200, 20 };
IXpsOMGeometryFigure *rectFigure;
IXpsOMGeometry *imageRectGeometry;
IXpsOMGeometryFigureCollection *geomFigureCollection;
// Define the start point and create an empty figure.
XPS_POINT origin = { rect.x, rect.y };
hr = xpsFactory->CreateGeometryFigure(&origin, &rectFigure);
// Define the segments of the geometry figure.
// First, define the type of each segment.
XPS_SEGMENT_TYPE segmentTypes[3] =
{
XPS_SEGMENT_TYPE_LINE, // each segment is a straight line
XPS_SEGMENT_TYPE_LINE,
XPS_SEGMENT_TYPE_LINE
};
// Define the x and y coordinates of each corner of the figure
// the start point has already been defined so only the
// remaining three corners need to be defined.
FLOAT segmentData[6] =
{
rect.x, (rect.y + rect.height),
(rect.x + rect.width), (rect.y + rect.height),
(rect.x + rect.width), rect.y
};
// Describe if the segments are stroked (that is if the segment lines
// should be drawn as a line).
BOOL segmentStrokes[3] =
{
TRUE, TRUE, TRUE // Yes, draw each of the segment lines.
};
// Add the segment data to the figure.
hr = rectFigure->SetSegments(
3,
6,
segmentTypes,
segmentData,
segmentStrokes);
// Set the closed and filled properties of the figure.
hr = rectFigure->SetIsClosed(TRUE);
hr = rectFigure->SetIsFilled(TRUE);
// Create the geometry object.
hr = xpsFactory->CreateGeometry(&imageRectGeometry);
// Get a pointer to the figure collection interface of the geometry...
hr = imageRectGeometry->GetFigures(&geomFigureCollection);
// ...and then add the figure created above to this geometry.
hr = geomFigureCollection->Append(rectFigure);
// If not needed for anything else, release the rectangle figure.
rectFigure->Release();
// when done adding figures, release the figure collection.
geomFigureCollection->Release();
IXpsOMPath *rectPath = NULL;
IXpsOMVisualCollection *pageVisuals = NULL;
// Create the new path object.
hr = xpsFactory->CreatePath(&rectPath);
// Add the geometry to the path.
// imageRectGeometry is initialized outside of this example.
hr = rectPath->SetGeometryLocal(imageRectGeometry);
// Set the short description of the path to provide
// a textual description of the object for accessibility.
hr = rectPath->SetAccessibilityShortDescription(L"Red Rectangle");
// Set the fill and stroke brushes to use the brushes
// created in the first section.
hr = rectPath->SetFillBrushLocal(xpsFillBrush);
hr = rectPath->SetStrokeBrushLocal(xpsStrokeBrush);
// Get the visual collection of this page and add this path to it.
hr = xpsPage->GetVisuals(&pageVisuals);
hr = pageVisuals->Append(rectPath);
// If not needed for anything else, release the rectangle path.
rectPath->Release();
// When finished with the brushes, release the interface pointers.
if (NULL != xpsFillBrush) xpsFillBrush->Release();
//******************** I have commented out below code, ****************//
//******************** because I plan to use the brush to draw text ****//
//if (NULL != xpsStrokeBrush) xpsStrokeBrush->Release();
// When done with the geometry interface, release it.
imageRectGeometry->Release();
//========================= draw text =====================//
GUID fontNameGuid;
WCHAR guidString[128] = { 0 };
WCHAR uriString[256] = { 0 };
IStream *fontStream = NULL;
IOpcPartUri *fontUri = NULL;
IXpsOMFontResource *fontResource = NULL;
// Create font stream.
hr = xpsFactory->CreateReadOnlyStreamOnFile(
// I have hardcoded Arial here, just for testing
L"C:\\Windows\\Fonts\\Arial.ttf",
&fontStream);
// Create new obfuscated part name for this resource using a GUID.
hr = CoCreateGuid(&fontNameGuid);
hr = StringFromGUID2(
fontNameGuid,
guidString,
ARRAYSIZE(guidString));
// Create a URI string for this font resource that will place
// the font part in the /Resources/Fonts folder of the package.
wcscpy_s(uriString, ARRAYSIZE(uriString), L"/Resources/Fonts/");
// Create the part name using the GUID string as the name and
// ".odttf" as the extension GUID string start and ends with
// curly braces so they are removed.
wcsncat_s(uriString, ARRAYSIZE(uriString),
guidString + 1, wcslen(guidString) - 2);
wcscat_s(uriString, ARRAYSIZE(uriString), L".odttf");
// Create the font URI interface.
hr = xpsFactory->CreatePartUri(
uriString,
&fontUri);
// Create the font resource.
hr = xpsFactory->CreateFontResource(
fontStream,
XPS_FONT_EMBEDDING_OBFUSCATED,
fontUri,
FALSE, // isObfSourceStream
&fontResource);
if (NULL != fontUri) fontUri->Release();
LPCWSTR unicodeString = L"Test string";
// move test string below our rectangle
origin.y += 30.0f;
FLOAT fontEmSize = 7.56f;
IXpsOMGlyphsEditor *glyphsEditor = NULL;
IXpsOMGlyphs *xpsGlyphs = NULL;
// Create a new Glyphs object and set its properties.
hr = xpsFactory->CreateGlyphs(fontResource, &xpsGlyphs);
hr = xpsGlyphs->SetOrigin(&origin);
hr = xpsGlyphs->SetFontRenderingEmSize(fontEmSize);
//*************** I GET A CRASH BELOW !!!! ***************//
hr = xpsGlyphs->SetFillBrushLocal(xpsStrokeBrush); // <<---
// Some properties are inter-dependent so they
// must be changed by using a GlyphsEditor.
hr = xpsGlyphs->GetGlyphsEditor(&glyphsEditor);
hr = glyphsEditor->SetUnicodeString(unicodeString);
hr = glyphsEditor->ApplyEdits();
// Add the new Glyphs object to the page
hr = pageVisuals->Append(xpsGlyphs);
// Release interface pointers.
if (NULL != xpsGlyphs) xpsGlyphs->Release();
if (NULL != glyphsEditor) glyphsEditor->Release();
if (NULL != pageVisuals) pageVisuals->Release();
//******************** Releasing the brush here *******//
if (NULL != xpsStrokeBrush) xpsStrokeBrush->Release();
//========================= write to file ====================//
hr = xpsPackage->WriteToFile(
L"C:\\Users\\Smiljkovic\\Desktop\\xpsTest.xps",
NULL, // LPSECURITY_ATTRIBUTES
FILE_ATTRIBUTE_NORMAL,
FALSE); // Optimize Markup Size
//========================== cleanup ==================//
// Release interface pointer
if (NULL != xpsPage) xpsPage->Release();
if (NULL != pageRefs) pageRefs->Release();
if (NULL != fixedDocuments) fixedDocuments->Release();
if (NULL != xpsPageRef) xpsPageRef->Release();
if (NULL != xpsFD) xpsFD->Release();
if (NULL != xpsFDS) xpsFDS->Release();
if (NULL != xpsPackage) xpsPackage->Release();
xpsFactory->Release();
}
// Uninitialize COM when finished
CoUninitialize();
}
QUESTION:
How can I use the same brush ( xpsStrokeBrush from the above example ) for drawing both the text and the rectangle outline?
per SetStrokeBrushLocal documentation:
After you call SetStrokeBrushLocal, the stroke brush lookup key is released and GetStrokeBrushLookup returns a NULL pointer in the lookup parameter.
You could use Clone on the brush before using it.
But, if you plan on re-using brushes, then use the CreateDictionary, SetDictionaryLocal and then Append your brush there; which will let you use SetFillBrushLookup.
I already created treeview where I can add some items. Basicly I want to tree-view all directories and files with icons associated to them.
So I have these functions:
Adding items to treeview
HTREEITEM AddItemToTree(HWND hwndTree, char *text, int nLevel)
{
TVINSERTSTRUCT tvins;
static HTREEITEM hPrev = (HTREEITEM)TVI_FIRST;
static HTREEITEM hRootItem = NULL;
static HTREEITEM hPrevLev2Item = NULL;
AddIconToTree(hwndTree, text); //////////// THIS IS THE FUNCTION BELOW...
tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIS_STATEIMAGEMASK;
tvi.iImage = 0;
tvi.iSelectedImage = 0;
tvi.pszText = GetFileNameFromPath(text);
tvins.hInsertAfter = hPrev;
tvins.item = tvi;
if(nLevel == 1)
{
tvins.hParent = TVI_ROOT;
}
else if(nLevel == 2)
{
tvins.hParent = hRootItem;
}
else
{
TVITEM tviSetup;
tviSetup.hItem = hPrev;
tviSetup.mask = TVIF_PARAM;
TVITEM * tviLocal = &tviSetup;
TreeView_GetItem(hwndTree, tviLocal);
if(nLevel > tviLocal->lParam)
{
tvins.hParent = hPrev;
}
else
{
HTREEITEM hPrevLocal = TreeView_GetParent(hwndTree, hPrev);
tviLocal->hItem = hPrevLocal;
TreeView_GetItem(hwndTree, tviLocal);
for(int i = nLevel; i <= tviLocal->lParam;)
{
HTREEITEM hPrevLocalTemp = TreeView_GetParent(hwndTree, hPrevLocal);
hPrevLocal = hPrevLocalTemp;
tviLocal->hItem = hPrevLocal;
TreeView_GetItem(hwndTree, tviLocal);
}
tviLocal->mask = TVIF_TEXT;
TreeView_GetItem(hwndTree, tviLocal);
tvins.hParent = hPrevLocal;
}
}
hPrev = (HTREEITEM)SendMessage(hwndTree, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins);
if(hPrev == 0)
{
return false;
}
if(nLevel == 1)
{
hRootItem = hPrev;
}
return hPrev;
}
ADDING ICONS TO TREEVIEW:
int AddIconToTree(HWND hwndTree, char *strPath)
{
SHFILEINFO sfi;
memset(&sfi, 0, sizeof(sfi));
SHGetFileInfo(strPath, FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_USEFILEATTRIBUTES | SHGFI_SMALLICON);
int index = sfi.iIcon;
ICONINFO iconinfo;
GetIconInfo(sfi.hIcon, &iconinfo);
HBITMAP hBitmap = iconinfo.hbmColor;
DestroyIcon(sfi.hIcon);
himg = ImageList_Create(16, 16, ILC_COLOR32, 1, 1);
int iImageList = ImageList_Add(himg, hBitmap, NULL);
DeleteObject(hBitmap);
//TreeView_SetImageList(hwndTree, himg, TVSIL_NORMAL);
SendMessage(hwndTree, TVM_SETIMAGELIST, (WPARAM)TVSIL_NORMAL, (LPARAM)(HIMAGELIST)himg);
MessageBox(hwnd, strPath, "Path:", MB_OK); /* Because of this msgbox I found out what is
really happening, because without it everything I have seen when I run the program was
treeview with icon of the last file, which was folder...So blank icon.*/
return index;
}
My main problem is, that when I'm setting some icon, it is set not only for the one item as I'm expecting, but on all items in treeview. So basicly every item's icon is overwritten by new item's icon. By the way I know that if I want to get icon of folder, I need to use FILE_ATTRIBUTE_DIRECTORY...
So that's it.
Any help would be greatly appriciated!
Thank You in advance :-)
In your AddIconToTree function you're creating a brand new image list every time, which will only ever have one icon in it. You need to maintain the same image list and add additional icons to it rather than re-creating it for every item.
Alternatively, you can get a handle to the shell imagelist with the SHGetImageList function and then assign it to the tree directly. If you don't need to add any of your own images to the tree's image list this is a much easier way of displaying system icons for files and folders as the shell imagelist handles all that for you.
// To initialise the tree's image list - do this one time only
HIMAGELIST himg;
if (SUCCEEDED(SHGetImageList(SHIL_SMALL, IID_IImageList, reinterpret_cast<void**>(&himg))))
SendMessage(hwndTree, TVM_SETIMAGELIST, (WPARAM)TVSIL_NORMAL, (LPARAM)himg);
Then your AddIconToTree function simply becomes:
int AddIconToTree(HWND hwndTree, char *strPath)
{
SHFILEINFO sfi;
memset(&sfi, 0, sizeof(sfi));
// SHGFI_SYSICONINDEX will return the icon's index within the shell image list
SHGetFileInfo(strPath, FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(sfi),
SHGFI_SYSICONINDEX | SHGFI_USEFILEATTRIBUTES);
return sfi.iIcon;
}
And when you actually add items to the list, make sure you assign the index to the item:
tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIS_STATEIMAGEMASK;
tvi.iImage = tvi.iSelectedImage = AddIconToTree(hwndTree, text);
Sometimes, not all the time... when creating a D3D device, I get the error code D3DERR_DRIVERINVALIDCAL and then other times I get S_OK.
I've been stuck on this issue for the past 3 days, going on number 4.
Looking at the documentation on this error code, it describes it as not used, which is very confusing.
Can anybody shed some light?
HRESULT hr = S_OK;
HWND hwnd = NULL;
HMONITOR hMonitor = NULL;
UINT uAdapterID = D3DADAPTER_DEFAULT;
DWORD vp = 0;
D3DCAPS9 ddCaps;
ZeroMemory(&ddCaps, sizeof(ddCaps));
IDirect3DDevice9* pDevice = NULL;
// Hold the lock because we might be discarding an exisiting device.
AutoLock lock(m_ObjectLock);
if (!m_pD3D9 || !m_pDeviceManager)
{
return MF_E_NOT_INITIALIZED;
}
hwnd = GetDesktopWindow();
// Note: The presenter creates additional swap chains to present the
// video frames. Therefore, it does not use the device's implicit
// swap chain, so the size of the back buffer here is 1 x 1.
D3DPRESENT_PARAMETERS pp;
ZeroMemory(&pp, sizeof(pp));
pp.BackBufferWidth = 1;
pp.BackBufferHeight = 1;
pp.Windowed = TRUE;
pp.SwapEffect = D3DSWAPEFFECT_COPY;
pp.BackBufferFormat = D3DFMT_UNKNOWN;
pp.hDeviceWindow = hwnd;
pp.Flags = D3DPRESENTFLAG_VIDEO;
pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
// Find the monitor for this window.
if (m_hwnd)
{
hMonitor = MonitorFromWindow(m_hwnd, MONITOR_DEFAULTTONEAREST);
// Find the corresponding adapter.
CHECK_HR(hr = FindAdapter(m_pD3D9, hMonitor, &uAdapterID));
}
// Get the device caps for this adapter.
CHECK_HR(hr = m_pD3D9->GetDeviceCaps(uAdapterID, D3DDEVTYPE_HAL, &ddCaps));
if(ddCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
{
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
}
else
{
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}
IDirect3DDevice9Ex * pDeviceEx;
// Create the device.
CHECK_HR(hr = m_pD3D9->CreateDeviceEx(uAdapterID,
D3DDEVTYPE_HAL,
pp.hDeviceWindow,
vp | D3DCREATE_NOWINDOWCHANGES | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE,
&pp,
NULL,
&pDeviceEx));
UPDATE
wrapping CreateDeviceEx in a while loop until it does equal S_OK will eventually work... but what can cause this to happen in the first place?
I'm currently having issues displaying a monochrome bitmap to my form. I belive that somehow I am setting up my bitmap incorrectly, but I can't see where that would be at the moment. All I have to do to "fix" this issue is set the biBitCount to 24, but then when I call DWORD d = GetCharacterPlacementA latter on I'm seeing corrupted memory latter on. So I'm trying to keep my original desire for a monochrome bitmap and not leak memory.
Currently I'm storing my bitmap information in the standard variables:
BITMAPINFO bi24BitInfo;
HDC hMemoryDC;
HBITMAP hMemoryBitmap;
HGDIOBJ hDefaultBitmap;
HBITMAP hGdiBitmap;
This is how I am setting up the bitmap:
hMemoryDC = CreateCompatibleDC(NULL);
bi24BitInfo.bmiHeader.biSize = sizeof(bi24BitInfo.bmiHeader); // size of this struct
bi24BitInfo.bmiHeader.biWidth = 600;//sizeRect.cx; // width of window
bi24BitInfo.bmiHeader.biHeight = 600;//sizeRect.cy; // height of window
bi24BitInfo.bmiHeader.biPlanes = 1;
bi24BitInfo.bmiHeader.biBitCount = 1; // monochrome // rgb 8 bytes for each component(3)
bi24BitInfo.bmiHeader.biCompression = BI_RGB; // Means its uncompressed. Has nothing to do with color.
bi24BitInfo.bmiHeader.biSizeImage = 0;
bi24BitInfo.bmiHeader.biXPelsPerMeter = pelsPerMeter;
bi24BitInfo.bmiHeader.biYPelsPerMeter = pelsPerMeter;
bi24BitInfo.bmiHeader.biClrUsed = 2;
bi24BitInfo.bmiHeader.biClrImportant = 0;
bi24BitInfo.bmiColors[0].rgbBlue = 0;
bi24BitInfo.bmiColors[0].rgbRed = 0;
bi24BitInfo.bmiColors[0].rgbGreen = 0;
bi24BitInfo.bmiColors[0].rgbReserved = 0;
bi24BitInfo.bmiColors[1].rgbBlue = (BYTE)0xFF;
bi24BitInfo.bmiColors[1].rgbRed = (BYTE)0xFF;
bi24BitInfo.bmiColors[1].rgbGreen = (BYTE)0xFF;
bi24BitInfo.bmiColors[1].rgbReserved = 0;
// Create the memory bitmap
if (hMemoryBitmap != NULL)
{
DeleteObject(hMemoryBitmap);
}
hMemoryBitmap = CreateCompatibleBitmap(hMemoryDC, 600, 600);
hDefaultBitmap = SelectObject(hMemoryDC, hMemoryBitmap);
HGDIOBJ hOldFont = SelectObject(hMemoryDC, GetStockObject(NULL_BRUSH));
// Do not fill background
int nOldBkMode = GetBkMode(hMemoryDC);
SetBkMode(hMemoryDC, TRANSPARENT);
int nRet(0);
if (hDIB != NULL)
{
GlobalFree(hDIB);
}
DWORD dwBmpSize = ((bi24BitInfo.bmiHeader.biWidth * bi24BitInfo.bmiHeader.biBitCount + 31) / 32) * 4 * bi24BitInfo.bmiHeader.biHeight;
//DWORD dwBmpSize = ((bi24BitInfo.bmiHeader.biWidth * bi24BitInfo.bmiHeader.biHeight)/8);
// Starting with 32-bit Windows, GlobalAlloc and LocalAlloc are implemented as wrapper functions that call HeapAlloc using a handle
// to the process's default heap. Therefore, GlobalAlloc and LocalAlloc have greater overhead than HeapAlloc.
hDIB = GlobalAlloc(GHND, dwBmpSize);
DWORD D = GetLastError();
pBytes = (BYTE*)GlobalLock(hDIB);
D = GetLastError();
nRet = GetDIBits(hMemoryDC, hMemoryBitmap, 0, (UINT)bi24BitInfo.bmiHeader.biHeight, pBytes, (BITMAPINFO*)&bi24BitInfo, DIB_RGB_COLORS);
D = GetLastError();
if (pBitmap != NULL)
{
delete pBitmap;
pBitmap = NULL;
}
pBitmap = new Gdiplus::Bitmap(&bi24BitInfo, pBytes);
D = GetLastError();
GlobalUnlock(hDIB);
D = GetLastError();
Then after all of this I'm getting an error in the following:
pGraphics = Graphics::FromImage(pBitmap);
// set a graphics property
s = pGraphics->SetTextRenderingHint(TextRenderingHintAntiAlias);
After this pGraphics->LastResult is now set to "OutOfMemory" and s is set to the enum "InvalidParameter" from: http://msdn.microsoft.com/en-us/library/ms534175(v=VS.85).aspx
Any help on this would be appriciated.
BITMAPINFO only contains room for one palette entry; when you write to bi24BitInfo.bmiColors[1] you're clobbering the memory that follows, likely the hMemoryDC. Fix this by creating another structure that contains BITMAPINFO at the front and an array for the palette following.
Edit: It appears you aren't able to create a Graphics object from a monochrome bitmap. From the Graphics::FromImage documentation:
This method also fails if the image
has one of the following pixel
formats:
PixelFormatUndefined
PixelFormatDontCare
PixelFormat1bppIndexed
PixelFormat4bppIndexed
PixelFormat8bppIndexed
PixelFormat16bppGrayScale
PixelFormat16bppARGB1555