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

Changing screen resolution with VB 2005
Tekzel
here's a working api way:
' 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
Grismath
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
Tech Guy
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
DxVBLibPublic
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 SubEnd Class
Sarmad
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.
Shrad
Hey,
Actually, I have did a mistake, Now its works fine.
Thanks for the help and reply.
Nice to meet you.
Regards,
Sujatha.
idunkn0
Sameer Seth
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
Mehdi311ggg
bijie85
dib
lprigmore
Thanks for this excellent code
It worked!!!
// PCM2 and bevin
Mike Henrickson
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()
inetnerd
Christian Liensberger
You complete noob
Actually upon reflection that was totally uncalled for. You aren't a noob at all.