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("wins pool.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(j ob_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.AllocH Global), 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.PtrToSt ruct 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.FreeHG lobal).
Example : (!!You need to use the corrected structs by Tom)
[DllImport("wins pool.drv", CharSet=CharSet .Auto)]
public static extern bool OpenPrinter( string pPrinterName, out IntPtr
phPrinter, IntPtr pDefault );
[DllImport("wins pool.drv", CharSet=CharSet .Auto)]
public static extern bool ClosePrinter( IntPtr hPrinter // handle to printer
object );
[DllImport("wins pool.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\psc7 50, 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.AllocHG lobal ( 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.PtrToSt ruct( new IntPtr(pTemp),
typof(JOB_INFO_ 1) );
pTemp+= Marshal.SizeOf( typeof (JOB_INFO_1 );
}
// cleanup unmanaged memory
Marshal.FreeHGl obal ( pData );
// close printer
ClosePrinter ( handle );
// printer jobs are in the jobs array
}
HTH,
greetings
"Kevin" <an*******@disc ussions.microso ft.com> wrote in message
news:20******** *************** ***********@mic rosoft.com...
Hi all
I have an interesting question.... I am working witha Win API this is the
Function: Public Declare Function EnumJobs Lib "winspool.d rv" 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("wins pool.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(La youtKind.Sequen tial)]
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(La youtKind.Sequen tial)]
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