15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


Как правильно работать с API функциями Win32 Spooler

Данный набор API функций Win32 спулера занимается в основном заполнением массива структур. Однако, структуры обычно включают в себя указатели на строки либо на другие данные. Эти посторонние данные также должны быть сохранены в возвращаемой памяти, соответственно они добавляются в конец массива. Поэтому, простого объявления массива таких структур в стеке будет недостаточно, чтобы хранить всю информацию, которую возвращают данные API функции.

Итак, речь идёт о функциях: EnumForms(), EnumJobs(), EnumMonitors(), EnumPorts(), EnumPrinterDrivers(), EnumPrinters(), и EnumPrintProcessors(). Кстати, функции GetJob(), GetPrinter(), и DocumentProperties() требуют идентичной обработки. Каждую функцию необходимо вызывать дважды. Первый вызов предназначен для определения необходимого размера буфера, а последующий вызов необходим для передачи указателя на динамически распределённый буфер достаточного размера. Код, представленный ниже, является консольным приложением, и демонстрирует использование функции EnumJobs():

   BOOL ListJobsForPrinter( LPTSTR szPrinterName )
   {

   HANDLE         hPrinter;
   DWORD          dwNeeded, dwReturned, i;
   JOB_INFO_1     *pJobInfo;

   // Нам понадобится дескриптор принтера, поэтому откроем его
   if( ! OpenPrinter( szPrinterName, &hPrinter, NULL ) )
     return FALSE;

   // Сперва вызовем EnumJobs() чтобы определить, сколько нам потребуется
   // памяти
   if( ! EnumJobs( hPrinter, 0, 0xFFFFFFFF, 1, NULL, 0, &dwNeeded,
                   &dwReturned ) )
   {
     // В любом случае надо обработать ошибку нехватки памяти
     if( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
     {
       ClosePrinter( hPrinter );
       return FALSE;
     }
   }
   // Распределяем достаточное количество памяти для структуры JOB_INFO_1
   // плюс дополнительные данные - dwNeeded из предыдущего вызова
   // говорит нам, какой объём необходим
   if( (pJobInfo = (JOB_INFO_1 *)malloc( dwNeeded )) == NULL )
   {
     ClosePrinter( hPrinter );
     return FALSE;
   }
   // Вызываем EnumJobs() снова, заполняя тем самым структуры
   if( ! EnumJobs( hPrinter, 0, 0xFFFFFFFF, 1, (LPBYTE)pJobInfo,
                   dwNeeded, &dwNeeded, &dwReturned ) )
   {
     ClosePrinter( hPrinter );
     free( pJobInfo );
     return FALSE;
   }
   // Больше дескриптор принтера нам не нужен, поэтому закрываем его
   ClosePrinter( hPrinter );

   // dwReturned говорит нам, сколько текущих заданий
   // Просто отображаем количество найденных заданий
   printf( "%d jobs\n", dwReturned );
   // Проще сделать это в цикле и пройтись по каждому заданию
   for(i=0;i<dwReturned;i++)
   {
     // pJobInfo[i] это структура JOB_INFO_1 для данного задания
     printf( "[%d] [%s]\n", pJobInfo[i].JobId, pJobInfo[i].pDocument );
   }

   // Очищаем
   free( pJobInfo );
   return TRUE;
 }