Windows API

Yazıcı İşlemleri

Bu bölümde, Print Spooler API ve GDI Print API fonksiyonlarını kullanarak Windows API'de yazıcı işlemlerini gerçekleştirmeye çalışacağız.

GetDefaultPrinter(), CreateDC(), StartDoc(), StartPage(), EndDoc() ve DeleteDC() fonksiyonlarını kullanarak programınızda bulunan bir kontrolün tamamını bir anda veya satır satır olarak yazıcıya aktarabiliriz.

Bir kontrolü doğrudan veya satır satır yazıcıya yazdırma

1. Öncelikle Burada gösterildiği gibi bir Windows API projesi oluşturalım. Projeyle birlikte otomatik olarak oluşturulan main.c dosyası içine aşağıda gösterilen kodları ekleyelim:

#define IDC_BUTTON01 101
#define IDC_BUTTON02 102

/* LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES parametrelerinin kullanımı için gerekli */
#define _WIN32_IE 0x0600
#define _WIN32_WINNT 0x0501
#define WINVER 0x0501

#include <commctrl.h> /* ListView işlemleri için */
#include <stdio.h>    /* sprintf() işlemleri için */

case WM_CREATE:

     CreateListView(hwnd); /* Listview oluşturma */
     hwndButton01 = CreateWindowEx(0, "BUTTON", "Komple yazdır", /* Buton penceresi oluşturma */
                               WS_CHILD | WS_VISIBLE, 540, 20, 120, 24,
                               hwnd, (HMENU) IDC_BUTTON01, NULL, NULL);
     hwndButton02 = CreateWindowEx(0, "BUTTON", "Satır yazdır", /* Buton penceresi oluşturma */
                               WS_CHILD | WS_VISIBLE, 540, 54, 120, 24,
                               hwnd, (HMENU) IDC_BUTTON02, NULL, NULL);
     break;

case WM_COMMAND:

     if (HIWORD(wParam) == BN_CLICKED) {
         switch(LOWORD(wParam)) {
             case IDC_BUTTON01:
                PrintControl(hwndListView, 0);
                break;
             case IDC_BUTTON02:
                PrintControl(hwndListView, 1);
                break;
         }
     }
     break;

Yukarıdaki kodlarla bir ListView ve iki adet Buton kontrolü oluşturulur. ListView kontrolüne program başlangıcında satırlar eklenir. "Komple yazdır" butonuna tıkladığımızda ListView kontrolünün tamamı tek seferde yazıcıya gönderilir. "Komple yazdır" butonuna tıkladığımızda ise, ListView kontrolü satır satır yazıcıya gönderilir.

2. Şimdi, ListView kontrolünü oluşturmak için kullanacağımız CreateListView() fonksiyonu ile yazıcı işlemlerini gerçekleştiren PrintControl() fonksiyonunu programa ekleyelim.

void CreateListView(HWND hwndParent)
{
  char cdizi[20];
  LVCOLUMN lvc;
  LVITEM lvI;
  int idCol=4, idItem=10;
  int id1, id2;

  hwndListView = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, "",
                                  WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SHOWSELALWAYS,
                                  20, 20, 485, 185, hwndParent,
                                  0, 0, NULL);

  ListView_SetExtendedListViewStyle(hwndListView, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);

  /* LVCOLUMN structure için ilk değer atama işlemlerini yapar. */
  lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  lvc.cx = 120;           /* Sütun genişliği değeri */
  lvc.fmt = LVCFMT_LEFT;  /* Sütunları sol tarafa ayarlar */

  /* Sütun ekleme işlemleri */
  for (id1=0; id1<idCol; id1++) {
       lvc.iSubItem = id1;
       sprintf(cdizi, "%s%d", "Column", id1+1);
       lvc.pszText = cdizi;
       /* Sütun ekleme işlemi */
       ListView_InsertColumn(hwndListView, id1, &lvc);
  }

  /* LVITEM structure için ilk değer atama işlemlerini yapar. */
  lvI.mask = LVIF_TEXT | LVIF_STATE;
  lvI.stateMask = 0;
  lvI.iSubItem  = 0;
  lvI.state = 0;

  /* Satır ekleme işlemleri */
  for (id1=0; id1<idItem; id1++) {
       lvI.iItem  = id1;
       sprintf(cdizi, "%s%d", "Item", id1+1);
       lvI.pszText   = cdizi;
       /* İlk sütun için öğe ekleme işlemleri */
       ListView_InsertItem(hwndListView, &lvI);

       /* Diğer sütunlar için öğe ekleme işlemleri */
       for (id2=1; id2<idCol; id2++) {
            sprintf(cdizi, "%s%d-%d", "SubItem", id1+1, id2+1);
            ListView_SetItemText(hwndListView, id1, id2, cdizi);
       }
  }
}

BOOL PrintControl(HWND hwnd, int mode)
{
  HDC hdcPrint;
  char cprinter[500];
  DWORD kapa=500;
  DOCINFO di;
  int nError;
  int cWidthPels, cHeightPels;
  RECT rcLV;
  char cdizi[30];
  HFONT hFont;
  RECT rcLine;
  HDITEM hdi = { 0 };
  int id1, id2;
  int nCol, wCol=80, hItem=20;
  float scaleX, scaleY;

  /* Lokal bilgisayarda aktif kullanıcı için ön tanımlı olan yazıcı adını alma */
  if (!GetDefaultPrinter(cprinter, &kapa)) {
      MessageBox(NULL, "Ön tanımlı yazıcı bulunamadı!", "Yazıcı hatası", MB_OK | MB_ICONWARNING);
      return 0;
  }

  /* Yazıcı için bir device context (DC) oluşturma */
  hdcPrint = CreateDC(NULL, cprinter, NULL, NULL);

  /* DOCINFO yapı değerlerini atama */
  memset(&di, 0, sizeof(DOCINFO));
  di.cbSize = sizeof(DOCINFO);
  di.lpszDocName = "PrintDoc";
  di.lpszOutput = (LPTSTR) NULL;
  di.lpszDatatype = (LPTSTR) NULL;
  di.fwType = 0;

  /* Yazdırma işlemini başlatma */
  nError = StartDoc(hdcPrint, &di);
  if (nError <= 0) {
      MessageBox(NULL, "Yazıcı başlatılamıyor!", "Yazıcı hatası", MB_OK | MB_ICONWARNING);
      return 0;
  }

  /* Yazıcı için aygıt ölçülerini alma  */
  cWidthPels = GetDeviceCaps(hdcPrint, LOGPIXELSY);
  cHeightPels = GetDeviceCaps(hdcPrint, LOGPIXELSX);

  /* Yazıcı aygıt ölçülerini ekran çıktı değerine bölerek oran hesaplama */
  scaleX = cWidthPels / 72;
  scaleY = cHeightPels / 72;

  /* Yazıcı sürücüsünü veriyi almak üzere hazırlama */
  nError = StartPage(hdcPrint);
  if (nError <= 0) {
      MessageBox(NULL, "Yazıcı sayfası başlatılamıyor!", "Yazıcı hatası", MB_OK | MB_ICONWARNING);
      return 0;
  }

  if (mode) { /* Satır satır yazma */
      hFont = CreateFont(0, 0, 0, 0, 0, 0, 0, 0, TURKISH_CHARSET, 0, 0, 0, 0, TEXT("Tahoma"));
      SelectObject(hdcPrint, hFont);

      rcLine.left = 20*scaleX;
      rcLine.right = rcLine.left + (wCol*scaleX);
      rcLine.top = 20*scaleY;
      rcLine.bottom = rcLine.top + (hItem*scaleY);

      hdi.mask = HDI_TEXT;
      hdi.pszText = cdizi;
      hdi.cchTextMax = 30;

      nCol = Header_GetItemCount(ListView_GetHeader(hwnd));

      for (id1=0; id1<nCol; id1++) {
           Header_GetItem(ListView_GetHeader(hwnd), id1, &hdi);
           DrawText(hdcPrint, cdizi, strlen(cdizi), &rcLine, DT_TOP|DT_LEFT);
           rcLine.left += (wCol*scaleX);
           rcLine.right = rcLine.left + (wCol*scaleX);
      }

      rcLine.top += hItem*scaleY;
      rcLine.bottom = rcLine.top + (hItem*scaleY);

      for (id1=0; id1<ListView_GetItemCount(hwnd); id1++) {
           rcLine.left = 20*scaleX;
           rcLine.right = rcLine.left + (wCol*scaleX);
           for (id2=0; id2<nCol; id2++) {
                ListView_GetItemText(hwnd, id1, id2, cdizi, sizeof(cdizi));
                DrawText(hdcPrint, cdizi, strlen(cdizi), &rcLine, DT_LEFT);
                rcLine.left += wCol*scaleX;
                rcLine.right = rcLine.left + (wCol*scaleX);
           }
           rcLine.top += hItem*scaleY;
           rcLine.bottom = rcLine.top + (hItem*scaleY);
      }

  }
  else { /* ListView kontrol içeriğini doğrudan yazıcıya aktarma */
      GetWindowRect(hwnd, &rcLV);
      StretchBlt(hdcPrint, 0, 0, (rcLV.right-rcLV.left)*scaleX, (rcLV.bottom-rcLV.top)*scaleY, GetDC(hwnd), 0, 0, rcLV.right-rcLV.left, rcLV.bottom-rcLV.top, SRCCOPY);
  }

  /* Yazıcıya sayfa yazım işleminin sona erdiğini bildirme */
  nError = EndPage(hdcPrint);
  if (nError <= 0) {
      MessageBox(NULL, "Yazıcı sayfası sonlandırılamıyor!", "Yazıcı hatası", MB_OK | MB_ICONWARNING);
      return 0;
  }

  /* Yazdırma işlemini sona erdirme */
  nError = EndDoc(hdcPrint);
  if (nError <= 0) {
      MessageBox(NULL, "Yazıcı sonlandırılamıyor!", "Yazıcı hatası", MB_OK | MB_ICONWARNING);
      return 0;
  }

  DeleteDC(hdcPrint);

  return 1;
}

Yukarıdaki kodların tamamını eklediğimizde, main.c dosyasının en son hali aşağıdaki şekilde olacaktır.

main.c

#if defined(UNICODE) && !defined(_UNICODE)
    #define _UNICODE
#elif defined(_UNICODE) && !defined(UNICODE)
    #define UNICODE
#endif

#define IDC_BUTTON01 101
#define IDC_BUTTON02 102

/* LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES parametrelerinin kullanımı için gerekli */
#define _WIN32_IE 0x0600
#define _WIN32_WINNT 0x0501
#define WINVER 0x0501

#include <tchar.h>
#include <windows.h>
#include <commctrl.h> /* ListView işlemleri için */
#include <stdio.h>    /* sprintf() işlemleri için */

/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

/*  Make the class name into a global variable  */
TCHAR szClassName[ ] = _T("DenemeApp");

HWND hwndListView, hwndButton01, hwndButton02;
void CreateListView(HWND hwndParent);
BOOL PrintControl(HWND hwnd, int mode);

int WINAPI WinMain (HINSTANCE hThisInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR lpszArgument,
                     int nCmdShow)
{
    HWND hwnd;               /* This is the handle for our window */
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */

    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);

    /* Use default icon and mouse-pointer */
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default colour as the background of the window */
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;

    /* The class is registered, let's create the program*/
    hwnd = CreateWindowEx (
           0,                       /* Extended possibilites for variation */
           szClassName,             /* Classname */
           _T("Deneme Uygulaması"), /* Title Text */
           WS_OVERLAPPEDWINDOW,     /* default window */
           CW_USEDEFAULT,           /* Windows decides the position */
           CW_USEDEFAULT,           /* where the window ends up on the screen */
           700,                     /* The programs width */
           375,                     /* and height in pixels */
           HWND_DESKTOP,            /* The window is a child-window to desktop */
           NULL,                    /* No menu */
           hThisInstance,           /* Program Instance handler */
           NULL                     /* No Window Creation data */
           );

    /* Make the window visible on the screen */
    ShowWindow (hwnd, nCmdShow);

    /* Run the message loop. It will run until GetMessage() returns 0 */
    while (GetMessage (&messages, NULL, 0, 0))
    {
        /* Translate virtual-key messages into character messages */
        TranslateMessage(&messages);
        /* Send message to WindowProcedure */
        DispatchMessage(&messages);
    }

    /* The program return-value is 0 - The value that PostQuitMessage() gave */
    return messages.wParam;
}

/*  This function is called by the Windows function DispatchMessage()  */
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
        case WM_CREATE:

             CreateListView(hwnd); /* Listview oluşturma */
             hwndButton01 = CreateWindowEx(0, "BUTTON", "Komple yazdır", /* Buton penceresi oluşturma */
                                       WS_CHILD | WS_VISIBLE, 540, 20, 120, 24,
                                       hwnd, (HMENU) IDC_BUTTON01, NULL, NULL);
             hwndButton02 = CreateWindowEx(0, "BUTTON", "Satır yazdır", /* Buton penceresi oluşturma */
                                       WS_CHILD | WS_VISIBLE, 540, 54, 120, 24,
                                       hwnd, (HMENU) IDC_BUTTON02, NULL, NULL);
             break;

        case WM_COMMAND:

             if (HIWORD(wParam) == BN_CLICKED) {
                 switch(LOWORD(wParam)) {
                     case IDC_BUTTON01:
                        PrintControl(hwndListView, 0);
                        break;
                     case IDC_BUTTON02:
                        PrintControl(hwndListView, 1);
                        break;
                 }
             }
             break;

        case WM_DESTROY:
             PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
             break;
        default:                        /* for messages that we don't deal with */
             return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}

void CreateListView(HWND hwndParent)
{
  char cdizi[20];
  LVCOLUMN lvc;
  LVITEM lvI;
  int idCol=4, idItem=10;
  int id1, id2;

  hwndListView = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, "",
                                  WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SHOWSELALWAYS,
                                  20, 20, 485, 185, hwndParent,
                                  0, 0, NULL);

  ListView_SetExtendedListViewStyle(hwndListView, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);

  /* LVCOLUMN structure için ilk değer atama işlemlerini yapar. */
  lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  lvc.cx = 120;           /* Sütun genişliği değeri */
  lvc.fmt = LVCFMT_LEFT;  /* Sütunları sol tarafa ayarlar */

  /* Sütun ekleme işlemleri */
  for (id1=0; id1<idCol; id1++) {
       lvc.iSubItem = id1;
       sprintf(cdizi, "%s%d", "Column", id1+1);
       lvc.pszText = cdizi;
       /* Sütun ekleme işlemi */
       ListView_InsertColumn(hwndListView, id1, &lvc);
  }

  /* LVITEM structure için ilk değer atama işlemlerini yapar. */
  lvI.mask = LVIF_TEXT | LVIF_STATE;
  lvI.stateMask = 0;
  lvI.iSubItem  = 0;
  lvI.state = 0;

  /* Satır ekleme işlemleri */
  for (id1=0; id1<idItem; id1++) {
       lvI.iItem  = id1;
       sprintf(cdizi, "%s%d", "Item", id1+1);
       lvI.pszText   = cdizi;
       /* İlk sütun için öğe ekleme işlemleri */
       ListView_InsertItem(hwndListView, &lvI);

       /* Diğer sütunlar için öğe ekleme işlemleri */
       for (id2=1; id2<idCol; id2++) {
            sprintf(cdizi, "%s%d-%d", "SubItem", id1+1, id2+1);
            ListView_SetItemText(hwndListView, id1, id2, cdizi);
       }
  }
}

BOOL PrintControl(HWND hwnd, int mode)
{
  HDC hdcPrint;
  char cprinter[500];
  DWORD kapa=500;
  DOCINFO di;
  int nError;
  int cWidthPels, cHeightPels;
  RECT rcLV;
  char cdizi[30];
  HFONT hFont;
  RECT rcLine;
  HDITEM hdi = { 0 };
  int id1, id2;
  int nCol, wCol=80, hItem=20;
  float scaleX, scaleY;

  /* Lokal bilgisayarda aktif kullanıcı için ön tanımlı olan yazıcı adını alma */
  if (!GetDefaultPrinter(cprinter, &kapa)) {
      MessageBox(NULL, "Ön tanımlı yazıcı bulunamadı!", "Yazıcı hatası", MB_OK | MB_ICONWARNING);
      return 0;
  }

  /* Yazıcı için bir device context (DC) oluşturma */
  hdcPrint = CreateDC(NULL, cprinter, NULL, NULL);

  /* DOCINFO yapı değerlerini atama */
  memset(&di, 0, sizeof(DOCINFO));
  di.cbSize = sizeof(DOCINFO);
  di.lpszDocName = "PrintDoc";
  di.lpszOutput = (LPTSTR) NULL;
  di.lpszDatatype = (LPTSTR) NULL;
  di.fwType = 0;

  /* Yazdırma işlemini başlatma */
  nError = StartDoc(hdcPrint, &di);
  if (nError <= 0) {
      MessageBox(NULL, "Yazıcı başlatılamıyor!", "Yazıcı hatası", MB_OK | MB_ICONWARNING);
      return 0;
  }

  /* Yazıcı için aygıt ölçülerini alma  */
  cWidthPels = GetDeviceCaps(hdcPrint, LOGPIXELSY);
  cHeightPels = GetDeviceCaps(hdcPrint, LOGPIXELSX);

  /* Yazıcı aygıt ölçülerini ekran çıktı değerine bölerek oran hesaplama */
  scaleX = cWidthPels / 72;
  scaleY = cHeightPels / 72;

  /* Yazıcı sürücüsünü veriyi almak üzere hazırlama */
  nError = StartPage(hdcPrint);
  if (nError <= 0) {
      MessageBox(NULL, "Yazıcı sayfası başlatılamıyor!", "Yazıcı hatası", MB_OK | MB_ICONWARNING);
      return 0;
  }

  if (mode) { /* Satır satır yazma */
      hFont = CreateFont(0, 0, 0, 0, 0, 0, 0, 0, TURKISH_CHARSET, 0, 0, 0, 0, TEXT("Tahoma"));
      SelectObject(hdcPrint, hFont);

      rcLine.left = 20*scaleX;
      rcLine.right = rcLine.left + (wCol*scaleX);
      rcLine.top = 20*scaleY;
      rcLine.bottom = rcLine.top + (hItem*scaleY);

      hdi.mask = HDI_TEXT;
      hdi.pszText = cdizi;
      hdi.cchTextMax = 30;

      nCol = Header_GetItemCount(ListView_GetHeader(hwnd));

      for (id1=0; id1<nCol; id1++) {
           Header_GetItem(ListView_GetHeader(hwnd), id1, &hdi);
           DrawText(hdcPrint, cdizi, strlen(cdizi), &rcLine, DT_TOP|DT_LEFT);
           rcLine.left += (wCol*scaleX);
           rcLine.right = rcLine.left + (wCol*scaleX);
      }

      rcLine.top += hItem*scaleY;
      rcLine.bottom = rcLine.top + (hItem*scaleY);

      for (id1=0; id1<ListView_GetItemCount(hwnd); id1++) {
           rcLine.left = 20*scaleX;
           rcLine.right = rcLine.left + (wCol*scaleX);
           for (id2=0; id2<nCol; id2++) {
                ListView_GetItemText(hwnd, id1, id2, cdizi, sizeof(cdizi));
                DrawText(hdcPrint, cdizi, strlen(cdizi), &rcLine, DT_LEFT);
                rcLine.left += wCol*scaleX;
                rcLine.right = rcLine.left + (wCol*scaleX);
           }
           rcLine.top += hItem*scaleY;
           rcLine.bottom = rcLine.top + (hItem*scaleY);
      }

  }
  else { /* ListView kontrol içeriğini doğrudan yazıcıya aktarma */
      GetWindowRect(hwnd, &rcLV);
      StretchBlt(hdcPrint, 0, 0, (rcLV.right-rcLV.left)*scaleX, (rcLV.bottom-rcLV.top)*scaleY, GetDC(hwnd), 0, 0, rcLV.right-rcLV.left, rcLV.bottom-rcLV.top, SRCCOPY);
  }

  /* Yazıcıya sayfa yazım işleminin sona erdiğini bildirme */
  nError = EndPage(hdcPrint);
  if (nError <= 0) {
      MessageBox(NULL, "Yazıcı sayfası sonlandırılamıyor!", "Yazıcı hatası", MB_OK | MB_ICONWARNING);
      return 0;
  }

  /* Yazdırma işlemini sona erdirme */
  nError = EndDoc(hdcPrint);
  if (nError <= 0) {
      MessageBox(NULL, "Yazıcı sonlandırılamıyor!", "Yazıcı hatası", MB_OK | MB_ICONWARNING);
      return 0;
  }

  DeleteDC(hdcPrint);

  return 1;
}

Programı derleyip çalıştırdığımızda 4 sütunlu ve 10 satırlı bir ListView kontrolü oluşturulur. "Komple yazdır" butonuna tıkladığımızda ListView kontrolünün tamamı tek seferde yazıcıya gönderilir. "Komple yazdır" butonuna tıkladığımızda ise, ListView kontrolü satır satır yazıcıya gönderilir. Bu durumda, program aşağıdakine benzer bir görüntü oluşturacaktır: