Programlama yapalım ve Öğrenelim. - Delphi Eğitim97
  Ana Sayfa
  .NET Eğitim Notları
  Visual C# .NET Örnek Kodları
  VisualBasic.NET Örnek Kodları
  J# Örnekleri
  ASP.NET Örnek Kodları
  Delphi Eğitim
  => Delphi Eğitim1
  => Delphi Eğitim2
  => Delphi Eğitim3
  => Delphi Eğitim4
  => Delphi Eğitim5
  => Delphi Eğitim6
  => Delphi Eğitim7
  => Delphi Eğitim8
  => Delphi Eğitim9
  => Delphi Eğitim10
  => Delphi Eğitim11
  => Delphi Eğitim13
  => Delphi Eğitim14
  => Delphi Eğitim15
  => Delphi Eğitim16
  => Delphi Eğitim17
  => Delphi Eğitim18
  => Delphi Eğitim19
  => Delphi Eğitim20
  => Delphi Eğitim21
  => Delphi Eğitim22
  => Delphi Eğitim23
  => Delphi Eğitim24
  => Delphi Eğitim25
  => Delphi Eğitim26
  => Delphi Eğitim27
  => Delphi Eğitim28
  => Delphi Eğitim29
  => Delphi Eğitim30
  => Delphi Eğtim31
  => Delphi Eğitim32
  => Delphi Eğitim33
  => Delphi Eğitim34
  => Delphi Eğitim35
  => Delphi Eğitim36
  => Delphi Eğitim37
  => Delphi Eğitim38
  => Delphi Eğitim39
  => Delphi Eğitim40
  => Delphi Eğitim41
  => Delphi Eğitim42
  => Delphi Eğitim43
  => Delphi Eğitim44
  => Delphi Eğitim45
  => Delphi Eğitim46
  => Delphi Eğitim47
  => Delphi Eğitim48
  => Delphi Eğitim49
  => Delphi Eğitim50
  => Delphi Eğitim51
  => Delphi Eğitim52
  => Delphi Eğitim53
  => Delphi Eğitim54
  => Delphi Eğitim55
  => Delphi Eğitim56
  => Delphi Eğitim57
  => Delphi Eğitim58
  => Delphi Eğitim59
  => Delphi Eğitim60
  => Delphi Eğitim61
  => Delphi Eğitim62
  => Delphi Eğitim63
  => Delphi Eğitim64
  => Delphi Eğitim65
  => Delphi Eğitim66
  => Delphi Eğitim67
  => Delphi Eğitim68
  => Delphi Eğitim69
  => Delphi Eğitim70
  => Delphi Eğitim71
  => Delphi Eğitim72
  => Delphi Eğitim73
  => Delphi Eğitim74
  => Delphi Eğitim75
  => Delphi Eğitim76
  => Delphi Eğitim77
  => Delphi Eğitim78
  => Delphi Eğitim79
  => Delphi Eğitim80
  => Delphi Eğitim81
  => Delphi Eğitim82
  => Delphi Eğitim83
  => Delphi Eğitim84
  => Delphi Eğitim85
  => Delphi Eğitim86
  => Delphi Eğitim87
  => Delphi Eğitim88
  => Delphi Eğitim89
  => Delphi Eğitim90
  => Delphi Eğitim91
  => Delphi Eğitim92
  => Delphi Eğitim93
  => Delphi Eğitim94
  => Delphi Eğitim95
  => Delphi Eğitim96
  => Delphi Eğitim97
  => Delphi Eğitim98
  => Delphi Eğitim99
  => Delphi Eğitim100
  => Delphi Eğitim101
  => Delphi Eğitim102
  => Delphi Eğitim103
  => Delphi Eğitim104
  => Delphi Eğitim105
  => Delphi Eğitim106
  => Delphi Eğitim107
  => Delphi Eğitim108
  => Delphi Eğitim109
  => Delphi Eğitim110
  => Delphi Eğitim111
  => Delphi Eğitim112
  => Delphi Eğitim113
  => Delphi Eğitim114
  => Delphi Eğitim115
  => Delphi Eğitim116
  => Delphi Eğitim117
  => Delphi Eğitim118
  => Delphi Eğitim119
  => Delphi Eğitim120
  => Delphi Eğitim121
  => Delphi Eğitim122
  => Delphi Eğitim123
  => Delphi Eğitim124
  => Delphi Eğitim125
  => Delphi Eğitim126
  => Delphi Eğitim127
  => Delphi Eğitim128
  => Delphi Eğitim129
  => Delphi Eğitim130
  => Delphi Eğitim131
  => Delphi Eğitim132
  => Delphi Eğitim133
  => Delphi Eğitim134
  => Delphi Eğitim135
  => Delphi Eğitim136
  => Delphi Eğitim137
  => Delphi Eğitim138
  => Delphi Eğitim139
  => Delphi Eğitim140
  => Delphi Eğitim141
  => Delphi Eğitim142
  => Delphi Eğitim143
  => Delphi Eğitim144
  => Delphi Eğitim145
  => Delphi Eğitim146
  => Delphi eğitim147
  => Delphi Eğitim148
  => Delphi Eğitim149
  => Delphi Eğitim150
  => Delphi Eğitim151
  => Delphi Eğitim152
  => Delphi Eğitim153
  => Delphi Eğitim154
  => Delphi Eğitim155
  => Delphi Eğitim156
  => Delphi Eğitim157
  => Delphi Eğitim158
  => Delphi Eğitim159
  => Delphi Eğitim160
  => Delphi Eğitim161
  => Delphi Eğitim162
  => Delphi Eğitim164
  => Delphi Eğitim165
  => Delphi Eğitim166
  => Delphi Eğitim167
  => Delphi Eğitim168
  => Delphi Eğitim169
  => Delphi Eğitim170
  => Delphi Eğitim171
  => Delphi Eğitim172
  => Delphi Eğitim173
  => Delphi Eğitim174
  => Delphi Eğitim175
  => Delphi Eğitim176
  => Delphi Eğitim177
  => Delphi Eğitim178
  => Delphi Eğitim179
  => Delphi Eğitim180
  => Delphi Eğitim181
  => Delphi Eğitim182
  => Delphi Eğitim183
  => Delphi Eğitim184
  => Delphi Eğitim185
  => Delphi Eğitim186
  => Delphi Eğitim187
  => Delphi Eğitim188
  => Delphi Eğitim189
  => Delphi Eğitim190
  => Delphi Eğitim191
  => Delphi Eğitim192
  => Delphi Eğitim193
  => Delphi Eğitim194
  => Delphi Eğitim195
  => Delphi Eğitim196
  => Delphi Eğitim197
  => Delphi Eğitim198
  => Delphi Eğitim199
  => Delphi Eğitim200
  => Delphi Eğitim201
  => Delphi Eğitim202
  => Delphi Eğitim203
  => Delphi Eğitim204
  => Delphi Eğitim205
  => Delphi Eğitim206
  => Delphi Eğitim207
  => Delphi Eğitim208
  => Delphi Eğitim209
  => Delphi Eğitim210
  => Delphi Eğitim211
  => Delphi Eğitim212
  => Delphi Eğitim213
  => Delphi Eğitim214
  => Delphi Eğitim215
  => Delphi Eğitim216
  => Delphi Eğitim217
  => Delphi Eğitim218
  => Delphi Eğitim219
  => Delphi Eğitim220
  => Delphi Eğitim221
  => Delphi Eğitim222
  => Delphi Eğitim223
  => Delphi Eğitim224
  => Delphi Eğitim225
  => Delphi Eğitim226
  => Delphi Eğitim227
  => Delphi Eğitim228
  => Delphi Eğitim229
  => Delphi Eğitim230
  => Delphi Eğitim231
  => Delphi Eğitim232
  => Delphi Eğitim233
  => Delphi Eğitim234
  => Delphi Eğitim235
  => Delphi Eğitim236
  => Delphi Eğitim237
  => Delphi Eğitim238
  => Delphi Eğitim239
  => Delphi Eğitim240
  => Delphi Eğitim241
  => Delphi Eğitim242
  İletişim

CD-Rom sürücüyü açmak ve kapamak

 

uses kısmına MMSystem unitini ekleyin.

 

mciSendString('Set cdaudio door open wait', nil, 0, handle); //aç

mciSendString('Set cdaudio door closed wait', nil, 0, handle); //kapa

 

 

 

-----------------------------------------------------------------------------------------------------------

 

 

 

 Uygulamanızın Görev Çubuğundaki butonunu gizleme

 

Uygulamanızın Görev Çubuğundaki butonunu gizlemek için; programınızın ana formunun OnCreate olayına

aşağıdaki kodu yazın;

 

SetWindowLong(Application.Handle,GWL_EXSTYLE, WS_EX_TOOLWINDOW);

 

 ico'dan bmp'ye çevirme

 

var

  Icon : TIcon;

  Bitmap : TBitmap;

begin

  Icon := TIcon.Create;

  Bitmap := TBitmap.Create;

  Icon.LoadFromFile('c:picture.ico');

  Bitmap.Width := Icon.Width;

  Bitmap.Height := Icon.Height;

  Bitmap.Canvas.Draw(0, 0, Icon );

  Bitmap.SaveToFile('c:picture.bmp');

  Icon.Free;

  Bitmap.Free;

end;

 

-----------------------------------------------------------------------------------------------------------

 

 

 

Programım sadece bir kez çalışsın

 

Normalde kullanıcı programınızı istediği kadar çalıştırabilir veya bazı sabırsız kullanıcılar program

simgesine ard arda birkaç defa tıklayıp, aynı anda birden fazla program penceresi açabilirler.

Yani kullanıcı aynı anda 2-3 tane programı açabilir. Bazı durumlarda, programınızın sadece bir kez

çalışmasını isteyebilirsiniz :

 

Ana formunuzun Public kısmında şu tanımlamayı yapın :

 

Atom : Word;

 

Ana formun OnCreate olayına aşağıdaki kodu ekleyin:

 

if GlobalFindAtom('PROGRAM_RUNNING') = 0 then

  atom := GlobalAddAtom('PROGRAM_RUNNING')

else

begin

  MessageDlg('Program zaten çalışıyor!', mtWarning, [mbOK], 0);

  Halt;

end;

 

ve formun OnDestroy olayına da aşağıdaki kodu ekleyin. Hepsi bu kadar.

 

GlobalDeleteAtom(atom);

 

 

 

-----------------------------------------------------------------------------------------------------------

 

 

 

Listbox'a yatay kaydırma çubuğu eklemek

 

Formunuzun OnCreate olayına aşağıdaki kodu ekleyin.

 

SendMessage(Listbox1.Handle, LB_SetHorizontalExtent, 1000, Longint(0));

 

 

 

 

 

Combobox'ın listesini kod ile açıp kapatın

 

SendMessage(ComboBox1.Handle, CB_SHOWDROPDOWN, 1, 0); {listeyi açar}

 

SendMessage(ComboBox1.Handle, CB_SHOWDROPDOWN, 0, 0); {listeyi kapatır}

 

 

-----------------------------------------------------------------------------------------------------------

 

 

Listbox'ta kaydırma çubuğunu kod ile aşağı çekme

 

Listbox'ta 11. öğeyi listenin en başına getirmek için için aşağıdaki kodu yazın.

 

SendMessage(ListBox1.Handle, lb_SetTopIndex, 10, 0);

 

Eğer 25. öğeyi liste başı yapmak istiyorsanız

 

SendMessage(ListBox1.Handle, lb_SetTopIndex, 24, 0);

 

Enter tuşuna bastığınızda bir sonraki kontrole geçme

 

Enter tuşuna bastığınızda Windows'un bir sonraki kontrole geçmesi için (Tab tuşuna basılmış gibi)

Formunuzun KeyPreview özelliğini True yapın ve formun OnKeyPress olayına aşağıdaki kodu yazın.

 

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);

begin

  if (Key = #13) then

    begin

      Key := #0;

      Perform(WM_NEXTDLGCTL, 0, 0);

    end;

end;

 

 

 

-----------------------------------------------------------------------------------------------------------

 

 

 

Dos modunda yazı yazdırma

 

QuickReport ve benzeri raporlama araçları grafik modda baskı yaptıkları için baskı yavaş olur.

Dos modunda, hızlı yazı yazdırmak için, bu iş için özel tasarlanmış, bedava olan ZReport isimli

raporlama bileşenini kullanabilirsiniz. Bileşeni www.torry.net adresinden aratarak bulun ve indirin.

 

 

 

-----------------------------------------------------------------------------------------------------------

 

 

Kurulum (install) hazırlama

 

Delphi ile birlikte InstallShield Express'in Borland kısıtlı sürümü de dağıtılıyor.

Kurulum seti hazırlamak için bunu kullanabilirsiniz, ancak bu program biraz hantal.

Bunun yerine ben inno setup + istool ikilisini kullanmanızı tavsiye ederim. inno setup çok kullanışlı,

 görsel yönden güzel, bedava, source kodu açık bir kurulum programı. Script desteği de var.

 istool ise inno setup script'lerini görsel ekranlarla hazırlayan bir inno setup eklentisi.

 Sitelerinden bu programları indirebilirsiniz.

 

inno setup : www.innosetup.com , istool : www.istool.org

 

 

-----------------------------------------------------------------------------------------------------------

 

 

 

QuickReport bıktırdıysa, alternatif raporlama araçları

 

Qr(Quick Report) Delphi içinde bundle ettiği zaman piyasadaki en iyi raporlama araçlarından biri idi.

Ancak Qr zamanla kendini geliştiremedi. Mevcut hatalar düzeltilemedi, çok istenen eksikler yapılamadı.

Özellikle destek noktasında çok büyük sıkıntı oluştu ve gelişen zaman içinde programcıların Delphi içindeki

en büyük sorunu Qr oldu.

 

Borland'da bunu dikkate alarak Delphi 7'den itibaren Rave'i raporlama aracı olarak dağıtmaya başladı.

Bu karar ne derece doğru bilemiyorum. Bunu zaman gösterecek. Ama piyasada çok tutulan ve ihtiyaç duyduğunuz

eksikleri tamamlayacak 2 raporlama aracı var. İkisi de ticari ürünler, yani para ile satılıyorlar ve

ikisinin de desteği çok iyi. Bunlar :

 

Report Builder : http://www.digital-metaphors.com/

 

Gerçekten çok iyi bir raporlama aracı. Yıllar boyu yapılan anketlerde uzak ara hep birinciliği alıyor.

Çok iyi bir teknik desteği var. Verdiğiniz paraya değecek bir ürün.

 

Fast Report : www.fastreport.ru

 

Bu raporlama aracı da çok iyi. Çok iyi bir teknik desteği var ve fiyatı biraz daha uygun.

 

Her ikisi de güzel araçlar. İkisininde deneme sürümlerini sitelerinden indirip deneyebilirsiniz.

 

 

Bedava Raporlama Araçları

 

Free Report : www.fastreport.ru

 

Bu da fast report'u üreten firmanın bedava ve source kodu ile dağıttığı bir raporlama aracı.

Fast Report kadar olmasa da gayet iyi. Qr'den bıktım diyenlere

 

ZReport : www.torry.net

 

ZReport'ta yine bedava ve source kod ile dağıtılan, Dos modunda hızlı baskı yapmak için özel bir

raporlama aracı. Yazan kişinin web sayfası yok. Ancak torry'den arattırıp indirebilirsiniz.

 

 

 

 

-----------------------------------------------------------------------------------------------------------

 

 

Seri portlara erişim

 

Seri portlarla haberleşmek için bedava bir bileşen olan TurboPower Async Pro'yu kullanabilirsiniz.

Detaylar ve link için 3. Parti Bileşenler bölümündeki TurboPower makalesine bakınız.

 

-----------------------------------------------------------------------------------------------------------

 

 

Programı parametre ile açmak

 

Bu iş için ParamCount ve ParamStr'yi kullanabilirsiniz.

 

ParamCount : verilen parametre sayısını

ParamStr(x) : verilen parametreyi döndürür.

 

0 : exe'nin kendisini (path'i ile birlikte) döndürür.

1 : birinci parametreyi döndürür

2 : ikinci parametreyi döndürür ...

 

ana formun OnShow olayına aşağıdaki gibi bir kod yazmalısınız.

 

 

if ParamCount<> 1 then {eğer parametre verilmemişse veya birden fazla ise kapat}

  Close; {bu iki satır seçimlik, istersen yazmayabilirsin}

 

if ParamStr(1) = '0' then // parametre olarak 0 verilmişse

  {şunları şunları yap}

else

if ParamStr(1) = '1' then // parametre olarak 1 verilmişse

  {şunları şunları yap}

 

QuickReport'ta toplam sayfa sayısını hesaplama

 

Qr'nin Prepare metodunu kullanırsanız, rapor önizleme açılmadan ve yazdırılmadan oluşturulur.

Prepare ile raporu oluşturduktan sonra QrPrinter.PageCount ile sayfa sayısını alabilirsiniz. Örnek kod :

 

QuickRep1.Prepare;

QuickRep1.ReportTitle := 'Bu rapor toplam : ' + IntToStr(QuickRep1.QRPrinter.PageCount) + ' sayfadır.';

QuickRep1.QRPrinter.Free;

QuickRep1.QRPrinter := nil;

QuickRep1.Preview;

 

 

 

-----------------------------------------------------------------------------------------------------------

 

 

 

 

Programınızı koruma ve demo olarak dağıtma

 

Bazen programınızı potansiyel müşterilerinizin denemesi için demo olarak dağıtmak isteyebilirsiniz.

Bunlarda genel mantık belli bir süre veya belli bir sayıda programın çalışması, bu süre sonunda çalışmayı

kesmesidir. Artık bedava dağıtılan TurboPower OnGuard paketi ile dene-satın al türü uygulamalar oluşturabilirsiniz.

Kullanıcı kısıtlı sürümü kurduktan sonra, sizden şifre alıp, aynı exe dosya ile limitsiz kullanıma ulaşabilir.

Şifre kendi bilgisayarına özgü olduğu için başkalarına programı dağıtamaz.

 

Bu paketi indirip kurun. İndirme detayları için sitedeki 3. Parti bileşenler kısmındaki TurboPower

yazısına bakabilirsiniz.

 

Outlook Express'i dosya ekleyerek (attach) açma

 

uses kısmına mapi unitini ekleyin.

 

function SendMail(const Subject, Body, FileName,

                  SenderName, SenderEMail,

                  RecipientName, RecipientEMail: string): Integer;

var

  Message: TMapiMessage;

  lpSender, lpRecipient: TMapiRecipDesc;

  FileAttach: TMapiFileDesc;

 

  SM: TFNMapiSendMail;

  MAPIModule: HModule;

begin

  FillChar(Message, SizeOf(Message), 0);

  with Message do

  begin

    if (Subject <> '') then

      lpszSubject := PChar(Subject);

 

    if (Body <> '') then

      lpszNoteText := PChar(Body);

 

    if (SenderEmail <> '') then

    begin

      lpSender.ulRecipClass := MAPI_ORIG;

      if (SenderName = '') then

        lpSender.lpszName := PChar(SenderEMail)

      else

        lpSender.lpszName := PChar(SenderName);

      lpSender.lpszAddress := PChar(SenderEmail);

      lpSender.ulReserved := 0;

      lpSender.ulEIDSize := 0;

      lpSender.lpEntryID := nil;

      lpOriginator := @lpSender;

    end;

 

    if (RecipientEmail <> '') then

    begin

      lpRecipient.ulRecipClass := MAPI_TO;

      if (RecipientName = '') then

        lpRecipient.lpszName := PChar(RecipientEMail)

      else

        lpRecipient.lpszName := PChar(RecipientName);

      lpRecipient.lpszAddress := PChar(RecipientEmail);

      lpRecipient.ulReserved := 0;

      lpRecipient.ulEIDSize := 0;

      lpRecipient.lpEntryID := nil;

      nRecipCount := 1;

      lpRecips := @lpRecipient;

    end

    else

      lpRecips := nil;

 

    if (FileName = '') then

    begin

      nFileCount := 0;

      lpFiles := nil;

    end

    else

    begin

      FillChar(FileAttach, SizeOf(FileAttach), 0);

      FileAttach.nPosition := Cardinal($FFFFFFFF);

      FileAttach.lpszPathName := PChar(FileName);

 

      nFileCount := 1;

      lpFiles := @FileAttach;

    end;

  end;

 

  MAPIModule := LoadLibrary(PChar(MAPIDLL));

  if MAPIModule = 0 then

    Result := -1

  else

    try

      @SM := GetProcAddress(MAPIModule, 'MAPISendMail');

      if @SM <> nil then

      begin

        Result := SM(0, Application.Handle, Message, MAPI_DIALOG or

MAPI_LOGON_UI, 0);

      end

      else

        Result := 1;

    finally

      FreeLibrary(MAPIModule);

    end;

 

  if Result <> 0 then

    MessageDlg('Mesaj gönderilemedi (' + IntToStr(Result) + ').',

mtError, [mbOK], 0);

end;

 

Kullanımı : SendMail ( 'Deneme', '', c:deneme.txt, '', 'aaa@bbb.com', '', 'xyz@bbb.com' );

 

 

 

 

-----------------------------------------------------------------------------------------------------------

 

 

 

 

 

QuickReport'taki verileri text dosyaya kaydetmek

 

Qr ile hazır gelen export filtreleri var. Bunları kullanarak .txt, .csv (Excel) vs. aktarım yapabilirsiniz.

ASCII (txt) olanı raporun olduğu forma koy, Ön izleme ekranında Save butonuna bastığında (*.txt) de çıkacaktır artık. Koddan yapmak istersen :

 

QuickRep1.ExportToFilter(TQRAsciiExportFilter.Create('c:rapor.txt'));

 

Auto-run (otomatik açılan) CD'ler oluşturmak

 

Bu olayın direk olarak Delphi ile alakası yok ama lazım olabilir. Notepad ile ismi "autorun.inf" olan

ve aşağıdaki gibi bir metni içeren bir text dosya oluşturun.

 

[autorun]

OPEN=myprogram.EXE

ICON=myicon.ICO

 

Burada Open kısmına çalışacak olan programın ismini, icon kısmına da CD'yi takınca gözükecek simgeyi

yazmalısınız.

 

 

-----------------------------------------------------------------------------------------------------------

 

 

 

 

Windows Metafile'ı (.wmf) bitmap'e (.bmp) çevirme

 

procedure ConvertWMF2BMP (const WMFFileName, BMPFileName: TFileName);

var

  MetaFile : TMetafile;

  Bitmap : TBitmap;

begin

  Metafile := TMetaFile.Create;

  Bitmap := TBitmap.Create;

  try

    MetaFile.LoadFromFile(WMFFileName);

    with Bitmap do

    begin

      Height := Metafile.Height;

      Width  := Metafile.Width;

      Canvas.Draw(0, 0, MetaFile);

      SaveToFile(BMPFileName);

    end;

  finally

    Bitmap.Free;

    MetaFile.Free;

  end;

end;

 

 

Kullanımı : ConvertWMF2BMP('c:mypic.wmf', 'c:mypic.bmp')

 

 

 

 

 

-----------------------------------------------------------------------------------------------------------

 

 

 

 

Bitmap'i (.bmp) Windows Metafile'a (.wmf') çevirme

 

procedure ConvertBMP2WMF (AImage: TImage; FileName: String);

var

 Wmf      : TMetafile;

 WmfCanvas: TMetafileCanvas;

begin

 Wmf := TMetafile.Create;

 try

   //Must set width + Height before creating the canvas

   Wmf.Width := AImage.Picture.Bitmap.Width;

   Wmf.Height := AImage.Picture.Bitmap.Height;

 

   WmfCanvas := TMetafileCanvas.Create(Wmf, 0);

   try

     WmfCanvas.Draw(0,0,AImage.Picture.Bitmap);

   finally

     WmfCanvas.Free;

   end;

 

   Wmf.SaveToFile(FileName);

 finally

  Wmf.Free;

 end;

end;

 

 

Kullanımı : ConvertBMP2WMF(Image1, 'c:mypic.wmf'); // bitmap resim image1'de yüklü.

 

 

 

 

 

-----------------------------------------------------------------------------------------------------------

 

 

 

TColor'u HTML Color'a çevirme

 

Bir ColorDialog, bir label ve bir buton koyup aşağıdaki kodu yazın.

 

procedure TForm1.Button1Click(Sender: TObject);

 

 function ColorToHtml(DColor:TColor):string;

 var

   tmpRGB : TColorRef;

 begin

   tmpRGB := ColorToRGB(DColor);

   Result:=Format('#%.2x%.2x%.2x',

                  [GetRValue(tmpRGB),

                   GetGValue(tmpRGB),

                   GetBValue(tmpRGB)]);

 end; {function ColorToHtml}

 

begin

 if ColorDialog1.Execute then

  Label1.Caption:=ColorToHtml(ColorDialog1.Color);

end;

 

 

 

-----------------------------------------------------------------------------------------------------------

 

 

 

 

 

 

Delphi 7'de Quick Report'u nasıl yüklerim

 

Quick Report, Delphi 7 ile birlikte dağıtılıyor, ancak kurulu olarak gelmiyor. Quick Report'u Delphi 7'ye

kurmak için :

 

1. Component menüsünden Install Packages komutunu verin.

2. Add butonuna tıklatın ve Delphi7Bin klasöründeki dclqrt70.bpl isimli dosyayı seçin.

 

SMS Göndermek

 

Bu iş için bir kaç yöntem var :

 

1. Dahili modemi olan bir cep telefonunu kablo ile bağlayıp göndermek. Normal SMS ücreti ödersiniz.

   Bu iş için TurboPower Async Pro veya TOxygenSMS bileşenini (http://www.oxygensoftware.com) kullanabilirsiniz.

 

2. Dahili SMS modemler var. Bunu bilgisayarınıza takıyorsunuz ve SIM kart takıyorsunuz üstüne.

   Yine SMS ücreti ödersiniz.

 

3. Internet üzerinden bedava SMS hizmeti veren siteleri http ile kullanarak gönderebilirsiniz ancak

   bunlar Türkiye için pek kullanışlı değil. Çok sık takip etmeniz lazım. Ya servis kapanıyor ya da

   firmalar (Turkcell, Telsim vb.) bu tip servislerden gelen mesajları iletmeyebiliyor.

 

4. Yüklü miktarda SMS gönderecekseniz ve iletilmesi önemli ise Turkcell ve Telsim gibi hizmet aldığınız

   firmalarla anlaşma yapıp, http kullanarak daha uygun fiyatlı SMS gönderebilirsiniz.

   Bu durumda firma size gönderme bilgilerini verecektir.

 

Az mesaj gönderiyorsanız 1 veya 2'yi, Şirket için ve yüklü miktarda SMS gidecekse 4'ü,kişisel bir çalışma ise 3'ü seçin.

 

 

 

 

-----------------------------------------------------------------------------------------------------------

 

 

 

 

Fax Gönderme ve Alma

 

Fax gönderme ve alma işini bedava olarak dağıtılan TurboPower Async Pro ile yapabilirsiniz.Examples klasöründe örnekleri var

 

 

 

-----------------------------------------------------------------------------------------------------------

 

 

 

Barkod Bileşenleri

 

Artık bedava olarak dağıtılan Turbopower SysTools paketi içinde barkod bileşenleri var.

Barkod işlemleriniz için bu bileşenleri kullanabilirsiniz.

 

 

 

-----------------------------------------------------------------------------------------------------------

 

 

 

USB Porttan Bilgi Okuma

 

1. USB/Serial dönüştürücüler var. Bunları kurduğunuz zaman USB potta, serial (COM) portlarda

yapabildiğin şeyleri yapabilirsin. Mesela http://www.ftdichip.com/

 

2. Turbopower Async Pro USB serial cihazlarla haberleşebiliyor. Onu kullanabilirsiniz.

 

 

 

-----------------------------------------------------------------------------------------------------------

 

 

 

 

 

ICQ'ya Mesaj Gönderme

 

Turbopower iPro (Internet Pro) paketi içinde pager bileşenleri vardı. Bu bileşen ile mesaj atabilirsiniz.

 

 

-----------------------------------------------------------------------------------------------------------

 

 

Office XP Tarzı Menüler Oluşturmak

 

1. Güzel bir menü bileşeni olan Toolbar 2000 ve eklentisi TBX ile de yapabilirsiniz.

İkisi de bedava. www.jrsoftware.org

2. XP menu bileşeni ile yapabilirsiniz. O da bedava. Normal menu ve formlarla tasarımı yapıp,

bu bileşeni forma koyduğunuz anda çalışma anında herşey XP tarzı oluyor.

 

-----------------------------------------------------------------------------------------------------------

 

 

 

Show ile ShowModal Arasındaki Fark

 

Show ile açarsanız formu kapatmadan başka formlara ulaşabilirsiniz, mesela ana form.

Ama ShowModal ile açarsanız, arka planda kalan diğer formlara ulaşamazsınız.

 

Netmaster Paketinde Yer Alan NMSMTP Bileşenini Delphi 7'de Bulamıyorum?

 

Netmaster paketi artık Delphi ile dağıtılmıyor ve Delphi 7 ile de gelmiyor. Yeni kullanacaklar için,

ileriye doğru sıkıntı olmaması için Indy kullanmanızı öneririm. Yarın birgün Delphi'nizi yenilerseniz,

kodları değiştirmeniz gerekmez.

 

 

-----------------------------------------------------------------------------------------------------------

 

 

 

.mp3 Dosyalarını Çalma

 

Windows'un çalabildiği tüm ses dosyalarını System tabındaki MediaPlayer bileşeni ile çalabilirsiniz.

Ayrıca PlaySound API'si ile de çalma işlemini gerçekleştirebilirsiniz.

 

Ağ üzerinde Mesaj Gönderme (net send, winpopup gibi)

 

Windows işletim sistemlerinde ağ üzerindeki bilgisayarlar birbirlerine mesaj atabilirler.

Windows NT/2000/XP'de bunun için "net send" komutu kullanılır. Windows 9x'te ise Winpopup isimli

program kullanılır.

 

Delphi'de yazacağınız program içersiniden bu tarz mesaj atmak için, bedava olarak dağıtılan

TurboPower SysTools paketi içerisindeki stNetMessage isimli bileşeni kullanabilirsiniz.

 

 

-----------------------------------------------------------------------------------------------------------

 

 

 

Farklı Ekran Çözünürlüklerinde Formların Düzgün Gözükmesi

 

Align ve Anchors özelliklerini kullanarak formlarınızın farklı ekran çözünürlüklerinde en iyi şekilde

görünmesini sağlayabilirsiniz. Form üzerine birkaç bileşen koyup, bu özellikleri değiştirerek görsel

 olarak olayı anlayabilirsiniz.

 

Align : bileşenin duracağı yeri belirler. Mesela bir panelin Align özelliğini alBottom verirseniz,

pencereyi naparsanız yapın, panel hep ekranın altında kalır.

 

Anchors : bileşenin hangi kenara göre kendini ayarlayacağını belirler. Mesela sadece [akRight] derseniz,

sağ kenara göre aradaki uzaklık sabit kalacak şekilde kendini ayarlar. Mesela sağ kenardan 100

 birim uzakta ise, formu büyütünce ve küçültünce yine sağ kenardan 100 birim uzakta kalır.

 

 

-----------------------------------------------------------------------------------------------------------

 

 

System.pas not found Hatası

 

Delphi'de programı derlemek için gerekli olan unitlerin Library Path'te tanımlı olması gerekir.

 Delphi uniti proje klasöründe bulamazsa bu klasörlere bakarak uniti bulur ve programı derler.

 

Bazen bu Library Path tanımı silinebiliyor. Buna da genellikle bozuk ayarlanmış bileşenleri kurmak

neden oluyor. Delphi'nin eski sürümlerinde eğer bu Library Path tanımı çok uzunsa yine problem çıkıyordu.

Bunu sonraki sürümlerde düzelttiler.

 

Bu hatayı düzeltmek için ilgili unitin bulunduğu klasörleri Library Path'e eklemeniz gerekir.

Örneğin system.pas not found hatası almışsanız :

 

1. Diskinizde "system.dcu" dosyasını aratın ve bulunduğu klasörü tespit edin.

2. Tools -> Environment Options komutunu verin.

3. Library sekmesine geçin.

4. Library Path'in yanındaki ... butonuna tıklatın.

5. Açılan pencerede yine ... butonuna basıp, system.dcu dosyasının bulunduğu klasörü seçin.

6. Add butonuna tıklatıp klasörü listeye ekleyin.

7. OK'leyerek pencereleri kapatın.

 

Bu hatanın önüne geçmek içinde birkaç önerimiz var :

 

1. Her önünüze gelen bileşeni yüklemeyin. Bozuk bileşenler Delphinizin düzenini ciddi manada bozabilir.

2. Yüklediğiniz ve kullanmadığınız bileşenler varsa silin ve klasörünü Library Path'ten kaldırın.

3. Bileşen kurmadan önce Library Path bilgisini copy-paste ile bir text dosyaya kaydedin.

 Problem çıkarsa, tekrar copy-paste ile yapıştırsınız, tek tek seçmek için uğraşmazsınız.

4. $Delphi alias'ını kullanabilirsiniz. Bu Library Path'te kullanabileceğiniz geçerli bir yazımdır ve

Delphi klasörünü gösterir. Yani $Delphi = C:Program FilesBorlandDelphi7'dir. Tabi bu kurduğunuz klasöre

göre değişebilir.

 

 

 

-----------------------------------------------------------------------------------------------------------

 

 

 

 

Banker (parasal) Yuvarlaması

 

Parasal değerlerde bazen normal yuvarlama yerine 3-4 basamak birden yuvarlama yapmanız gerekebilir.

Mesela 15.557.850 TL tutan bir ücreti 100 binlik bir hassasiyet ile yuvarlayarak 15.600.000 TL yapmak

isteyebilirsiniz. İşte bunu RoundTo fonksiyonu ile yapabilirsiniz

 

 

 

-----------------------------------------------------------------------------------------------------------

 

 

Ekranları XP Görünümlü Yapmak

 

Delphi 7 içinde XP Manifest diye bir component var. Onu ana forma koyarsanız herşey XP görünümü çıkar.

XP Manifest'in herhangi bir ayarı yok. Bileşeni ana forma koyun. Programı Windows XP'de çalıştırırsanız,

program XP arayüzü ile açılır. Eğer diğer işletim sistemlerinde çalıştırırsanız, normal arayüzle çalışır.

 

Eğer daha önceki bir Delphi sürümü kullanıyorsanız, bedava olarak dağıtılan XP Menu isimli bileşen ile bu

işi yapabilirsiniz : www.torry.net ten indirebilirsiniz.

 

Delphi'de zip Sıkıştırma Formatını Kullanma

 

Turbopower Abbrevia ile zip, Microsoft CAB, tar ve gzip formatlarını kullanabilirsiniz.

 

.exe Dosyaların Boyutunu Küçültmek

 

Eğer sık sık program güncelliyorsanız ve bunuda internet gibi bir ortamdan dağıtıyorsanız .exe

dosyanın boyutu bazen sıkıntı olabilir. .exe dosyanın boyutunu %99'lara varan oranda küçültme için

.bpl'leri kullanabilirsiniz. Bir denememde 4 MB'lık bir dosyayı 40 KB'ye düşürdü.

 

Project - Options - Packages kısmındaki Built with runtime packages seçeneğini işaretleyin ve

bu şekilde derleyin. Bir de bu seçeneğin hemen altında ismi yazan bpl'leri programı yüklediğiniz

bilgisayarın WindowsSystem32 klasörüne bir sefer kopyalamanız yeterli.

 

QuickReport'ta sayfaların altına sayfa numarasının yazdırılması

 

1. Eğer sadece sayfa numarasının gösterilmesini istiyorsanız QrSysData isimli bileşen ile yapabilirsiniz.

Bu bileşeni Qr üzerine koyun ve Data özelliğinden qrsPageNumber'ı seçin.

 

2. Eğer sayfa numaralarını sayfa/toplam sayfa sayısı şeklinde yazdırmak istiyorsanız,

sayfa numarasını yazdırmak için yine QrSysData'yı kullanın. Yanına bir QrLabel koyup,

raporu yazdırmadan önce toplam sayfa sayısını hesaplatıp, başına / işaretini de koyarak yazdırın.

Toplam sayfa sayısını hesaplatmakla ilgili kod bu sayfada yukarlarda var.

 

Delphi - .....................................

 

sanal tus_klavyeden bir tusa bastiginda hepsini tek tek bulmak _ sanal tus kodu_ virtual key codes

//bende yeni yeni delphi ogrenmeye basladim ve buldugum dokumanlari sizlerle

//paylasmak istedim.maalesef tamamen c/p ama onemli olan dokumanlarin artmasi

 

 //kod bu

 

 function GetCharFromVirtualKey(Key: Word): string;

var

   keyboardState: TKeyboardState;

   asciiResult: Integer;

begin

   GetKeyboardState(keyboardState) ;

 

   SetLength(Result, 2) ;

   asciiResult := ToAscii(key, MapVirtualKey(key, 0), keyboardState, @Result[1], 0) ;

   case asciiResult of

     0: Result := '';

     1: SetLength(Result, 1) ;

     2:;

     else

       Result := '';

   end;

end;

 

// kullanimi (usage)__ornek

//forma bir memo ekleyin.memonun keydown olayina su kodlari ekleyin

 

procedure TForm1.Memo1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState) ;

begin

   Self.Caption := GetCharFromVirtualKey(Key) ;

end;

 

Delphi - .....................................

 

sanal tus_klavyeden bir tusa bastiginda hepsini tek tek bulmak _ sanal tus kodu_ virtual key codes

//bende yeni yeni delphi ogrenmeye basladim ve buldugum dokumanlari sizlerle

//paylasmak istedim.maalesef tamamen c/p ama onemli olan dokumanlarin artmasi

 

 //kod bu

 

 function GetCharFromVirtualKey(Key: Word): string;

var

   keyboardState: TKeyboardState;

   asciiResult: Integer;

begin

   GetKeyboardState(keyboardState) ;

 

   SetLength(Result, 2) ;

   asciiResult := ToAscii(key, MapVirtualKey(key, 0), keyboardState, @Result[1], 0) ;

   case asciiResult of

     0: Result := '';

     1: SetLength(Result, 1) ;

     2:;

     else

       Result := '';

   end;

end;

 

// kullanimi (usage)__ornek

//forma bir memo ekleyin.memonun keydown olayina su kodlari ekleyin

 

procedure TForm1.Memo1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState) ;

begin

   Self.Caption := GetCharFromVirtualKey(Key) ;

end;

 

Delphi - .....................................

 

sanak tus kodlari (tamamı)

//en sol taraftakiler sembolleridir

//ortadakiler degerleri

//en sagdakiler ise degerlerin klavye veya mouse taki karsiliklaridir

 

Symbolic      -        -

constant name -   Value  - Keyboard (or mouse) equivalent

-----------------------------------------------------------------------------

VK_LBUTTON        01   Left mouse button

VK_RBUTTON 02    Right mouse button

VK_CANCEL   03    Control-break processing

VK_MBUTTON 04    Middle mouse button (three-button mouse)

VK_BACK     08    BACKSPACE key

VK_TAB      09    TAB key

VK_CLEAR    0C    CLEAR key

VK_RETURN   0D    ENTER key

VK_SHIFT    10    SHIFT key

VK_CONTROL 11    CTRL key

VK_MENU     12    ALT key

VK_PAUSE    13    PAUSE key

VK_CAPITAL 14    CAPS LOCK key

VK_ESCAPE   1B    ESC key

VK_SPACE    20    SPACEBAR

VK_PRIOR    21    PAGE UP key

VK_NEXT     22    PAGE DOWN key

VK_END      23    END key

VK_HOME     24    HOME key

VK_LEFT     25    LEFT ARROW key

VK_UP       26    UP ARROW key

VK_RIGHT    27    RIGHT ARROW key

VK_DOWN     28    DOWN ARROW key

VK_SELECT   29    SELECT key

VK_PRINT    2A    PRINT key

VK_EXECUTE 2B    EXECUTE key

VK_SNAPSHOT       2C    PRINT SCREEN key

VK_INSERT   2D    INS key

VK_DELETE   2E    DEL key

VK_HELP     2F    HELP key

      30    0 key

      31    1 key

      32    2 key

      33    3 key

      34    4 key

      35    5 key

      36    6 key

      37    7 key

      38    8 key

      39    9 key

      41    A key

      42    B key

      43    C key

      44    D key

      45    E key

      46    F key

      47    G key

      48    H key

      49    I key

      4A    J key

      4B    K key

      4C    L key

      4D    M key

      4E    N key

      4F    O key

      50    P key

      51    Q key

      52    R key

      53    S key

      54    T key

      55    U key

      56    V key

      57    W key

      58    X key

      59    Y key

      5A    Z key

VK_NUMPAD0 60    Numeric keypad 0 key

VK_NUMPAD1 61    Numeric keypad 1 key

VK_NUMPAD2 62    Numeric keypad 2 key

VK_NUMPAD3 63    Numeric keypad 3 key

VK_NUMPAD4 64    Numeric keypad 4 key

VK_NUMPAD5 65    Numeric keypad 5 key

VK_NUMPAD6 66    Numeric keypad 6 key

VK_NUMPAD7 67    Numeric keypad 7 key

VK_NUMPAD8 68    Numeric keypad 8 key

VK_NUMPAD9 69    Numeric keypad 9 key

VK_SEPARATOR      6C    Separator key

VK_SUBTRACT       6D    Subtract key

VK_DECIMAL 6E    Decimal key

VK_DIVIDE   6F    Divide key

VK_F1       70    F1 key

VK_F2       71    F2 key

VK_F3       72    F3 key

VK_F4       73    F4 key

VK_F5       74    F5 key

VK_F6       75    F6 key

VK_F7       76    F7 key

VK_F8       77    F8 key

VK_F9       78    F9 key

VK_F10      79    F10 key

VK_F11      7A    F11 key

VK_F12      7B    F12 key

VK_F13      7C    F13 key

VK_F14      7D    F14 key

VK_F15      7E    F15 key

VK_F16      7F    F16 key

VK_F17      80H   F17 key

VK_F18      81H   F18 key

VK_F19      82H   F19 key

VK_F20      83H   F20 key

VK_F21      84H   F21 key

VK_F22      85H   F22 key

VK_F23      86H   F23 key

VK_F24      87H   F24 key

VK_NUMLOCK 90    NUM LOCK key

VK_SCROLL   91    SCROLL LOCK key

VK_LSHIFT   A0    Left SHIFT key

VK_RSHIFT   A1    Right SHIFT key

VK_LCONTROL       A2    Left CONTROL key

VK_RCONTROL       A3    Right CONTROL key

VK_LMENU    A4    Left MENU key

VK_RMENU    A5    Right MENU key

VK_PLAY     FA    Play key

VK_ZOOM     FB    Zoom key

 

Delphi - .....................................

 

sanak tus kodlari (tamamı)

//en sol taraftakiler sembolleridir

//ortadakiler degerleri

//en sagdakiler ise degerlerin klavye veya mouse taki karsiliklaridir

 

Symbolic      -        -

constant name -   Value  - Keyboard (or mouse) equivalent

-----------------------------------------------------------------------------

VK_LBUTTON        01   Left mouse button

VK_RBUTTON 02    Right mouse button

VK_CANCEL   03    Control-break processing

VK_MBUTTON 04    Middle mouse button (three-button mouse)

VK_BACK     08    BACKSPACE key

VK_TAB      09    TAB key

VK_CLEAR    0C    CLEAR key

VK_RETURN   0D    ENTER key

VK_SHIFT    10    SHIFT key

VK_CONTROL 11    CTRL key

VK_MENU     12    ALT key

VK_PAUSE    13    PAUSE key

VK_CAPITAL 14    CAPS LOCK key

VK_ESCAPE   1B    ESC key

VK_SPACE    20    SPACEBAR

VK_PRIOR    21    PAGE UP key

VK_NEXT     22    PAGE DOWN key

VK_END      23    END key

VK_HOME     24    HOME key

VK_LEFT     25    LEFT ARROW key

VK_UP       26    UP ARROW key

VK_RIGHT    27    RIGHT ARROW key

VK_DOWN     28    DOWN ARROW key

VK_SELECT   29    SELECT key

VK_PRINT    2A    PRINT key

VK_EXECUTE 2B    EXECUTE key

VK_SNAPSHOT       2C    PRINT SCREEN key

VK_INSERT   2D    INS key

VK_DELETE   2E    DEL key

VK_HELP     2F    HELP key

      30    0 key

      31    1 key

      32    2 key

      33    3 key

      34    4 key

      35    5 key

      36    6 key

      37    7 key

      38    8 key

      39    9 key

      41    A key

      42    B key

      43    C key

      44    D key

      45    E key

      46    F key

      47    G key

      48    H key

      49    I key

      4A    J key

      4B    K key

      4C    L key

      4D    M key

      4E    N key

      4F    O key

      50    P key

      51    Q key

      52    R key

      53    S key

      54    T key

      55    U key

      56    V key

      57    W key

      58    X key

      59    Y key

      5A    Z key

VK_NUMPAD0 60    Numeric keypad 0 key

VK_NUMPAD1 61    Numeric keypad 1 key

VK_NUMPAD2 62    Numeric keypad 2 key

VK_NUMPAD3 63    Numeric keypad 3 key

VK_NUMPAD4 64    Numeric keypad 4 key

VK_NUMPAD5 65    Numeric keypad 5 key

VK_NUMPAD6 66    Numeric keypad 6 key

VK_NUMPAD7 67    Numeric keypad 7 key

VK_NUMPAD8 68    Numeric keypad 8 key

VK_NUMPAD9 69    Numeric keypad 9 key

VK_SEPARATOR      6C    Separator key

VK_SUBTRACT       6D    Subtract key

VK_DECIMAL 6E    Decimal key

VK_DIVIDE   6F    Divide key

VK_F1       70    F1 key

VK_F2       71    F2 key

VK_F3       72    F3 key

VK_F4       73    F4 key

VK_F5       74    F5 key

VK_F6       75    F6 key

VK_F7       76    F7 key

VK_F8       77    F8 key

VK_F9       78    F9 key

VK_F10      79    F10 key

VK_F11      7A    F11 key

VK_F12      7B    F12 key

VK_F13      7C    F13 key

VK_F14      7D    F14 key

VK_F15      7E    F15 key

VK_F16      7F    F16 key

VK_F17      80H   F17 key

VK_F18      81H   F18 key

VK_F19      82H   F19 key

VK_F20      83H   F20 key

VK_F21      84H   F21 key

VK_F22      85H   F22 key

VK_F23      86H   F23 key

VK_F24      87H   F24 key

VK_NUMLOCK 90    NUM LOCK key

VK_SCROLL   91    SCROLL LOCK key

VK_LSHIFT   A0    Left SHIFT key

VK_RSHIFT   A1    Right SHIFT key

VK_LCONTROL       A2    Left CONTROL key

VK_RCONTROL       A3    Right CONTROL key

VK_LMENU    A4    Left MENU key

VK_RMENU    A5    Right MENU key

VK_PLAY     FA    Play key

VK_ZOOM     FB    Zoom key

 

Delphi - .....................................

 

windows apileri_ingilizce

//bende yeni yeni delphi ogrenmeye basladim ve buldugum dokumanlari sizlerle

//paylasmak istedim.maalesef tamamen c/p ama onemli olan dokumanlarin artmasi

 

Windows API calls are just calls to dynamic link libraries

 

Back in the early days of Windows, PCs had much less memory available than today.

The first version of Windows required only 256k of memory and two floppy drives...

amazingly little by today's standards. The designers of windows had to fit a lot

of code and resources into that 256k of memory, and still leave room for multiple

programs to run.

 

This feat was achieved by allowing multiple programs to share commonly used code

and resources. The vehicle used to provide this magic is the dynamic link library.

 

 

Functions and resources contained in dynamic link libraries can be shared by

multiple applications.  The code and resources contained in a dynamic link

library are generally not loaded until needed, and can be freed when not in

use.

 

 

Most of the Windows system is comprised of dynamic link libraries. Usually dynamic

link libraries have the extension of  ".DLL" , but this is not a requirement.

An example would be in the heart of Windows itself : GDI.EXE, GDI32.DLL, USER.EXE,

USER32.DLL, KERNEL.EXE, KERNEL32.DLL, printer drivers (.drv), system drivers(.drv),

and some fonts(.fon).

 

An example of a resource only dynamic link library is contained in the  MORICONS.DLL

file that ships with Windows. It contains a variety of extra icons for Windows users

to brighten their desktops with.

 

 

Some of the other advantages of placing code and resources in a dynamic link library

are:

 

 

 Disk space is saved if multiple applications use a dynamic link library. This can

 sometimes make a drastic difference in the cost of deploying your applications

 since you can place common functions and resources in a single .DLL file, reducing

 the size of your executables.

 

 The ability to upgrade and replace parts of the program without shipping a whole

 new executable.

 

 The ability to load and execute different resources and code based on some specific

 criteria available only at runtime. A good example would be " PlugIn "

 applets that can be dynamically loaded by your application at runtime, without

 knowing what " PlugIns " might be available at compile time.

 

 This can make your program automatically extendible with after-market products.

 

 

Loading a dynamic link library

 

Your compiler most likely includes interface files to most of the Windows system

functions.  You simply link to the interface files, and any dynamic link libraries

that are used by your program are automatically loaded when your program is started.

In 16 Bit Windows, the actual function code is not added to your program, but

rather a pointer to the module name of the dynamic link library and the name of

the function (or its exported index number) is added.

 

In Win32, the DLL is mapped into the process' address space.  The dynamic link

library's file must exist at runtime or an error will occur.

 

 

If your compiler does not include an interface to the function or dynamic link

library you want to use, you are going to have to declare a function prototype,

and a linking interface, to let your compiler know about the function you are

dynamically linking to. The instructions to do this should be included with your

compiler's documentation.

 

A short example of a function prototype in  Pascal  for a dynamic link library

would be:

 

 {$IFDEF Win32}

 function MessageBeep(BeepType: Integer):Bool stdcall; external 'USER32';

{$ELSE}

 procedure MessageBeep(BeepType: Integer); far; external 'USER';

{$ENDIF}

 

This prototype tells the compiler to link to a function named " MessageBeep "

located in USER32.DLL (if compiling under 32 bits), or a procedure named " MessageBeep "

located in USER.EXE (if compiling under 16 bits). The compiler is also made aware

that " MessageBeep " takes a integer size parameter, and uses the " stdcall "

passing convention (if compiling under 32 bits).

 

When declaring an interface to a dynamic link library, you must be careful to

specify the way that the function expects to have its parameters and return value

passed, and who will maintain the stack. There are various calling techniques used

including:  PASCAL, CDECL, STDCALL,  and  FASTCALL .

 

In 16 bit Windows, most functions are exported using the  PASCAL  calling convention.

In 32 bit Windows,  STDCALL  is preferred since this should be compatible w/most

other languages.

 

Most API functions are declared with " C " prototypes. If you are wanting

to port an interface to a  Pascal  based language, and you are not familiar with " C ",

your best bet is to get  Alain Tadros's  technical paper --

"Using Borland's Delphi and C++ Together" .

 

It is available from Borland's World Wide Web site, Compuserve, and the Borland

BBS system and has some excellent additions by  Eric Uber .

 

 

Dynamic loading at runtime

 

Loading a dynamic link library at runtime allows you to load dynamic link libraries

that are not known at compile time,   or load a library for only a short time.

Printer drivers are a good example: You don't know what printer drivers will be

available on a users system until runtime, and you would only want to load a printer

driver during the printing phase of your program.

 

One of the advantages to loading libraries dynamically is that you don't use up

resources (memory) until you actually load the library and the function you wish

to call.

 

You load a dynamic link library at runtime by calling the Windows API function

LoadLibrary() .  Then you can search for a given function within the library

using the Windows API function  GetProcAddress() . Once you have the address of

the function you want, you can call it from your code.

 

One thing to remember: Always call the Windows API function  FreeLibrary()  when

you are done using the dynamic link library.

 

 Example:

 

 procedure Win31LoadUserAndCallBeepFn;

var

 DllHandle: THandle;

 BeepFn: procedure(BeepType: Integer);

begin

 DllHandle := LoadLibrary('USER');

 if DllHandle >= 32 then begin

   @BeepFn := GetProcAddress(DllHandle, 'MessageBeep');

   if @BeepFn <> nil then

     BeepFn(-1);

   FreeLibrary(DllHandle);

 end;

end;

 

 

procedure Win32LoadUserAndCallBeepFn;

var

 DllHandle: THandle;

 BeepFn: function(BeepType: Integer): Bool stdcall;

begin

 DllHandle := LoadLibrary('USER32');

 if DllHandle <> 0 then begin

   @BeepFn := GetProcAddress(DllHandle, 'MessageBeep');

   if @BeepFn <> nil then

     BeepFn($FFFFFFFF);

   FreeLibrary(DllHandle);

 end;

end;

 

 

Here we have two code snippets showing the differences between loading a library

under 16 and 32 bit Windows. In this case, we must mark the function we are calling

as using the " stdcall " calling convention under 32 bit Windows, where

under 16 bit windows the " pascal " calling convention is assumed. Note

that the 16 bit version of  MessageBeep()  is a procedure, and the 32 bit version

is a function.

 

The  LoadLibrary()  function takes a null-terminated string that names the library

file to be loaded. If the string does not contain a path, Windows searches for the

library in this order: the current directory; the Windows directory; the Windows

system directory; the directory containing the executable file for the current

task; the directories listed in the PATH environment variable; and finally, the

list of directories mapped in a network. If no extension is used, the extension

of " .DLL " is assumed. We check the value of the handle returned by

LoadLibrary()  for an error.

 

Under 16 bit Windows, the return value will be less than 32 if an error occurs,

and under 32 bit Windows, the return value will be 0 if an error occurs. We then

call the  GetProcAddress()  function to get the address of the  MessageBeep()

function.  The spelling of the function name is critical, and can be case sensitive

under different environments. If GetProcAddress()  successfully returns the address

of the function, then we can safely call the function. Finally we unload the

library to free up memory.

 

 

Resource only dynamic link libraries

 

As mentioned, dynamic link libraries can hold resources as well. To use resources

contained in a dynamic link library, you simply make a call to  LoadLibrary() ,

then you can load resources from the library using one of the Windows API resource

functions such as  LoadBitmap() , passing the handle to the dynamic link library

that you received from the  LoadLibrary()  call. Just don't forget to free your

resources and the library when you are done.

 

You can use the snipit from the above section " Loading dynamic link libraries

at runtime " to load a dynamic link library, and then load a resource from the

library.

 

 Example:

 

 LoadBitmap(DllHandle,'SOMEBMP');

 

 

Stack usage and dynamic link libraries

 

When you call a function in a dynamic link library, the library generally uses the

stack of the calling application. Applications running under 16 Bit Windows had much

less stack space available (<64k) than what is available under 32 bit Windows

(1 MB). Since functions in a dynamic link library can call functions in other

dynamic link libraries as well as making callbacks, you should always thoroughly

test your program to make sure you have setup adequate stack space.

 

 

Callback functions

 

Callback functions are a really wonderful feature of the Windows environment.

Callback functions allow you to send the " instanced " address of a

function in your application to a function contained in a dynamic link library.

The dynamic link library function can then call back to the function in your

application to pass back information.

 

A good example of a Windows API function that utilizes callbacks is the  EnumFonts()

function. The  EnumFonts()  function enumerates fonts available to a given device

context. For each font enumerated, the  EnumFonts()  function will call back to a

function in your application, passing back information about that font. This

process continues as long as their are more fonts to enumerate, or until your

function returns zero, meaning that you wish to stop further enumerations.

 

Most Windows API functions that accept a callback function as a parameter will

also accept an  lpData  parameter. This  lpData  parameter is used for " application

defined data ". You are free to define what this parameter is used for. The

lpData  parameter is usually passed to the dynamic link library as a longint, and

rarely as a far pointer. It is likely you will want to send something besides a

longint. You can always typecast a pointer to a data structure in your application

to a longint when calling dynamically linked functions, and typecast the longint

passed back to your callback function to a pointer so your may access your data

structure.

 

As mentioned, when your callback function is called by the Windows API function,

the  lpData  parameter you originally passed to the Windows API function will be

passed back to your callback function for your use. This avoids having to declare

a global variable in your program. A good example of how this works would be if

you were to create a program containing a dialog box to show all the available

fonts in a drop-down listbox.  When you process the  WM_INITDIALOG  message, you

call the EnumFonts()  function, passing the instanced address of your callback

function that will process the font information.

 

Your callback function will perform the work to add each font's name to the

listbox. The only problem: your callback function does not have a handle to the

listbox. You could create a global variable to hold the listbox handle, but

instead, you should pass the handle of the listbox to your callback function

through the lpData  parameter, and let the dynamically linked function pass the

handle of the listbox back to your callback function.

 

While it is always nice to keep global variables to a minimum, having the ability

to pass user defined data to the callback function becomes critically important

when you create callback functions inside a 16-bit dynamic link library.

 

Generally, under 16-bit Windows, a dynamic link library has only one data segment.

Since multiple applications can use a single dynamic link library, and, since a

16-bit dynamic Link Library has a single data segment, any global variables

defined in the dynamic link library exist in memory only once.

 

If you create a callback function in a dynamic link library, and use a global

variable to store data used during the callback, you run the risk of data

corruption.  Consider the following scenario: You have written several applications

that use your font dialog box. Rather than include your font dialog in each

application, you opt to store the dialog in a dynamic link library.

 

Suppose that you use a global variable in the dynamic link library to store the

listbox handle for your callback function.  Now suppose that more than one

application loads the dialog box at the same time. Each "copy" of your

font dialog box contains a different handle to it's listbox. Clearly, using a

global variable to hold the listbox handle will not work since the listbox handle

will be different for each dialog, and the global variable used to hold this

handle will get trashed. The way around this, is to pass the listbox handle to

the  EnumFonts()  function using the  lpData  parameter. This is not a problem,

when writing 32-bit dynamic link libraries for use under  Windows 95  and

Windows NT , as under both environments, dynamic link libraries have a separate

data area for each application that loads them.

 

None the less, it is still a good practice to always keep global variables to

a minimum.

 

 

The Hook functions

 

A " hook " function is a callback function that can be inserted in the

Windows message system so an application can access the message stream before

other processing of the message takes place. Often times, there will be other

hooks already installed in the messaging system, so there will be times you will

need to call the next hook in the " Hook Chain " to allow the other

hooks in the chain to access the messages as well.

 

When you install a hook function using the Windows API function  SetWindowsHookEx(),

you will receive a 32 bit handle to your installed hook function.  You will use

this handle to both remove the hook when you are done via the Windows API function

UnHookWindowsHookEx() , and when calling the next hook in the " Hook Chain " via

the Windows API function  CallNextHookEx() .  We have chosen to use the Windows " Ex "

hook functions since we want to be able to port to 32 bit Windows.

 

System wide hooks require that your hook filter function reside in a dynamic link

library.  The filter function for an application specific hook may reside either

in the application or a dynamic link library.

 

 

Different types of Windows Hooks:

 

Windows defines the following types of hook functions:

 

  WH_CALLWNDPROC - A window procedure hook called whenever the  SendMessage()

   function is called.

  WH_CBT    - A computer based training hook called before activating, creating,

   destroying, minimizing, maximizing, moving, or sizing a window; before completing

   a system command; before removing a mouse or keyboard event; before setting

   input focus; and before synchronizing the system message queue.

  WH_DEBUG -A debugging hook called before any other filter installed by the

   SetWindowsHookEx()  function is called.

  WH_GETMESSAGE   - A message hook called whenever the  GetMessage()  function

   has retrieved a message from an application queue.

  WH_HARDWARE     - A nonstandard hardware message hook called whenever the

   application calls the  GetMessage()  or  PeekMessage()  function and there is

   a hardware event (other than a mouse or keyboard event) to process.

  WH_JOURNALRECORD      - A journaling record hook called when the system removes

   messages from the system message queue.

  WH_JOURNALPLAYBACK    - A journaling playback hook used to insert mouse and

   keyboard messages into the system message queue.

  WH_KEYBOARD     - A keyboard hook called whenever the application calls the

   GetMessage()  or  PeekMessage()  function and there is a  WM_KEYUP  or

   WM_KEYDOWN  keyboard message to process.

  WH_MOUSE - A mouse message hook called whenever the application calls the

   GetMessage()  or  PeekMessage()  function and there is a mouse message to

   process.

  WH_MSGFILTER    - An application message hook called after a dialog box, message

   box, or menu has retrieved a message, but before the message isprocessed.

  WH_SHELL - A shell application hook called when notification messages from

   the system have been made.

  WH_SYSMSGFILTER       - A system wide message hook called after a dialog box, message

   box, or menu has retrieved a message, but before the message is processed.

 

Note: Debugging Windows hooks can be very difficult. The documentation has much

to be desired, so before you make the jump, always consult the  Microsoft Knowledge

Base  for any additional information regarding the hook you are designing for. If

your hook hangs the system, pressing  CTRL+ESC  or  CTRL+AlT+DEL  should unhook

any system wide hooks that are in effect.

 

 

Data storage in dynamic link libraries

 

Under 16 bit Windows, a dynamic link library is only loaded once no matter how

many applications request the library to be loaded, generally contains a single

data segment, and all global variables in the dynamic link library exist across

all applications that load the dynamic link library.  If any process causes

corruption in the data segment of the dynamic link library, other applications

using the dynamic link library can be affected. Many argue that sharing data

between applications through a 16 bit dynamic link library is considered a very

bad practice.

 

Under  Windows 95 , the code for a dynamic link library is only loaded once no

matter how many applications request the library to be loaded, and the link to a

running application gets its own data storage area.  This provides some additional

crash protection to other applications, since any corrupted global variables in a

dynamic link library caused by one application will not adversely affect other

applications using that dynamic link library.

 

Under  Windows NT , a separate copy of both the dynamic link library's data and

code is linked to the calling application.  If we think about how the DLL is loaded,

we can still realize a memory saving when we talk about physical memory usage.

Each process does indeed gets its own copy of the DLL and the DLL data.  However,

it obtains this through a memory mapping of the DLL. That is, the DLL code is

mapped to each processes address space. In physical memory (as seen by the system)

the DLL is loaded only once.

 

 

Instanced addresses and thunking

 

As already mentioned, 16-bit dynamic link libraries have only one data segment.

When you call a function in a dynamic link library, the data segment must be

switched from your application's data segment to that of the dynamic link library's

data segment, and back again after the function returns. If the dynamically linked

function happens to make a callback to a function in your application, the data

segment must be switched back to your application's data segment during the callback,

and back again to the dynamic link library's data segment when your function returns.

 

When making a call to a dynamically linked function, the fixup code to switch the

data segment is transparent. In the case of a callback, additional magic is needed

by your application. The magic is made possible by using the Windows API function

MakeProcInstance()  to receive an " instance thunk " to your callback

procedure. This " instance thunk " is the glue that holds your callback

function and your data segment together during the callback. The procedure address

passed to the  MakeProcInstance()  function needs to be marked with both the " far "

and " exported " attributes. After the dynamic link library is through

using your callback function, and returns, you should always call the Windows API

FreeProcInstance()  function to free the instance thunk.

 

Using the  MakeProcInstance()  function is not necessary in 32 bit applications,

or any dynamic link library (16 or 32 bit). It is, however, safe to use under these

conditions, so any code you have that uses these functions can be safely ported

to dynamic link libraries and 32 bit versions of Windows.

 

 

The example:

 

We will now present an example of using Windows API functions by creating an

application that serves the useful function of hooking into the Windows messaging

system, and recording any keyboard and mouse input to be used for later playback.

We will call our macro recording application "  Hookit!  ". Our " Hookit! "

application is a great starting place for a full featured Windows macro recorder,

reminiscent of the early days of DOS and my favorite " Sidekick's Sidekick ",

Borland's highly successful TSR program " SuperKey "! It's worth noting

that unlike 16 bit Windows, neither  Windows 95  or  Windows NT  shipped with a

macro recording feature.

 

Since " Hookit! " will use system wide Windows hook functions for

JournalRecord  and  JournalPlayback , we will also create a Windows dynamic link

library along the way! Both the application and the dynamic link library will

perform callbacks.

 

Pascal  was originally designed to be a teaching language, thus the code example

presented was written in  Pascal , and can easily be ported to other languages such

as " C ". Note that the code cannot be ported to  Visual Basic,  since,

as of this writing,  Visual Basic  does not support creating dynamic link libraries

or callback functions.

 

The code presented may also be directly ported between 16 and 32 bit compilers,

and will successfully compile with Borland's  Turbo Pascal for Windows 1.5, Borland

Pascal for Windows 7.0 / 7.01, Delphi 1.0 / 1.02, and Delphi 2.0 .  To make it easy

to port to other languages, no Pascal or  Delphi  specific features are used. The

code also serves as a model for creating a " traditional " Windows program

in  Delphi , and utilizing a dialog box template for the main window of a program.

 

Although " Hookit! " uses features designed to run on Windows 3.1 or above,

the example code can be adapted to run on earlier versions of Windows ( 2.x and 3.0 ).

 

 

The Journal Hooks: JournalRecord and JournalPlayback

 

The Journal hook functions provide a easy way to record keyboard and mouse events

on a system-wide basis, and play the events back at some later date.

 

You can install a  JournalRecord  or  JournalPlayback  hook callback function by

calling the Windows API function  SetWindowsHookEx() , and passing the address of

your hook callback function. An instanced address is not needed, as both the

JournalRecord  and  JournalPlayback  callback functions are system wide hooks,

and must reside in a dynamic link library. Calling  SetWindowHookEx()  will

return a 32 bit handle to your hook callback function for you to identify yourself

to other hook functions already in the " Hook Chain ", and to remove

your hook from the chain when you are done recording.

 

When you call  SetWindowsHookEx()  with the address of your  JournalRecord  callback

function, Windows will return immediately, and the recording begins. Your  JournalRecord

callback function will get called with a code indicating the following conditions:

 

  There is a keyboard

or mouse event to record.

  The system is entering

a modal state.

  The system leaving

a modal state.

  The system wants you

to call the next hook in the hook chain.

 

If there is a keyboard or mouse event, the code will equal " HC_ACTION ",

and you are free to record the event. A pointer to an  EVENTMSG  is passed to you

in the lParam parameter of your  JournalRecord  callback function. The system time

that the event was originally fired is contained in time parameter of the  EVENTMSG

structure.  For playback purposes, you will need to make a copy of the  EVENTMSG

and change the time in the copy to reflect the net time into the recording, since

you will need to synchronize the playback of the message to the system time at

playback. This is done by getting the system time when you start the recording,

and subtracting it from the message time.

 

If the system enters a modal state, the code will equal " HC_SYSMODALON ",

indicating something bad has happened to the system, and you should temporarily

stop recording, and call the next message hook in the " Hook Chain ",

so hooks further down the chain will know what is going on. When the system

returns from a modal state, the code will equal " HC_SYSMODALOFF" ,

and you may resume recording.

 

Finally, if the code is less than zero, the system is asking you to call the next

hook in the chain, and you should do so without further processing. When you are

through recording, you can simply call the Windows API function

UnHookWindowsHookEx()  passing back the 32 bit handle given to you when you

originally called the  SetWindowsHookEx()  function, and Windows will remove your

hook callback function from the " Hook Chain ".

 

When you are ready to playback your recording, you will call  SetWindowsHookEx()

again, passing the address of your  JournalPlayback  callback function.  Windows

will return immediately, and the playback begins. During playback, normal mouse

and keyboard input is automatically disabled by the system.

 

Your JournalPlayback callback function will get called with a code indicating one

the following conditions:

 

  HC_SKIP   - You should retrieve the next message. If there are no more messages

   to play, then you may safely call the Windows API function  UnHookWindowsHookEx() ,

   passing the handle to your hook function to end the playback.

  HC_GETNEXT      - You should play the current message.

  HC_SYSMODALON   - The system is entering a modal state. This indicates something

   bad has happened. You should call the next hook in the hook chain, so other hooks

   will know something is up.

  HC_SYSMODALOFF - The system leaving a modal state, and Windows has unhooked

   your JournalPlayback callback procedure right out from under you. You are done.

   As your last act, you should call the next hook in the hook chain, so other

   hooks will know they are hosed as well.

  Code < 0 - The system wants you to call the next hook in the hook chain

   without further processing.

 

You should go ahead and retrieve the first message before you call the SetWindowsHookEx()

 function, since the system will ask you to play the first message before requesting

 the next message. You will also need to get the system time, since you will need

 to " fix up " the playback time of each of your recorded messages to synchronize

 with the system time at playback.

 

Windows may ask you to play the same message more than once. The first time Windows

asks you to play the current message, your  JournalPlayback  callback function

should return the difference between the current time and the time the message is

scheduled to play.

 

If the difference between the current time and the time the message is scheduled

to play is negative, your  JournalPlayback callback function should return zero.

The  JournalPlayback  callback function must also return zero if the same message

is requested to be played more than once.

 

 

How HOOKIT! works

 

Our application ( HOOKIT.EXE ) will contain four buttons:

 

 Start Recording

 Stop Recording

 Playback

 Done

 

and one callback function:

 

 PlaybackFinished()

 

Our dynamic link library ( HOOKLIB.DLL ) will contain three functions that our

calling application will use:

 

 StartRecording()

 StopRecording()

 Playback()

 

and two hook functions that Windows will use:

 

 JournalRecordProc()

 JournalPlaybackProc()

 

 

HOOKIT! application logic:

 

Allow the program to start only if the version of Windows is equal or greater

than Window's 3.1.

 

We will need to supply a callback function to be called whenever a macro's playback

has finished, since the  Playback()  function will return immediately, and our

application will continue to execute during playback.  We will need to call

MakeProcInstance()  to get the instanced address of our callback function

PlaybackFinished()  to pass to the  Playback()  function. Since we cannot call

FreeProcInstance()  in the middle of the callback, we must declare a global

variable to hold the instanced address of  PlaybackFinished()  on program startup,

and free it on exit from the program.

 

 

Create a main window from a Dialog Box template.

 

Upon creation of our main window, we will enable the " Start Recording " and " Done "

button. We will disable the  "Stop Recording " and " Playback " button,

since we have no recording to stop or playback.

 

When the " Done " button is selected we will free the instanced address

of our callback function  PlaybackFinished()  and exit the program.

 

When the " Start Recording " button is selected, we will disable the "

Start Recording " and " Done " button, since we don't want to allow

more than one recording at a time, and we don't want to allow the user to quit in

the middle of recording.

 

We will enable the " Stop Recording " button and call our  StartRecording()  function.

If the  StartRecoding()  function returns an error, we will announce the error to

the user, and reset the buttons to their default state before the " Start

Recording " button was pressed.

 

When the " End Recoding " button is pressed, We will call the  StopRecording()

function passing it the filename to store the macro in. Then we will enable both the " Done "

and " StartRecording " buttons, since we can now allow the user to quit,

and we want the user to have the option to record or rerecord the session.  We

will enable " Playback " button only if anything has successfully been

recorded.

 

When the " Playback " button is selected, we will disable all of our buttons,

and call the  Playback()  function, passing it the filename of the macro to play, the

instanced address of our callback function  PlaybackFinished() , and a handle to

our main window to be passed back to us as application defined data. When the

macro playback is done, our hook function will callback to our program's

PlaybackFinished()  function, letting us know it has finished, and passing us back

the handle to our main window as application data. We must do this since the

Playback()  function will return immediately, causing our program to continue to

run during the macro's playback.

 

This will allow us to know when it safe to enable our program's buttons again.

If the  Playback()  function returns an error, we will reset the buttons to their

default state before the " Playback " button was pressed.

 

When our callback function  PlaybackFininshed()  is called, we can enable the

" Start Recording ", " Playback " and " Done " buttons.

 

 

HOOKLIB dynamic link library logic:

 

If an error occurs during the call to  StartRecord() , or, we are already recording

or playing, we will return zero without further processing.

 

During the recording process, we will save keyboard and mouse events to an array.

For the sake of simplicity, we will limit the number of recorded events to what

will fit in a 64k memory block.

 

When  StopRecording()  is called, if any events have been recorded, we will write

the recorded events to the disk for later playback. We will then unhook our

JournalRecordProc()  from the hook chain. We will return an error code of -1 if

nothing is currently recording or -2 if there was trouble unhooking from the " Hook Chain ".

Otherwise we will return the number of messages recorded.

 

When the  Playback()  function is called, we will start the playback. If an error

occurs or their is nothing to playback, we will return zero without further

processing.

 

When the playback is finished, we will callback to the application announcing we

are done playing back the macro.

 

Since the  SetWindowsHookEx()  function does not allow us an appdata parameter

for application defined data, we must declare several global variables for our

hook callback functions, and avoid letting more than one application invoke

either the  StartRecord()  and  Playback()  functions at any given time under

Windows 3.1.

 

We will define a global pointer called " PMsgBuff  "that will point to

an array of  EventMsg  structures to record to and playback from.  Upon library

startup, we will initialize this pointer to nil.  Only when we are recording or

playing a macro will this pointer actually point to a memory block, otherwise it

will be nil. This will give us a way to determine whether or not we are in the

process of recording or playing a macro.

 

We will also need to define global variables for:

 

" TheHook "- A 32 bit handle to our hook proc.

" StartTime "- The starting time of the recording or playback.

" MsgCount "- The total number of messages recorded.

" CurrentMsg "- The current message playing.

" ReportDelayTime "- If we should report a delay time.

" SysModalOn "- If the system is currently in a " modal " state.

" cbPlaybackFinishedProc "- The instanced address of the application's

 PlaybackFinished() callback function.

" cbAppData "- The user defined application data parameter passed to our

 Playback()  function.

 

 

Got-Ya's!

 

JournalRecordProc()  is incorrectly documented as receiving a  MSG  structure.

JournalRecordProc()  actually receives the same  EVENTMSG  structure that is

documented by  JournalPlaybackProc() .

 

The  JournalRecordProc()  and  JournalPlaybackProc()  hook procedures do not

provide a user defined lpData parameter, so you must use global variables in

your dynamic link library.

 

Mouse events recorded with  JournalRecord  may not play back correctly if the

display resolution has changed, or a window's position has changed.

 

Keyboard events recorded with  JournalRecord  on a Windows system other than Windows

NT  will not play back correctly under  Windows NT . Under Windows 3.1, the keyboard

repeat count is stored in the ParamH parameter of the  EVENTMSG  structure. Under

Windows NT , this parameter is always 1.  The size of the  EVENTMSG  structure

also changes under Win32.

 

Your  JournalPlaybackProc  may be called many times with the  HC_GETNEXT message.

The system expects you to continue providing the same event to play until you

receive a  HC_SKIP  message.

 

Be sure to return a non-zero delay time only once for each unique event you process

in your JournalPlaybackProc , else  Windows NT  may hang due to timing differences.

If your  JournalPlaybackProc()  gets called with a code of  HC_GETNEXT  more than

once for the same event, return zero from your  JournalPlaybackProc .

 

Interactive debugging of a journal hook cannot be done on a single machine. A

Windows NT  or  Win32  application has an advantage that the system will send a

WM_CANCELJOURNAL  message to all applications when the system pulls the hook out

from under the application when the user presses  CTRL+ESC  or  CTRL+ALT+DEL.

" HOOKIT! " handles this event gracefully.

 

The  SetWindowsHookEx()  function will return immediately. This can be a problem

if your program needs to know when the playback has finished.

 

Since you will most likely use the Windows API function  GetTickCount()  for

calculating messaging times, you always run the risk that the system time will

wrap if windows has not been restarted in the last 49 days.  If you account for

the fact that not all compilers support unsigned 32 bit integers, the system time

will appear to go negative sometime into the 24th day.

 

The " handle " passed back from  SetWindowsHookEx()  is 32 bits wide,

even in 16 bit environments.

 

You may need to set your compiler's link buffer to compile to disk when building

dynamic link libraries. If the file image is only created in memory, it will not

be available to the program that uses it.

 

JournalRecordProc()  does not get along well with the new  Windows 95  " StartKey "

contained on some new keyboards.

 

 

Source code for HOOKLIB.DLL

 

Note: Save the source as  HOOKLIB.PAS  for Pascal or HOOKLIB.DPR for Delphi .

 

{$C FIXED PRELOAD PERMANENT}

 

library HOOKLIB;

 

{$IFDEF Win32}

 

uses

  Windows;

 

type

  TwMsg = Longint;

  TwParam = Longint;

  TlParam = Longint;

 

{$ELSE}

 

uses

 {$IFDEF VER15}

  WinTypes, WinProcs, Win31;

 {$ELSE}

 {$IFDEF VER70}

  WinTypes, WinProcs, Win31;

 {$ELSE}

  WinTypes, WinProcs;

 {$ENDIF}

 {$ENDIF}

 

type

  TwMsg = Word;

  TwParam = Word;

  TlParam = Longint;

 

{$ENDIF}

 

const

  MAXMSG = 6500;

 

type

  PEventMsg = ^TEventMsg;

  TMsgBuff = Array[0..MAXMSG]

of TEventMsg;

  TcbPlaybackFinishedProc

= Procedure(AppData: Longint)

 

 {$IFDEF Win32} stdcall; {$ELSE} ; {$ENDIF}

 

var

  PMsgBuff: ^TMsgBuff;

  TheHook: HHook;

  StartTime: Longint;

  MsgCount: Longint;

  CurrentMsg: Longint;

  ReportDelayTime: Bool;

  SysModalOn: Bool;

  cbPlaybackFinishedProc:

TcbPlaybackFinishedProc;

  cbAppData: Longint;

 

 

{ ************************* }

{ function JournalRecordProc(Code: Integer; }

{  wParam: TwParam;                         }

{  lParam: TlParam): Longint;               }

{ Parameters: action to perform and message data. }

{ Returns: zero unless code < 0, in which case return the result }

{          from CallNextHookEx(). }

{ ************************* }

function JournalRecordProc(Code:

Integer;

 

 wParam: TwParam;

 

 lParam: TlParam): Longint

 

{$IFDEF Win32} stdcall; {$ELSE} ; export; {$ENDIF}

begin

  JournalRecordProc := 0;

  case Code of

 

    HC_ACTION: begin

      if SysModalOn then exit;

      if MsgCount > MAXMSG

then exit;

     {record the message}

      PMsgBuff^[MsgCount]

:= PEventMsg(lParam)^;

     {set the delta time of

the message}

      Dec(PMsgBuff^[MsgCount].Time,StartTime);

      Inc(MsgCount);

      exit;

    end;

 

    HC_SYSMODALON: begin

      SysModalOn := True;

      CallNextHookEx(TheHook,

Code, wParam, lParam);

      exit;

    end;

 

    HC_SYSMODALOFF: begin

      SysModalOn := False;

      CallNextHookEx(TheHook,

Code, wParam, lParam);

      exit;

    end;

 

  end;

  if code < 0 then

    JournalRecordProc := CallNextHookEx(TheHook,

              Code,

              wParam,

              lParam);

end;

 

 

{ ************************* }

{ function StartRecording: Integer;}

{ Parameters: none. }

{ Returns: non zero if successful. }

{ ************************* }

function StartRecording: Integer

                      {$IFDEF

Win32} stdcall; {$ELSE} ; export; {$ENDIF}

begin

  StartRecording := 0;

  if pMsgBuff <> nil

then exit;

  GetMem(PMsgBuff, Sizeof(TMsgBuff));

  if PMsgBuff = nil then exit;

  SysModalOn := False;

  MsgCount := 0;

  StartTime := GetTickCount;

  TheHook := SetWindowsHookEx(WH_JOURNALRECORD,

    JournalRecordProc,

    hInstance,

    0);

  if TheHook <> 0 then

begin

    StartRecording := 1;

    exit;

  end else begin

    FreeMem(PMsgBuff, Sizeof(TMsgBuff));

    PMsgBuff := nil;

  end;

end;

 

 

{ ************************* }

{ function StopRecording(lpFileName: PChar): Integer; }

{ Parameters: pointer to filename to save to. }

{ Returns: number of records written. }

{          -1 if not recording. }

{          -2 unable to unhook. }

{ ************************* }

function StopRecording(lpFileName:

PChar): Longint

                      {$IFDEF

Win32} stdcall; {$ELSE} ; export; {$ENDIF}

 

var TheFile: File;

begin

  if PMsgBuff = nil then begin

    StopRecording := -1;

    exit;

  end;

  if UnHookWindowsHookEx(TheHook)

= False then begin

    StopRecording := -2;

    exit;

  end;

  TheHook := 0;

  if MsgCount > 0 then

begin

    Assign(TheFile, lpFileName);

   {$I-}

    Rewrite(TheFile, Sizeof(TEventMsg));

   {$I+}

    if IOResult <> 0

then begin

      FreeMem(PMsgBuff, Sizeof(TMsgBuff));

      PMsgBuff := nil;

      StopRecording := 0;

      exit;

    end;

   {$I-}

    Blockwrite(TheFile, PMsgBuff^,

MsgCount);

   {$I+}

    if IOResult <> 0

then begin

      FreeMem(PMsgBuff, Sizeof(TMsgBuff));

      PMsgBuff := nil;

      StopRecording := 0;

     {$I-}

      Close(TheFile);

     {$I+}

      if IOResult <>

0 then exit;

      exit;

    end;

   {$I-}

    Close(TheFile);

   {$I+}

    if IOResult <> 0

then begin

      FreeMem(PMsgBuff, Sizeof(TMsgBuff));

      PMsgBuff := nil;

      StopRecording := 0;

      exit;

    end;

  end;

  FreeMem(PMsgBuff, Sizeof(TMsgBuff));

  PMsgBuff := nil;

  StopRecording := MsgCount;

end;

 

 

{ ************************* }

{ function JournalPlaybackProc(Code: Integer; }

{  wParam: TwParam; }

{  lParam: TlParam): Longint; }

{ Parameters: action to perform and message data. }

{ Returns:  if Code < 0, returns the result from CallNextHookEx(), }

{            otherwise returns the requested time to wait to fire }

{            the next event or zero. }

{ ************************* }

function JournalPlaybackProc(Code:

Integer;

   wParam: TwParam;

   lParam: TlParam): Longint

  {$IFDEF Win32} stdcall; {$ELSE} ; export; {$ENDIF}

var

  TimeToFire: Longint;

begin

  JournalPlaybackProc := 0;

  case Code of

    HC_SKIP: begin

     {get the next message}

      Inc(CurrentMsg);

      ReportDelayTime := True;

     {are we finished?}

      if CurrentMsg >=

(MsgCount-1) then

        if TheHook <>

0 then

          if UnHookWindowsHookEx(TheHook)

= True then begin

            TheHook := 0;

            FreeMem(PMsgBuff,

Sizeof(TMsgBuff));

            PMsgBuff := nil;

           {callback to the

application announcing we are finished}

            cbPlaybackFinishedProc(cbAppData);

          end;

      exit;

    end;

 

    HC_GETNEXT: begin

     {play the current message}

      PEventMsg(lParam)^ :=

PMsgBuff^[CurrentMsg];

      PEventMsg(lParam)^.Time

:= StartTime + PMsgBuff^[CurrentMsg].Time;

     {if first time this message

has played - report the delay time}

      if ReportDelayTime then

begin

        ReportDelayTime :=

False;

        TimeToFire := PEventMsg(lParam)^.Time

- GetTickCount;

        if TimeToFire >

0 then JournalPlaybackProc := TimeToFire;

      end;

      exit;

    end;

 

    HC_SYSMODALON:begin

     {something is wrong}

      SysModalOn := True;

      CallNextHookEx(TheHook,

Code, wParam, lParam);

      exit;

    end;

 

    HC_SYSMODALOFF:begin

     {we have been hosed by

the system - our hook has been pulled!}

      SysModalOn := False;

      TheHook := 0;

      FreeMem(PMsgBuff, Sizeof(TMsgBuff));

      PMsgBuff := nil;

     {callback to the application

announcing we are finished}

      cbPlaybackFinishedProc(cbAppData);

      CallNextHookEx(TheHook,

Code, wParam, lParam);

      exit;

    end;

 

  end;

  If code < 0  then

    JournalPlaybackProc :=

CallNextHookEx(TheHook,

                Code,

                wParam,

                lParam);

end;

 

{ ************************* }

{ function Playback(lpFileName: PChar; }

{                    EndPlayProc: TcbPlaybackFinishedProc; }

{                    AppData: Longint): Integer; }

{ Parameters: pointer to filename to play. }

{             application's EndPlay callback function. }

{             application's defined data. }

{ Returns: non zero if successful. }

{ ************************* }

function Playback(lpFileName:

PChar;

                   EndPlayProc:

TcbPlaybackFinishedProc;

                   AppData:

Longint): Integer

                  {$IFDEF

Win32} stdcall; {$ELSE} ; export; {$ENDIF}

var

  TheFile: File;

begin

  Playback := 0;

  If PMsgBuff <> nil

then exit;

  GetMem(PMsgBuff, Sizeof(TMsgBuff));

  If PMsgBuff = nil then exit;

  Assign(TheFile, lpFileName);

 {$I-}

  Reset(TheFile, Sizeof(TEventMsg));

 {$I+}

  if IOResult <> 0 then

begin

    FreeMem(PMsgBuff, Sizeof(TMsgBuff));

    PMsgBuff := nil;

    exit;

  end;

 {$I-}

  MsgCount := FileSize(TheFile);

 {$I+}

  if IOResult <> 0 then

begin

    FreeMem(PMsgBuff, Sizeof(TMsgBuff));

    PMsgBuff := nil;

   {$I-}

    Close(TheFile);

   {$I+}

    if IOResult <> 0

then exit;

    exit;

  end;

  if MsgCount = 0 then begin

    FreeMem(PMsgBuff, Sizeof(TMsgBuff));

    PMsgBuff := nil;

   {$I-}

    Close(TheFile);

   {$I+}

    if IOResult <> 0

then exit;

    exit;

  end;

 {$I-}

  Blockread(TheFile, PMsgBuff^,

MsgCount);

 {$I+}

  if IOResult <> 0 then

begin

    FreeMem(PMsgBuff, Sizeof(TMsgBuff));

    PMsgBuff := nil;

   {$I-}

    Close(TheFile);

   {$I+}

    if IOResult <> 0

then exit;

    exit;

  end;

 {$I-}

  Close(TheFile);

 {$I+}

  if IOResult <> 0 then

begin

    FreeMem(PMsgBuff, Sizeof(TMsgBuff));

    PMsgBuff := nil;

    exit;

  end;

  CurrentMsg := 0;

  ReportDelayTime := True;

  SysModalOn := False;

 {save the application's callback

procedure}

  cbPlaybackFinishedProc :=

EndPlayProc;

 {save the application's defined

data parameter}

  cbAppData := AppData;

  StartTime := GetTickCount;

  TheHook := SetWindowsHookEx(WH_JOURNALPLAYBACK,

    JournalPlayBackProc,

    hInstance,

    0);

  if TheHook = 0 then begin

    FreeMem(PMsgBuff, Sizeof(TMsgBuff));

    PMsgBuff := nil;

    exit;

  end;

  Playback := 1;

end;

 

exports

  JournalRecordProc index

1 name 'JOURNALRECORDPROC' resident,

  StartRecording index 2 name

'STARTRECORDING' resident,

  StopRecording index 3 name

'STOPRECORDING' resident,

  JournalPlayBackProc index

4 name 'JOURNALPLAYBACKPROC' resident,

  Playback index 5 name 'PLAYBACK'

resident;

 

begin

  PMsgBuff := nil;

end.

 

Resource statements to build:

HOOKIT16.RES and HOOKIT32.RES

 

Note: Save the source as  HOOKIT16.RC  for 16 bit environments

or  HOOKIT32.RC  for 32 bit environments.  Use the  Borland Resource

Command Line Compiler BRCC.EXE  to compile a 16 bit resource file and

BRCC32.EXE  to compile a 32 bit resource file.

 

 HOOKIT DIALOG 15, 15, 63, 60

STYLE WS_OVERLAPPED | WS_VISIBLE | WS_CAPTION | WS_MINIMIZEBOX

CLASS "HOOKITDIALOGCLASS"

CAPTION "HookIt!"

BEGIN

  CONTROL "Start Recording",

101, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE

| WS_GROUP | WS_TABSTOP, 0, 0, 63, 15

  CONTROL "Stop Recording",

102, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE

| WS_GROUP | WS_TABSTOP, 0, 15, 63, 15

  CONTROL "PlayBack",

103, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE

| WS_GROUP | WS_TABSTOP, 0, 30, 63, 15

  CONTROL "Done!",

1, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE |

WS_GROUP | WS_TABSTOP, 0, 45, 63, 15

END

 

Source code for HOOKIT.EXE

 

Note: Save the source as  HOOKIT.PAS  for  Pascal  or  HOOKIT.DPR  for  Delphi .

 

 program HookIt;

 

{$D HookIt!}

 

{$C MOVEABLE PRELOAD PERMANENT}

 

{$IFDEF Win32}

 

{$R HOOKIT32.RES}

 

uses

  Windows, Messages;

 

type

  TwMsg = Longint;

  TwParam = Longint;

  TlParam = Longint;

 

{$ELSE}

 

{$R HOOKIT16.RES}

 

uses

 {$IFDEF VER15}

  WinTypes, WinProcs, Win31;

 {$ELSE}

 {$IFDEF VER70}

  WinTypes, WinProcs, Win31;

 {$ELSE}

  WinTypes, WinProcs, Messages;

 {$ENDIF}

 {$ENDIF}

 

type

  TwMsg = Word;

  TwParam = Word;

  TlParam = Longint;

 

{$ENDIF}

 

type

  TWinVersion = record

   WinMajor : Byte;

   WinMinor : Byte;

   DosMajor : Byte;

   DosMinor : Byte;

  end;

 

  TcbPlaybackFinishedProc = Procedure(AppData: Longint)

                          {$IFDEF Win32} stdcall; {$ELSE} ; {$ENDIF}

 

const

  APPNAME = 'HookIt!';

  CLASSNAME ='HOOKITDIALOGCLASS';

  ID_BTN_START_RECORDING =

101;

  ID_BTN_STOP_RECORDING =

102;

  ID_BTN_PLAYBACK = 103;

  ID_BTN_DONE = IDOK;

  FILENAME = 'HOOKIT.MAC';

 

var

  PlaybackFinishedProc :TcbPlaybackFinishedProc;

 

function StartRecording: Integer

                       {$IFDEF

Win32} stdcall; {$ELSE} ; far; {$ENDIF}

                        external

'HOOKLIB' index 2;

 

 

function StopRecording(lpFileName:

PChar): Integer

                      {$IFDEF

Win32} stdcall; {$ELSE} ; far; {$ENDIF}

                       external

'HOOKLIB' index 3;

 

 

function Playback(lpFileName:

PChar;

                  EndPlayProc:

TcbPlaybackFinishedProc;

                  AppData:

Longint): Integer

                 {$IFDEF Win32}

stdcall; {$ELSE} ; far; {$ENDIF}

                  external

'HOOKLIB' index 5;

 

 

procedure PlaybackFinished(AppData:

Longint)

 

{$IFDEF Win32} stdcall; {$ELSE} ; export; {$ENDIF}

 

begin

  EnableWindow(GetDlgItem(hWnd(AppData),

ID_BTN_START_RECORDING), True);

  EnableWindow(GetDlgItem(hWnd(AppData),

ID_BTN_STOP_RECORDING), False);

  EnableWindow(GetDlgItem(hWnd(AppData),

ID_BTN_PLAYBACK), True);

  EnableWindow(GetDlgItem(hWnd(AppData),

ID_BTN_DONE), True);

  SetFocus(GetDlgItem(hWnd(AppData),

ID_BTN_PLAYBACK));

end;

 

 

function HookitDialogProc(Dialog:

HWnd;

 

Msg: TwMsg;

 

WParam: TwParam;

 

LParam: TlParam): Longbool

                         {$IFDEF

Win32} stdcall; {$ELSE} ; export; {$ENDIF}

begin

  HookitDialogProc := True;

 {do any default class handling

here for HookItDlg}

  HookitDialogProc := Longbool(DefDlgProc(Dialog,

Msg, WParam, LParam));

end;

 

 

function MainDlgProc(Dialog: HWnd;

                     Msg:TwMsg;

                     WParam:TwParam;

                     LParam:TlParam): Bool

                    {$IFDEF Win32} stdcall; {$ELSE} ; export; {$ENDIF}

begin

  MainDlgProc := True;

  case Msg Of

 

    WM_INITDIALOG: begin

      EnableWindow(GetDlgItem(Dialog,

ID_BTN_START_RECORDING), True);

      EnableWindow(GetDlgItem(Dialog,

ID_BTN_STOP_RECORDING), False);

      EnableWindow(GetDlgItem(Dialog,

ID_BTN_PLAYBACK), False);

      EnableWindow(GetDlgItem(Dialog,

ID_BTN_DONE), True);

      exit;

    end;

 

    WM_COMMAND: begin

 

      case WParam of

 

        ID_BTN_START_RECORDING:

begin

            EnableWindow(GetDlgItem(Dialog,

ID_BTN_STOP_RECORDING), True);

            SetFocus(GetDlgItem(Dialog,

ID_BTN_STOP_RECORDING));

            EnableWindow(GetDlgItem(Dialog,

ID_BTN_START_RECORDING), False);

            EnableWindow(GetDlgItem(Dialog,

ID_BTN_PLAYBACK), False);

            EnableWindow(GetDlgItem(Dialog,

ID_BTN_DONE), False);

            if StartRecording

= 0 then begin

              EnableWindow(GetDlgItem(Dialog,

ID_BTN_START_RECORDING), True);

              SetFocus(GetDlgItem(Dialog,

ID_BTN_START_RECORDING));

              EnableWindow(GetDlgItem(Dialog,

ID_BTN_STOP_RECORDING), False);

              EnableWindow(GetDlgItem(Dialog,

ID_BTN_PLAYBACK), False);

              EnableWindow(GetDlgItem(Dialog,

ID_BTN_DONE), True);

              Messagebox(Dialog,

                         'Unable

to start recording!',

                         APPNAME,

                         MB_OK);

            end;

          exit;

        end;

 

        ID_BTN_STOP_RECORDING:

begin

          if StopRecording(FILENAME)

> 0 then begin

            EnableWindow(GetDlgItem(Dialog,

ID_BTN_START_RECORDING), True);

            EnableWindow(GetDlgItem(Dialog,

ID_BTN_PLAYBACK), True);

            SetFocus(GetDlgItem(Dialog,

ID_BTN_PLAYBACK));

          end else begin

            EnableWindow(GetDlgItem(Dialog,

ID_BTN_START_RECORDING), True);

            SetFocus(GetDlgItem(Dialog,

ID_BTN_START_RECORDING));

            EnableWindow(GetDlgItem(Dialog,

ID_BTN_PLAYBACK), False);

          end;

          EnableWindow(GetDlgItem(Dialog,

ID_BTN_STOP_RECORDING), False);

          EnableWindow(GetDlgItem(Dialog,

ID_BTN_DONE), True);

          exit;

        end;

 

        ID_BTN_PLAYBACK: begin

          EnableWindow(GetDlgItem(Dialog,

ID_BTN_START_RECORDING), False);

          EnableWindow(GetDlgItem(Dialog,

ID_BTN_STOP_RECORDING), False);

          EnableWindow(GetDlgItem(Dialog,

ID_BTN_PLAYBACK), False);

          EnableWindow(GetDlgItem(Dialog,

ID_BTN_DONE), False);

          if PlayBack(FILENAME,

PlaybackFinishedProc, Dialog) = 0 then begin

            EnableWindow(GetDlgItem(Dialog,

ID_BTN_START_RECORDING), True);

            EnableWindow(GetDlgItem(Dialog,

ID_BTN_STOP_RECORDING), False);

            EnableWindow(GetDlgItem(Dialog,

ID_BTN_PLAYBACK), True);

            EnableWindow(GetDlgItem(Dialog,

ID_BTN_DONE), True);

            SetFocus(GetDlgItem(hWnd(Dialog),

ID_BTN_PLAYBACK));

          end;

          exit;

        end;

 

        ID_BTN_DONE: begin

          EndDialog(Dialog,

ID_BTN_DONE);

          exit;

        end;

 

      end; {wParam}

 

    end; {WM_COMMAND}

 

    WM_CLOSE: begin

      FreeProcInstance(@PlaybackFinishedProc);

      EndDialog(Dialog, IDOK);

      exit;

    end;

 

  end;

  MainDlgProc := False;

end;

 

 

procedure Init;

var

  WindowClass: TWndClass;

  WinVer: TWinVersion;

begin

  Longint(WinVer) := GetVersion;

  if ((WinVer.WinMajor <

3) OR

      ((WinVer.WinMajor =

3) AND

       (WinVer.WinMinor <

10)) ) then begin

    Messagebox(0,

               'Microsoft

Windows 3.10 or greater required!',

               APPNAME,

               MB_OK);

    halt;

  end;

  @PlaybackFinishedProc :=

MakeProcInstance(@PlaybackFinished, hInstance);

  If @PlaybackFinishedProc

= nil then begin

    Messagebox(0,

               'Cannot create

instance thunk!',

               APPNAME,

               MB_OK);

    halt;

  end;

 

  if FindWindow(CLASSNAME,

APPNAME) <> 0 then begin

    Messagebox(0,

               'Multiple Sessions

not allowed',

               APPNAME,

               MB_OK);

    halt;

  end else begin

    WindowClass.Style

    := CS_BYTEALIGNWINDOW;

    WindowClass.lpfnWndProc

  := @HookItDialogProc;

    WindowClass.cbClsExtra

   := 0;

    WindowClass.cbWndExtra

   := DLGWINDOWEXTRA;

    WindowClass.hInstance

    := hInstance;

    WindowClass.hIcon

    := LoadIcon(0, IDI_APPLICATION);

    WindowClass.hCursor

    := LoadCursor(0, IDC_ARROW);

    WindowClass.hbrBackground

:= GetStockObject(WHITE_BRUSH);

    WindowClass.lpszMenuName

 := nil;

    WindowClass.lpszClassName

:= CLASSNAME;

    if not Bool(RegisterClass(WindowClass))

then begin

      Messagebox(0,

                 'RegisterClass

Failed!',

                 APPNAME,

                 MB_OK);

      halt;

    end;

  end;

end;

 

procedure MyWinMain;

var

  WindowProc:TFarProc;

begin

  WindowProc:=MakeProcInstance(@MainDlgProc,

hInstance);

  DialogBox(hInstance, 'HOOKIT',

0, WindowProc);

  FreeProcInstance(WindowProc);

end;

 

 

{WinMain}

begin

  Init;

  MyWinMain;

end.

 

 

Conclusion:

 

While writing Windows applications gets easier as development tools get more

sophisticated, there will be times when you must "bite the bullet" and a interface

to new functions that are not handled by your current tools.

 

Remember... before you explore unchartered paths, check available resources for

documentation that may help to make your journey a pleasant and rewarding

experience.

 

 

 

//bunu http://www.delphi.about.com dan kopyaladim cok uzun o yuden ceviremiyecegim ama

//ingilizce bilenler icin yararli bir kaynak

 

Delphi - .....................................

Bu web sitesi ücretsiz olarak Bedava-Sitem.com ile oluşturulmuştur. Siz de kendi web sitenizi kurmak ister misiniz?
Ücretsiz kaydol