Changing screen resolution with VB 2005

I'm having a difficult time converting a Windows API call that works fine in VB6 to run in VB 2005 (Windows XP with SP2 in both cases). I reduced the problem code down to its core which is below. I'm trying to change the screen resolution with the ChangeDisplaySettingsEx call; the idea is that on entering the program it shifts to high resolution and at the end it restores the original settings. I left the restore part out because I get the same error. Which is "An invalid parameter was passed in. This can include an invalid flag or combination of flags." I'm trying to use exactly the same parameters, but somewhere in the conversion process from VB6 a fatal change crept in. My guess is that it's either in the ByRef/ByVal or Short/Integer/Long alternatives, or in the conversion of the Devmode structure which included fixed-length strings (OK in VB6 but not allowed in VB.NET). But all my fiddling so far has not produced a solution. I got the same error code back in VB6 when I tried to set a display frequency that was not supported at the resolution I requested, but even leaving the values unmodified (in effect setting them to what they are now, with no change) gives the same error. Any ideas So far as I can tell, there is no alternative to the API to accomplish this goal; would be interested to know if I missed it.

' ==========================
'Imports System, .Drawing, .Windows.Forms
Public Class frmDX9RKS
Inherits Form
'==== screen-resolution API, constants, etc. ====

Public Declare Function ChangeDisplaySettingsEx Lib "user32" _
Alias "ChangeDisplaySettingsExA" _
(ByRef lpszDeviceName As Integer, _
ByRef lpDevMode As DEVMODE, _
ByVal hWnd As Integer, _
ByVal dwFlags As Integer, _
ByRef lParam As Integer) As Integer

Const CCDEVICENAME As Integer = 32
Const CCFORMNAME As Integer = 32

Enum CDSXRC As Integer 'change-display-settings return codes
'From winuser.h
DISP_CHANGE_SUCCESSFUL = 0
DISP_CHANGE_RESTART = 1
DISP_CHANGE_FAILED = -1
DISP_CHANGE_BADMODE = -2
DISP_CHANGE_NOTUPDATED = -3
DISP_CHANGE_BADFLAGS = -4
DISP_CHANGE_BADPARAM = -5
End Enum

Public Structure DEVMODE
<VBFixedString(CCDEVICENAME), _
System.Runtime.InteropServices.MarshalAs( _
System.Runtime.InteropServices.UnmanagedType.ByValArray, _
SizeConst:=(CCDEVICENAME))> Public dmDeviceName() As Char
Dim dmSpecVersion As Short
Dim dmDriverVersion As Short
Dim dmSize As Short
Dim dmDriverExtra As Short
Dim dmFields As Integer
Dim dmOrientation As Short
Dim dmPaperSize As Short
Dim dmPaperLength As Short
Dim dmPaperWidth As Short
Dim dmScale As Short
Dim dmCopies As Short
Dim dmDefaultSource As Short
Dim dmPrintQuality As Short
Dim dmColor As Short
Dim dmDuplex As Short
Dim dmYResolution As Short
Dim dmTTOption As Short
Dim dmCollate As Short
<VBFixedString(CCFORMNAME), _
System.Runtime.InteropServices.MarshalAs( _
System.Runtime.InteropServices.UnmanagedType.ByValArray, _
SizeConst:=(CCFORMNAME))> Public dmFormName() As Char
Dim dmUnusedPadding As Short
Dim dmBitsPerPel As Short
Dim dmPelsWidth As Integer
Dim dmPelsHeight As Integer
Dim dmDisplayFlags As Integer
Dim dmDisplayFrequency As Integer
Dim dmICMMethod As Integer 'NT 4.0
Dim dmICMIntent As Integer 'NT 4.0
Dim dmMediaType As Integer 'NT 4.0
Dim dmDitherType As Integer 'NT 4.0
Dim dmReserved1 As Integer 'NT 4.0
Dim dmReserved2 As Integer 'NT 4.0
Dim dmPanningWidth As Integer 'Win2000
Dim dmPanningHeight As Integer 'Win2000
End Structure

Public Declare Function EnumDisplaySettings Lib "user32" _
Alias "EnumDisplaySettingsA" ( _
ByVal lpszDeviceName As Integer, _
ByVal iModeNum As Integer, _
ByRef lpDevMode As DEVMODE) As Boolean

Shared Sub Main()
Dim frm As New frmDX9RKS()
End Sub 'Main

Public Sub New()
Const DM_PELSWIDTH As Integer = &H80000
Const DM_PELSHEIGHT As Integer = &H100000
Const DM_DISPLAYFREQUENCY As Integer = &H400000
Const CDS_TEST As Integer = &H4

InitializeComponent() 'required by the Windows Form Designer.
' Add any initialization after the Initialize-Component() call.

Const HiResW As Integer = 1600 'hi-res width in pixels
Const HiResH As Integer = 1200 'hi-res height in pixels
Const ENUM_CURRENT_SETTINGS As Integer = -1

Static OldWd As Integer 'screen width in pixels
Static OldHt As Integer 'screen height in pixels
Static OldFreq As Integer 'screen-refresh frequency

Dim DevM As New DEVMODE 'added New in V3.2, 3/22/06
Dim boRetn As Boolean 'boolean return code
Dim ResChgRtCd As Integer 'As CDSXRC 'resolution-change return code

Debug.Print("Original - width: " & DevM.dmPelsWidth & _
" Height: " & DevM.dmPelsHeight & _
" Freq: " & DevM.dmDisplayFrequency & _
" DevmodeSize: " & DevM.dmSize & _
" dmFields: " & DevM.dmFields)

DevM.dmSize = CShort(Len(DevM)) 'set up dev-mode
'set field bits: Horiz, Vert, Freq
DevM.dmFields = DM_PELSWIDTH Or DM_PELSHEIGHT Or DM_DISPLAYFREQUENCY

'save orig values and set to high resolution
boRetn = EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, DevM)
Debug.Print("Color: " & DevM.dmBitsPerPel & " bits/pixel")

OldWd = DevM.dmPelsWidth 'save orig width in pixels
OldHt = DevM.dmPelsHeight 'save orig height in pixels
OldFreq = DevM.dmDisplayFrequency 'save orig refresh freq
DevM.dmPelsWidth = HiResW
DevM.dmPelsHeight = HiResH
DevM.dmDisplayFrequency = 60 'use lower (hard-coded) freq for LCD hi-res
Debug.Print("Before change - width: " & DevM.dmPelsWidth & _
" Height: " & DevM.dmPelsHeight & _
" Freq: " & DevM.dmDisplayFrequency & _
" DevmodeSize: " & DevM.dmSize & _
" dmFields: " & DevM.dmFields)
'Stop
ResChgRtCd = ChangeDisplaySettingsEx(0, DevM, 0, CDS_TEST, 0)

If ResChgRtCd <> CDSXRC.DISP_CHANGE_SUCCESSFUL Then 'if change failed,
subBadResChgDiag((ResChgRtCd)) ' tell why
Stop
Exit Sub
End If

End Sub

Private Sub subBadResChgDiag(ByRef CDSRetCode As Integer)
Dim strErr As String
Dim strBase As String

strBase = "Screen-resolution change failed;" & vbCrLf & vbCrLf & "Code is: "

Select Case CDSRetCode
Case CDSXRC.DISP_CHANGE_RESTART
strErr = strBase & "CHANGE_RESTART"
Case CDSXRC.DISP_CHANGE_FAILED
strErr = strBase & "CHANGE_FAILED"
Case CDSXRC.DISP_CHANGE_BADMODE
strErr = strBase & "CHANGE_BADMODE"
Case CDSXRC.DISP_CHANGE_NOTUPDATED
strErr = strBase & "CHANGE_NOTUPDATED"
Case CDSXRC.DISP_CHANGE_BADFLAGS
strErr = strBase & "CHANGE_BADFLAGS"
Case CDSXRC.DISP_CHANGE_BADPARAM
strErr = strBase & "CHANGE_BADPARAM"
Case Else
strErr = strBase & "Unknown resolution-change error"
End Select
MsgBox(strErr)

End Sub

End Class



Answer this question

Changing screen resolution with VB 2005

  • NathanLiu

    I'm not entirely sure what the problem is. The code I wrote using DirectX was written in VB Express 2005 (I can't afford the full version ). It should work with any video card supported by DirectX. Could you explain in more detail what the problem is


  • Kapil Arya

    Hi Robinjam,

    I have tried this code with my system , But, Its shows the exception like

    NotImplementedException was unhandled by user code on CONST_DDSDMFLAGS.DDSDM_DEFAULT

    And, Please tell me, what sholud i do for this error.

    Sujatha.


  • Ratzu

    It's no problem at all. I wanted to do something different anyway. :)

  • Danieletor

    Thanks for the suggestion. As it happened, I was just rummaging around some more and found the ChangeDisplaySettings call; it only works on the default display adapter unlike ChangeDisplaySettingsEx, but that's all I need for this app. So far as I can tell, the problem was somewhere in the three null arguments I was trying to set (based on help files for C++ usage, which was all I could find for the API), and in converting from the "As Any" which is no longer allowed in a Declare statement.
  • mushy26

    Just forget trying to use the API to change the display mode. Instead:

    1. Add a COM reference to 'DirectX 7 for Visual Basic Type library'

    2. At the top of your code for your main form, before the class declaration, add 'Imports DxVbLib'

    3. After the class declaration, add:

         Dim dx as New DirectX7

         Dim dd as DirectDraw7

    4. Add the following code to your Form_Load event handler:

        dd=dx.DirectDrawCreate("")

        dd.setDisplayMode(800,600,16,0,CONST_DDSDMFLAGS.DDSDM_DEFAULT)

    Note: Change '800' to the desired width of the display mode, '600' should be the height, and '16' should be the color depth.

    Example

     

    Imports DxVBLib

    Public Class frmMain

      Dim dx As New DirectX7

      Dim dd As DirectDraw7

      Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        Me.Show()

        dd = dx.DirectDrawCreate("")

        dim Height as Integer

        dim Width as Integer

        dim Depth as Integer

        Height=600 ' Change this to the correct number

        Width=800 ' Change this to the correct number

        Depth=16 ' Change this to the correct number

        dd.SetDisplayMode(Height, Width, Depth, 0, CONST_DDSDMFLAGS.DDSDM_DEFAULT)

      End Sub

    End Class



  • blade00007

    Although the DirectX method involves simpler coding, there is a caveat to using this method: You are only able to change to display modes which DirectX recognizes and not necessarily to any of the modes which your display adapter might support.

    For example, on my system I am only able to change BitDepth to 16 or 32 bits. Nothing lower. If I want to change to 256-color mode I cannot do it with DirectX.

    (refer to http://msdn.microsoft.com/archive/default.asp url=/archive/en-us/directx9_m_Summer_04/directx/direct3d/gettingstarted/direct3dsurfaces/surfaceformats.asp for details about supported formats).

    I'm really not too familiar with the DirectDraw API, so if someone knows a way to enumerate and change to all the adapters supported modes, please post.

    FYI, I'm working on wrapping the API functions into a VB.Net (2005) class which can be dropped into an app or used via DLL. I'll post back when it is finished for anyone who might be interested.

    Cheers,

    Dean


  • mrfantasy999

    here's a working api way:

    Code Block
    Imports System.Runtime.InteropServices

    ' see msdn on "Changing Screen Orientation Programmatically" for tablet pc.
    ' note: I couldn't change orientation on xp, or find anyone claiming they could!
    ' http://msdn.microsoft.com/library/default.asp url=/library/en-us/dntablet/html/tbconChgScrn.asp


    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
    Friend Structure DEVMODE

    <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=32)> _
    Public dmDeviceName As String
    Public dmSpecVersion As Short
    Public dmDriverVersion As Short
    Public dmSize As Short
    Public dmDriverExtra As Short
    Public dmFields As Integer
    Public dmPositionX As Integer
    Public dmPositionY As Integer
    Public dmDisplayOrientation As Integer
    Public dmDisplayFixedOutput As Integer
    Public dmColor As Short
    Public dmDuplex As Short
    Public dmYResolution As Short
    Public dmTTOption As Short
    Public dmCollate As Short
    <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=32)> _
    Public dmFormName As String
    Public dmLogPixels As Short
    Public dmBitsPerPel As Short
    Public dmPelsWidth As Integer
    Public dmPelsHeight As Integer
    Public dmDisplayFlags As Integer
    Public dmDisplayFrequency As Integer
    Public dmICMMethod As Integer
    Public dmICMIntent As Integer
    Public dmMediaType As Integer
    Public dmDitherType As Integer
    Public dmReserved1 As Integer
    Public dmReserved2 As Integer
    Public dmPanningWidth As Integer
    Public dmPanningHeight As Integer
    End
    Structure

    Friend
    Class NativeMethods

    ' PInvoke declaration for EnumDisplaySettings Win32 API
    <DllImport("user32.dll", CharSet:=CharSet.Ansi)> _
    Public Shared Function EnumDisplaySettings( _
    ByVal lpszDeviceName As String, _
    ByVal iModeNum As Integer, _
    ByRef lpDevMode As DEVMODE) As Integer
    End Function

    ' PInvoke declaration for ChangeDisplaySettings Win32 API
    <DllImport("user32.dll", CharSet:=CharSet.Ansi)> _
    Public Shared Function ChangeDisplaySettings( _
    ByRef lpDevMode As DEVMODE, _
    ByVal dwFlags As Integer) As Integer
    End Function

    End
    Class

    Public
    Class ResolutionChanger

    Private Shared Function CreateDevMode() As DEVMODE
    Dim dm As New DEVMODE
    dm.dmDeviceName =
    New String(New Char(32) {})
    dm.dmFormName =
    New String(New Char(32) {})
    dm.dmSize =
    CShort(Marshal.SizeOf(dm))
    Return dm
    End Function

    Public Enum DisplayChangeResultCode
    DISP_CHANGE_SUCCESSFUL = 0
    DISP_CHANGE_RESTART = 1
    DISP_CHANGE_FAILED = -1
    DISP_CHANGE_BADMODE = -2
    DISP_CHANGE_NOTUPDATED = -3
    DISP_CHANGE_BADFLAGS = -4
    DISP_CHANGE_BADPARAM = -5
    DISP_CHANGE_BADDUALVIEW = -6
    End Enum

    Public Shared Sub ChangeResolution(ByVal width As Integer, ByVal height As Integer, ByVal freq As Integer)

    Const DM_PELSWIDTH As Integer = &H80000
    Const DM_PELSHEIGHT As Integer = &H100000
    Const DM_DISPLAYFREQUENCY As Integer = &H400000
    Const ENUM_CURRENT_SETTINGS As Integer = -1
    Dim DevM As DEVMODE = CreateDevMode()
    Dim enumResult As Integer
    Dim changeResult As DisplayChangeResultCode

    DevM.dmFields = DM_PELSWIDTH
    Or DM_PELSHEIGHT Or DM_DISPLAYFREQUENCY

    enumResult = NativeMethods.EnumDisplaySettings(
    Nothing, ENUM_CURRENT_SETTINGS, DevM)

    DevM.dmPelsWidth = width
    DevM.dmPelsHeight = height
    DevM.dmDisplayFrequency = freq

    changeResult =
    CType(NativeMethods.ChangeDisplaySettings(DevM, 0), DisplayChangeResultCode)

    If changeResult <> DisplayChangeResultCode.DISP_CHANGE_SUCCESSFUL Then
    Throw New Exception("Failed to change resolution: " & changeResult.ToString)
    End If

    End Sub

    End
    Class

    see also :

    http://cid-862dee3ec267cb5c.skydrive.live.com/self.aspx/Public/DisplaySettings.zip


  • SQLMonger66

    And sorry it took me so long to reply...


  • Shy Cohen - MSFT

    You complete noob

    Actually upon reflection that was totally uncalled for. You aren't a noob at all.



  • Erik Arfeuille

    Hi,

    It seems like the initial poster figured out how to change the user's display using the API. I tried the DirectX and even though the code is well documented and explained, it doesn't work on my XP platform.

    I was wondering if anyone has been able to get this to function with Visual Basic Express 2005. I have been tasked to accomplish this in VB Express and I just cannot find a work-able solution. Any assistance would be helpful.

    Thanks!

    Christine



  • yyll

    Sorry, I don't know what went wrong. Try just replacing CONST_DDSDMFLAGS.DDSDM_DEFAULT with 0.

  • Hooray_for_Boobies

    i found a problem with the return resolution, i changed from 1024 x 768 to 800 x 600.

    when the program exited, it put the resolution back to 1024 x 768 however the working desktop was actually fixed in the res of 800 x 600. people will only find this error if they shrink to a lower res.

    if they put this in an exit code it will fix the problem and the user will have full control of the desktop:

    dd.RestoreDisplayMode()


  • phita

    Thanks for this excellent code

    It worked!!!

    // PCM2 and bevin


  • Yasir Khokhar

    Hey,

    Actually, I have did a mistake, Now its works fine.

    Thanks for the help and reply.

    Nice to meet you.

    Regards,

    Sujatha.


  • Changing screen resolution with VB 2005