By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
444,234 Members | 1,869 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 444,234 IT Pros & Developers. It's quick & easy.

How to copy an address into a pointer

P: n/a
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 "RtlMoveMemory"
(ByVal pDest As Integer, ByRef Source As Byte, ByVal cbCopy As Integer)


'Copy address of lDevModeAsByte into lPrtInfo2 structure

Kernel.CopyMemory1(lPrtInfo2.pDevMode, lDevModeAsByte(0), 4)
Nov 21 '05 #1
Share this Question
Share on Google+
7 Replies


P: n/a
In article <un**************@TK2MSFTNGP12.phx.gbl>, Just Me wrote:
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 "RtlMoveMemory"
(ByVal pDest As Integer, ByRef Source As Byte, ByVal cbCopy As Integer)


'Copy address of lDevModeAsByte into lPrtInfo2 structure

Kernel.CopyMemory1(lPrtInfo2.pDevMode, lDevModeAsByte(0), 4)


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.Allocate (myObject, GCHandleType.Pinned)

Try

Dim objectAddress As IntPtr = objHandle.AddrOfPinnedObject ()

Call MyFunckyUnmanagedCodeWithObjectAddress (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]
Nov 21 '05 #2

P: n/a
> 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?

Thanks again

Public Shared Sub SetPrinterSettings(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 lDevModeAsByteSize As Integer

Dim lPrtInfo2 As WinSpool.PRINTER_INFO_2

Dim lPrtInfo2AsByte() As Byte

Dim lPrtInfo2AsByteSize As Integer

Dim lFlag As Integer

Dim lPrinterDefaults As WinSpool.PRINTER_DEFAULTS

Dim lErrorCode As Integer

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

Kernel.ZeroMemory(lPrinterDefaults, Marshal.SizeOf(lPrinterDefaults))

lPrinterDefaults.DesiredAccess = WinSpool.PRINTER_ALL_ACCESS

'lPrinterDefaults.DesiredAccess = WinSpool.PRINTER_ACCESS_ADMINISTER

'Get a handle to the printer.

lFlag = WinSpool.OpenPrinter(printerName, lPrinterHandle, lPrinterDefaults)

If lFlag = 0 Then

lErrorCode = Marshal.GetLastWin32Error()

If lErrorCode = User.ERROR_ACCESS_DENIED Then

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

End If

Exit Sub

End If

'This GetPrinter call determines the size needed for lPrtInfo2AsByte

lFlag = WinSpool.GetPrinter(lPrinterHandle, 2, 0, 0, lPrtInfo2AsByteSize)

If lFlag = 0 Then

lErrorCode = Marshal.GetLastWin32Error()

If lErrorCode <> 122 Then GoTo CLEAN_UP

End If

'Allocate space for lPrtInfo2AsByte

ReDim lPrtInfo2AsByte(lPrtInfo2AsByteSize - 1)

'The second GetPrinter call fills lPrtInfo2AsByte with the current settings

lFlag = WinSpool.GetPrinter(lPrinterHandle, 2, lPrtInfo2AsByte(0),
lPrtInfo2AsByteSize, lPrtInfo2AsByteSize)

If lFlag = 0 Then

lErrorCode = Marshal.GetLastWin32Error()

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

End If

'Copy lPrtInfo2AsByte to the structure

Kernel.CopyMemory2(lPrtInfo2, lPrtInfo2AsByte(0), Marshal.SizeOf(lPrtInfo2))

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

lDevModeAsByteSize = WinSpool.DocumentProperties(windowHandle,
lPrinterHandle, printerName, 0, 0, 0)

'Reserve memory for the total size of the DeviceMode bytes

ReDim lDevModeAsByte(lDevModeAsByteSize - 1)

'Fill the DeviceMode bytes from the printer.

lFlag = WinSpool.DocumentProperties(windowHandle, lPrinterHandle,
printerName, lDevModeAsByte(0), 0, GDI.DM_OUT_BUFFER)

If lFlag < 0 Then

lErrorCode = Marshal.GetLastWin32Error()

Console.WriteLine("DocumentProperties exited with code: {0}", lErrorCode)

End If

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

Kernel.CopyMemory3(lDevMode, lDevModeAsByte(0), Marshal.SizeOf(lDevMode))

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

lDevMode.dmFields = GDI.DM_ORIENTATION 'Or DM_DUPLEX Or DM_PAPERSIZE

If isLandscape Then

lDevMode.u.dmOrientation = GDI.DMORIENT_LANDSCAPE

Else

lDevMode.u.dmOrientation = GDI.DMORIENT_PORTRAIT

End If

'Set/Change PaperSize

'lDevMode.dmPaperSize = aNewPaperSize

'On Error Resume Next

'lDevMode.dmDuplex = aNewDuplex

'On Error GoTo 0

'Copy changed structure back to the bytes

Kernel.CopyMemory4(lDevModeAsByte(0), lDevMode, Marshal.SizeOf(lDevMode))

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

lFlag = WinSpool.DocumentProperties(windowHandle, lPrinterHandle,
printerName, lDevModeAsByte(0), lDevModeAsByte(0), GDI.DM_IN_BUFFER Or
GDI.DM_OUT_BUFFER)

' lFlag = WinSpool.DocumentProperties(windowHandle, lPrinterHandle,
printerName, lDevModeAsByte(0), lDevModeAsByte(0), GDI.DM_IN_PROMPT)

'Copy address of lDevModeAsByte into lPrtInfo2 structure

' Kernel.CopyMemory1(lPrtInfo2.pDevMode, lDevModeAsByte(0),
Marshal.SizeOf(lDevMode))

Kernel.CopyMemory1(lPrtInfo2.pDevMode, lDevModeAsByte(0), 4)

'Update lPrinterInfoAsByte with the updated structure

Kernel.CopyMemory5(lPrtInfo2AsByte(0), lPrtInfo2, Marshal.SizeOf(lDevMode))

lFlag = WinSpool.SetPrinter(lPrinterHandle, 2, lPrtInfo2AsByte(0), 0)

If lFlag = 0 Then

lErrorCode = Marshal.GetLastWin32Error()

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

End If

CLEAN_UP:

WinSpool.ClosePrinter(lPrinterHandle) 'Close the handle

End Sub
Nov 21 '05 #3

P: n/a
On 2005-06-03, Just Me <gr****@a-znet.com> wrote:
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?


The System.Drawing.Printing.PageSettings class?

Dim doc As New PrintDocument ()

doc.DefaultPageSettings.Landscape = True

' Do your printing...

--
Tom Shelton [MVP]
Nov 21 '05 #4

P: n/a
I'm trying to set the system wide orientation properties.

BTW
what are
doc.PrinterSettings.DefaultPageSettings
used for?

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

Thanks

"Tom Shelton" <ts******@YOUKNOWTHEDRILLcomcast.net> wrote in message
news:%2****************@TK2MSFTNGP14.phx.gbl...
On 2005-06-03, Just Me <gr****@a-znet.com> wrote:
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?


The System.Drawing.Printing.PageSettings class?

Dim doc As New PrintDocument ()

doc.DefaultPageSettings.Landscape = True

' Do your printing...

--
Tom Shelton [MVP]

Nov 21 '05 #5

P: n/a
On 2005-06-04, Just Me <gr****@a-znet.com> wrote:
I'm trying to set the system wide orientation properties.

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.GetLastWin32Error () or the intrinsic VB.NET Err object's
LastDllError property. Both of thes methods preserve the last user called API
error codes.
BTW
what are
doc.PrinterSettings.DefaultPageSettings
used for?

Setting printer settings... System.Drawing.Printing would be the
relavent namespace to start looking at the docs..
I've been trying for a while to find out.

Thanks

"Tom Shelton" <ts******@YOUKNOWTHEDRILLcomcast.net> wrote in message
news:%2****************@TK2MSFTNGP14.phx.gbl...
On 2005-06-03, Just Me <gr****@a-znet.com> wrote:
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?


The System.Drawing.Printing.PageSettings class?

Dim doc As New PrintDocument ()

doc.DefaultPageSettings.Landscape = True

' Do your printing...

--
Tom Shelton [MVP]


--
Tom Shelton [MVP]
Nov 21 '05 #6

P: n/a
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 SetPrinterSettings(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 lPrinterDefaults As WinSpool.PRINTER_DEFAULTS

Dim lErrorCode As Integer

Dim lDevMode As GDI.DEVMODE

Dim lDevModeSize As Integer

Dim lPointerToDevMode As IntPtr

Dim lPrtInfo2 As WinSpool.PRINTER_INFO_2 = New WinSpool.PRINTER_INFO_2

Dim lPrtInfo2Size As Integer

Dim lPointerToPrinterInfo2 As IntPtr

lPrinterDefaults.DesiredAccess = WinSpool.PRINTER_ALL_ACCESS

'lPrinterDefaults.DesiredAccess = WinSpool.PRINTER_ACCESS_ADMINISTER

'Get a handle to the printer.

lFlag = WinSpool.OpenPrinter(printerName, lPrinterHandle, lPrinterDefaults)

If lFlag = 0 Then

lErrorCode = Marshal.GetLastWin32Error()

If lErrorCode = User.ERROR_ACCESS_DENIED Then

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

End If

Exit Sub

End If

'This GetPrinter call determines the size needed for lPointerToPrinterInfo2

lFlag = WinSpool.GetPrinter(lPrinterHandle, 2, IntPtr.Zero, 0,
lPrtInfo2Size)

If lFlag = 0 Then

lErrorCode = Marshal.GetLastWin32Error()

If lErrorCode <> 122 Then GoTo CLEAN_UP

End If

'Allocate space for lPointerToPrinterInfo2 data

lPointerToPrinterInfo2 = Marshal.AllocCoTaskMem(lPrtInfo2Size)

'The second GetPrinter call fills lPointerToPrinterInfo2 data with the
current settings

lFlag = WinSpool.GetPrinter(lPrinterHandle, 2, lPointerToPrinterInfo2,
lPrtInfo2Size, lPrtInfo2Size)

If lFlag = 0 Then

lErrorCode = Marshal.GetLastWin32Error()

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

End If

'Copy lPointerToPrinterInfo2 data to the structure

lPrtInfo2 = Marshal.PtrToStructure(lPointerToPrinterInfo2,
lPrtInfo2.GetType)

'Get the total size of the DeviceMode

lDevModeSize = WinSpool.DocumentProperties(windowHandle, lPrinterHandle,
printerName, 0, 0, 0)

'Reserve lPointerToDevMode data memory for the total size of the DeviceMode

lPointerToDevMode = Marshal.AllocCoTaskMem(lDevModeSize)

'Fill the lPointerToDevMode data from the printer driver

lFlag = WinSpool.DocumentProperties(windowHandle, lPrinterHandle,
printerName, lPointerToDevMode, IntPtr.Zero, GDI.DM_OUT_BUFFER)

If lFlag < 0 Then

lErrorCode = Marshal.GetLastWin32Error()

Console.WriteLine("DocumentProperties exited with code: {0}", lErrorCode)

End If

'Copy the lPointerToDevMode data to the structure

lDevMode = Marshal.PtrToStructure(lPointerToDevMode, lDevMode.GetType)

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

lDevMode.dmFields = GDI.DM_ORIENTATION 'Or DM_DUPLEX Or DM_PAPERSIZE

If isLandscape Then

lDevMode.dmOrientation = GDI.DMORIENT_LANDSCAPE

Else

lDevMode.dmOrientation = GDI.DMORIENT_PORTRAIT

End If

'Set/Change PaperSize

'lDevMode.dmPaperSize = aNewPaperSize

'On Error Resume Next

'lDevMode.dmDuplex = aNewDuplex

'On Error GoTo 0

'Copy changed structure back to the lPointerToDevMode data

Marshal.StructureToPtr(lDevMode, lPointerToDevMode, True)

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

' lFlag = WinSpool.DocumentProperties(windowHandle, lPrinterHandle,
printerName, lPointerToDevMode, lPointerToDevMode, GDI.DM_IN_BUFFER Or
GDI.DM_OUT_BUFFER)

lFlag = WinSpool.DocumentProperties(windowHandle, lPrinterHandle,
printerName, lPointerToDevMode, lPointerToDevMode, GDI.DM_IN_BUFFER Or
GDI.DM_OUT_BUFFER Or GDI.DM_IN_PROMPT)

lDevMode = Marshal.PtrToStructure(lPointerToDevMode, lDevMode.GetType)

'Copy address of lPointerToDevMode into lPrtInfo2 structure

'Dim objHandle As GCHandle = GCHandle.Alloc(lPointerToDevMode,
GCHandleType.Pinned)

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

Dim objectAddress As IntPtr = objHandle.AddrOfPinnedObject()

lPrtInfo2.pDevMode = objectAddress

lFlag = WinSpool.SetPrinter(lPrinterHandle, 2, lPointerToPrinterInfo2, 0)

If lFlag = 0 Then

lErrorCode = Marshal.GetLastWin32Error()

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

If lErrorCode = 5 Then

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

End If

End If

lFlag = WinSpool.GetPrinter(lPrinterHandle, 2, lPointerToPrinterInfo2,
lPrtInfo2Size, lPrtInfo2Size)

Marshal.StructureToPtr(lDevMode, lPointerToDevMode, True)

CLEAN_UP:

objHandle.Free()

If (lPrinterHandle.ToInt32 <> 0) Then WinSpool.ClosePrinter(lPrinterHandle)

End Sub
Nov 21 '05 #7

P: n/a
Tom,

Thank for the help.
It works now


Nov 21 '05 #8

This discussion thread is closed

Replies have been disabled for this discussion.