Re: Win AP question

Tech-Archive recommends: Repair Windows Errors & Optimize Windows Performance

From: BMermuys (someone_at_someone.com)
Date: 04/16/04


Date: Fri, 16 Apr 2004 15:47:11 +0200

Hi,

First of all lets look at the c sign :

BOOL EnumJobs(
  HANDLE hPrinter, // handle to printer object
  DWORD FirstJob, // index of first job
  DWORD NoJobs, // number of jobs to enumerate
  DWORD Level, // information level
  LPBYTE pJob, // job information buffer
  DWORD cbBuf, // size of job information buffer
  LPDWORD pcbNeeded, // bytes received or required
  LPDWORD pcReturned // number of jobs received
);

After reading the information you'll see that pJob should be a buffer large
enough to hold all structs *plus* the data the struct points to (string
data). (There are other api's which uses this "strategy" too)

This means that you can't just pass an array of structs. You must supply
memory which is large enough for the structs and the string data. In memory
it would be something like :
struct1
struct2
struct3
all other data where the structs point to (eg. string data)

So, we declare it in c# as follow :

[DllImport("winspool.drv", CharSet=CharSet.Auto)]
public static extern int EnumJobs(
    IntPtr hPrinter,
    int FirstJob,
    int NoJobs,
    int Level,
    IntPtr pInfo,
    int cdBuf,
    out int pcbNeeded,
    out int pcReturned);

pInfo is an IntPtr which we can point to allocated memory. One of the
problems of the used "strategy" is that you can't easily know who many bytes
you will need, you can't do NoJobs*sizeof(job_info_1) because there is
additional memory needed as explained.

You can guess the memory needed and if it fails you can try with more
memory. There is a better way : call the function first with cdBuf=0 then
it will return the bytes required in pcbNeeded.

Once you know the bytes needed, you can allocate memory with
(Marshal.AllocHGlobal), then you can call the function again with cdBuf set
to the last return pcbNeeded. Now the memory will be filled with structs
and extra data. You can then use Marshal.PtrToStruct to marshal these
struct into managed memory (it will also marshal the extra data because the
struct members point to it). After this you clean up unmanaged memory
(Marshal.FreeHGlobal).

Example : (!!You need to use the corrected structs by Tom)

[DllImport("winspool.drv", CharSet=CharSet.Auto)]
public static extern bool OpenPrinter( string pPrinterName, out IntPtr
phPrinter, IntPtr pDefault );

[DllImport("winspool.drv", CharSet=CharSet.Auto)]
public static extern bool ClosePrinter( IntPtr hPrinter // handle to printer
object );

[DllImport("winspool.drv", CharSet=CharSet.Auto)]
public static extern int EnumJobs( IntPtr hPrinter, int FirstJob, int
NoJobs, int Level, IntPtr pInfo, int cdBuf, out int pcbNeeded, out int
pcReturned);

public void test()
{
    IntPtr handle;
    int FirstJob = 1;
    int NumJobs = 2;
    int pcbNeeded;
    int pcReturned;

    // open printer
    OpenPrinter ( @\\server1\psc750, out handle, IntPtr.Zero );

    // get num bytes required
    EnumJobs ( handle, FirstJob, NumJobs, 1, IntPtr.Zero, 0, out pcbNeeded,
out pcReturned);

    // allocate unmanaged memory
    IntPtr pData = Marshal.AllocHGlobal ( pcbNeeded );

    // get structs
    EnumJobs ( handle, FirstJob, NumJobs, 1, pData, pcbNeeded, out
pcbNeeded, out pcReturned);

    // create array of managed job structs
    JOB_INFO_1 [] jobs = new JOB_INFO_1[pcReturned];

    // marshal struct to managed
    int pTemp = pData.ToInt32(); //start pointer
    for (int i=0; i<pcReturned; ++i)
    {
        jobs[i] = (JOB_INFO_1) Marshal.PtrToStruct( new IntPtr(pTemp),
typof(JOB_INFO_1) );
        pTemp+= Marshal.SizeOf( typeof (JOB_INFO_1 );
    }

    // cleanup unmanaged memory
    Marshal.FreeHGlobal ( pData );

    // close printer
    ClosePrinter ( handle );

    // printer jobs are in the jobs array
}

HTH,
greetings

"Kevin" <anonymous@discussions.microsoft.com> wrote in message
news:20929CEC-6D0E-4CAD-B796-236730113440@microsoft.com...
> Hi all
>
> I have an interesting question.... I am working witha Win API this is the
Function:
> Public Declare Function EnumJobs Lib "winspool.drv" Alias "EnumJobsA"
(ByVal hPrinter As Long, ByVal FirstJob As Long, ByVal NoJobs As Long, ByVal
Level As Long, pJob As Byte, ByVal cdBuf As Long, pcbNeeded As Long,
pcReturned As Long) As Long
>
> Which I got from the API viewer that comes with VB 6. I have tried to
convert it to the following:
>
> [DllImport("winspool.drv")]
> public static extern long EnumJobs(long hPrinter,long FirstJob,long
NoJobs,long Level,ref JOB_INFO_1 jInfo,long cdBuf,long pcbNeeded,long
pcReturned );
>
> however i think I may have gotten a few things wrong, which I am hoping
someone will be able to correct me.
>
> 1. In the Declare statement there is a parameter that is : pJob As Byte
and I've even seen it as : pJob As Any
> Now my question is that can I pass my struct(JOB_INFO_1) in there? even
though the datatype it wants is byte, can I still pass the struct in there?
How do i get my struct popultaed from this call, when it accepts a byte? do
i need to do anything with how I created my strcut, this is my sample code
of the strcut declaration :
> [StructLayout(LayoutKind.Sequential)]
> public struct JOB_INFO_1
> {
> public long JobId;
> public string pPrinterName;
> public string pMachineName;
> public string pUserName;
> public string pDocument;
> public string pDatatype;
> public string pStatus;
> public long Status;
> public long Priority;
> public long Position;
> public long TotalPages;
> public long PagesPrinted;
> public SYSTEMTIME Submitted;
> }
>
> [StructLayout(LayoutKind.Sequential)]
> public struct SYSTEMTIME
> {
> public int wYear;
> public int wMonth;
> public int wDayOfWeek;
> public int wDay;
> public int wHour;
> public int wMinute;
> public int wSecond;
> public int wMilliseconds;
> }
>
> 2. If ever I see another winAPI that accepts a datatype of "Any" what do I
know what is "supposed to get there"?
>
> Thanks for any help
> Kevin
>
>
>



Relevant Pages

  • Beware CS1612 when dealing with "Point" (its not really a structure like most of us think of)
    ... modify a Point, which I had made have a property. ... like 'int' or 'nullable' types, and does not really have 'member ... allow you to return a reference to a value type. ... The only issue I have with the way that structs are implemented ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Is Class Synonymous with Type?
    ... So-called "Native Types" (int, double, struct, enum, etc) ARE classes, which ... Similarly Structs are not classes. ... that encapsulate the native types. ... The above declare three variables in C of type int, float and pointer to ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: valid types for Keys (Hashtable, Dictionary)
    ... structs have very specific applications in .NET, ... just like an int or a double. ... public override int GetHashCode() ...
    (microsoft.public.dotnet.languages.csharp)
  • [RFC 2/3] Linux Kernel Markers - Create modpost file
    ... This adds some new magic in the MODPOST phase for CONFIG_MARKERS. ... as long as the marker structs are always defined by this macro. ... +static void read_markers(const char *fname) ... int main ...
    (Linux-Kernel)
  • [patch 2/2] Linux Kernel Markers - Create modpost file
    ... This adds some new magic in the MODPOST phase for CONFIG_MARKERS. ... as long as the marker structs are always defined by this macro. ... +static void read_markers(const char *fname) ... int main ...
    (Linux-Kernel)