Reading the PrtDevMode structure

Viewed 233

I tried to read the Report.PrtDevMode property using the appropriate structures. If I do a Unicode conversion on the string I get closer, but the values still don't seem correct.

I expect to see intOrientation = 2 and strDeviceName = "C552 Color" and a paper size of 11x17.

enter image description here

I am testing on Windows 10 and Server 2008 with Microsoft Access 2010 (32-bit)

What I have Tried

A simplified copy and paste from the help file:

Private Type str_DEVMODE
    RGB As String * 94
End Type
    
Private Type type_DEVMODE
    strDeviceName As String * 32
    intSpecVersion As Integer
    intDriverVersion As Integer
    intSize As Integer
    intDriverExtra As Integer
    lngFields As Long
    intOrientation As Integer
    intPaperSize As Integer
    intPaperLength As Integer
    intPaperWidth As Integer
    intScale As Integer
    intCopies As Integer
    intDefaultSource As Integer
    intPrintQuality As Integer
    intColor As Integer
    intDuplex As Integer
    intResolution As Integer
    intTTOption As Integer
    intCollate As Integer
    strFormName As String * 32
    lngPad As Long
    lngBits As Long
    lngPW As Long
    lngPH As Long
    lngDFI As Long
    lngDFr As Long
End Type
    
Public Sub CheckCustomPage()
    
    Dim DevString As str_DEVMODE
    Dim DM As type_DEVMODE
    Dim strDevModeExtra As String
    Dim rpt As Report
    Dim intResponse As Integer
        
    ' Opens report in Design view.
    DoCmd.OpenReport "rptNavigationPaneGroups", acDesign
    Set rpt = Reports("rptNavigationPaneGroups")
        
    If Not IsNull(rpt.PrtDevMode) Then
        strDevModeExtra = rpt.PrtDevMode
            
        ' Gets current DEVMODE structure.
        ' (I added the StrConv function)
        DevString.RGB = StrConv(strDevModeExtra, vbUnicode)
        LSet DM = DevString
            
        ' List the device name.
        If DM.strDeviceName <> rpt.Printer.DeviceName Then
            Debug.Print "Found: '" & DM.strDeviceName & _
              "' instead of '" & rpt.Printer.DeviceName & "'"
        End If
    End If
    Set rpt = Nothing
        
End Sub

If I use the vbUnicode conversion, I get this output:

Found: 'C552 Color ”-é/ '

instead of 'C552 Color'

Without the conversion, the name is completely unreadable:

Found: '????? ?? A?A?????? ?'

instead of 'C552 Color

I reviewed numerous articles, documentation, and posts describing the usage of the .PrtDevMode property and associated structure.
I compared the structure type with examples in the help file, online documentation, and other sources, but I don't find any examples that involve Unicode conversion, which seems like it might be a piece of the puzzle.

I could use the .Printer object to retrieve many of these properties, but I understand that some settings like the Media Type are only available through the PrtDevMode structure (which is designed to mirror the Win32 SDK).

I could resort to using API calls to query the system printers, but this doesn't solve the problem of needing to write the structure back to the report print settings.

Using this structure would also help me to serialize this data in a readable format so that it can be stored in version control, and written back to the report after the database is rebuilt from source files (which is my ultimate goal).

Any non-null pointers in the right direction?

1 Answers

After further testing, I was able to get it working this morning. As I suspected, I was close on the Unicode conversion, but there were three important modifications that made the difference.

First, I needed to declare the two strings as byte arrays, not simply string buffers. While the string buffer works with the winspool.drv API calls, reading the Report.PrtDevMode property works better with a byte array.

Private Type type_DEVMODE
    strDeviceName(1 To 32) As Byte   ' <--- Byte array
    'strDeviceName As String * 32
    intSpecVersion As Integer
    intDriverVersion As Integer
    intSize As Integer
    ...

The second part was that the conversion from Unicode needs to be performed only on the string values, not the entire structure.

' Read the string values from DevMode structure
strDevice = NTrim(StrConv(dm.strDeviceName, vbUnicode))
strForm = NTrim(StrConv(dm.strFormName, vbUnicode))

Thirdly, the string is a null-terminated string, so it needs to be trimmed at the null character after the conversion from Unicode.

'---------------------------------------------------------------------------------------
' Procedure : NTrim
' Author    : Adam Waller
' Date      : 5/15/2020
' Purpose   : Trim a null-terminated string.
'---------------------------------------------------------------------------------------
'
Public Function NTrim(strText) As String
    Dim lngPos As Long
    lngPos = InStr(1, strText, vbNullChar)
    If lngPos > 0 Then
        NTrim = Left$(strText, lngPos - 1)
    Else
        NTrim = strText
    End If
End Function

With these three changes, I am now able to read the .PrtDevMode property with the expected values. Hopefully this will be helpful for someone else out there as well!

If you find that it works differently on your system, or have additional input, please feel free to leave a comment!

Related