FreeBASIC  0.91.0
io_printer.c
Go to the documentation of this file.
1 /* printer access for Windows */
2 
3 #include "../fb.h"
4 #include <ctype.h>
5 #include <windows.h>
6 #include <winspool.h>
7 
8 typedef BOOL (WINAPI *FnGetDefaultPrinter)(LPTSTR pszBuffer, LPDWORD pcchBuffer);
9 
10 struct _W32_PRINTER_INFO;
11 
12 typedef void (*FnEmuPrint)(struct _W32_PRINTER_INFO *pInfo,
13  const void *pText,
14  size_t uiLength,
15  int isunicode );
16 
17 /* Win32-specific printer information */
18 typedef struct _W32_PRINTER_INFO {
21  HDC hDc;
22  struct {
31 
34  HFONT hFont;
35  COLORREF clFore, clBack;
39 
41  } Emu;
43 
44 /* Entry for the list of available printers */
45 typedef struct _DEV_PRINTER_DEVICE {
47  char *device;
48  char *printer_name;
50 
51 /* Information about a single printer emulation mode */
52 typedef struct _DEV_PRINTER_EMU_MODE {
53  const char *pszId;
56 
57 static
58 void EmuBuild_LOGFONT( LOGFONT *lf,
59  W32_PRINTER_INFO *pInfo,
60  unsigned uiCPI );
61 static
62  void EmuUpdateInfo( W32_PRINTER_INFO *pInfo );
63 static
64  void EmuPrint_RAW( W32_PRINTER_INFO *pInfo, const void *pText, size_t uiLength, int isunicode );
65 static
66  void EmuPrint_TTY( W32_PRINTER_INFO *pInfo, const void *pText, size_t uiLength, int isunicode );
67 #if 0
68 static
69  void EmuPrint_ESC_P2( W32_PRINTER_INFO *pInfo, const void *pText, size_t uiLength, int isunicode );
70 #endif
71 
72 /* List of all known printer emulation modes */
74  { "RAW", EmuPrint_RAW }
75  , { "TTY", EmuPrint_TTY }
76 #if 0
77  , { "ESC/P2", EmuPrint_ESC_P2 }
78 #endif
79 };
80 
83 static void
85 {
86  fb_hListDynInit( list );
87 }
88 
93 static DEV_PRINTER_DEVICE *
94 fb_hListDevElemAlloc ( FB_LIST *list, const char *device, const char *printer_name )
95 {
96  DEV_PRINTER_DEVICE *node = (DEV_PRINTER_DEVICE*) calloc( 1, sizeof(DEV_PRINTER_DEVICE) );
97  node->device = strdup(device);
98  node->printer_name = strdup(printer_name);
99  fb_hListDynElemAdd( list, &node->elem );
100  return node;
101 }
102 
105 static void
107 {
108  fb_hListDynElemRemove( list, &node->elem );
109  free(node->device);
110  free(node->printer_name);
111  free(node);
112 }
113 
116 static void
118 {
119  while( list->head != NULL ) {
120  fb_hListDevElemFree( list, (DEV_PRINTER_DEVICE*) list->head );
121  }
122 }
123 
126 static DEV_PRINTER_DEVICE*
127 fb_hListDevFindDevice( FB_LIST *list, const char *pszDevice )
128 {
129  DEV_PRINTER_DEVICE* node = (DEV_PRINTER_DEVICE*) list->head;
130  for( ;
131  node!=NULL;
132  node = (DEV_PRINTER_DEVICE*) node->elem.next )
133  {
134  if( strcasecmp( pszDevice, node->device )==0 )
135  return node;
136  }
137  return NULL;
138 }
139 
142 static DEV_PRINTER_DEVICE*
143 fb_hListDevFindName ( FB_LIST *list, const char *pszPrinterName )
144 {
145  DEV_PRINTER_DEVICE* node = (DEV_PRINTER_DEVICE*) list->head;
146  for( ;
147  node!=NULL;
148  node = (DEV_PRINTER_DEVICE*) node->elem.next )
149  {
150  if( strcasecmp( pszPrinterName, node->printer_name )==0 )
151  return node;
152  }
153  return NULL;
154 }
155 
156 static PRINTER_INFO_5 *GetDefaultPrinters( int *pCount )
157 {
158  DWORD dwNeeded = 0, dwReturned = 0;
159  PRINTER_INFO_5 *result = NULL;
160  DWORD dwFlags = PRINTER_ENUM_DEFAULT;
161 
162  DBG_ASSERT(pCount!=NULL);
163 
164  *pCount = 0;
165 
166  BOOL fResult = EnumPrinters(dwFlags,
167  NULL,
168  5,
169  NULL,
170  0,
171  &dwNeeded,
172  &dwReturned);
173 
174  while (!fResult) {
175  if (GetLastError()!=ERROR_INSUFFICIENT_BUFFER)
176  break;
177 
178  result = (PRINTER_INFO_5*) realloc( result, dwNeeded );
179  if( result == NULL )
180  break;
181 
182  fResult = EnumPrinters(dwFlags,
183  NULL,
184  5,
185  (BYTE*) result,
186  dwNeeded,
187  &dwNeeded,
188  &dwReturned);
189  }
190 
191  *pCount = dwReturned;
192 
193  return result;
194 }
195 
196 static PRINTER_INFO_2 *GetPrinters( int *pCount )
197 {
198  DWORD dwNeeded = 0, dwReturned = 0;
199  PRINTER_INFO_2 *result = NULL;
200  DWORD dwFlags = PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS;
201 
202  DBG_ASSERT(pCount!=NULL);
203 
204  *pCount = 0;
205 
206  BOOL fResult = EnumPrinters(dwFlags,
207  NULL,
208  2,
209  NULL,
210  0,
211  &dwNeeded,
212  &dwReturned);
213 
214  while (!fResult) {
215  if (GetLastError()!=ERROR_INSUFFICIENT_BUFFER)
216  break;
217 
218  result = (PRINTER_INFO_2*) realloc( result, dwNeeded );
219  if( result == NULL )
220  break;
221 
222  fResult = EnumPrinters(dwFlags,
223  NULL,
224  2,
225  (BYTE*) result,
226  dwNeeded,
227  &dwNeeded,
228  &dwReturned);
229  }
230 
231  *pCount = dwReturned;
232 
233  return result;
234 }
235 
236 static char *GetDefaultPrinterName(void)
237 {
238  char *result = NULL;
239  int count;
240  PRINTER_INFO_5 *printers = GetDefaultPrinters(&count);
241  if( count==0 ) {
242  HMODULE hMod = LoadLibrary(TEXT("winspool.drv"));
243  if (hMod!=NULL) {
244 #ifdef UNICODE
245  LPCTSTR pszPrinterId = TEXT("GetDefaultPrinterW");
246 #else
247  LPCTSTR pszPrinterId = TEXT("GetDefaultPrinterA");
248 #endif
249  FnGetDefaultPrinter pfnGetDefaultPrinter =
250  (FnGetDefaultPrinter) GetProcAddress(hMod, pszPrinterId);
251  if (pfnGetDefaultPrinter!=NULL) {
252  TCHAR *buffer = NULL;
253  DWORD dwSize = 0;
254  BOOL fResult = pfnGetDefaultPrinter(NULL, &dwSize);
255  while (!fResult) {
256  if (GetLastError()!=ERROR_INSUFFICIENT_BUFFER)
257  break;
258  buffer = (TCHAR*) realloc(buffer, dwSize * sizeof(TCHAR));
259  fResult = pfnGetDefaultPrinter(buffer, &dwSize);
260  }
261  if (dwSize>1) {
262  result = buffer;
263  }
264 
265  }
266  FreeLibrary(hMod);
267  }
268  } else {
269  result = strdup(printers->pPrinterName);
270  }
271  free(printers);
272  return result;
273 }
274 
275 static void
277 {
278  int i, count;
279  PRINTER_INFO_2 *printers = GetPrinters(&count);
280  for( i=0; i!=count; ++i ) {
281  PRINTER_INFO_2 *printer = printers + i;
282  if( printer->pServerName==NULL ) {
283  /* get the port from local printers only */
284  LPTSTR pPortName = printer->pPortName;
285  LPTSTR pFoundPos = strchr(pPortName, ',');
286  while (pFoundPos) {
287  DEV_PRINTER_DEVICE* node;
288  *pFoundPos = 0;
289 
290  /* We only add printers to the list that are attached to
291  * an LPTx: port */
292  if( strncasecmp( pPortName, "LPT", 3 )==0 ) {
293  node = fb_hListDevFindDevice( list, pPortName );
294  if( node==NULL ) {
295  fb_hListDevElemAlloc ( list, pPortName, printer->pPrinterName );
296  }
297  }
298 
299  pPortName = pFoundPos + 1;
300  while( isspace( *pPortName ) )
301  ++pPortName;
302  pFoundPos = strchr(pPortName, ',');
303  }
304  if( strncasecmp( pPortName, "LPT", 3 )==0 ) {
305  DEV_PRINTER_DEVICE* node = fb_hListDevFindDevice( list, pPortName );
306  if( node==NULL ) {
307  fb_hListDevElemAlloc ( list, pPortName, printer->pPrinterName );
308  }
309  }
310  }
311  }
312  free(printers);
313 }
314 
315 static int
317 {
318  char Buffer[32];
319  int iPort = iStartPort - 1;
320  char *printer_name = GetDefaultPrinterName( );
321 
322  if( printer_name!=NULL ) {
323  if( fb_hListDevFindName( list, printer_name )==NULL ) {
324  DEV_PRINTER_DEVICE* node;
325 
326  do {
327  ++iPort;
328  sprintf( Buffer, "LPT%d", iPort );
329  node = fb_hListDevFindDevice( list, Buffer );
330  } while( node!=NULL );
331 
332  fb_hListDevElemAlloc ( list, Buffer, printer_name );
333  }
334  free( printer_name );
335  }
336 
337  return iPort + 1;
338 }
339 
340 static int
342 {
343  char Buffer[32];
344  int i, count, iPort = iStartPort - 1;
345  PRINTER_INFO_2 *printers = GetPrinters(&count);
346 
347  for( i=0; i!=count; ++i ) {
348  PRINTER_INFO_2 *printer = printers + i;
349  if( fb_hListDevFindName( list, printer->pPrinterName )==NULL ) {
350  DEV_PRINTER_DEVICE* node;
351  do {
352  ++iPort;
353  sprintf( Buffer, "LPT%d", iPort );
354  node = fb_hListDevFindDevice( list, Buffer );
355  } while( node!=NULL );
356 
357  fb_hListDevElemAlloc ( list, Buffer, printer->pPrinterName );
358  }
359  }
360  free(printers);
361 
362  return iPort + 1;
363 }
364 
365 static void
367 {
369 
370  /* The default printer should be mapped to LPT1: if no other local printer
371  * is mapped to LPT1: */
372  fb_hPrinterBuildListDefault( list, 1 );
373 
374  /* Other printers that aren't local or attached to an LPTx: port
375  * are mapped to LPT128: and above. */
376  fb_hPrinterBuildListOther( list, 128 );
377 }
378 
379 int fb_PrinterOpen( DEV_LPT_INFO *devInfo, int iPort, const char *pszDevice )
380 {
381  int result = fb_ErrorSetNum( FB_RTERROR_OK );
382  const DEV_PRINTER_EMU_MODE *pFoundEmu = NULL;
383  DWORD dwJob = 0;
384  BOOL fResult;
385  HANDLE hPrinter = NULL;
386  HDC hDc = NULL;
387 
388  char *printer_name = NULL;
389  char *doc_title = NULL;
390 
391  DEV_LPT_PROTOCOL *lpt_proto;
392  if ( !fb_DevLptParseProtocol( &lpt_proto, pszDevice, strlen(pszDevice), TRUE ) )
393  {
394  if( lpt_proto!=NULL )
395  free(lpt_proto);
397  }
398 
399  /* Allow only valid emulation modes */
400  if( *lpt_proto->emu!=0 ) {
401  int i;
402  for( i=0;
403  i!=sizeof(aEmulationModes)/sizeof(aEmulationModes[0]);
404  ++i )
405  {
406  const DEV_PRINTER_EMU_MODE *pEmu = aEmulationModes + i;
407  if( strcasecmp( lpt_proto->emu, pEmu->pszId )==0 ) {
408  pFoundEmu = pEmu;
409  break;
410  }
411  }
412  if( !pFoundEmu )
413  {
414  if( lpt_proto!=NULL )
415  free(lpt_proto);
417  }
418  }
419 
420  if( iPort==0 ) {
421  /* LPT:[PrinterName] */
422  if( *lpt_proto->name )
423  {
424  printer_name = strdup( lpt_proto->name );
425  } else {
426  printer_name = GetDefaultPrinterName();
427  }
428 
429  } else {
430  /* LPTx: */
431  FB_LIST dev_printer_devs;
432  DEV_PRINTER_DEVICE* node;
433 
434  fb_hListDevInit( &dev_printer_devs );
435  fb_hPrinterBuildList( &dev_printer_devs );
436 
437  /* Find printer attached to specified device */
438  node = fb_hListDevFindDevice( &dev_printer_devs, lpt_proto->proto );
439  if( node!=NULL ) {
440  printer_name = strdup( node->printer_name );
441  }
442 
443  fb_hListDevClear( &dev_printer_devs );
444  }
445 
446  if( printer_name == NULL ) {
448  } else {
449  if( *lpt_proto->emu!= '\0' ) {
450  /* When EMULATION is used, we have to use the DC instead of
451  * the PRINTER directly */
452  hDc = CreateDCA( "WINSPOOL",
453  printer_name,
454  NULL,
455  NULL );
456  fResult = hDc!=NULL;
457  } else {
458  /* User PRINTER directly */
459  fResult = OpenPrinter(printer_name, &hPrinter, NULL);
460  }
461  if( !fResult ) {
463  }
464  }
465 
466  if( lpt_proto->title && *lpt_proto->title ) {
467  doc_title = strdup( lpt_proto->title );
468  } else {
469  doc_title = strdup( "FreeBASIC document" );
470  }
471 
472  if( result==FB_RTERROR_OK ) {
473  if( *lpt_proto->emu!= '\0' ) {
474  int iJob;
475  DOCINFO docInfo;
476  memset( &docInfo, 0, sizeof(DOCINFO) );
477  docInfo.cbSize = sizeof(DOCINFO);
478  docInfo.lpszDocName = doc_title;
479  iJob = StartDoc( hDc, &docInfo );
480  if( iJob <= 0 ) {
481  result = fb_ErrorSetNum( FB_RTERROR_FILEIO );
482  } else {
483  dwJob = (DWORD) iJob;
484  }
485  } else {
486  DOC_INFO_1 DocInfo;
487  DocInfo.pDocName = doc_title;
488  DocInfo.pOutputFile = NULL;
489  DocInfo.pDatatype = TEXT("RAW");
490 
491  dwJob = StartDocPrinter( hPrinter, 1, (BYTE*) &DocInfo );
492  if( dwJob==0 ) {
493  result = fb_ErrorSetNum( FB_RTERROR_FILEIO );
494  }
495  }
496  }
497 
498  if( result==FB_RTERROR_OK ) {
499  W32_PRINTER_INFO *pInfo = calloc( 1, sizeof(W32_PRINTER_INFO) );
500  if( pInfo==NULL ) {
502  } else {
503  devInfo->driver_opaque = pInfo;
504  pInfo->hPrinter = hPrinter;
505  pInfo->dwJob = dwJob;
506  pInfo->hDc = hDc;
507  if( hDc!=NULL ) {
508  LOGFONT lf;
509 
510  pInfo->Emu.dwFullSizeX = GetDeviceCaps( hDc, PHYSICALWIDTH );
511  pInfo->Emu.dwFullSizeY = GetDeviceCaps( hDc, PHYSICALHEIGHT );
512  pInfo->Emu.dwSizeX = GetDeviceCaps( hDc, HORZRES );
513  pInfo->Emu.dwSizeY = GetDeviceCaps( hDc, VERTRES );
514  pInfo->Emu.dwOffsetX = GetDeviceCaps( hDc, PHYSICALOFFSETX );
515  pInfo->Emu.dwOffsetY = GetDeviceCaps( hDc, PHYSICALOFFSETY );
516  pInfo->Emu.dwDPI_X = GetDeviceCaps( hDc, LOGPIXELSX );
517  pInfo->Emu.dwDPI_Y = GetDeviceCaps( hDc, LOGPIXELSY );
518 #if 0
519  pInfo->Emu.dwCurrentX = pInfo->Emu.dwOffsetX;
520  pInfo->Emu.dwCurrentY = pInfo->Emu.dwOffsetY;
521 #else
522  pInfo->Emu.dwCurrentX = 0;
523  pInfo->Emu.dwCurrentY = 0;
524 #endif
525  pInfo->Emu.clFore = RGB(0,0,0);
526  pInfo->Emu.clBack = RGB(255,255,255);
527 
528  /* Start in 12 CPI monospace mode */
529  EmuBuild_LOGFONT( &lf, pInfo, 12 );
530 
531  /* Should never fail - except when some default fonts were
532  * removed by hand (which is very unlikely) */
533  pInfo->Emu.hFont = CreateFontIndirect( &lf );
534  DBG_ASSERT( pInfo->Emu.hFont!=NULL );
535 
536  /* Register PRINT function */
537  pInfo->Emu.pfnPrint = pFoundEmu->pfnPrint;
538 
539  /* Should not be necessary because this is the default */
540  SetTextAlign( hDc, TA_TOP | TA_LEFT | TA_NOUPDATECP );
541 
542  EmuUpdateInfo( pInfo );
543  }
544  }
545  }
546 
547  if( result!=FB_RTERROR_OK ) {
548  if( dwJob!=0 ) {
549  if( *lpt_proto->emu != '\0' ) {
550  EndDoc( hDc );
551  } else {
552  EndDocPrinter( hPrinter );
553  }
554  }
555  if( hPrinter!=NULL ) {
556  ClosePrinter( hPrinter );
557  }
558  if( hDc!=NULL ) {
559  DeleteDC( hDc );
560  }
561  }
562 
563  if( printer_name!=NULL )
564  free( printer_name );
565  if( doc_title!=NULL )
566  free( doc_title );
567  if( lpt_proto!=NULL )
568  free(lpt_proto);
569 
570  return result;
571 }
572 
573 static
574 void EmuBuild_LOGFONT( LOGFONT *lf,
575  W32_PRINTER_INFO *pInfo,
576  unsigned uiCPI )
577 {
578  memset( lf, 0, sizeof( LOGFONT ) );
579  lf->lfHeight = pInfo->Emu.dwDPI_Y*10/72; /* default height */
580  lf->lfWeight = FW_NORMAL;
581  lf->lfCharSet = OEM_CHARSET;
582  lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
583  lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
584  lf->lfQuality = DRAFT_QUALITY;
585  if( uiCPI!=0 ) {
586  lf->lfWidth = pInfo->Emu.dwDPI_X/uiCPI;
587  lf->lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
588  strcpy( lf->lfFaceName, "System" );
589  } else {
590  lf->lfWidth = 0;
591  lf->lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS;
592  strcpy( lf->lfFaceName, "MS Sans Serif" );
593  }
594 }
595 
596 static void EmuUpdateInfo( W32_PRINTER_INFO *pInfo )
597 {
598  TEXTMETRIC tm;
599 
600  SelectObject( pInfo->hDc, pInfo->Emu.hFont );
601 
602  GetTextMetrics( pInfo->hDc, &tm );
603  pInfo->Emu.dwFontSizeX = tm.tmMaxCharWidth;
604  pInfo->Emu.dwFontSizeY = tm.tmHeight;
605 }
606 
607 static void EmuPageStart( W32_PRINTER_INFO *pInfo )
608 {
609  if( pInfo->Emu.iPageStarted )
610  return;
611 
612  StartPage( pInfo->hDc );
613  pInfo->Emu.iPageStarted = TRUE;
614 
615  EmuUpdateInfo( pInfo );
616 
617  SetTextColor( pInfo->hDc, pInfo->Emu.clFore );
618  SetBkColor( pInfo->hDc, pInfo->Emu.clBack );
619 }
620 
621 static void EmuPrint_RAW( W32_PRINTER_INFO *pInfo,
622  const void *pText,
623  size_t uiLength,
624  int isunicode )
625 {
626  while( uiLength-- ) {
627  if( !isunicode )
628  {
629  char ch = *(char *)pText;
630  pText += sizeof(char);
631 
632  EmuPageStart( pInfo );
633  TextOut( pInfo->hDc,
634  pInfo->Emu.dwCurrentX, pInfo->Emu.dwCurrentY,
635  &ch, 1 );
636  } else {
637  FB_WCHAR ch = *(FB_WCHAR *)pText;
638  pText += sizeof(FB_WCHAR);
639 
640 
641  EmuPageStart( pInfo );
642  TextOutW( pInfo->hDc,
643  pInfo->Emu.dwCurrentX, pInfo->Emu.dwCurrentY,
644  &ch, 1 );
645  }
646 
647  pInfo->Emu.dwCurrentX += pInfo->Emu.dwFontSizeX;
648 
649  if( pInfo->Emu.dwCurrentX>=pInfo->Emu.dwSizeX ) {
650  pInfo->Emu.dwCurrentX = 0;
651  pInfo->Emu.dwCurrentY += pInfo->Emu.dwFontSizeY;
652  if( pInfo->Emu.dwCurrentY>=pInfo->Emu.dwSizeY ) {
653  pInfo->Emu.dwCurrentY = 0;
654  EndPage( pInfo->hDc );
655  pInfo->Emu.iPageStarted = FALSE;
656  }
657  }
658  }
659 }
660 
661 static
663  int x1,
664  int y1,
665  int x2,
666  int y2,
667  int rows)
668 {
669  W32_PRINTER_INFO *pInfo = handle->Opaque;
670  int page_rows = (pInfo->Emu.dwSizeY + pInfo->Emu.dwFontSizeY - 1)
671  / pInfo->Emu.dwFontSizeY;
672  if( !pInfo->Emu.iPageStarted ) {
673  StartPage( pInfo->hDc );
674  }
675  EndPage( pInfo->hDc );
676  while( rows >= page_rows ) {
677  StartPage( pInfo->hDc );
678  EndPage( pInfo->hDc );
679  rows -= page_rows;
680  }
681  pInfo->Emu.iPageStarted = FALSE;
682  if( rows!=0 )
683  --rows;
684  handle->Coord.Y = rows;
685 }
686 
687 static
689  const void *buffer,
690  size_t length )
691 {
692  W32_PRINTER_INFO *pInfo = handle->Opaque;
693  pInfo->Emu.dwCurrentX = handle->Coord.X * pInfo->Emu.dwFontSizeX;
694  pInfo->Emu.dwCurrentY = handle->Coord.Y * pInfo->Emu.dwFontSizeY;
695  EmuPrint_RAW( pInfo, buffer, length, FALSE );
696  return TRUE;
697 }
698 
699 static
701  const void *buffer,
702  size_t length )
703 {
704  W32_PRINTER_INFO *pInfo = handle->Opaque;
705  pInfo->Emu.dwCurrentX = handle->Coord.X * pInfo->Emu.dwFontSizeX;
706  pInfo->Emu.dwCurrentY = handle->Coord.Y * pInfo->Emu.dwFontSizeY;
707  EmuPrint_RAW( pInfo, buffer, length, TRUE );
708  return TRUE;
709 }
710 
711 static void EmuPrint_TTY( W32_PRINTER_INFO *pInfo,
712  const void *pText,
713  size_t uiLength,
714  int isunicode )
715 {
716  fb_ConHooks hooks;
717 
718  hooks.Opaque = pInfo;
721  hooks.Border.Left = 0;
722  hooks.Border.Top = 0;
723  hooks.Border.Right =
724  ( pInfo->Emu.dwSizeX - pInfo->Emu.dwFontSizeX + 1 ) / pInfo->Emu.dwFontSizeX;
725  hooks.Border.Bottom =
726  ( pInfo->Emu.dwSizeY - pInfo->Emu.dwFontSizeX + 1 ) / pInfo->Emu.dwFontSizeY;
727 
728  hooks.Coord.X = pInfo->Emu.dwCurrentX / pInfo->Emu.dwFontSizeX;
729  hooks.Coord.Y = pInfo->Emu.dwCurrentY / pInfo->Emu.dwFontSizeY;
730 
731  if( !isunicode )
732  {
733 
734  while( uiLength!=0 ) {
735  char chControl = 0;
736  unsigned uiLengthTTY = uiLength, ui;
737  /* Check for additional control characters */
738  for( ui=0; ui!=uiLength; ++ui ) {
739  int iFound = FALSE;
740  char ch = ((char *)pText)[ui];
741  switch( ch ) {
742  case 12:
743  /* FormFeed */
744  iFound = TRUE;
745  break;
746  }
747  if( iFound ) {
748  chControl = ch;
749  uiLengthTTY = ui;
750  break;
751  }
752  }
753  fb_ConPrintTTY( &hooks,
754  (char *)pText,
755  uiLengthTTY,
756  TRUE );
757  if( uiLength!=uiLengthTTY ) {
758  /* Found a control character that's not handled by the TTY output
759  * routines */
760  ++uiLengthTTY;
761  switch( chControl ) {
762  case 12:
763  /* FormFeed */
764  fb_hHookConPrinterScroll( &hooks, 0, 0, 0, 0, 0 );
765  break;
766  }
767  }
768  pText += uiLengthTTY * sizeof(char);
769  uiLength -= uiLengthTTY;
770  }
771 
772  } else {
773 
774  while( uiLength!=0 ) {
775  char chControl = 0;
776  unsigned uiLengthTTY = uiLength, ui;
777  /* Check for additional control characters */
778  for( ui=0; ui!=uiLength; ++ui ) {
779  int iFound = FALSE;
780  char ch = ((FB_WCHAR *)pText)[ui];
781  switch( ch ) {
782  case 12:
783  /* FormFeed */
784  iFound = TRUE;
785  break;
786  }
787  if( iFound ) {
788  chControl = ch;
789  uiLengthTTY = ui;
790  break;
791  }
792  }
793  fb_ConPrintTTYWstr( &hooks,
794  (FB_WCHAR *)pText,
795  uiLengthTTY,
796  TRUE );
797  if( uiLength!=uiLengthTTY ) {
798  /* Found a control character that's not handled by the TTY output
799  * routines */
800  ++uiLengthTTY;
801  switch( chControl ) {
802  case 12:
803  /* FormFeed */
804  fb_hHookConPrinterScroll( &hooks, 0, 0, 0, 0, 0 );
805  break;
806  }
807  }
808  pText += uiLengthTTY * sizeof(FB_WCHAR);
809  uiLength -= uiLengthTTY;
810  }
811 
812  }
813 
814  if( hooks.Coord.X != hooks.Border.Left
815  || hooks.Coord.Y != (hooks.Border.Bottom+1) )
816  {
817  fb_hConCheckScroll( &hooks );
818  }
819 
820  pInfo->Emu.dwCurrentX = hooks.Coord.X * pInfo->Emu.dwFontSizeX;
821  pInfo->Emu.dwCurrentY = hooks.Coord.Y * pInfo->Emu.dwFontSizeY;
822 }
823 
824 #if 0
825 static void EmuPrint_ESC_P2( DEV_LPT_INFO *devInfo,
826  const char *pachText,
827  size_t uiLength )
828 {
829  W32_PRINTER_INFO *pInfo = (W32_PRINTER_INFO*) devInfo->driver_opaque;
830 }
831 #endif
832 
833 int fb_PrinterWrite( DEV_LPT_INFO *devInfo, const void *data, size_t length )
834 {
835  W32_PRINTER_INFO *pInfo = (W32_PRINTER_INFO*) devInfo->driver_opaque;
836  DWORD dwWritten;
837 
838  if( !pInfo->hPrinter ) {
839  pInfo->Emu.pfnPrint( pInfo, data, length, FALSE );
840 
841  } else if( !WritePrinter( pInfo->hPrinter,
842  (LPVOID) data,
843  length,
844  &dwWritten ) )
845  {
847 
848  } else if ( dwWritten != length ) {
850 
851  }
852 
853  return fb_ErrorSetNum( FB_RTERROR_OK );
854 }
855 
856 int fb_PrinterWriteWstr( DEV_LPT_INFO *devInfo, const FB_WCHAR *data, size_t length )
857 {
858  W32_PRINTER_INFO *pInfo = (W32_PRINTER_INFO*) devInfo->driver_opaque;
859  DWORD dwWritten;
860 
861  if( !pInfo->hPrinter ) {
862  pInfo->Emu.pfnPrint( pInfo, data, length, TRUE);
863 
864  } else if( !WritePrinter( pInfo->hPrinter,
865  (LPVOID) data,
866  length * sizeof( FB_WCHAR ),
867  &dwWritten ) )
868  {
870 
871  } else if ( dwWritten != length * sizeof( FB_WCHAR )) {
873  }
874 
875  return fb_ErrorSetNum( FB_RTERROR_OK );
876 }
877 
879 {
880  W32_PRINTER_INFO *pInfo = (W32_PRINTER_INFO*) devInfo->driver_opaque;
881 
882  if( pInfo->hDc!=NULL ) {
883  if( pInfo->Emu.iPageStarted )
884  EndPage( pInfo->hDc );
885  EndDoc( pInfo->hDc );
886  DeleteDC( pInfo->hDc );
887  } else {
888  EndDocPrinter( pInfo->hPrinter );
889  ClosePrinter( pInfo->hPrinter );
890  }
891 
892  if( devInfo->driver_opaque )
893  free(devInfo->driver_opaque);
894 
895  devInfo->driver_opaque = NULL;
896 
897  return fb_ErrorSetNum( FB_RTERROR_OK );
898 }