Windows change system resolution c++ - windows

I am trying to change system resolution programatically. What I need to achieve is set system resolution to maximum value.
Below is code the code which change the screen resolution to maximum available value.
DEVMODE devmode = { 0 };
int i=0;
QList<int>widths;
QList<int>heights;
while (1) {
if(EnumDisplaySettings( NULL,i, &devmode )!=true)
break;
widths.append(devmode.dmPelsWidth);
heights.append(devmode.dmPelsHeight);
qDebug()<<devmode.dmPelsWidth<<" X "<<devmode.dmPelsHeight;
i++;
}
EnumDisplaySettings( NULL,ENUM_CURRENT_SETTINGS, &devmode );
devmode.dmSize = sizeof(DEVMODE);
devmode.dmPelsWidth = widths.at(widths.size()-1); //take last item maximum value
devmode.dmPelsHeight = heights.at(widths.size()-1); //take last item maximum value
long result = ChangeDisplaySettings(&devmode, DM_PELSWIDTH || DM_PELSHEIGHT);
And it works fine when,
When the system resolution is maximum(1920x1080) I change to the same value.
When the system resolution is higher and I am changed to lower value.
But it doesn't work when I am changing from lower value to higher, like current resolution is 1600X900 and when I am changing to 1920x1080 then it wont work.
And I am getting -2 as return value and which stand for The graphics mode is not supported on the doc.

There are 2 issues with the way you're calling the function.
First, there is a typo. DM_PELSWIDTH || DM_PELSHEIGHT evaluates to 1, not the combination of the two flags. You probably meant DM_PELSWIDTH | DM_PELSHEIGHT
Second, those are not the flags you should be passing to ChangeDisplaySettings. Here's the correct way to call the function:
DEVMODE desiredMode = { 0 };
desiredMode.dmSize = sizeof(DEVMODE);
desiredMode.dmPelsWidth = 1920;
desiredMode.dmPelsHeight = 1080;
desiredMode.dmFields = DM_PELSHEIGHT | DM_PELSWIDTH;
LONG res = ChangeDisplaySettings(&desiredMode, CDS_UPDATEREGISTRY | CDS_GLOBAL | CDS_RESET);
The dmFields member of the DEVMODE structure is where you tell the system which fields you want to change. The flags on ChangeDisplaySettings specify how those settings are applied. The reason why the call with DM_PELSWIDTH || DM_PELSHEIGHT didn't fail with DISP_CHANGE_BADFLAGS is that 1 is the value of the CDS_UPDATEREGISTRY flag.
As a side note: if you are just temporarily changing resolution for your application (like games do) then pass the flag CDS_FULLSCREEN by itself and it will revert the settings when your application exits. The combination of flags in the example above, sets the settings for all users, stores it in the registry, and applies the change immediately.

Related

How do I convert this piece of code in c# to make it work in c++?

my aim is to capture the screen of a windows form using c++/cli. Below is the code to capture the window, however, it is in C#. What changes do I have to make to the code for it to work in c++?
Graphics myGraphics = this.CreateGraphics();
Size s = this.Size;
memoryImage = new Bitmap(s.Width, s.Height, myGraphics);
Graphics memoryGraphics = Graphics.FromImage(memoryImage);
memoryGraphics.CopyFromScreen(this.Location.X, this.Location.Y, 0, 0, s);
What I've tried:
I've tried using the code below in c++, however, I get errors for the part in ** **.
The error says expected a ; after Size i.e. Size; s = this->Size; which does not make sense to me
Graphics^ myGraphics = this->CreateGraphics();
Size **s** = this->Size;
memoryImage = gcnew Bitmap(**s**->Width, s->Height, myGraphics);
Graphics^ memoryGraphics = Graphics::FromImage(memoryImage);
memoryGraphics->CopyFromScreen(this->Location.X, this->Location.Y, 0, 0, s);
Your code looks mostly correct.
I think that Size s is getting confused because Size is both the name of a type, and the name of a property on this object. It thinks you're trying to retrieve the Size property and throw away the result. To fix this, use the full name of the type for the declaration: System.Drawing.Size s = this->Size;. (You could also use auto, or remove the local variable entirely and just call this->Size several times.)
System.Drawing.Size is a value struct, not a ref class. It's a value type, not a reference type, so you need to do s.Width and s.Height.
This is similar to Location: Location returns a Point, which is a value type, and you're already doing Location.X, not Location->X.

Specifying the width of a TaskDialog

I'm using a task dialog via the TaskDialogIndirect function.
Everything works as expected except that the width of the dialog is exactly twice of what I specified in the cxWidth field of the TASKDIALOGCONFIG structure.
Relevant code:
TASKDIALOGCONFIG tdc;
ZeroMemory(&tdc, sizeof(tdc));
tdc.cbSize = sizeof(TASKDIALOGCONFIG);
tdc.hwndParent = hwndParent;
tdc.hInstance = NULL;
tdc.pszWindowTitle = L"Title";
tdc.pszMainInstruction = L"Foo";
tdc.pszContent = L"Bar";
tdc.dwFlags = TDF_POSITION_RELATIVE_TO_WINDOW;
tdc.cxWidth = 150;
int result;
HRESULT hr = TaskDialogIndirect(&tdc, &result, NULL, NULL);
The documentation says that the cxWidth is the width in dialog units.
With the code above the width of the dialog is 300 pixels instead of 150 which means that one horizontal dialog unit is 2 which seems really small.
If I want to specify the width of the task dialog explicitely, how should I proceed? Is suppose I cannot rely on the fact that one horizontal dialog unit is always 2 in this case.

av_seek_frame() Can't seek to the place I want

I want to intercept a frame of my video file, so I used the av_seek_frame function, the timestamp value I tried using timestamp*AV_TIME_BASE and timestamp/(av_q2d(videostream->time_base)*av_TIME_BASE), but no matter what I use Which one, the obtained frame is always not what I want, and it is observed that the frame time that I want is very different (so the accuracy problem of AVSEEK_FLAG_BACKWARD is excluded here).
My code is as follows:
double tmp0 = timeStamp/(av_q2d(inputVideoStream->time_base)*AV_TIME_BASE);
// double tmp0 = timeStamp * AV_TIME_BASE;
code = av_seek_frame(inputAVFormatContext, videoStreamIndex, tmp0, AVSEEK_FLAG_BACKWARD);

Video decoding using ffms2 (ffmpegsource)

I'm using ffms2 (aka FFmpegSource) for decoding video frames and display on UI based on wxWidgets.
My player works fine for low resolution video (320*240, 640*480) but for higher resolution (1080) it is very slow. I'm not able to meed the desired frame for high resolution video.
After time analysis I found that FFMS_GetFrame() frame function takes much longer time for high resolution frame.
Here are the results.
1. 320*240 FFMS_GetFrame takes 4-6ms
2. 640*480 FFMS_GetFrame takes >20ms
3. 1080*720 FFMS_GetFrame takes >40
Which means that I'll never meets 30 fps requirement for 1080p frame with FFMS2. But I'm not sure if this is the case.
Please suggest what could be going wrong.
void SetPosition(int64 pos)
{
uint8_t* data_ptr = NULL;
/*check if position is valid*/
if (!m_track || pos < 0 && pos > m_videoProp->NumFrames - 1)
return; // ERR_POS;
wxMilliClock_t start_wx_t = wxGetLocalTimeMillis();
long long start_t = start_wx_t.GetValue();
m_frameId = pos;
if(m_video)
{
m_frameProp = FFMS_GetFrame(m_video, m_frameId, &m_errInfo);
if(!m_frameProp) return;
if(m_frameProp)
{
m_width_ffms2 = m_frameProp->EncodedWidth;
m_height_ffms2 = m_frameProp->EncodedHeight;
}
wxMilliClock_t end_wx_t = wxGetLocalTimeMillis();
long long end_t = end_wx_t.GetValue();
long long diff_t = end_t - start_t;
wxLogDebug(wxString(wxT("Frame Grabe Millisec") + ToString(diff_t)));
//m_frameInfo = FFMS_GetFrameInfo(m_track, FFMS_TYPE_VIDEO);
/* If you want to change the output colorspace or resize the output frame size, now is the time to do it.
IMPORTANT: This step is also required to prevent resolution and colorspace changes midstream. You can
always tell a frame's original properties by examining the Encoded properties in FFMS_Frame. */
/* A -1 terminated list of the acceptable output formats (see pixfmt.h for the list of pixel formats/colorspaces).
To get the name of a given pixel format, strip the leading PIX_FMT_ and convert to lowercase. For example,
PIX_FMT_YUV420P becomes "yuv420p". */
#if 0
int pixfmt[2];
pixfmt[0] = FFMS_GetPixFmt("bgr24");
pixfmt[1] = -1;
#endif
// FFMS_SetOutputFormatV2 returns 0 on success. It Returns non-0 and sets ErrorMsg on failure.
int failure = FFMS_SetOutputFormatV2(m_video, pixfmt, m_width_ffms2, m_height_ffms2, FFMS_RESIZER_BICUBIC, &m_errInfo);
if (failure)
{
//FFMS_DestroyVideoSource(m_video);
//m_video = NULL;
return; //return ERR_POS;
}
data_ptr = m_frameProp->Data[0];
}
else
{
m_width_ffms2 = 320;
m_height_ffms2 = 240;
}
if(data_ptr)
{
memcpy(m_buf, data_ptr, 3*m_height_ffms2 * m_width_ffms2);
}
else
{
memset(m_buf, 0, 3*m_height_ffms2 * m_width_ffms2);
}
}
Slower video decoding with larger frames is totally normal. 1080x720 has about ten times as many pixels as 320x240, so having GetFrame take about ten times as long is not surprising (it's not a strictly linear relationship as there's a lot of other factors that play into decoding speed, but pixel count and time to decode are fairly correlated).
Setting the output format for every frame is unnecessary and is going to be making things a lot slower. Unless you specifically want the output format to change you should call it just once after opening the video, and it'll apply to all frames requested after that.

How to get correct hDevMode values from CPrintDialogEx (PrintDlgEx)?

I'm displaying a CPrintDialogEx dialog to choose a printer and modify the settings. I set the hDevNames member so that a default printer will be selected, but I leave hDevMode set to NULL. On successful return I pull some values such as paper size out of the returned DEVMODE structure from hDevMode.
I'm having a problem because hDevMode appears to be initialized with the values from the default printer that I passed in, not the printer that was finally selected. How do I get the parameters from the actual selected printer?
As requested here's the relevant part of the code. I've deleted some of it in the interest of space. TOwnedHandle is a smart pointer I wrote for holding a memory handle and locking it automatically.
CPrintDialogEx dlg(PD_ALLPAGES | PD_NOCURRENTPAGE | PD_NOPAGENUMS | PD_NOSELECTION, this);
ASSERT(dlg.m_pdex.hDevMode == NULL);
ASSERT(dlg.m_pdex.hDevNames == NULL);
dlg.m_pdex.hDevNames = GlobalAlloc(GHND, sizeof(DEVNAMES) + iSizeName);
DEVNAMES * pDevNames = (DEVNAMES *) GlobalLock(dlg.m_pdex.hDevNames);
// ...
GlobalUnlock(dlg.m_pdex.hDevNames);
if ((dlg.DoModal() == S_OK) && (dlg.m_pdex.dwResultAction == PD_RESULT_PRINT))
{
TOwnedHandle<DEVMODE> pDevMode = dlg.m_pdex.hDevMode;
TRACE("Printer config = %dx%d %d\n", (int)pDevMode->dmPaperWidth, (int)pDevMode->dmPaperLength, (int)pDevMode->dmOrientation);
// ...
}
Edit: I've determined that I don't get the problem if I don't set the hDevNames parameter. I wonder if I've discovered a Windows bug? This is in XP, I don't have a more recent version of Windows handy to test with.
I've distilled the code into a test that doesn't use MFC, this is strictly a Windows API problem. This is the whole thing, nothing left out except the definition of pDefaultPrinter - but of course it doesn't do anything useful anymore.
PRINTDLGEX ex = {sizeof(PRINTDLGEX)};
ex.hwndOwner = m_hWnd;
ex.Flags = PD_ALLPAGES | PD_NOCURRENTPAGE | PD_NOPAGENUMS | PD_NOSELECTION;
ex.nStartPage = START_PAGE_GENERAL;
#if 1
int iSizeName = (strlen(pDefaultPrinter) + 1) * sizeof(char);
ex.hDevNames = GlobalAlloc(GHND, sizeof(DEVNAMES) + iSizeName);
DEVNAMES * pDevNames = (DEVNAMES *) GlobalLock(ex.hDevNames);
ASSERT(pDevNames != NULL);
pDevNames->wDeviceOffset = sizeof(DEVNAMES);
strcpy((char *)pDevNames + pDevNames->wDeviceOffset, pDefaultPrinter);
GlobalUnlock(ex.hDevNames);
#endif
HRESULT hr = PrintDlgEx(&ex);
if ((hr == S_OK) && (ex.dwResultAction == PD_RESULT_PRINT))
{
DEVMODE * pdm = (DEVMODE *) GlobalLock(ex.hDevMode);
ASSERT(pdm != NULL);
TRACE("Printer config = %dx%d %d\n", (int)pdm->dmPaperWidth, (int)pdm->dmPaperLength, (int)pdm->dmOrientation);
GlobalUnlock(ex.hDevMode);
DEVNAMES * pdn = (DEVNAMES *) GlobalLock(ex.hDevNames);
ASSERT(pdn != NULL);
TRACE(_T("Printer device = %s\n"), (char *)pdn + pdn->wDeviceOffset);
GlobalUnlock(ex.hDevNames);
}
If I can't get a fix, I'd love to hear of a work-around.
After much head scratching I think I've figured it out.
When the dialog comes up initially, the hDevMode member gets filled with the defaults for the printer that is initially selected. If you select a different printer before closing the dialog, that DEVMODE structure is presented to the new printer driver; if the paper size doesn't make sense to the driver it may change it, and the drivers are not consistent.
The reason this tripped me up is that I was switching between three printers: two label
printers with very different characteristics, and a laser printer with US Letter paper.
The laser printer always responds with the proper dimensions but may indicate a wrong paper size code.
The first label printer will override the size provided by the laser printer but not the other label printer.
The second label printer will accept the size provided by the first label printer, because it's capable of using that size even though it's not loaded and not configured. It modifies the size provided by the laser printer by returning the maximum width and the Letter size length of 11 inches.
I determined two ways to work around the problem. The first is to implement IPrintDialogCallback and respond to SelectionChange calls by reloading the default DEVMODE for the newly selected printer. EDIT: I tried this and it does not work. CPrintDialogEx already implements an IPrintDialogCallback interface, making this easy. It appears that PrintDlgEx has its own internal handle that it uses to track the current DEVMODE structure and only uses the one in the PRINTDLGEX structure for input/output. There's no way to affect the DEVMODE while the dialog is up, and by the time it returns it's too late.
The second solution is to ignore the returned results entirely and work from the default paper configuration for the printer. Any changes made from the printer defaults within the dialog are lost completely, but for my application this is acceptable.
bool MyDialog::GetPaperSize(const TCHAR * pPrinterName, double & dPaperWidth, double & dPaperLength)
{
// you need to open the printer before you can get its properties
HANDLE hPrinter;
if (OpenPrinter((TCHAR *)pPrinterName, &hPrinter, NULL))
{
// determine how much space is needed for the DEVMODE structure by the printer driver
int iDevModeSize = DocumentProperties(m_hWnd, hPrinter, (TCHAR *)pPrinterName, NULL, NULL, 0);
ASSERT(iDevModeSize >= sizeof(DEVMODE);
// allocate a DEVMODE structure and initialize it to a clean state
std::vector<char> buffer(iDevModeSize, 0);
DEVMODE * pdm = (DEVMODE *) &buffer[0];
pdm->dmSpecVersion = DM_SPECVERSION;
DocumentProperties(m_hWnd, hPrinter, (TCHAR *)pPrinterName, pdm, NULL, DM_OUT_BUFFER);
ClosePrinter(hPrinter);
// convert paper size from tenths of a mm to inches
dPaperWidth = pdm->dmPaperWidth / 254.;
dPaperLength = pdm->dmPaperLength / 254.;
return true;
}
return false;
}

Resources