Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / Interop / December 2004

Tip: Looking for answers? Try searching our database.

GetHdevmode, GetHdevnames and PtrToStructure

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Tom - 18 Jul 2003 13:22 GMT
Answering my question may require some familiarity with printer
drivers in addition to interop. I'm trying to implement some interop
code between a C# application and our UniDriver printer driver. I'm
having two problems really:

1) I need to set some data in the OEMDEVMODE portion of the private
devmode section. Using the GetHdevmode method of the PrinterSettings
class and Marshall.PtrToStructure, I can successfully retrieve the
standard DevMode structure data. This is possible because the
definition of this structure is known. I also know the definition of
our OEMDEVMODE structure. The problem is that there is a UniDrv
devmode structure between the two. The definition of this structure is
not known. The standard devmode structure has two fields that hold the
length of the standard devmode and the length of the unidrv devmode
PLUS our OEMDEVMODE. Is it possible using managed C# code to retrieve
the standard devmode, do some pointer math, and then retrieve just the
OEMDEVMODE?

2) Our C# application needs to recognize when we're printing using our
printer driver as opposed to any other printer. I planned to do this
by using the GetHdevnames() method provided by the PrinterSettings
class and looking at the port name. However, unlike the success I had
in retrieving the standard devmode using the GetHdevmode method, the
data retrieved using the GetHdevnames doesn't look right. Here's the
code:

    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
    struct DEVNAMES
    {
        public short dnDriverOffset;
        public short dnDeviceOffset;
        public short dnOutputOffset;
        public short dnDefault;
    }

    // Get a handle to the devnames for this printer
    IntPtr hDevNames = pd.PrinterSettings.GetHdevnames();
    IntPtr pDevNames = GlobalLock( hDevNames );
    DEVNAMES devnames = (DEVNAMES)Marshal.PtrToStructure( pDevNames,
typeof(DEVNAMES) );
    GlobalUnlock( hDevNames );

The problem is that the structure members are supposed to be offsets
from the start of the structure to the beginning of null terminated
strings. The value I get for the first offset is 4! The next is 5.
This would point into the structure itself. Even if the offsets looked
correct, I'd have to know how to use them (more pointer math?) to
retrieve the strings.

Would appreciate any help you can give me.

Thanks,
Tom Demler
Mattias Sj?gren - 18 Jul 2003 14:59 GMT
Tom,

>1) I need to set some data in the OEMDEVMODE portion of the private
>devmode section. Using the GetHdevmode method of the PrinterSettings
[quoted text clipped - 8 lines]
>the standard devmode, do some pointer math, and then retrieve just the
>OEMDEVMODE?

Absolutely. If I got everything rigth, you should find your OEMDEVMODE
like this

IntPtr hDevMode = printerSettings.GetHdevmode();
IntPtr pDevMode = GlobalLock( hDevMode );
DEVMODE devmode = (DEVMODE)Marshal.PtrToStructure( pDevMode,
typeof(DEVMODE) );
int offset = devmode.dmSize + devmode.dmDriverExtra
            - Marshal.SizeOf( typeof(OEMDEVMODE) );
IntPtr pOemDevMode = (IntPtr)((int)pDevMode + offset);
OEMDEVMODE oemdevmode = (OEMDEVMODE)Marshal.PtrToStructure(
pOemDevMode, typeof(OEMDEVMODE) );

>However, unlike the success I had
>in retrieving the standard devmode using the GetHdevmode method, the
>data retrieved using the GetHdevnames doesn't look right.

I looked at the GetHdevnames implementation with Anakrino, and it does
look broken, so I'm not surprised you get back unexpected data. It
calculates the offset of the end of the structure as
(8/Marshal.System.DefaultCharSize) (8 being the size of DEVNAMES), so
that explains why you get 4 as the first offset running on a Unicode
OS. It also writes the strings in Unicode format when running on a
Unicode OS, which I think is incorrect (DEVNAMES should be ANSI
strings only AFAICT). I suggest you report this as a bug to Microsoft
and see if there's a fix available.

>Even if the offsets looked
>correct, I'd have to know how to use them (more pointer math?) to
>retrieve the strings.

string driverName = Marshal.PtrToStringAnsi((IntPtr)((int)pDevNames +
devnames.dnDriverOffset));
string deviceName = Marshal.PtrToStringAnsi((IntPtr)((int)pDevNames +
devnames.dnDeviceOffset));
string outputPort = Marshal.PtrToStringAnsi((IntPtr)((int)pDevNames +
devnames.dnOutputOffset));

Mattias

Signature

Mattias Sjögren [MVP]  mattias @ mvps.org
http://www.msjogren.net/dotnet/
Please reply only to the newsgroup.

Mattias Sj?gren - 18 Jul 2003 16:01 GMT
>>However, unlike the success I had
>>in retrieving the standard devmode using the GetHdevmode method, the
[quoted text clipped - 9 lines]
>strings only AFAICT). I suggest you report this as a bug to Microsoft
>and see if there's a fix available.

Forget all that. I did some testing, and I was obviously wrong, and
the GetHdevnames implementation is probably correct after all.

To get the correct string byte offset, multiply the value in the
DEVNAMES struct with Marshal.SystemDefaultCharSize.

>string driverName = Marshal.PtrToStringAnsi((IntPtr)((int)pDevNames +
>devnames.dnDriverOffset));
>string deviceName = Marshal.PtrToStringAnsi((IntPtr)((int)pDevNames +
>devnames.dnDeviceOffset));
>string outputPort = Marshal.PtrToStringAnsi((IntPtr)((int)pDevNames +
>devnames.dnOutputOffset));

So this should actually be

string driverName = Marshal.PtrToStringAnsi((IntPtr)((int)pDevNames +
devnames.dnDriverOffset*Marshal.SystemDefaultCharSize));
string deviceName = Marshal.PtrToStringAnsi((IntPtr)((int)pDevNames +
devnames.dnDeviceOffset*Marshal.SystemDefaultCharSize));
string outputPort = Marshal.PtrToStringAnsi((IntPtr)((int)pDevNames +
devnames.dnOutputOffset*Marshal.SystemDefaultCharSize));

Mattias

Signature

Mattias Sjögren [MVP]  mattias @ mvps.org
http://www.msjogren.net/dotnet/
Please reply only to the newsgroup.

Mattias Sj?gren - 18 Jul 2003 16:05 GMT
>string driverName = Marshal.PtrToStringAnsi((IntPtr)((int)pDevNames +
>devnames.dnDriverOffset*Marshal.SystemDefaultCharSize));
>string deviceName = Marshal.PtrToStringAnsi((IntPtr)((int)pDevNames +
>devnames.dnDeviceOffset*Marshal.SystemDefaultCharSize));
>string outputPort = Marshal.PtrToStringAnsi((IntPtr)((int)pDevNames +
>devnames.dnOutputOffset*Marshal.SystemDefaultCharSize));

Damn, I can't anything right today. All those PtrToStringAnsi should
actually be PtrToStringAuto.

Mattias

Signature

Mattias Sjögren [MVP]  mattias @ mvps.org
http://www.msjogren.net/dotnet/
Please reply only to the newsgroup.

heino - 30 Dec 2004 15:58 GMT
Hello,

Can you share how you solved your problem??

I am trying to read public and private DEVMODE structures
using GethDevMode and SethDevMode commands of PrinterSettings.

This thing has stumped me.

Thanks.

heino

> Answering my question may require some familiarity with printer
> drivers in addition to interop. I'm trying to implement some interop
[quoted text clipped - 49 lines]
> Thanks,
> Tom Demler

Rate this thread:







Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.