How to copy an address into a pointer

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Just Me

    How to copy an address into a pointer

    I know (or at least think) the following is not correct.

    The comment says what I want to do, but I think the code will copy the data
    not the address.

    Is this one of the things that can't be done with VB?

    Any suggestions?

    Thanks





    Public Declare Auto Sub CopyMemory1 Lib "KERNEL32" Alias "RtlMoveMem ory"
    (ByVal pDest As Integer, ByRef Source As Byte, ByVal cbCopy As Integer)




    'Copy address of lDevModeAsByte into lPrtInfo2 structure

    Kernel.CopyMemo ry1(lPrtInfo2.p DevMode, lDevModeAsByte( 0), 4)


  • Tom Shelton

    #2
    Re: How to copy an address into a pointer

    In article <unVgrAIaFHA.33 20@TK2MSFTNGP12 .phx.gbl>, Just Me wrote:[color=blue]
    > I know (or at least think) the following is not correct.
    >
    > The comment says what I want to do, but I think the code will copy the data
    > not the address.
    >
    > Is this one of the things that can't be done with VB?
    >
    > Any suggestions?
    >
    > Thanks
    >
    >
    >
    >
    >
    > Public Declare Auto Sub CopyMemory1 Lib "KERNEL32" Alias "RtlMoveMem ory"
    > (ByVal pDest As Integer, ByRef Source As Byte, ByVal cbCopy As Integer)
    >
    >
    >
    >
    > 'Copy address of lDevModeAsByte into lPrtInfo2 structure
    >
    > Kernel.CopyMemo ry1(lPrtInfo2.p DevMode, lDevModeAsByte( 0), 4)
    >
    >[/color]

    CopyMemory is a almost always a bad idea to use in VB.NET. There are
    almost always better alternatives. If you need to pass an address of a
    managed object to an unmanaged function, then the address needs to be
    pinned for the duration of that operation. The reason being, that GC
    could kick in which may result in the relocation of the object - and
    that could be bad ju-ju for the unmanaged code. However, there are
    performance issues involved here, since leaving a lot of objects pinned
    for a long time can result in heap fragmentation. So the idea, is pin
    the object, do your deed, and unpin as soon as possible.

    You can achive this pinning using the GCHandle class's Allocate method:

    Dim objHandle As GCHandle = _
    GCHandle.Alloca te (myObject, GCHandleType.Pi nned)

    Try

    Dim objectAddress As IntPtr = objHandle.AddrO fPinnedObject ()

    Call MyFunckyUnmanag edCodeWithObjec tAddress (objectAddress)

    Finally
    'Were done, so unpin this sucker...
    objHandle.Free ()
    End Try

    You have to make sure that for each handle that Free is only called
    once. Anyway, it would be more helpful if we knew exactly what you were
    trying to accomplish. It's pretty obvious that your trying to call a
    Win32 api of some sort - but knowing which one would be helpful.
    Working with API's is, IMHO, significantly different in VB.NET then
    VB.CLASSIC.

    --
    Tom Shelton [MVP]

    Comment

    • Just Me

      #3
      Re: How to copy an address into a pointer

      > Anyway, it would be more helpful if we knew exactly what you were[color=blue]
      > trying to accomplish. It's pretty obvious that your trying to call a
      > Win32 api of some sort - but knowing which one would be helpful.
      > Working with API's is, IMHO, significantly different in VB.NET then
      > VB.CLASSIC.
      >
      > --
      > Tom Shelton [MVP][/color]

      Thanks

      I'm trying to use an old routine for setting the system default printer's
      Landscape mode.

      Any other suggestion?



      Thanks again

      Public Shared Sub SetPrinterSetti ngs(ByRef windowHandle As IntPtr, ByRef
      printerName As String, ByRef isLandscape As Boolean) ', ByRef aNewPaperSize
      As Short, ByRef aNewDuplex As Short)

      Dim lPrinterHandle As IntPtr

      Dim lDevMode As GDI.DEVMODE

      Dim lDevModeAsByte( ) As Byte

      Dim lDevModeAsByteS ize As Integer

      Dim lPrtInfo2 As WinSpool.PRINTE R_INFO_2

      Dim lPrtInfo2AsByte () As Byte

      Dim lPrtInfo2AsByte Size As Integer

      Dim lFlag As Integer

      Dim lPrinterDefault s As WinSpool.PRINTE R_DEFAULTS

      Dim lErrorCode As Integer

      'You should probably look at the PtrToStructure and StructureToPtr methods
      rather than Copy.

      Kernel.ZeroMemo ry(lPrinterDefa ults, Marshal.SizeOf( lPrinterDefault s))

      lPrinterDefault s.DesiredAccess = WinSpool.PRINTE R_ALL_ACCESS

      'lPrinterDefaul ts.DesiredAcces s = WinSpool.PRINTE R_ACCESS_ADMINI STER

      'Get a handle to the printer.

      lFlag = WinSpool.OpenPr inter(printerNa me, lPrinterHandle, lPrinterDefault s)

      If lFlag = 0 Then

      lErrorCode = Marshal.GetLast Win32Error()

      If lErrorCode = User.ERROR_ACCE SS_DENIED Then

      MessageBox.Show ("Requires adminstrative rights to change default printer",
      "Error", MessageBoxButto ns.OK, MessageBoxIcon. Exclamation)

      End If

      Exit Sub

      End If

      'This GetPrinter call determines the size needed for lPrtInfo2AsByte

      lFlag = WinSpool.GetPri nter(lPrinterHa ndle, 2, 0, 0, lPrtInfo2AsByte Size)

      If lFlag = 0 Then

      lErrorCode = Marshal.GetLast Win32Error()

      If lErrorCode <> 122 Then GoTo CLEAN_UP

      End If

      'Allocate space for lPrtInfo2AsByte

      ReDim lPrtInfo2AsByte (lPrtInfo2AsByt eSize - 1)

      'The second GetPrinter call fills lPrtInfo2AsByte with the current settings

      lFlag = WinSpool.GetPri nter(lPrinterHa ndle, 2, lPrtInfo2AsByte (0),
      lPrtInfo2AsByte Size, lPrtInfo2AsByte Size)

      If lFlag = 0 Then

      lErrorCode = Marshal.GetLast Win32Error()

      'Console.WriteL ine("GetPrinter exited with code : {0}", lErrorCode)

      End If

      'Copy lPrtInfo2AsByte to the structure

      Kernel.CopyMemo ry2(lPrtInfo2, lPrtInfo2AsByte (0), Marshal.SizeOf( lPrtInfo2))

      'Get the total size of the DeviceMode bytes (lDevModeAsByte )

      lDevModeAsByteS ize = WinSpool.Docume ntProperties(wi ndowHandle,
      lPrinterHandle, printerName, 0, 0, 0)

      'Reserve memory for the total size of the DeviceMode bytes

      ReDim lDevModeAsByte( lDevModeAsByteS ize - 1)

      'Fill the DeviceMode bytes from the printer.

      lFlag = WinSpool.Docume ntProperties(wi ndowHandle, lPrinterHandle,
      printerName, lDevModeAsByte( 0), 0, GDI.DM_OUT_BUFF ER)

      If lFlag < 0 Then

      lErrorCode = Marshal.GetLast Win32Error()

      Console.WriteLi ne("DocumentPro perties exited with code: {0}", lErrorCode)

      End If

      'Copy the Public shared (predefined) portion of the DeviceMode bytes to the
      structure

      Kernel.CopyMemo ry3(lDevMode, lDevModeAsByte( 0), Marshal.SizeOf( lDevMode))

      'Set the dmFields bit flag to indicate what we are changing

      lDevMode.dmFiel ds = GDI.DM_ORIENTAT ION 'Or DM_DUPLEX Or DM_PAPERSIZE

      If isLandscape Then

      lDevMode.u.dmOr ientation = GDI.DMORIENT_LA NDSCAPE

      Else

      lDevMode.u.dmOr ientation = GDI.DMORIENT_PO RTRAIT

      End If

      'Set/Change PaperSize

      'lDevMode.dmPap erSize = aNewPaperSize

      'On Error Resume Next

      'lDevMode.dmDup lex = aNewDuplex

      'On Error GoTo 0

      'Copy changed structure back to the bytes

      Kernel.CopyMemo ry4(lDevModeAsB yte(0), lDevMode, Marshal.SizeOf( lDevMode))

      'Merge the printer driver's current print settings with the settings in the
      lDevModeAsByte

      lFlag = WinSpool.Docume ntProperties(wi ndowHandle, lPrinterHandle,
      printerName, lDevModeAsByte( 0), lDevModeAsByte( 0), GDI.DM_IN_BUFFE R Or
      GDI.DM_OUT_BUFF ER)

      ' lFlag = WinSpool.Docume ntProperties(wi ndowHandle, lPrinterHandle,
      printerName, lDevModeAsByte( 0), lDevModeAsByte( 0), GDI.DM_IN_PROMP T)

      'Copy address of lDevModeAsByte into lPrtInfo2 structure

      ' Kernel.CopyMemo ry1(lPrtInfo2.p DevMode, lDevModeAsByte( 0),
      Marshal.SizeOf( lDevMode))

      Kernel.CopyMemo ry1(lPrtInfo2.p DevMode, lDevModeAsByte( 0), 4)

      'Update lPrinterInfoAsB yte with the updated structure

      Kernel.CopyMemo ry5(lPrtInfo2As Byte(0), lPrtInfo2, Marshal.SizeOf( lDevMode))



      lFlag = WinSpool.SetPri nter(lPrinterHa ndle, 2, lPrtInfo2AsByte (0), 0)

      If lFlag = 0 Then

      lErrorCode = Marshal.GetLast Win32Error()

      Console.WriteLi ne("SetPrinter exited with code : {0}", lErrorCode)

      End If

      CLEAN_UP:

      WinSpool.CloseP rinter(lPrinter Handle) 'Close the handle

      End Sub


      Comment

      • Tom Shelton

        #4
        Re: How to copy an address into a pointer

        On 2005-06-03, Just Me <groups@a-znet.com> wrote:[color=blue][color=green]
        >> Anyway, it would be more helpful if we knew exactly what you were
        >> trying to accomplish. It's pretty obvious that your trying to call a
        >> Win32 api of some sort - but knowing which one would be helpful.
        >> Working with API's is, IMHO, significantly different in VB.NET then
        >> VB.CLASSIC.
        >>
        >> --
        >> Tom Shelton [MVP][/color]
        >
        > Thanks
        >
        > I'm trying to use an old routine for setting the system default printer's
        > Landscape mode.
        >
        > Any other suggestion?[/color]

        The System.Drawing. Printing.PageSe ttings class?

        Dim doc As New PrintDocument ()

        doc.DefaultPage Settings.Landsc ape = True

        ' Do your printing...

        --
        Tom Shelton [MVP]

        Comment

        • Just Me

          #5
          Re: How to copy an address into a pointer

          I'm trying to set the system wide orientation properties.

          BTW
          what are
          doc.PrinterSett ings.DefaultPag eSettings
          used for?

          I've been trying for a while to find out.

          Thanks



          "Tom Shelton" <tshelton@YOUKN OWTHEDRILLcomca st.net> wrote in message
          news:%23CFJutKa FHA.2212@TK2MSF TNGP14.phx.gbl. ..[color=blue]
          > On 2005-06-03, Just Me <groups@a-znet.com> wrote:[color=green][color=darkred]
          >>> Anyway, it would be more helpful if we knew exactly what you were
          >>> trying to accomplish. It's pretty obvious that your trying to call a
          >>> Win32 api of some sort - but knowing which one would be helpful.
          >>> Working with API's is, IMHO, significantly different in VB.NET then
          >>> VB.CLASSIC.
          >>>
          >>> --
          >>> Tom Shelton [MVP][/color]
          >>
          >> Thanks
          >>
          >> I'm trying to use an old routine for setting the system default
          >> printer's
          >> Landscape mode.
          >>
          >> Any other suggestion?[/color]
          >
          > The System.Drawing. Printing.PageSe ttings class?
          >
          > Dim doc As New PrintDocument ()
          >
          > doc.DefaultPage Settings.Landsc ape = True
          >
          > ' Do your printing...
          >
          > --
          > Tom Shelton [MVP][/color]


          Comment

          • Tom Shelton

            #6
            Re: How to copy an address into a pointer

            On 2005-06-04, Just Me <groups@a-znet.com> wrote:[color=blue]
            > I'm trying to set the system wide orientation properties.
            >[/color]

            Well... What can I say. I'm looking at the code. First off, you may
            want to spend some time with the interop and marshalling documentation.
            At first glance, I think you can dispense with all of the calls to
            RtlMoveMemory.. . You probably can do this using Marshalling attributes
            and the methods of the System.Runtime. InteropServices .Marshal class -
            though, I will say that this routine would probably be easier to write
            in C# using unsafe code (and probably would performe better). I will
            try and see if I can get time to convert this function, but right now I
            can't promise anything.

            Also, you should not EVER call GetLastError from VB.NET (or from VB.CLASSIC
            for that matter). The return result is meaningless since the runtime
            may call API functions that set that value before you call it. You should
            either use Marshal.GetLast Win32Error () or the intrinsic VB.NET Err object's
            LastDllError property. Both of thes methods preserve the last user called API
            error codes.
            [color=blue]
            > BTW
            > what are
            > doc.PrinterSett ings.DefaultPag eSettings
            > used for?
            >[/color]

            Setting printer settings... System.Drawing. Printing would be the
            relavent namespace to start looking at the docs..
            [color=blue]
            > I've been trying for a while to find out.
            >
            > Thanks
            >
            >
            >
            > "Tom Shelton" <tshelton@YOUKN OWTHEDRILLcomca st.net> wrote in message
            > news:%23CFJutKa FHA.2212@TK2MSF TNGP14.phx.gbl. ..[color=green]
            >> On 2005-06-03, Just Me <groups@a-znet.com> wrote:[color=darkred]
            >>>> Anyway, it would be more helpful if we knew exactly what you were
            >>>> trying to accomplish. It's pretty obvious that your trying to call a
            >>>> Win32 api of some sort - but knowing which one would be helpful.
            >>>> Working with API's is, IMHO, significantly different in VB.NET then
            >>>> VB.CLASSIC.
            >>>>
            >>>> --
            >>>> Tom Shelton [MVP]
            >>>
            >>> Thanks
            >>>
            >>> I'm trying to use an old routine for setting the system default
            >>> printer's
            >>> Landscape mode.
            >>>
            >>> Any other suggestion?[/color]
            >>
            >> The System.Drawing. Printing.PageSe ttings class?
            >>
            >> Dim doc As New PrintDocument ()
            >>
            >> doc.DefaultPage Settings.Landsc ape = True
            >>
            >> ' Do your printing...
            >>
            >> --
            >> Tom Shelton [MVP][/color]
            >
            >[/color]


            --
            Tom Shelton [MVP]

            Comment

            • Just Me

              #7
              Re: How to copy an address into a pointer

              Thanks

              I took your eariler advise and got rid of the RtlMoveMemory's

              I'll keep plugging and learning as I go along.



              Thanks

              BTW this is where I am now:



              Public Shared Sub SetPrinterSetti ngs(ByRef windowHandle As IntPtr, ByRef
              printerName As String, ByRef isLandscape As Boolean) ', ByRef aNewPaperSize
              As Short, ByRef aNewDuplex As Short)

              Dim lPrinterHandle As IntPtr

              Dim lFlag As Integer

              Dim lPrinterDefault s As WinSpool.PRINTE R_DEFAULTS

              Dim lErrorCode As Integer

              Dim lDevMode As GDI.DEVMODE

              Dim lDevModeSize As Integer

              Dim lPointerToDevMo de As IntPtr

              Dim lPrtInfo2 As WinSpool.PRINTE R_INFO_2 = New WinSpool.PRINTE R_INFO_2

              Dim lPrtInfo2Size As Integer

              Dim lPointerToPrint erInfo2 As IntPtr

              lPrinterDefault s.DesiredAccess = WinSpool.PRINTE R_ALL_ACCESS

              'lPrinterDefaul ts.DesiredAcces s = WinSpool.PRINTE R_ACCESS_ADMINI STER

              'Get a handle to the printer.

              lFlag = WinSpool.OpenPr inter(printerNa me, lPrinterHandle, lPrinterDefault s)

              If lFlag = 0 Then

              lErrorCode = Marshal.GetLast Win32Error()

              If lErrorCode = User.ERROR_ACCE SS_DENIED Then

              MessageBox.Show ("Requires adminstrative rights to change default printer",
              "Error", MessageBoxButto ns.OK, MessageBoxIcon. Exclamation)

              End If

              Exit Sub

              End If

              'This GetPrinter call determines the size needed for lPointerToPrint erInfo2

              lFlag = WinSpool.GetPri nter(lPrinterHa ndle, 2, IntPtr.Zero, 0,
              lPrtInfo2Size)

              If lFlag = 0 Then

              lErrorCode = Marshal.GetLast Win32Error()

              If lErrorCode <> 122 Then GoTo CLEAN_UP

              End If

              'Allocate space for lPointerToPrint erInfo2 data

              lPointerToPrint erInfo2 = Marshal.AllocCo TaskMem(lPrtInf o2Size)

              'The second GetPrinter call fills lPointerToPrint erInfo2 data with the
              current settings

              lFlag = WinSpool.GetPri nter(lPrinterHa ndle, 2, lPointerToPrint erInfo2,
              lPrtInfo2Size, lPrtInfo2Size)

              If lFlag = 0 Then

              lErrorCode = Marshal.GetLast Win32Error()

              'Console.WriteL ine("GetPrinter exited with code : {0}", lErrorCode)

              End If

              'Copy lPointerToPrint erInfo2 data to the structure

              lPrtInfo2 = Marshal.PtrToSt ructure(lPointe rToPrinterInfo2 ,
              lPrtInfo2.GetTy pe)

              'Get the total size of the DeviceMode

              lDevModeSize = WinSpool.Docume ntProperties(wi ndowHandle, lPrinterHandle,
              printerName, 0, 0, 0)

              'Reserve lPointerToDevMo de data memory for the total size of the DeviceMode

              lPointerToDevMo de = Marshal.AllocCo TaskMem(lDevMod eSize)

              'Fill the lPointerToDevMo de data from the printer driver

              lFlag = WinSpool.Docume ntProperties(wi ndowHandle, lPrinterHandle,
              printerName, lPointerToDevMo de, IntPtr.Zero, GDI.DM_OUT_BUFF ER)

              If lFlag < 0 Then

              lErrorCode = Marshal.GetLast Win32Error()

              Console.WriteLi ne("DocumentPro perties exited with code: {0}", lErrorCode)

              End If

              'Copy the lPointerToDevMo de data to the structure

              lDevMode = Marshal.PtrToSt ructure(lPointe rToDevMode, lDevMode.GetTyp e)

              'Set the dmFields bit flag to indicate what we are changing

              lDevMode.dmFiel ds = GDI.DM_ORIENTAT ION 'Or DM_DUPLEX Or DM_PAPERSIZE

              If isLandscape Then

              lDevMode.dmOrie ntation = GDI.DMORIENT_LA NDSCAPE

              Else

              lDevMode.dmOrie ntation = GDI.DMORIENT_PO RTRAIT

              End If

              'Set/Change PaperSize

              'lDevMode.dmPap erSize = aNewPaperSize

              'On Error Resume Next

              'lDevMode.dmDup lex = aNewDuplex

              'On Error GoTo 0

              'Copy changed structure back to the lPointerToDevMo de data

              Marshal.Structu reToPtr(lDevMod e, lPointerToDevMo de, True)

              'Merge the printer driver's current print settings with the settings in the
              lPointerToDevMo de data

              ' lFlag = WinSpool.Docume ntProperties(wi ndowHandle, lPrinterHandle,
              printerName, lPointerToDevMo de, lPointerToDevMo de, GDI.DM_IN_BUFFE R Or
              GDI.DM_OUT_BUFF ER)

              lFlag = WinSpool.Docume ntProperties(wi ndowHandle, lPrinterHandle,
              printerName, lPointerToDevMo de, lPointerToDevMo de, GDI.DM_IN_BUFFE R Or
              GDI.DM_OUT_BUFF ER Or GDI.DM_IN_PROMP T)

              lDevMode = Marshal.PtrToSt ructure(lPointe rToDevMode, lDevMode.GetTyp e)

              'Copy address of lPointerToDevMo de into lPrtInfo2 structure

              'Dim objHandle As GCHandle = GCHandle.Alloc( lPointerToDevMo de,
              GCHandleType.Pi nned)

              Dim objHandle As GCHandle = GCHandle.Alloc( lDevMode, GCHandleType.Pi nned)

              Dim objectAddress As IntPtr = objHandle.AddrO fPinnedObject()

              lPrtInfo2.pDevM ode = objectAddress

              lFlag = WinSpool.SetPri nter(lPrinterHa ndle, 2, lPointerToPrint erInfo2, 0)

              If lFlag = 0 Then

              lErrorCode = Marshal.GetLast Win32Error()

              Console.WriteLi ne("SetPrinter exited with code : {0}", lErrorCode)

              If lErrorCode = 5 Then

              MessageBox.Show ("Access denied", "Unable To Set Printer",
              MessageBoxButto ns.OK, MessageBoxIcon. Exclamation)

              End If

              End If

              lFlag = WinSpool.GetPri nter(lPrinterHa ndle, 2, lPointerToPrint erInfo2,
              lPrtInfo2Size, lPrtInfo2Size)

              Marshal.Structu reToPtr(lDevMod e, lPointerToDevMo de, True)

              CLEAN_UP:

              objHandle.Free( )

              If (lPrinterHandle .ToInt32 <> 0) Then WinSpool.CloseP rinter(lPrinter Handle)

              End Sub


              Comment

              • Just Me

                #8
                Re: How to copy an address into a pointer

                Tom,

                Thank for the help.
                It works now




                Comment

                Working...