2014. 2. 13. 16:21

델파이 API

■윈도우API
●System Modal 폼을 만들려면?
 윈도우 API 함수인 SetSysModalWindow를 사용하면 가능하다.
 다은 System Modal 창을 보여주는 간단한 예제이다.


procedure TMainForm1.Create(Application) do
begin
 SetSysModalWindow(Handle);
end;


●.RES 파일에서 비트맵을 불러 오려면?
 다음과 같이 선언한다.


implementation
{$R C:DelphiMydirMyRes.Res} <- .RES 파일이 있는 경로명과 파일명


 위와 같이 선언한 후에 사용시에는 다음과 같이 윈도우 API 함수를 이용한다.


Image1.Picture.Bitmap.Handle := LoadBitmap(HInstance, 'BITMAP1');


●Win95와 W3.X를 구별하는 법은?
 윈도우 API 함수인 GetVersion을 쓰면 가능하다.
 다음은 버튼을 누르면 윈도우의 버전을 보여준다.


procedure TForm1.Button1Click(Sender : TObject);
var
 x : Lonhint;
 y,z : integer;
begin
 x := GetVersion;
 y := integer(x and $ff);
 z := integer(x shr 8) and $ff);
 Edit1.Text := IntToStr(y);
 Edit2.Text := IntToStr(z);
end;


●마우스 커서를 보이지 않게 하려면?
 윈도우 API 함수인 ShowCursor에서 값을 False 로 준다.


●정의된 Message Handler에 다른 작업을 추가하려면?
 예를 들어, CM_DIALOGKEY Message가 발생되었을 때 원하는 작업을 추가하려고 한다면 Public Section에 다음과 같이 선언한다.


procedure CMDialogKey(var Message : TCMDialogKey);message DM_DIALOGKEY;


procedure 이름을 Message 이름에서 _(밑줄) 표시를 뺀다. Procedure 의 정의는 다음과 같다.


procedure TForm1.CMDialogKey(var Message : TCMDialogKey);
begin
 if CharCode = VK_TAB then begin
   {Process the Alt+Tab key here}
   result := 1;
   exit;
 end;
 inherited;
end;


Result를 1로 Setting하면 더 이상 실행시키지 않고 중단시키겠다는 뜻이고, inherited 문은 Parent Handler 로 제어를 보냄을 의미한다.
 모든 작업을 일일이 처리하지 않으려면 inherited 문을 사용하기 바란다.


●런타임시에 DLL을 Load하고 Free시키는 방법은?
 if H<32 then begin
   ShowMessage('No DLL');
   exit;
 end;
 DicProc := TDisProc(GetProcAddress(H, 'displayTable'));
 edit1.Text := DisProc;
 FreeLibrary(H);
end;


●비정상적으로 종료된 DLL 프로그램을 강제적으로 Unload하는 방법은?
 윈도우 API 함수인 GetModuleHandle 은 DLL의 Handle을 돌려주므로 ModuleHandle 이 0을 리턴할 때까지 Freelibrary를 Call한다.
 만약 DLL이 다른 DLL을 Load했다면 Child DLL을 먼저 Free 시킨다.


●DLL의 Data Segment를 Fixed에서 Movable로 바꾸는 방법은?
 DLL 외부에서 GlobalPageUnlock(DESG)를 부르면 된다. 이 함수는 DLL 소스에서 Pointer 등을 이용하지 않는다면 정상적으로 실행될 것이다.


●Title Bar가 없는 Form을 움직이게 하려면?
 폼 위에서 마우스 커서가 움직이면, 윈도우는 폼에 WM_NCHitTest 메시지를 보낸다. 이때 폼은 마우스가 폼의 어느 위치에 있는지를 메시지로 주게 된다. 마우스의 버튼을 누르는 것과 같은 Event가 발생하면 윈도우는 이 정보를 써서 특정 행동을 수행하게 되는 것이다.
 다음은 WM_NCHitTest 메시지가 특정한 값을 주는 예제 코드이다.


procedure TNoCapForm.WMNCHitTest(var Msg : TMessage);
begin
 if GetAsynKeyState(VK_LBUTTON) < 0 then
   Msg.Result := HTCAPTION
 else
   Msg.Result := HTCLIENT;
end;


●Resource를 동적으로 Load/Free하는 방법은?
 윈도우가 제공하는 LoadResource(), FreeResource() API 함수를 사용한다.


●Visual Basic의 doEvent 와 같은 기능을 사용하려면?
 다음과 같이 함수를 만들 수 잇다.


function doEvents : Boolean;
var
 msg : TMsg;
begin
 while PeekMessage(msg, 0, 0, 0, PM_REMOVE) do
 begin
   if msg.message = WM_QUIT then
   begin
    PostQuitMessage(msg.wParam);
    doEvents := true;
    exit;
   end
   else
   begin
    TranslateMessage(msg);
    DispatchMessage(msg);
   end;
 end;
 doEvents := false;
end;


●프로그램의 실행이 끝나기를 기다리는 법은?
 윈도우 함수는 핸들을 돌려주므로 이것을 이용한다.


procedure SomeProc;
var
 ProgramHandle : THandle;
begin
 ProgramHandle := WinExec('C:Program.exe', SW_SHOWNORMAL);


 {프로그램이 종료될 때까지 반복}
 while GetMoudleusage(ProgramHandle) <> 0 do Application.ProcessMessages;
end;


●프로그램 실행중에 잠시 멈추고 다른 프로세스를 실행하려면?
 다음과 같은 코드를 작성할 수 있다.


procedure TForm1.Delay(msecs : integer);
var
 FirstTickCount : longint;
begin
 FirstTickCount := GetTickCount;
 repeat
   {실행을 잠시 중단하고 다른 프로세스를 실행한다.}
   Application.ProcessMessages;
 until ((GetTickCount-FirstTickCount) >= LongInt(msecs));
end;


 참고로 Application.ProcessMessages는 메시지 큐에 쌓여 있는 메시지 중 하나를 처리하고 메시지가 큐에 없으면 False를 리턴한다.


●Control의 Handle 이나 ID를 얻는 방법은?
 Control Object의 Pointer를 알고 있다면 PointerToMyControl^.HWindow가 바로 윈도우 핸들이다.


 만약, Control 의 Handle을 알고 있다면 GetDlgCtrlID() API 함수는 ID를 돌려준다.


ControlID := GetDlgCtrlID(ControlHandle);


 만약 Control의 Pointer를 모르고 ID만 알고 있다면, GetDlgItem() API 함수는 Handle을 돌려준다.


ControlHandle := GetDlgItem(DialogHandle, COntrolID);


●프로그램이 실행된 디렉토리를 알 수 있는 방법은?
 다음의 함수는 Application 이라는 개체의 ExeName 속성으로부터 디렉토리 경로를 추출해낸다.


function GetExePath : String;
var
 LastBackSlashPos, Index : Integer;
begin
 Result := Application.ExeName;
 for Index := 1 to length(Result) do
   if REsult[Index] = '' then LastBackSlashPos := Index;


 {'' 기호가 붙지 않도록 하려면 LastBackSlashPos에서 1을 빼야 한다}
 Result[0] := chr(LastBackSlashPos - 1);
end;


●Directory를 만드는 방법은?
 MKDIR Procedure를 이용하면 된다.


MkDir('C:DelphiMyDir');


●MediaPlayer를 이용하지 않고 Sound를 발생할 수 있는 방법은?
 mmSystem에 있는 SndPlaySound Function을 이용하면 된다.


SndPlaySound('C:Windowsding.WAV', snd_Async);


●윈도우의 Message를 처리하는 방법은?
 다음 윈도우 메시지를 처리하는 Procedure를 참고하기 바란다.


procedure YieldToOthers;
var
 MSG : TMSG;
begin
 while PeekMessage(MSG, 0, 0, 0, PM_REMOVE) do begin
   if Msg.Message = WM_QUIT then exit;
   TranslateMessage(Msg);
   DispatchMessage(Msg);
 end;
end;


●윈도우의 Main Message Procedure를 만드는 방법은?
 다음 예제 Procedure를 참고하기 바란다.


procedure TForm1.ClientWndProc(var Message : TMessage);
begin
 with Message do
   case Msg of
    WM_MOUSEMOVE : Memo1.Lines.Add('Mouse Move');
    WM_LBUTTONDOWN : Memo1.Lines.Add('LeftButton down');
   else
    Result := CallWindowProc(FPrevClientProc, Handle, Msg, wParam, lParam);
   end;
end;


●다른 응용프로그램의 메뉴 기능을 실행하려면?
 다음 예제 Procedure를 참고하기 바란다.


CurrWnd := GetWindow(Application.Handle, gw_hwndfirst);
length := GetWindowText(Currwnd, tmpstr, 255);


if length > 0 then
begin
 if(pos('훈민정음‘, strpas(tmpstr)) > 0) and (strpas(pAttach^.filepath.tmpstr) <> nil) then
   CurrWnd := 0;
end;


tmpname := ExtractFilename(strpas(pAttach^.filepath));


while CurrWnd <> 0 do
begin
 length := GetWindowText(CurrWnd, tmpstr, 255);


 if (length > 0) and (pos('훈민정음‘, strpas(tmpstr) > 0) and (pos(tmpname,
                                                       StrPas(tmpstr)) > 0) then
   break;


 CurrWnd := GetWindow(CurrWnd, GW_HWNDNEXT);
 Application.ProcessMessages;
end;


Handle := CurrWnd;


if Handle <> 0 then
begin
 SendMessage(Handle, WM_COMMAND, 4005, 0);
 SendMessage(Handle, WM_SYSCOMMAND, SC_CLOSE, 0);
end;


●폼이 최소화되지 못하게 하려면?
 다음과 같이 WM_SYSCOMMAND 메시지를 처리하면 된다.


type
 TForm1 = class(TForm)
   public :
       procedure WMSysCommand(var Msg : TWMSysCommand);message
                                                       WM_SYSCOMMAND;
   end;


procedure TForm1.WMSysCommand(var Msg : TWMSysCommand);
begin
 {최소화/최대화 버튼을 누를 때 아무 작용을 하지 않게 한다}
 if (Msg.CmdType = SC_MINIMIZE) or (Msg.CmdType = SC_MAXMIZE) then
   Msg.CmdType := SC_RESTORE;
 DefaultHandler(Msg);
end;


●DPR 파일의 Application.Run이 실행되기 전에 Window 메시지를 가로채는 방법은?
 다음과 같이 새로운 Windows Message Procedure를 정의하고, 그것을 Main Windows Procedure 로 설정한다.
 다음 예제 Procedure를 참고하기 바란다.


program Project1;
uses
 Forms, messages, wintypes, winprocs,
 Unit1 in 'UNIT1.PAS';


{$R *.RES}


var
 OldWndProc : TFarProc;


function NewWndProc(hWndAppl : HWnd; Msg, wParam : Word; lParam : Longint):
                       Longint; export;
begin
 result := 0; {Default WndProc return value}
 {message 처리 루틴이 들어갈 곳}
 result := CallWindowProc(OldWndProc, hWndAppl, Msg, wParam, lParam);
end;


begin
 Application.CreateForm(TForm1, Form1);
 OldWndProc := TFarProc(GetWindowLong(Application.Handle, GWL_WNDPROC));
 SetWindowLong(Application.Handle, GWL_WNDPROC, longint(@NewWndProc));
 Application.Run;
end.


●Task Handling 방법은?
 ToolHelp unit 에 저으이되어 있는 함수들을 이용하면 된다.
 다음은 TaskFirst, TaskNext 등을 이용한 예제이다.


function isTaskInstance(HInst : Longint) : Boolean;
var
 CurrentTask : TTaskEntry;
 Success : boolean;
begin
 Result := false;
 Yield;
 CurrentTask.dwSize := SizeOf(CurrentTask);
 Success := TaskFirst(@CurrentTask);
 while success do begin
   if CurrentTask.HInst = HInst then begin
     Result := true;
     exit;
   end;
   Success := TaskNext(@CurrentTask);
 end;
end;


●Virtual Key Code List는 어디서 찾나?
 Windows.pas에 있다.


●현재 원하는 프로그램이 실행중인지를 찾는 방법은?
 Findwindow를 사용하기 바란다.


procedure TForm1.Button1Click(Sender : TObject);
var
 Apppath : string;
 Fhandle : HWND;
begin
 Apppath := ExtractFilepath(Application.exename);
 WinExec(Pchar(Apppath+'project1.exe'),SW_SHOW)
 Application.ProcessMessage;
 while FHandle = 0 do
   Fhandle := FindWindow('Tapplication', 'project1');
end;


●DLL 사용법
 1.C에서 작성한 DLL을 델파이에서 사용시


C에서 DLL 만들 때
_declspec(dllexport) int fixtags(char *filename, short level, char* tag_prfix)
{
}
Delphi에서 사용.
Interface
 function fixtags(filename : PChar; level : Smallint; tagprefix : Pchar): integer;FAR
                                                                       ;CDECL;
implementation
 function fixtags(filename : PChar; level : Smallint; tagprefix : Pchar): integer; external
               'dllfix.dll' name 'fixtags';


2.델파이에서 작성한 DLL을 델파이에서 사용시


implementation
 function GetPassword(Apassword : Pchar): WordBool; far; external PASSWORD.dll';


●윈도우 메시지로 Edit의 Text Handling 하려면?
procedure TForm1.Button1Click(Sender : TObject);
var
 p : pChar;
 I : integer;
begin
 I := edit1.perform(wm_GetTextLength, 0, 0) + 1;
 p := AllocMem(i);
 edit1.perform(wm_GetText, I, longint(p));
 edit2.perform(wm_SetText, 0, longint(p));
 FreeMem(p, I);
end;


●Cursor를 Load하려면?
delphiimagescursors 안에 있는 CURSOR를 사용한다.
Image Editor를 상ㅇ하여 Res File로 Load 한다.


{$R programsdelphiMyFile.res}


const Cursorx = 1; {임시 숫자}


procedure stuff;
begin
 Screen.cursors[Cursorx] := LoadCursor(hInstance, pchar('cursor_1'));
 Screen.cursors := PutitHere;
end;


●Mouse 위치를 제조정하려면?
procedure PlaceMouse(x,y : word);
var
 tp : TPoint;
begin
 tp := ClientToScreen(point(x, y));
 SetCursorPos(tp.x, tp.y);
end;


●Application을 Program Manager/Start Menu에 추가하려면?
1.TDDEClientConv Component를 Form 에 추가한다.
2.다음의 코드를 추가한다.


var
 Macro : String;
 Command : Array[0..255] of Char;
begin
 {link를 연다.}
 DDEClient.OpenLink;


 {group을 생성}
 Macro := Format('[CreateGroup(%s)]', ['<your group name>']) + #13#10;
 StrPcopy(Command, Macro);
 if not DDEClient.ExecuteMacro(Command, False) then
   MessageDlg('<your error message>', mtError, [mbok], 0);
 {application을 추가}
 Macro := '[AddItem('+<your application>+', '+<your description>+')]' + #13#10;
 StrPcopy(Command, Macro);
 if not DDEClient.ExecuteMacro(Command, False) then
   MessageDlg('your error message>', mtError, [mbok], 0);


 {새로운 group를 보여줌}
 StrPCopy(Command, '[ShowGroup(NonExist, 1)]');
 DDEClient.ExecuteMacro(Command, False);


 {link를 닫음}
 DDEClient.OpenLink;
end;


●Text를 Rotate 하려면?
procedure TextRotate(LocalCanvas : TCanvas; Text : String; X : Integer; Y : Integer;
                       RotateAngle : Integer);
var
 Logfont : TLogFont;
begin
 {font 정보를 구함}
 GetObject(LocalCanvas.Handle, Sizeof(TLogFont), LogFont);


 LogFont.lfEscapement := RotateAngle * 10;


 {새로운 rotated font handle을 할당}
 LocalCanvas.Font.Handle := CreateFontIndirect(LogFont);


 {print text}
 LocalCanvas.TextOut(X, Y, Text);
end;


●on_click Event를 발생하지 않고 ComboBox를 체크하려면?
procedure CheckNoClick(CB : TCheckBox; CheckIt : Boolean);
begin
 CB.Perform(BM_SETCHECK, Ord(CheckIt), 0);
end;


<CheckNoClick 프로시저 호출하는 방법>
CheckNoClick(ComboBox1, True);


●프로그램상에서 Network Drive를 연결하려면?
procedure TForm1.Button1Click(Sender : TObject);
var
 NRW : TNetResource;
begin
 with NRW do
   begin
    dwType := RESOURCETYPE_ANY;
    lpLocalName := 'X:';         //map to this driver letter
    lpRemoteName := '\ MyServerMyDirectory';
    // Must be filled in. if an empty string is used,
    // it will use the lpRemoteName.
    lpProvider := '';
   end;
 WNetAddConnection2(NRW, 'MyPassword', 'MyUserName',
                               CONNECT_UPDATE_PROFILE);
end;


●PORT를 인식하려면?
<읽기>
function GetPort() : Byte;
var
 InValue : Byte;
 Address : Word;
begin
 asm
   mov DX, Address
   in AL,DX
   mov InValue, AL
 end;


 GetPort := InValue;
end;


<쓰기>
procedure SetPort(OutValue : Byte);
var
 Address : Word;
begin
 Address : Word;
begin
 asm
   mov DX,Address
   mov AL, OutValue
   out DX, AL
 end;
end;


●그래픽으로 프린트하는 대신에 TPrinter에게 프린터에 내장된 기본 글꼴을 사용하도록 하려면?
 윈도우 API 함수인 GetStockObject() 함수를 사용해서 디바이스 디폴트 글꼴 핸들을 얻고, Printer.Font.Handle 에 대입하면 된다.


uses Printers;


procedure TForm1.Button1Click(Sender : TObject);
var
 tm : TTextMetric;
 I : integer;
begin
 if PrintDialog1.Execute then begin
   Printer.BeginDoc;
   Printer.Canvas.Font.Handle := GetStockObject(DEVICE_DEFAULT_FONT);
   GetTextMetrics(Printer.Canvas.Handle, tm);
   for I := 1 to 10 do begin
    Printer.Canvas.TextOut(100, i*tmHeight + tm.tmExternalLeading, 'Test');
   end;
   Printer.EndDoc;
 end;
end;


●윈도우 95의 시작 버튼의 문서 메뉴에 문서를 추가하려면?
 Shell 함수인 SHAddToRecentDocs를 사용한다.


uses ShlOBJ;


procedure TForm1.Button1Click(Sender : TObject);
var
 s : string;
begin
 s := 'C:DownLoadntkfaq.html';
 SHAddToRecentDocs(SHARD_PATH, pChar(s));
end;


●응용프로그램에 할당된 CPU 시간을 변경하려면?
 다음 예제는 응용프로그램에 주어지는 CPU 우선순위를 변경하는 것이다. 이 우선 순위를 변경할 때에는 너무 높은 값을 주지 않도록 한다.
 추가 정보는 Win32 도움말 중에서 SetThreadPriority() 함수를 참조하기 바란다.


procedure TForm1.Button1Click(Sender : TObject);
var
 ProcessID : DWORD;
 ProcessHandle : THandle;
 ThreadHandle : THandle;
begin
 ProcessID := GetCurrentProcessID;
 ProcessHandle := OpenProcess(PROCESS_SET_INFORMATION, false, ProcessID);
 SetPriorityClass(ProcessHandle, REALTIME_PRIORITY_CLASS);
 ThreadHandle := GetCurrentThread;
 SetThreadPriority(ThreadHandle, THREAD_PRIORITY_TIME_CRITICAL);
end;


●문자열의 배경색을 변경하려면?
 API 함수인 SetBkColor() 과 TextOut()을 사용한다.


procedure TForm1.Button1Click(Sender : TObject);
var
 OldTextColor : TColorRef;
 OldBkColor : TColorRef;
 OldBkMode : Integer;
begin
 OldTextColor := SetTextColor(Form1.Canvas.Handle, RGB(0,0,255));
 OldBkColor := SetBkColor(Form1.Canvas.Handle, RGB(255,0,0));
 OldBkMode := SetBkMode(Form1.Canvas.Handle, OPAQUE);
 TextOut(Form1.Canvas.Handle, 100, 100, 'Blue text on red Background', 27);
 SetBkMode(Form1.Canvas.Handle, OldBkMode);
 SetBkColor(Form1.Canvas.Handle, OldBkColor);
 SetTextColor(Form1.Canvas.Handle, OldTextColor);
end;


●코드에서 Display 모드 설정을 변경하려면?
 윈도우 API 함수인 EnumDisplaySettings()을 사용하여 설정되어 있는 모드 설정에 대한 리스트를 얻을 수 있고, ChangeDisplaySettings()는 디스플레리 설정을 변경 하기 위해서 사용될 수 있다. 그러나 많은 드라이버들은 변경사항이 가능하도록 설정했어도, 컴퓨터를 재부팅하지 않고 재설정을 수행할 수 없다.


unit Unit1;


interface


uses
 Windows, Messages, Sysutils, Classes, Graphics, Control, Forms,
 Dialogs, StdCtrls, Spin;


type
 PdmArray = ^TDmArray;
 TDmArray = array[0..] of TDeviceMode;


type
 TForm1 = class(TForm)
   Memo1 : TMemo;
   SpinEdit1 : TSpinEdit;
   Button1 : TButton;
   procedure FormCreate(Sender : TObject);
   procedure FormDestroy(Sender : TObject);
   procedure Button1Click(Sender : TObject);
 private
   lpDmArray : PDmArray;
   NumModes : integer;
   {            }
 public
   {            }
end;


var
 Form1 : TForm1;


implementation
{$R *.DFM}


procedure TForm1.FormCreate(Sender : TObject);
var
 I : integer; //auto-initialized to zero
 MoreModes : bool;
 dm : TDeviceMode;
begin
 Memo1.Lines.Clear;
 MoreModes := True;


 while MoreModes do begin
   MoreModes := EumDisplaySettings(nil, I, Dm);
   Memo1.Lines.Add('Mode '+
    IntToStr(i) + ': '+
    IntToStr(Dm.DmBitsPerPel) + ' Bits Per Pixel ' +
    IntToStr(Dm.DmPelsWidth) + ' X ' +
    IntToStr(Dm.DmPelsHeight));
   Inc(i);
 end;


 NumModes := I;
 SpinEdit1.MinValue := 0;
 SpinEdit1.MaxValue := NumModes;


 GetMem(lpDmArray, sizeof(TDeviceMode) * NumModes);
 FillChar(lpDmArray^, sizeof(TDeviceMode) * NumModes, #0);


{$IFOPT R+}
 {$DEFINE CKRANGE}
 {$R-}
{$ENDIF}
 for I := 0 to (NumModes - 1) do
   EnumDiaplaySettings(nil, I, lpDmarray[i]);
{$IFDEF CKRANGE}
 {$UNDEF CKRANGE}
 {$R+}
{$ENDIF}
end;


procedure TForm1.Button1Click(Sender : TObject);
var
 ReturnVal : Longint;
begin
{$IFOPT R+}
 {$DEFINE CKRANGE}
 {$R-}
{$ENDIF}
 ReturnVal := ChangeDisplaySettings(lpDmArray[SpinEdit1.Value],
                                       CDS_UPDATEREGISTRY);
{$IFDEF CJRANGE}
 {$UNDEF CKRANGE}
 {$R+}
{$ENDIF}
 with Memo1.Lines do begin
   case ReturnVal of
    DISP_CHANGE_SUCCESSFUL : Add('DISP_CHANGE_SUCCESSFUL');
    DISP_CHANGE_RESTART : Add('DISP_CHANGE_RESTART');
    DISP_CHANGE_BADFLAGS : Add('DISP_CHANGE_BADFLAGS');
    DISP_CHANGE_FAILED : Add('DISP_CHANGE_FAILED');
    DISP_CHANGE_BADMODE : Add('DISP_CHANGE_BADMODE');
    DISP_CHANGE_NOTUPDATED : Add('DISP_CHANGE_NOTUPDATED');
   end;
 end;
end;


procedure TForm1.FormDestroy(Sender : TObject);
begin
 FreeMem(lpDmArray, sizeof(TDeviceMode) * NumModes);
end;


end.


●인쇄시 용지 크기를 바꾸려면?
 인쇄 작업의 시작에서 프린터의 설정을 변경하기 위해서는 프린터의 디바이스 모드 구조를 변경해야 한다.


※참고
 델파이의 DEVMODE 도움말 파일.


다음 예는 사용되는 용지 설정과 용지 크기를 변경하는 코드이다.


procedure TForm1.Button1Click(Sender : TObject);
var
 Device : array[0..255] of char;
 Driver : array[0..255] of char;
 Port : array[0..255] of char;
 hDMode : THandle;
 PDMode : PDEVMODE;
begin
 Printer.PrinterIndex := Printer.PrinetrIndex;
 Printer.GetPrinter(Device, Driver, Port, hDMode);
 if hDMode <> 0 then begin
   pDMode := GlobalLock(hDMode);
   if pDMode <> nil then begin
    {Set to legal}
    pDMode^.DmFields := pDMode^.DmFields or Dm_PaperSize;
    pDMode^.DmPaperSize := DMPAPER_LEGAL;


    {Set to custom size}
    pDMode^.DmFields := pDMode^.DmFieldS or
                       DM_PAPERSIZE or
                       DM_PAPERWIDTH or
                       DM_PAPERLENGTH;
    pDMode^.DmPaperSize := DMPAPER_USER;
    pDMode^.DmPaperWidth := 100 {SomeValueInTenthsOfAMillimeter};
    pDMode^.DmPaperLength := 100 {SomeValueInTenthsOfAMillimeter};


    {Set the bin to use}
    pDMode^.DmFields := pDMode^.DmFields or DMBIN_MANUAL;
    pDMode^.DmDefaultSource := DMBIN_MANUAL;


    GlobalUnlock(hDMode);
   end;
 end;
 Printer.PrinterIndex := Printer.PrinterIndex;
 Printer.BeginDoc;
 Printer.Canvas.TextOut(100, 100, 'Test 1');
 Printer.EndDoc;
end;


●코드에서 주어진 프린터의 포트를 변경하려면?
 포트를 변경하기 위해서는 TPrinter의 SetPrinter 메소드를 사용할 수 있다.
다음 예는 파일로 인쇄할 포트를 변경하는 것이다.


uses Printers;


{$IFNDEF WIN32}
 const MAX_PATH = 144;
{$ENDIF}


procedure TForm1.Button1Click(Sender : TObject);
var
 pDevice : pChar;
 pDriver : pChar;
 pPort : pChar;
 hDMode : THandle;
 PDMode : PDEVMODE;
begin
 if PrintDialog1.Execute then begin
   GetMem(pDevice, cchDeviceName);
   GetMem(pDriver, MAX_PATH);
   GetMem(pPort, MAX_PATH);
   Printer.GetPrinter(pDevice, pDriver, pPort, hDMode);
   Printer.SetPrinter(pDevice, PDriver, 'FILE:', hDMode);
   FreeMem(pDevice, cchDeviceName);
   FreeMem(pDriver, MAX_PATH);
   FreeMem(pPort, MAX_PATH);
   Printer.BeginDoc;
   Printer.Canvas.TextOut(100, 100, 'Delphi is RAD!');
   Printer.EndDoc;
 end;
end;


●기본 윈도우 프린터를 변경하려면?
 Win.ini 파일에서 Windows 섹션의 Device 키에 Device 키에 목록화된 프린터, 드라이버, 포트를 변경하기 위해서 WM_WININICHANGE 메시지를 보내야 한다.


uses
 IniFiles;


procedure TForm1.Button1Click(Sender : TObject);
var
 WinIni : TIniFile;
 WinFileName : array[0..MAX_PATH] of char;
 s : array[0..64] of char;
begin
 GetWindowDirectory(WinIniFileName, sizeof(WinIniFileName));
 StrCat(WinIniFileName, 'win.ini');
 WinIni := TIniFile.Create(WinIniFileName);
 try
   WinIni.WriteString('windows','device', 'HP LaserJet Series II, HPPCL, LPT1 :');
 finnaly
   WinIni.Free;
 end;


 StrCopy(S, 'windows');
 SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, LongInt(@S));
end;


●윈도우의 시작 메뉴에 현재의 문서들의 목록들을 제거하려면?
 윈도우의 API 함수인 SHAddToRecentDocs()에 파일 이름 매개변수에 nil을 넘겨 호출한다.


uses
 ShlOBJ;


procedure TForm1.Button1Click(Sender : TObject);
begin
 SHAddToRecentDocs(SHARD_PATH, nil);
end;


●Tray 응용프로그램에서 팝업 메뉴가 포커스를 잃을 때 종료되지 않는 경우가 있는데, 종료하려면?
 메뉴를 팝업 처리하기 위해서 매시지를 처리할 때, 즉 foreground 윈도우로 설정되었을 때, 팝업 메뉴 후에 WM_NULL 메시지를 보내면 된다.


procedure TForm1.WndProc(var Msg : TMessage);
var
 p : TPoint;
begin
 case Msg.Msg of
   WM_USER + 1:
   case Msg.lParam of
    WM_RBUTTONDOWN : begin
       SetForegroundWindow(Handle);
       GetCursorPos(p);
       PopupMenu1.Popup(p.x, p.y);
       PostMessage(Handle, WM_NULL, 0, 0);
    end;
   end;
 end;
 inherited;
end;


●real only 로 설정된 String Grid가 있다. 만약 String Grid에 키 입력을 하려 하고 &Exit 라는 Caption을 가진 버튼이 있을 때, Stringgrid에서 사용자가 x 키를 누를 때마다(Alt 키를 누르지 않았어도), 버튼 클릭이 실행된다. 이를 방지하려면?
 다음 예는 폼 레벨에서 DM_DIALOGCHAR 메시지를 가죠 오는 예이다. 이것은 Alt 키를 누른다면 다이얼로그 문자에 응답할 기회를 주는 것으로 문자 단축키의 기본 핸들링을 막는 것이다.


type
 TForm1 = class(TForm)
   Button1 : TButton;
   StringGrid1 : TStringGrid;
   procedure FormCreate(Sender : TObject);
   procedure Button1Click(Sender : TObject);
   procedure StringGrid1KeyDown(Sender : TObject; var Key : Word; Shift :
                                       TShiftState);
 private
   {            }
   procedure CMDialogChar(var Message : TCMDialogChar);
               message CM_DIALOGCHAR;
 public
   {            }
end;


var
 Form1 : TForm1;


implementation
{$R *.DFM}


procedure TForm1.FormCreate(Sender : TObject);
begin
 Button1.Caption := '&Exit';
end;


procedure TForm1.Button1Click(Sender : TObject);
begin
 Application.Terminate;
end;


procedure TForm1.StringGrid1KeyDown(Sender : TObject; var Key : Word;
                                       Shift : TshiftState);
begin
 ShowMessage('Grid keypress = ' + Char(Key));
 Key := 0;
end;


procedure TForm1.CMDialogChar(var Message : TCMDialogChar);
begin
 if ssAlt in KeyDataToShiftState(Message.KeyData) then
   inherited;
end;


●주어진 파일의 이름 또는 경로명을 알려면?
 윈도우 API 함수인 GetShortPathName을 사용하면 된다.


procedure TForm1.Button1Click(Sender : TObject);
var
 Buffer : array[0..255] of char;
begin
 GetShortPathName('C:Program FilesBorlandCommon FilesBdeBde32.hlp', @buffer,
                       sizeof(Buffer));
 Memo1.Lines.Add(Buffer);
end;


●그룹 지어진 파일이나, 파일을 복사할 때 윈도우 탐색기에서 사용하는 복사 애니메이션 다이얼로그 화면을 사용하려면?
 다음 예는 그룹지어진 파일을 복사하는 함수인 SHFileOperation을 사용하고, 처리 과정 다이얼로그를 보여주는 예이다. 삭제, 이동, 이름 변경에 대해서는 다음의 플래그를 사용할 수 있다.


TO_COPY
FO_DELETE
FO_MOVE
FO_RENAME


uses ShellAPI;


procedure TForm1.Button1Click(Sender : TObject);
var
 Fo : TSHFileOpStruct;
 buffer : array[0..4096] of char;
 p : pchar;
begin
 FillChar(Buffer, sizeof(Buffer), #0);
 p := @buffer;
 p := StrECopy(p, 'C:Download1.ZIP') + 1;
 p := StrECopy(p, 'C:Download2.ZIP') + 1;
 p := StrECopy(p, 'C:Download3.ZIP') + 1;
 StrECopy(p, 'C:Download4.ZIP');


 FillChar(Fo, sizeof(Fo), #0);
 Fo.Wnd := Handle;
 Fo.wFunc := FO_COPY;
 Fo.pForm := @Buffer;
 Fo.pTo := 'D:';
 Fo.fFlags := 0;
 if ((SHFileOperation(Fo) <> 0) or (Fo.fAnyOperationsAborted <> false)) then
   ShowMessage('Cancelled');
end;


●픽셀 배열로부터 Bitmap을 빠르게 생성하려면?
 픽셀 배열로부터 Bitmap을 생성하는 방법은 윈도우 API 함수인 CreateDiBitmap()을 사용한다. 이것은 윈도우가 픽셀 데이터를 저장하기 위해서 사용하는 Bitmap 형식에 독립적인 많은 디바이스들 중 하나를 사용하는 것이다. 이것은 윈도우 시스템에서 작동하는 이점을 가진다.
 다음의 예는 픽셀 배열로부터 256 Color Bitmap을 생성한다. 이 Bitmap은 256 회색 그림자를 사용하여 흰색에서 검은 색으로 점점 색이 변한다. 윈도우는 시스템 색상들을 사용하기 위해서 첫 번째와 마지막의 10가지 색상들을 따로 보관한다. 그래서 256 회색 그림자들 중 Maximum을 가져올 수 잇다.


{$IFNDEF WIN32}
type
 {Used for pointer math under Win16}
 PPtrRec = ^TPtrRec;
 TPtrRec = record
   Lo : Word;
   Hi : Word;
 end;
{$ENDIF}


{Used for huge pointer math}
function GetBigPointer(lp : pointer; Offset : Longint) : Pointer;
begin
 {$IFDEF WIN32}
 GetBigPointer := @PByteArray(lp)^[Offset];
 {$ELSE}
 Offset := Offset + TPtrRec(lp).Lo;
 GetBigPointer := Ptr(TPtrRec(lp).Hi + TPtrRec(Offset).Hi * SelectorInc,
                       TPtrRec(Offset).Lo);
 {$EBDIF}
end;


procdure TForm1.Button1Click(Sender : TObject);
var
 hPixelBuffer : THandle; {Handle to the pixel buffer}
 lpPixelBuffer : pointer; {pointer to the pixel buffer}
 lpPalBuffer : PLogPalette; {the palette buffer}
 lpBitmapInfo : PBitmapInfo; {The bitmap info header}
 BitmapInfoSize : longint; {Size of the bitmap info header}
 BitmapSize : longint; {Size of the pixel array}
 PaletteSize : integer; {Size of the palette buffer}
 I : longint; {loop variable}
 j : longint; {loop variable}
 OldPal : hPalette; {temp palette}
 hPal : hPalette; {handle to our palette}
 hBm : hBitmap; {handle to our bitmap}
 Bm : TBitmap; {temporary Tbitmap}
 Dc : hdc; {used to convert the doB to a DDB}
 IsPaletteDevice : bool;
begin
 Application.ProcessMessages;
 {if range checking is on - turn it off for now}
 {we will remember if range checking was on by defining}
 {a define called CKRANGE if range checking is on.}
 {We do this to access array members past the arrays}
 {defined index range without causing a range check}
 {error at runtime. To satisfy the compiler, we must}
 {also access the indexes with a variable. ie : if we}
 {have an array defined as a: array[0..0] of byte,}
 {and an integer I, we can now access a[3] by setting}
 {i := 3; and then accessing a[i] without error}
 {$IFOPT R+}
  {$DEFINE CKRANGE}
  {$R-}
 {$ENDIF}


 {Lets check to see if this is a palette device - if so, then}
 {We must do palette handling for a successful operation.}
 {Get the screen's dc to use since memory dc's are not reliable}
 dc := GetDc(0);
 IsPaletteDevice := GetDeviceCaps(dc, RASTERCAPS) and RC_PALETTE =
                                                               RCPALETTE;
 {give back the screen dc}
 dc := ReleaseDc(0, dc);


 {The bitmap info size must be the size of the BitmapInfo}
 {plus the size of the color table - one color table entry}
 {is already defined in TBitmapInfo}
 BitmapInfoSize := sizeof(TBitmapInfo) + (sizeof(TRGBQUAD) * 255);


 {The Bitmap size must be the width of the bitmap rounded}
 {up to the nearest 32 bit boundary}
 BitmapSize := (sizeof(byte) * 256) * 256;


 {The size of the palette must be the size of the bitmap rounded}
 {up to the nearest 32 bit boundary}
 BitmapSize := (sizeof(byte) * 256) * 256;


 {The size of the palette must be the size of a TLogPalette}
 {plus the number of color palette entries - 1, since there}
 {is already one palette entry defined in TLogPalette}
 if IsPaletteDevice then
   PaletteSize := sizeof(TLogPalette) + (sizeof(TPaletteEntry) * 255);


 {Get the memory for the BitmapInfo, the PixelBuffer, and the Palette}
 GetMem(lpBitmapInfo, BitmapInfoSize);
 hPixelBuffer := GlobalAlloc(GHND, BitmapSize);
 lpPixelBuffer := GlobalLock(hPixelBuffer);


 if IsPaletteDevice then
   GetMem(lpPalBuffer, PaletteSize);


 {Zero out the BitmapInfo, the PixelBuffer, and the Palette}
 FillChar(lpBitmapInfo^, BitmapInfoSize, #0);
 FillChar(lpPixelBuffer^, Bitmapsize, #0);


 if IsPaletteDevice then
   FillChar(lpPalBuffer^, PaletteSize, #0);


 {Fill in the BitmapInfo structure}
 lpBitmapInfo^.bmiHeader.biSize := sizeof(TBitmapInfoHeader);
 lpBitmapInfo^.bmiHeader.biWidth := 256;
 lpBitmapInfo^.bmiHeader.biHeight := 256;
 lpBitmapInfo^.bmiHeader.biPlanes := 1;
 lpBitmapInfo^.bmiHeader.biBitCount := 8;
 lpBitmapInfo^.bmiHeader.biCompression := BI_RGB;
 lpBitmapInfo^.bmiHeader.biSizeImage := BitmapSize;
 lpBitmapInfo^.bmiHeader.biXPelsPerMeter := 0;
 lpBitmapInfo^.bmiHeader.biYPelsPerMeter := 0;
 lpBitmapInfo^.bmiHeader.biClrUsed := 256;
 lpBitmapInfo^.bmiHeader.biClrImportant := 256;


 {Fill in the BitmapInfo color table with gray shades : black to white}
 for I := 0 to 255 do begin
   lpBitmapInfo^.bmiColors[i].rgbRed := I;
   lpBitmapInfo^.bmiColors[i].rgbGreen := I;
   lpBitmapInfo^.bmiColors[i].rgbBlue := I;
 end;


 {Fill in the pixel buffer array with shades : black to white}
 {In a 256 color bitmap the color is an index into the color table}
 for I := 0 to 255 do
   for j := 0 to 255 do
     Byte(GetBigPointer(lpPixelBuffer, i+(j*256))^) := j;


 {Fill in the palette structure}
 if IsPaletteDevice then begin
   lpPalBuffer^.palVersion := $300;
   lpPalBuffer^.palNumEntries := 256;
 {Fill in the palette structure color table}
 for I := 0 to 255 do begin
   lpPalBuffer^.PalPalEntry[i].peRed := I;
   lpPalBuffer^.PalPalEntry[i].peGreen := I;
   lpPalBuffer^.PalPalEntry[i].peBlue := I;
 end;


 {Create a palette}
 hPal := CreatePalette(lpPalBuffer^);
end;


{Get the screen's dc to use for the sonversion since}
{memory dc's are not reliable to ues for conversions}
dc := GetDc(0);


if IsPaletteDevice then begin
   {If we are using a palette, it must be}
   {selected into the dc during the conversion}
   OldPal := SelectPalette(dc, hPal, True);
   {Realize the palette}
   RealizePalette(dc);
end;


{Do the conversion}
hBm := CreateDiBitmap(dc, lpBitmapInfo^.bmiHeader, CBM_INIT, pChar(lpPixelBuffer),
                       lpBitmapInfo^, DIB_RGB_COLORS);


if IsPaletteDevice then begin
   {Select the Old palette back in}
   SelectPalette(dc, OldPal, true);
   {Realize the old palette}
   RealizePalette(dc);
end;


{Give back the screen dc}
dc := ReleaseDc(0, dc);


{Create a temporory TBitmap}
bm := Tbitmap.Create;


{Free up the memory we used}
if IsPaletteDevice then
   FreeMem(lpPalBuffer, PaletteSize);
GlobalUnlock(hPixelBuffer);
GlobalFree(hPixelBuffer);
FreeMem(lpBitmapInfo, BitmapInfoSize);


{Assign the palette}
if IsPaletteDevice then
   bm.Palette := hPal;


{Assign the handle}
bm.Handle := hBm;


{Size Image1}
Image1.Width := 256;
Image1.Height := 256;


{Assign the bitmap}
Image1.Picture.Bitmap := bm;


SelectPalette(Image1.Picture.Bitmap.Canvas.Handle, Image1.Picture.Bitmap.Palette, false);


{Turn range checking back on if it was on when we started}
{$IFDEF CKRANGE}
 {$UNDEF CKRANGE}
 {$R+}
{$ENDIF}
end;


●TTimer 컴포넌트를 사용하지 않고, 시스템을 Lock하지 않고 지연시키려면?
 다음 예는 시간의 체크하는 루프를 사용하고, 루프가 실행되는 동안 처리된 윈도우 메시지들을 수행하도록 하는 Application.ProcessMessages를 호출한다.


procedure Delay(ms : longint);
var
 TheTime : LongInt;
begin
 TheTime := GetTickCount + ms;


 while GetTickCount < YheTime do
   Application.ProcessMessages;
end;


procedure TForm1.Button1Click(Sender : TObject);
begin
 ShowMessage('Start Test');
 Delay(2000);
 ShowMessage('End Test');
end;


●Flashing Icon을 생성하려면?
 윈도우 API 함수인 FlashWindow()을 호출한다.


var
 Flash : bool;


procedure TForm1.Timer1Timer(Sender : TObject);
begin
 FlashWindow(Form1.Handle, Flash);
 FlashWindow(Application.Handle, Flash);
 Flash := not Flash;
end;


procedure TForm1.FormCreate(Sender : TObject);
begin
 Flash := False;
end;


●RTL은 하나의 입력 Palette에만 TLogPallette를 정의한다. 그런데 하나 이상의 입력을 가진 Palette를 생성하려면?
 RTL은 원하는 팔레트 입력들의 수를 가진 Palette를 동적으로 생성하도록 하기 위해서, 오직 한 개의 입력을 가진 TLogPalette를 정의한다. 추가적인 입력들을 액세스 하기 위해서 범위 체크가 없애야 한다. 그리고 변수를 사용하여 Palette 입력 인덱스를 액세스해야만 한다.
 다음 예는 256 입력들을 가진 논리적 Palette 구조를 동적으로 생성하는 것이다. 범위 체크를 없애고, 회색 그림자로 그들을 채움으로써 Palette 입력들을 액세스한다. 그리고 Palette 에 핸들을 생성하고, 할당된 리소스들을 없앤다.


procedure TForm1.Button1Click(Sender : TObject);
var
 lpPalette : PLogPalette;
 hPal : hPalette;
 I : integer;
begin
 {palette에 사용된 메모리를 할당한다.}
 GetMem(lpPalette, sizeof(TLogPalette)+ (255*sizeof(TPaletteEntry)));


 {palette header를 채운다}
 lpPalette^.palVersion := $300;
 lpPalette^.palNumEntries := 256;


 {범위 체크를 없앤다.}
 {범위 체크 상태를 기억한다.}
 {$IFOPT R+}
  {$DEFINE CKRANGE}
  {$R-}
 {$ENDIF}


 {회색 그림자로 palette 구조 색상 테이블을 채운다.}
 for I := 0 to 255 do begin
   lpPalette^.PalPalEntry[i].peRed := I;
   lpPalette^.PalPalEntry[i].peGreen := I;
   lpPalette^.PalPalEntry[i].peBlue := I;
 end;


 {Turn range checking back on if it was on when we started}
 {$IFDEF CKRANGE}
  {$UNDEF CKRANGE}
  {$R+}
 {$ENDIF}


 {palette 핸들을 생성한다.}
 hPal := CreatePalette(lpPalette^);


 {palette 구조에 의해서 메모리 사용을 해제한다.}
 FreeMem(lpPalette, sizeof(TLogPalette) + (255*sizeof(TPaletteEntry)));


 {이 부분에 palette를 가지고 코딩을 한다.}


 {사용 후에 palette 핸들을 삭제한다.}
 DeleteObject(hPal);
end;


●회전되는 글자체를 생성하려면?
 TrueType 글씨체를 사용해야 한다.
 다음의 코드는 45도로 회전하는 글꼴을 생성하는 예이다.


procedure TForm1.Button1Click(Sender : TObject);
var
 lf : TLogFont;
 tf : TFont;
begin
 with Form1.Canvas do begin
   Font.Name := 'Arial';
   Font.Size := 24;
   tf := TFont.Create;
   tf.Assign(Font);
   GetObject(tf.Handle, sizeof(lf), @lf);
   lf.lfEscapement := 450;
   lf.lfOrientation := 450;
   tf.Handle := CreateFontIndirect(lf);
   Font.Assign(tf);
   tf.Free;
   TextOut(20, Height div 2, 'Rotated Text!');
 end;
end;


●Language 정의를 받아 들이는 윈도우 API 함수들을 가지고 사용된 PRIMARYLANGID() , SUBLANGID() and MAKELANGID() 매크로들을 정의하려면?
 다음 예는 PRIMARYLANGID(), SUBLANGID(), 그리고 MAKELANGID() 메크로에 대해 동등한 기능을 하는 예제이다.


function PRIMARYLANGID(lgid : Word) : LongInt;
begin
 result := lgid and $3FF;
end;


function SUBLANGID(lgid : Word) : LongInt;
begin
 result := lgid shr 10;
end;


function MAKELANGID(sPrimaryLanguage : Word; sSubLanguage : Word) : Word;
begin
 result := (sSubLanguage shl 10) or sPrimaryLanguage;
end;


●주어진 시간에 Windows 인쇄 스풀러에서 얼마나 많은 인쇄 작업이 있는지를 알아내는 방법은?
 Windows 인쇄 스풀러는 스풀러 큐로부터 추가되거나 삭제될 때마다 WM_SPOOLERSTATUS 메시지를 보낸다.
 다음 예는 이 메시지를 가져 오는 예이다.


type
 TForm1 = class(TForm)
   Label1 : TLabel;
 private
   {            }
   procedure WM_SpoolerStatus(var Msg : TMSPOOLERSTATUS);
               message WM_SPOOLERSTATUS;
 public
   {            }
end;


var
 Fomr1 : TForm1;


implementation
{$R *.DFM}


procedure TForm1.WM_SpoolerStatus(var Msg : TWMSPOOLERSTATUS);
begin
 Label1.Caption := InttoStr(msg.JobLeft) + ' Jobs currenly in spooler');
 msg.Result := 0;
end;


●PrintScreen 키를 눌렀는지 알 수 있는 방법은?
 PrintScreen 시스템 키는 TForm의 Keydown 이벤트에서 처리되지 않는ㄷ다.


 다음 예는 Application.OnIdle 이벤트에서 API 함수인 GetAsyncKeyState()를 호출함으로써 PrintScreen 키를 눌렀는지를 테스트하는 것이다.


type
 TForm1 = class(TForm)
   Button1 : TButton;
   procedure formCreate(Sender : TObject);
 private
   {            }
   procedure AppIdle(Sender : TObject; var done : Boolean);
 public
   {            }
end;


var
 Form1 : TForm1;


implementation
{$R &.DFM}


procedure TForm1.FormCreate(Sender : TObject);
begin
 Application.OnIdle := AppIdle;
end;


procedure TForm1.AppIdle(Sender : TObject; var done : Boolean);
begin
 if GetAsyncKeystate(VK_SNAPSHOT) <> 0 then
   Form1.Caption := 'SnapShot');
 done := true;
end;


●다른 응용프로그램에 의해서 시스템 시간이 변경되었는지를 알아내는 방법은?
 다은 예는 WM_TIMECHANGE 메시지를 가져 오는 예제이다.


 시스템 시간이 변경된 응용프로그램은 모든 상위 레벨 윈도우들에게 WM_TIMECHANGE 메시지를 보낸다.


type
 TForm1 = class(TForm1)
 private
   {            }
   procedure WMTIMECHANGE(var Message : TWMTIMECHANGE);
               message WM_TIMECHANGE;
 public
   {            }
end;


var
 Form1 : TForm1;


implementation
{$R *.DFM}


procedure TForm1.WMTIMECHANGE(var Message : TWMTIMECHANGE);
begin
 Form1.Caption := 'Time Changed';
end;


●DLL이 어디에서 실행되었는지 완전한 경로명과 파일 이름을 알아내려면?
 다음 예는 DLL이 로드된 곳은 경로명을 알아내는 DLL 함수에 대한 것이다.


uses Windows;


procedure ShowDllPath stdcall;
var
 TheFileName : array[0..MAX_PATH] of char;
begin
 Fillchar(TheFileName, sizeof(TheFileName), #0);
 GetModulefileName(hInstance, TheFileName, sizeof(TheFileName));
 MessageBox(0, TheFileName, 'The DLL file name is : ', mb_ok);
end;


●주어진 파일에 대한 최근 액세스 시간을 정의하려면?
 다음 예는 주어진 파일이 액세스된 날짜와 시간을 가져 오는 것이다. 모든 파일 시스템들이 최신 액세스 시간을 지원하는 것은 아니다.


procedure TForm1.Button1Click(Sender : TObject);
var
 SearchRec : TSearchRec;
 Success : integer;
 DT : TFileTime;
 ST : TSystemTime;
begin
 Success := SysUtils.FindFirst('C:autoexec.bat', faAnyfile, SearchRec);
 if ((Success = 0) and
   ((TLargeInteger(searchRec.FindData.ftLastAccessTime).LowPart <> 0) or
   ((TLargeInteger(searchRec.FindData.ftLastAccessTime).HighPart <> 0))) then
   begin
    FileTimeToLocalFileTime(SearchRec.FindData.ftLastAccessTime, DT);
    FileTimeToSystemTime(DT, ST);
    Memo1.Lines.Clear;
    Memo1.Lines.Add('AutoExec.bat was last accessed at : ');
    Memo1.Lines.Add('Year := ' + IntToStr(st.wYear));
    Memo1.Lines.Add('Month := ' + IntToStr(st.wMonth));
    Memo1.Lines.Add('DayofWeek := ' + IntToStr(st.wDayOfWeek));
    Memo1.Lines.Add('Day := ' + IntToStr(st.wDay));
    Memo1.Lines.Add('Hour := ' + IntTostr(st.wHour));
    Memo1.Lines.Add('Minute := ' + IntToStr(st.wMinute));
    Memo1.Lines.Add('Second := ' + InttoStr(st.wSecond));
    Memo1.Lines.Add('Milluseconds := ' + IntToStr(st.wMilliseconds));
   end;
   SysUtils.FindClose(SearchRec);
end;


●주어진 프린터가 PostScript 파일에 대해서 인쇄가 가능한지를 알려면?
 다음 예제 코드는 주어진 프린터가 Adobe PostScript 페이지에 대해서 지원하는지를 알아내는 예제이다.


uses Printers;


function IsPostScriptPrinter(dc : hdc) : bool;
var
 TestInt : integer;
 a : array[0..255] of char;
 err : integer;
 s : string;
begin
 Result := false;
 TestInt := GETTECHNOLOGY;
 {$IFEDF WIN32}
 if ExtEscape(Dc, QUERYESCSUPPORT, sizeof(TestInt), @TestInt, 0, Nil) > 0 then
   begin
    Err := ExtEscape(Dc, GETTECHNOLOGY, 0, nil, 256, @a);
 {$ELSE}
 if ExtEscape(Dc, QUERYESCSUPPORT, sizeof(TestInt), @TestInt, 0, Nil) > 0 then
   begin
    Err := ExtEscape(Dc, GetTechnology, 0, nil, @a);
 {$ENDIF}
   if Err > 0 then begin
     s := UpperCase(StrPas(a));
     if Pos('POSTSCRIPT', s) > 0 then
       result := true;
   end;
 end;
end;


procedure TForm1.Button1Click(Sender : TObject);
begin
 if PrintDialog1.Execute then
   if IsPosScriptPinter(Printer.Handle) then
       ShowMessage('This is a Postscript Printer') else
       ShowMessage('This is not a Postscript Printer');
end;


●주어진 윈도우의 종료 버튼을 사용하지 못하게 하려면?
 다음 예는 주어진 윈도우에서 종료 버튼을 사용하지 못하도록 하는 예이다.


peoceudre TForm1.Button1Click(Sender : TObject);
var
 hwndHandle : THANDLE;
 hMenuHandle : HMENU;
begin
 hwndHandle := FindWindow(nil, 'Untitled - notepad');
 if (hwndHandle <> 0) then begin
   hMenuHandle := GetSystemMenu(hwndHandle, False);
   if (hMenuHandle <> 0) then
     DeleteMenu(hMenuHandle, SC_CLOSE, MF_BYCOMMAND);
 end;
end;


●Win95의 시작 버튼을 숨기거나 사용하지 못하게 하려면?
 다음 예는 윈도우 시작 버튼을 숨기거나 나타나게 하고 또한 사용이 가능하거나 불가능하도록 하는 예이다.


procedure TForm1.Button1Click(Sender : TObject);
var
 Rgn : hRgn;
begin
 {Hide the start button}
 Rgn := CreateRectRgn(0, 0, 0, 0);
 SetwindowRgn(FindWindowEx(FindWindow('Shell_TrayWnd', nil), 0, 'Button', nil) ,Rgn
               , true);
end;


procedure TForm1.Button2Click(Sender : TObject);
begin
 {Turn the start button back on}
 SetwindowRgn(FindWindowEx(FindWindow('Shell_TrayWnd', nil), 0, 'Button', nil) ,0
               , true);
end;


procedure TForm1.Button3Click(Sender : TObject);
begin
 {Disable the start button}
 EnableWindow(FindWindowEx(FindWindow('Shell_TrayWnd'), nil), 0, 'Button', nil),
               false );
end;


procedure Tform1.Button4click(Sender : TObject);
begin
 {enable the start button}
 EnableWindow(FindWindowEx(FindWindow('Shell_TrayWnd'), nil), 0, 'Button', nil),
               true );
end;
end.


●VB 함수 중 doEvent 와 동등한 것으로 델파이에서 사용하는 것은?
 Application.ProcessMessages.


●RichEdit 컨트롤에서 Page Brake를 추가하려면?
 불가능하다. Page라는 명령은 RichEdit 컨트롤로부터 제거되는 것이다.


●윈도우 API CallBack 함수인 EnumFontFamilies()를 사용하는 방법은?
 다음 예는 TMemo 컴포넌트에 현재 프린터에 대한 글꼴과 사이즈의 목록들을 추가하는 것이다.


uses Printers;


function EnumFontFamilyProc(var lf : TLogFont;
                               var tm : TNewTextMetric;
                               FontType : integer;
                               var Memo : TMemo) : integer;
{$IFDEF WIN32} stdcall; {$ELSE} ; export; {$ENDIF}
begin
 Memo.Lines.Add(StrPas(@lf.lfFaceName) + #32 + IntToStr(lf.lfHeight));
 result := 1;
end;


function EnumFontFamiliesProc(var lf : TLogFont;
                               var tm : TNewTextMetric;
                               FontType : integer;
                               var Memo : TMemo) : integer;
{$IFDEF WIN32} stdcall; {$ELSE} ; export; {$ENDIF}
begin
 if FontType = TRUETYPE_FONTTYPE then begin
   Memo.Lines.Add(StrPas(@lf.lfFaceName) + #32 + 'All Sizes');
 end else
   EnumFontFamilies(Printer.Handle, @lf.lfFaceName, @EnumFontFamilyProc,
                       LongInt(@Memo));
 result := 1;
end;


procedure TForm1.Button1Click(Sender : TObject);
var
 tm : TTextMetric;
 I : integer;
begin
 if PrintDialog1.Execute then begin
   EnumFontFamilies(Printer.Handle, nil, @EnumFontFamiliesProc, LongInt(@Memo1));
 end;
end;


●'.LNK' 파일을 실행하려면?
 다음 예느 윈도우의 시작 메뉴에서 .lnk 파일을 실행하는 예제이다.


uses ShellApi;


procedure TForm1.Button1Click(Sender : TObject);
begin
 ShellExecute(0,
               nil,
               'C:WINDOWSSTART MEMUDELPHI|Delpgi5.lnk',
               nil,
               nil,
               SW_SHOWNORMAL);
end;


●응용프로그램으로부터 다른 프로그램들을 실행하려면?
 WinExec 함수는 응용프로그램에서 다른 응용프로그램을 실행시키는 가장 쉬운 방법이다. 또는 위의 ‘LNK 파일을 실행하는 방법’ 부분에서 설명한 ShellExecute API 함수를 사용할 수도 있다. 관련된 API 함수의 도움말은 ‘Borland SharedMSHELPWind32.hlp 도움말 파일’을 참고하기 바란다.
 WinExec를 이용하여 일반적인 프로그램을 실행하려면 다음과 같이 한다.


WinExec('C:WINDOWSNOTEPAD.EXE', SW_SHOWNORMAL);
WunExec('C:WINDOWSNOTEPAD.EXE C:WINDOWSWIN.INI',
                                               SW_SHOWNORMAL);


Dos 화면을 보이기 위해서는 ..


WinExec('COMMAND.COM', SW_SHOWNORMAL);


Dos 명령을 수행하기 위해서는 ..


WinExec('COMMAND.COM /C DIR *.*', SW_SHOWNORMAL);


●윈도우 탐색기의 파일 찾기의 다일얼로그 박스를 실행하려면?
 다음 예는 DDE를 사용하여 탐색기의 파일 찾기 다이얼로그를 수행하는 예이다.
이것은 “C:DownLoad" 디렉토리에서 다이얼로그를 연다.


procedure TForm1.Button1click(Sender : TObject);
begin
 with TDDEClientConv.Create(Self) do begin
   ConnectMode := ddeManual;
   ServiceApplication := 'explorer.exe';
   SetLink('Folders', 'AppProperties');
   OpenLink;
   ExecuteMacro('FindFolder(, C:DOWNLOAD)]', False);
   CloseLink;
   Free;
 end;
end;


●ShellAPI 함수인 ExtractIconEX()를 가지고 주어진 파일로부터의 작은 아이콘, 큰 아이콘을 추출하려면?
 ShellAPI 함수인 ExtracIconEx() 는 실행 파일, 동적 링크 라이브러리(DLL) 또는 아이콘 파일에 사용할 수 있다.
 다음은 함수에 대한 정의이다.


Function ExtractIconEx(lpszFile : PAnsiChar;
                       nIconIndex : Integer;
                       phiconLarge : PhIconArray;
                       phiconSmall : PhIconArray;
                       nIcons : UNIT) : UNIT ; stdcall;


다음은 매개변수를 설명할 것이다.


---------------------------------------------------------------------
매개변수        설명
---------------------------------------------------------------------
lpszFile         아이콘을 추출하려는 실행 파일, DLL, 또는 아이콘 파일의 이름을 Null
               종료 문자열로 정의하는 포인터.
nIconIndex      아이콘의 인덱스를 정의한다. 만약 값이 0이라면 함수는 정의된 파일에 대
               해서 첫 번째 아이콘의 핸들을 리턴한다. 값이 -1이라면, 그리고
               phiconLarge 과 phiconSmall 이 모든 nil 이라면 함수는 실행 파일, dll, 또
               는 아이콘 파일에 아이콘의 총 수를 리턴한다. 파일이 실행파일이거나
               DLL이라면 리턴 값은 RT_GROUP_ICON 리소스들의 수이다. 만약 .ICO
               라면 리턴 값은 1이다.
phiconLarge    큰 아이콘에 대한 아이콘 핸들들에 대한 배열 포인터로 이 매개변수는 오
               직 한 개의 아이콘이 추출되면 nil 값을 가질 수 있다.
nIcons          아이콘의 수를 정의한다.
Return Value   리턴 값은 오직 한 개의 아이콘이라면 아이콘에 대한 핸들이다. 그리고 파
               일에서 어떤 아이콘도 찾을 수 없다면 리턴 값은 0이다.
---------------------------------------------------------------------


 다음 예는 ExtractIconEx() 함수를 사용하느 예이다.
 함수의 완전한 사용을 허락하기 위해서 ShellAPI 유닛에 정의된 것과 다르게 함수가 정의된 것을 주의하라.


type ThIconArray = array[0..0] of hIcon;
type PhIconArray = ^ThIconArray;


function ExtracIconExA(lpszFile : PAnsiChar;
                       nIconIndex : Integer;
                       phiconLarge : PhIconArray;
                       phiconSmall : PhIconArray;
                       nIcons : UINT) : UNIT ; stdcall;
   external 'shell32.dll' name 'ExtracIconExA';


function ExtracIconExW(lpszFile : PWideChar;
                       nIconIndex : Integer;
                       phiconLarge : PhIconArray;
                       phiconSmall : PhIconArray;
                       nIcons : UINT) : UNIT ; stdcall;
   external 'shell32.dll' name 'ExtracIconExW';


function ExtractIconEx(lpszFile : PAnsiChar;
                       nIconIndex : integer;
                       phiconLarge : PhIconArray;
                       phiconSmall : PhIconArray;
                       nIcons : UNIT) : UNIT; stdcall;
   external 'shell32.dll' name 'ExtracIconExA';


procedure TForm1.Button1Click(Sender : TObject);
var
 NumIcons : Integer;
 pTheLargeIcons : phIconArray;
 pThrSmallIcons : phIconArray;
 LargeIconWidth : integer;
 SmallIconWidth : integer;
 SmallIconHeight : integer;
 I : integer;
 TheIcon : TIcon;
 TheBitmap : TBitmap;
begin
 NumIcons :=
 ExtractIconEx('C:Program FilesBorlandDelphi 5BINDelphi32.exe', -1, nil, nil, 0);
 if NumIcons > 0 then begin
   LargeIconWidth := GetsystemMetrics(SM_CXICON);
   SmallIconWidth := GetSystemMetrics(SM_CXSMICON);
   SmallIconHeight := GetsystemMetrics(SM_CYSMICON);
   GetMem(pTheLargeIcons, NumIcons * sizeof(hIcon));
   GetMem(pTheSmallIcons, NumIcons * sizeof(hIcon));
   FillChar(pTheLargeIcons^, NumIcons * sizeof(hIcon), #0);
   FillChar(pTheSmallIcons^, NumIcons * sizeof(hIcon), #0);
   ExtractIconEx('C:Program FilesBorlandDelphi 5BINdelphi32.exe',
               0,
               pTheLargeIcons,
               pTheSmallIcons,
               numIcons);
   {$IFOPT R+}
    {$DEFINE CKRANGE}
    {$R-}
   {$ENDIF}
   for I := 0 to (NumIcons - 1) do begin
       DrawIcon(Form1.Canvas.Handle, i*LargeIconWidth, 0, pTheLargeIcons^[i]);
       TheIcon := TIcon.Create;
       TheBitmap := TBitmap.Create;
       TheIcon.Handle := pTheSmallIcons^[i];
       TheBitmap.Width := TheIcon.Width;
       TheBitmap.Height := TheIcon.Height;
       TheBitmap.Canvas.Draw(0,0, TheIcon);
       TheIcon.Free;
       Form1.Canvas.StrectchDraw(Rect(i * SmallIconWidth,
                                       100,
                                       (i + 1) * SmallIconHeight),
                                       TheBitmap);
       TheBitmap.Free);
   end;
   {$IFDEF CKRANGE}
    {$UNDEF CKRANGE}
    {$R+}
   {$ENDIF}
   FreeMem(pTheLargeIcons, NumIcons * sizeof(hIcon));
   FreeMem(pTheSmallIcons, NumIcons * sizeof(hIcon));
 end;
end;


end.


●주어진 Canvas를 지우는 가장 빠른 방법은?
 윈도우 API 함수인 PatBlt()를 사용하면 된다.


procedure TForm1.Button1Click(Sender : TObject);
begin
 PatBlt(Form1.Canvas.Handle, 0 , 0, Form1.ClientWidth, Form1.ClientHeight,
       WHITENESS);
end;


●Win32 아래의 드라이브를 포맷하려면?
 ShellAPI 함수인 shFormatDrive()를 사용할 수 있다.


const SHFMT_DRV_A = 0;
const SHFMT_DRV_B = 1;


const SHFMT_ID_DEFAULT = $FFFF;


const SHFMT_OPT_QUICKFORMAT = 0;
const SHFMT_OPT_FULLFORMAT = 1;
const SHFMT_OPT_SYSONLY = 2;
const SHFMT_ERROR = -1;
const SHFMT_CANCEL = -2;
const SHFMT_NOFORMAT = -3;


function SHFormatDrive(hWnd : HWND;
                       Drive : Word;
                       fmtID : Word;
                       Option : Word) : Longint
   stdcall; external 'Shell32.dll' name 'SHFormatDrive');


procedure TForm1.Button1click(Sender : TObject);
var
 FmtRes : longint;
begin
 try
   FmtRes := ShformatDrive(Handle,
                               SHFMT_DRV_A,
                               SHFMT_ID_DEFAULT,
                               SHFMT_OPT_QUICKFORMAT);
   case FmtRes of
    SHFMT_ERROR : ShowMessage('Error formatting the drive');
    SHFMT_CANCEL :
       ShowMessage('User canceled formatting the drive');
    SHFMT_NOFORMAT : ShowMessage('No Format');
   else
    ShowMessage('Disk has been formatted');
 except
 end;
end;


●Windows Console 응용프로그램을 일반화하려면?
 새로운 응용프로그램을 시작하고, Project Manager를 시작하여 프로젝트의 모든 유닛을 제거한다. 그리고 Project Source 에 다음의 코드를 추가한다.


program Project1;


uses
 Windows;
{$R *.RES}


begin
 Write('A Console Application');
 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
                       FOREGROUND_RED OR BACKGROUND_BLUE);
 Writeln('Red text on a blue background');
 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
                       FOREGROUND_BLUE OR BACKGROUND_RED);
 writeln('Blue text on a red background');
 {write text on black background}
 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
                       FOREGROUND_RED OR
                       FOREGROUND_GREEN OR
                       FOREGROUND_BLUE);
 Writeln('Press Enter To End');
 Readln;
end.


●시스템에서 가능한 드라이브들의 목록을 가져 오는 가장 빠른 방법은?
 다음 예는 시스템에서 가능한 논리적 드라이브들의 리스트를 가져 오는 것이다.


procedure TForm1.Button1Click(Sender : TObject);
var
 ld : DWORD;
 I : integer;
begin
 il := GetLogicalDrives;
 for I := 0 to 25 do begin
   if (ld and (1 shl I)) <> 0 then
       Memo1.Lines.Add(Char(Ord('A') + I) + ':');
 end;
end;


●DeviceCapabilities 를 사용하여 특정 프린터에 대한 모든 빈들의 이름들을 가져 오려면?
 다음 코드를 참조하기 바란다. 델파이에서 새로운 프로젝트를 시작하여 TButton 과 TMemo를 가져다 놓는다. 버튼의 on_click 이벤트에 다음과 같이 코드를 작성한다.


uses
 WinSpool;


const
 pName = 'DELPHI III';
 pPort = '\CONANDELPHI_III';


procedure TForm1.Button1Click(Sender : TObject);
var
 I : Integer;
 p : pChar;
begin
 GetMem(p, 24*DeviceCabilities(pName, PPort, DC_BINNAMES, nil, nil));
 with Memo1.Lines do begin
   Clear;
   for I:= 1 to DeviceCapabilities(pName, PPort, DC_BINNAMES, p, nil) do
       Add(p+24*(i-1));
   end;
   FreeMem(p);
end;


●Win32 아래에서 모뎀의 상태를 가져 오려면?
 다음 예는 Win32 아래에서 모뎀 Control-Register 값들을 가져 오는 것이다.


peocedure TForm1.Button1Click(Sender : TObject);
var
 CommPort : string;
 hCommFile : THandle;
 ModemStart : DWord;
begin
 CommPort := 'COM2';


 {Open the comm port}
 hCommFile := CreateFile(PChar(CommPort),
                       GENERIC_READ,
                       0,
                       nil,
                       OPEN_EXISTING,
                       FILE_ATTRIBUTE_NORMAL,
                       0);
 if hCommFile = INVALID_HANDLE_VALUE then
 begin
   ShowMessage('Unable to open ' + CommPort);
   exit;
 end;


 {Get the Modem Status}
 if GetCommMedemStatus(hCommFile, ModemStart) <> false then begin
   if MedemStat and MS_CTS_ON <> 0 then
       ShowMessage('The CTS (clear-to-send) is on.');
   if ModemStat and MS_DSR_ON <> 0 then
       ShowMessage('The DSR (data-set-ready) is on.');
   if MedemStat and MS_RING_ON <> 0 then
       ShowMessage('The ring indicator is on.');
   if ModemStat and MS_RLSD_ON <> 0 then
       ShowMessage('The RLSD (receive-line-singnal-detect) is on.');
 end;


 {Close the comm port}
 CloseHandle(hCommFile);
end;


●TPrinter 의 GetPrinter() 메소드들로부터 Printer의 드라이버나 포트명을 가져 오려면?
 보통 이들 매개변수들은 빈 문자열을 리턴한다. Windows.ini 파일로부터 할당된 Driver 와 Port를 가져 오기 위해서 윈도우 API 함수인 GetProfileString()을 사용할 수 있다.


uses Printers;


{$IFNDEF WIN32}
 const MAX_PATH = 144;
{$ENDIF}


procedure TForm1.Button1Click(Sender : TObject);
var
 pDevice : pChar;
 pDriver : pChar;
 pPort : pChar;
 hDMode : THandle;
begin
 if PrintDialog1.Execute then begin
   GetMem(pDevice, cchDeviceName);
   GetMem(pDriver, MAX_PATH);
   GetMem(pPort, MAX_PATH);
   Printer.GetPrineter(pDevice, pDevice, '', pDriver, MAX_PATH);
   if lStrLen(pDriver) = 0 then begin
       GetProfileString('Devices', pDevice, '', pDriver, MAX_PATH);
       pDriver[pos(',', pDriver) - 1] := #0;
   end;
   if lStrLen(pPort) = 0 then begin
       GetProfileString('Device', pDevice, '', pPort, MAX_PATH);
       lsStrCpy(pPort, @pPort[lsStrLen(pPort)+2]);
   end;
   Memo1.Lines.Add('Device := ' + StrPas(pDevice));
   Memo1.Lines.Add('Driver := ' + StrPas(pDriver));
   Memo1.Lines.Add('Port := ' + StrPas(pPort));
   FreeMem(pDevice, cchDeviceName);
   FreeMem(pDriver, MAX_PATH);
   FreeMem(pPort, MAX_PATH);
 end;
end;


●Dos 화면이나 모든 Console 응용프로그램을 포함하는 윈도우의 핸들을 가져 오려면?
 다음 예는 Console 모드 응용프로그램의 핸들을 가져 오기 위해서 윈도우 API 함수인 FindWindow()을 사용하는 예이다.
 Console Window의 WndClass 는 윈도우95와 윈도우 NT를 사용하는 경우가 다르고 윈도우의 타이틀도 윈도우 NT에서는 완전한 경로명을 포함한다.


procedure TForm1.Button1Click(Sender : TObject);
var
 info : TOSVersionInfo;
 ClassName : string;
 Title : string;
begin
 {See if we're running on Win95 or NT.}
 info.dwOSVersionInfoSize := sizeof(info);
 GetVersionEx(info);
 if (info.dwPlatformId = VER_PLATFORM_WIN32_NT) then begin
   ClassName := 'ConsoleWindowClass';
   Title := 'MS-DOS Prompt';
 end;
 ShowMessage(IntToStr(FindWindow(PChar(ClassName), PChar(Title))));
end;


●페이지의 인쇄 여백을 얻어 오려면?
 PHYSICALOFFSETX 와 PHYSICALOFFSETY 상수를 전달하는 윈도우 API 함수인 GetDeviceCaps()를 호출한다.


uses Printers;


procedure TForm1.Button1Click(Sender : TObject);
var
 EscapeCode : integer;
 Margin : TPoint;
begin
 if PrintDialog1.Execute then begin
   {$IFDEF WIN32}
   Margin.x := GetDeviceCaps(Printer.Handle, PHYSICALOFFSETX);
   Margin.y := GetDeviceCaps(Printer.Handle, PHYSICALOFFSETY);
   {$ELSE}
   EscapeCode := GETPRINTINGOFFSET;
   if Escape(Printer.Handle,
               QUERYSCSUPPORT,
               sizeof(EscapeCode),
               @EscapeCode, nil) <> 0 then
    if Escape(Printer.Handle,
               QUERYSCSUPPORT,
               0,
               nil, @Margin) < 1 then begin
       EscapeCode := GETPHYSPAGESIZE;
       if Escape(Printer.Handle,
               QUERYSCSUPPORT,
               sizeof(EscapeCode),
               @EscapeCode, nil) <> 0 then
       if Escape(Printer.Handle,
               GETPHYSPAGESIZE,
               0,
               nil, @Margin) > 0 then begin
        Margin.x := (Margin.x - GetDeviceCaps(Pinter.Handle, HorzRes)) div 2;
        Margin.y := (Margin.y - GetDeviceCaps(Pinter.Handle, VertRes)) div 2;
       end else begin
        Margin.x := 0;
        Margin.y := 0;
       end;
     end;
   {$ENDIF}
   Memo1.Lines.Add(IntToStr(Margin.x));
   Memo1.Lines.Add(IntToStr(Margin.y));
 end;
end;


●디스크의 시리얼 숫자를 가져 오려면?
 윈도우 API 함수인 GetVolumnInformation()을 사용한다.


procedure TForm1.Button1Click(Sender : TObject);
var
 VolumnSerialNumber : DWORD;
 MaximunCoponentLength : DWORD;
 FileSystemFlags : DWORD;
 SerialNumber : string;
begin
 GetVolumeInfomation('C:',
                       nil,
                       0,
                       @VolumeSerialNumber,
                       MaxinumComponentLength,
                       FilesystemFlags,
                       nil,
                       0);
 Serialnumber := IntToHex(HiWord(VolumeSerialNumber), 4) + '-' +
                IntToHex(LoWord(VolumeSerialNumber), 4);
 Memo1.Lines.Add(SerialNumber);
end;


●Universal Time에서 시간과 날짜를 얻어 오려면?
 윈도우 API 함수인 GetSystemTime을 사용한다.


procedure TForm1.Button1Click(Sender : TObject);
var
 lt : TSYSTEMTIME;
 st : TSYSTEMTIME;
begin
 GetLocalTime(lt);
 GetSystemTime(st);
 Memo1.Lines.Add('LocalTime = ' +
                       IntToStr(lt.wmonth) + '/' +
                       IntToStr(lt.wDay) + '/' +
                       IntToStr(lt.wYear) + '' +
                       IntToStr(lt.wHour) + ':' +
                       IntToStr(lt.wMinute) + ':' +
                       IntToStr(lt.wSecond));
 Memo1.Lines.Add('UTCTime = ' +
                       IntToStr(st.wmonth) + '/' +
                       IntToStr(st.wDay) + '/' +
                       IntToStr(st.wYear) + '' +
                       IntToStr(st.wHour) + ':' +
                       IntToStr(st.wMinute) + ':' +
                       IntToStr(st.wSecond));
end;


●윈도우로부터 사용자명과 회사 정보를 가져 오려면?
 윈도우의 레지스트리의 “HKEYCURRENT USER" 섹션 아래에 이 정보가 저장되어 있다. TRegIniFile을 사용하여 입력 정보를 가져 온다.


uses Registry;


procedure TForm1.Button1Click(Sender : TObject);
var
 reg : TRegIniFile;
begin
 reg := TRegIniFile.Create('SOFTWAREMICROSOFTMS SETUP(ACME)');
 Memo1.Lines.Add(reg.ReadString('USER INFO', 'DefName', 'Frank Borland'));
 Memo1.Lines.Add(reg.ReadString('USER INFO', 'DefCompany', 'A Valued Borland
                                       Customer'));
 reg.free;
end;


●응용프로그램의 시작 동안 키를 눌렀는지 알려면?
 윈도우 API 함수인 GetKeyState를 사용하여 메인 프로젝트 소스에서 키를 눌렀는지를 체크한다.


program Project1;


uses
 Windows, Forms,
 Unit1 in 'Unit1.pas' {Form1};


{$R *.RES}


begin
 if GetKeyState(vk_F8) < 1 then
   MessageBox(0, 'F8 was pressed during startup', 'MyApp', bm_ok);
 Application.Initialize;
 Application.CreateForm(TForm1, Form1);
 Application.Run;
end.


●설치된 com 포크들의 이름들을 알려면?
 다음은 Win32 레지스트리에 설치된 정보를 가져 오는 예이다.


uses Registry;


procedure TForm1.Button1Click(Sender : TObject);
var
 reg : TRegistry;
 ts : TStrings;
 I : integer;
begin
 reg := TRegistry.Create;
 reg.RootKey := HKEY_LOCAL_MACHINE;
 reg.OpenKey('hardwaredevicemapserialcomm', false);
 ts := TStringList.Create;
 reg.GetValueNames(ts);
 for I := 0 to ts.Count-1 do begin
   Memo1.Lines.Add(reg.ReadString(ts.Strings[i]));
 end;
 ts.Free;
 reg.CloseKey;
 reg.free;
end;


●Win32 아래에서 모뎀을 통해서 전화하는 방법은?
 com 포크에 대한 핸들을 가져 오기 위해서 윈도우 API 함수인 CreateFile()을 사용 할 수 있다. 그리고 주어진 포트를 가지고 통신하기 위해서 표준 파일 I/O를 사용한다.


var
 hCOmmFile : THandle;


procedure TForm1.Button1Click(Sender : TObject);
var
 PhoneNumber : String;
 CommPort : string;
 NumberWritten : LongInt;
begin
 PhoneNumber := 'ATDT 1-555-555-1212' + #13 + #10;
 CommPort := 'COM2';
 {Open the comm port}
 hCommFile := CreateFile(PChar(CommPort),
                       GENERIC_WRITE,
                       0,
                       nil,
                       OPEN_EXISTING,
                       FILE_ATTRIBUTE_NORMAL,
                       0);
 if hCommFile = INVALID_HANDLE_VALUE then
 begin
   ShowMessage('Unable to open '+ CommPort);
   exit;
 end;


 {Dial the phone}
 NumberWritten := 0;
 if WriteFile(hCommfile,
               PChar(PhoneNumber)^,
               Length(PhoneNumber),
               NumberWrutten,
               nil) = false then begin
   ShowMessage('Unable to open '+ CommPort);
 end;


peocedure Tform1.Button2click(Sender : TObject);
begin
 {close the port}
 CloseHandle(hCommFile);
end;


●기본 윈도우 폴더들을 가져 오려면?
 다음 예는 TMemo 컴포넌트에 기본 쉘 폴더들의 완전한 목록을 가져 오는 것이다.


uses Registry;


procedure TForm1.Button1Click(Sender : TObject);
var
 reg : TRegistry;
 ts : TStrings;
 I : integer;
begin
 reg := TRegistry.Create;
 reg.RootKey := HKEY_CURRENT_USER;
 reg.LazyWrite := false;
 reg.OpenKey(
  'SoftwareMicrosoftwindowsCurrentVersionExplorerSell Folders', false);
 ts := TStringList.Create;
 reg.GetValueNames(ts);
 for I := 0 to ts.Count-1 do begin
   Memo1.Lines.Add(ts.Strings[i] + ' = ' +reg.ReadString(ts.Strings[i]));
 end;
 ts.Free;
 reg.CloseKey;
 reg.free;
end;


●현재 디스플레이 모드가 지원하는 색들의 수를 찾는 방법은?
 다음 방법에서 Display context 의 Color Delth를 찾을 수 있다.


GetDeviceCaps(Form1.Canvas.Handle, BITSPIXEL) *
GetDeviceCaps(Form1.Canvas.Handle, PLANES)


픽셀당 사용된 색의 bit 들의 총수를 가져 온다.


1 = 2 colors bpp
4 = 16 colors bpp
8 = 256 colors bpp
15 = 32768 colors(will return 16 on most drivers) bpp
16 = 65535 colors bpp
24 = 16,777,216 colors bpp
32 = 16,777,216 colors (same as 24) bpp


색상들의 총수를 계산하기 위해서 다음을 사용한다.


NumberOfColors := (1 뇌
   (GetDeviceCaps(Form1.Canvas.Handle, BITSPIXEL) *
    GetDeviceCaps(Form1.Canvas.Handle, PLANES));


●문자열의 배경을 투명하게 하려면?
 윈도우 API 함수인 SetBkMode() 함수를 사용한다.


procedure TForm1.Button1Click(Sender : TObject);
var
 OldBkMode : integer;
begin
 with Form1.Canvas do begin
   Brush.Color := ClRed;
   FillRect(Rect(0, 0, 100, 100));
   Brush.Color := ClBlue;
   TextOut(10, 20, 'Not Transparent!');
   OldBkMode := SetBkMode(Handle, TRANSPARENT);
   TextOut(10, 50, 'Transparent!');
   SetBkMode(Handle, OldBkMode);
 end;
end;


●주어진 폴더에서 탐색기 윈도우를 열 수 있나?
 다음 예는 Windows 디렉토리의 내용을 포함한 탐색기 윈도우를 여는 것이다.


uses ShellApi;


procedure TForm1.Button1Click(Sender : TObject);
begin
 ShellExecute(0, 'explore', 'C:WIDOWS', nil, nil, SW_SHOWNORMAL);
end;


●프로그램의 실행에 대한 인스턴스를 한 개만 가능하도록 할 수 있나? 즉, 한 개 이상의 인스턴스를 시작하려면 이전의 인스턴스를 저장하고 Shut Down 시킬 수 있나?
 Win16에서는 HPrevInst를 변수를 시작하기 전에 체크하여 0이 아니면 애플리케이션이 이미 실행중임을 나타내는데, Win32에서는 hPrevInst를 사용할 수 없다. 다음의 예제를 참고하기 바란다.


{The code for OneInstance.dpr}


program OneInstance;


uses
 Windows, Forms,
 Unit1 in 'Unit1.pas' {Form1};


{$R *.RES}
begin
 {Attempt to create a named mutex}
 CreateMutex(nil, false, 'MyApp');
 {if it failed then there is another instance}
 if GetLastError = ERROR_ALREADY_EXISTS then begin
   {Send all windows our custom message - only our other}
   {instance will recognise it, and restore itself}
   SendMessage(HWND_BROADCAST, RegisterWindowMessage('MyApp'), 0 ,0);
   {Lets quit}
   Halt(0);
 end;


 Application.Initialize;
 {Tell Delphi to un-hide it's hidden application window}
 {This allows our instance to have a icon on the task bar}
 Application.ShowMainform := true;
 ShowWindow(Application.Handle, SW_RESTORE);
 Application.CreateForm(TForm1, Form1);
 Application.Run;
end.


{The code for unit1.pas}


unit Unit1;


interface
uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls,
 Forms, Dialogs;


type
 TForm1 = class(TForm)
   procedure FormCreate(Sender : TObject);
   procedure FormDestroy(Sender : TObject);
 private
 {             }
 public
   {            }
 end;


var
 Form1 : Tform1;


implemantation
{$R *.DFM}


var
 OldWindowProc : Pointer; {Variable for the old windows proc}
 MyMsg : DWord; {custom systemwide message}


function NewWindowProc(WindowHandle : hWnd;
                       TheMessage : LongInt;
                       ParamW : LongInt;
                       ParamL : LongInt) : LongInt stdcall;
begin
 if TheMessage = MyMsg then begin
   {Tell the application to restore, let it restore the form}
   SendMessage(Application.handle, WM_SYSCOMMAND, SC_RESTORE, 0);
   SetForegroundWindow(Application.Handle);
   {We handled the message - we are done}
   Result := 0;
   exit;
 end;
 {Call the original winproc}
 Result := CallWindowProc(OldWindowProc, WindowHandle, TheMessage, ParamW,
                               ParamL);
end;


procedure TForm1.FormCreate(Sender : TObject);
begin
 {Register a custom windows message}
 MyMsg := RegisterWindowMessage('MyApp');
 {Set form1's windows proc to ours and remember the old window proc}
 OldWindowProc := Pointer(SetWindowLong(Form1.Handle, GWL_WNDPROC,
                                          LongInt(@NewWindowProc)));
end;


procedure TForm1.FormDestory(Sender : TObject);
begin
 {Set form1's window proc back to it's original procedure}
 SetWindowLong(Form1.Handle, GWL_WNDPROC, LongInt(OldWindowProc));
end;


begin
 {Tell Delphi to hide it's hidden application window for now to avoid}
 {a "flash" on the taskbar if we halt due to another instance}
 ShowWindow(Application.Handle, SW_HIDE);
end.


●응용프로그램에서 Task Switching(Alt-Tab, Ctrl-Esc, Ctrl-Alt-Del)를 막으려면?
 응용프로그램에서 스위칭을 저지하는 것은 Screen Saver가 실행중인 것처럼 하여 윈도우에 속임수를 사용함으로써 가능하다.
 이 방법은 윈도우 NT에서는 불가능하다.
 다음의 코드는 Screen Saver가 실행중인 것처럼 속임수를 쓰는 것이다.


var
 OldValue : LongBool;
begin
 {turns the trap on}
 SystemParametersInfo(97, Word(True), @OldValue, 0);


 {turn the trap off}
 SystemParametersInfo(97, Word(False), @OldValue, 0);
end;


●TPrinter 유닛을 사용하지 않고 델파이에서 인쇄할 수 있나?
 다음 예는 윈도우 API 함수인 PrintDlg()를 사용하는 것으로, 이는 리턴된 dc를 사용하여 프린터를 선택하고 2개페이지를 인쇄하는 것이다.


uses CommDlg;


{$IFDEF WIN32}
const MAX_PATH = 144;
{$ENDIF}


procedure TForm1.Button1Click(Sender : TObject);
var
 pd : TPrintDlg;
 docInfo : TDocInfo;
begin
 FillChar(Pd, sizeof(Pd), #0);
 Pd.lStructSize := sizeof(Pd);
 Pd.hWndOwner := Form1.Handle;
 Pd.Flags := PD_RETURNDC;
 if PrintDlg(pd) then begin
   FillChar(DocInfo, sizeof(DocInfo), #0);
   docInfo.cbSize := Sizeof(DocInfo);
   GetMem(DocInfo.lpszDocName, 32);
   GetMem(DocInfo.lpszOutput, MAX_PATH);
   lStrCpy(DocInfo.lpszDocName, 'My documant');
   {Add this line to print to a file}
   lStrCpy(DocInfo.lpszOutPut, 'C:DownloadTest.doc');
   StartDoc(Pd.hDc, docInfo);
   StartPage(Pd.hDc);
   TextOut(Pd.hDc, 100, 100, 'Page1', 6);
   EndPage(Pd.hDc);
   StartPage(Pd.hDc);
   TextOut(Pd.hDc, 100, 100, 'Page 2', 6);
   EndPage(Pd.hDc);
   EndDoc(Pd.hDc);
   FreeMem(DocInfo.lpszDocName, 32);
   FreeMem(DocInfo.lpszOutput, MAX_PATH);
 end;
end;


●응용프로그램이 Custom Print Driver를 사용한다면, 사용자의 개입 없이 윈도우 3.1이나 윈도우 95에서 프린터 드라이버를 설치하는 것이 가능한가?
 다음 예는 프린터 드라이버를 설치하는 것이다. WindowsSystem 디렉토리에 프린트 드라이버 파일들을 복사하고, Win.ini 파일에 다음 값들을 추가해야 한다.


procedure TForm1.Button1Click(Sender : TObject);
var
 s : array[0..64] of char;
begin
 WriteProfileString('PrinterPorts', 'DriverName', 'DRVFILE,FILE : ,15,45');
 WriteProfileString('Devices', 'DriverName', 'DRVFILE,FILE : ');
 StrCopy(S, 'PrinterPorts');
 SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, LongInt(@S));
 StrCopy(S, 'Devices');
 SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, LongInt(@S));
end;


●프로그램에서 다른 응용프로그램을 종료시키려면?
 WM_QUIT 메시지를 응용프로그램에 보내면 된다.


PostMessage(FindWindow(Nil, 'window caption'), WM_QUIT, 0, 0);


 Window Caption에 메시지를 보낼 윈도우의 Caption이 들어가야 한다.


●Windows Desktop 아이콘들을 Refresh하려면?
 다음 예는 Windows Desktop 아이콘들을 Refresh하는 것이다.


procedure TForm1.Button1Click(Sender : TObject);
begin
 SendMessage(FindWindow('Program', 'Program Manager'), WM_COMMAND, $A065,
                                                                       0);
end;


●폼의 Caption Bar를 없애려면?
 폼의 스타일과 높이를 재설정한다.


procedure TForm1.formCreate(Sender : TObject);
begin
 SetWindowLong(Form1.Handle, GWL_STYLE,
               GetWindowLong(Handle,GWL_STYLE) and not WS_CAPTION);
 Height := ClientHeight;
end;


●응용프로그램에 전달되는 명령 라인으로부터 스페이스를 포함하는 긴 파일 이름을 가져 오려면?
 윈도우 API 함수인 GetCommandLine()은 응용프로그램에 완전한 명령 라인을 제공한다.


procedure TForm1.Button1Click(Sender : TObject);
var
 s : string;
begin
 s := GetCommandLine;
 Delete(s, 1, pos('exe"', s) + 4);
 Memo1.Lines.Add(s);
end;


●Windows의 32bit 버전에서 사용자의 로그인 이름을 가져 오려면?
 윈도우 API 함수인 GetuserName()을 호출함으로써 가능하다.


procedure TForm1.Button1Click(Sender : TObject);
var
 buffer : array[0..255] of char;
 buffSize : DWORD;
begin
 buffSize := sizeof(buffer);
 GetUserName(@buffer, buffSize);
 ShowMessage(buffer);
end;


char 배열을 사용한 메모리는 응용프로그램이 종료될 때 까지 free될 것이다.
이처럼 Long String를 사용할 수 있다.


procedure TForm1.button2Click(Sender : TObject);
var
 buffer : string;
 buffSize : DWORD;
begin
 buffSize := 128;
 SetLength(buffer, BuffSize);
 GetUserName(pChar(buffer), buffSize);
 ShowMessage(buffer);
end;


Long String을 사용한 메모리는 스코프가 끝날 때 해제된다.


●주어진 확장자를 가지는 프로그램들을 가져 오려면?
 다음 예는 파일 확장자를 가진 연결된 파일들 가져 오는 예이다.


uses
{$IFDEF WIN32}
 Registry; {We will get it from the registry}
{$ELSE}
 IniFiles; {We will get it from the win.ini file}
{$ENDIF}


{$IFNDEF WIN32}
 const MAX_PATH = 144;
{$ENDIF}


function GetProgramAssociation(Ext : string) : string;
var
{$IFDEF WIN32}
 reg : TRegistry;
 s : string;
{$ELSE}
 WinIni : TIniFile;
 WinIniFileName : array[0..MAX_PATH] of char;
 s : string;
{$ENFIF}
begin
{$IFDEF WIN32}
 s := '';
 reg := TRegistry.Create;
 reg.RootKey := HKEY_CLASSES_ROOOT;
 if reg.OpenKey('.' + ext + 'shellopencommand', false) <> false then begin
 {The Open command has been found}
   s := reg.ReadString('');
   reg.CloseKey;
 end else begin
   {perhaps thier is a system file pointer}
   if reg.OpenKey('.'+ext, false) <> false then begin
     s := reg.ReadString('');
     reg.CloseKey;
     if s <> '' then begin
       {A system file pointer was found}
       if reg.OpenKey(s + 'shellopencommand', false) <> false then
       {The Open command has been found}
         s := reg.ReadString('');
       reg.CloseKey;
     end;
   end;
 end;
{Delete any command kine, quotes and spaces}
 if Pos('%', s) > 0 then
   Delete(s, Pos('%', s), length(s));
 if ((length(s) > 0) and (s[1] = '"')) then
   Delete(s, 1, 1);
 if ((length(s) > 0) and (s[length(s)] = '"')) then
   Delete(s, Length(s), 1);
 while ((Length(s) > 0) and ((s[length(s)] = #32) or (s[Length(s)] = '"'))) do
   Delete(s, Length(s), 1);
{$ELSE}
 GetWindowsDirectory(WinIniFileName, sizeof(WinInifileName));
 StrCat(WinIniFileName, 'win.ini');
 WinIni := TIniFile.Create(WinIniFileName);
 s := WinIni.ReadString('Extensions', ext, '');
 WinIni.Free;
 {Delete any command line}
 if Pos(' ^', s) > 0 then
   Delete(s, Pos(' ^', s), length(s));
{$ENDIF}
 result := s;
end;


procedure TForm1.Button1click(Sender : TObject);
begin
 ShowMessage(GetProgramAssociation('gif'));
end;


●윈도우가 시작될 때마다 응용프로그램이 시작되도록 하려면?
 다음은 Windows 부트 시퀸스에 응용프로그램을 추가하는 것이다. 다음 코드는 Win32와 Win16 플랫폼에서 모두 가능하다.


uses
 Registry, {For Win32}
 IniFiles; {For Win16}


{$IFNDEF WIN32}
 const MAX_PATH = 144;
{$ENDIF}


{For Win32}
procedure TForm1.Button1Click(Sender : TObject);
var
 reg : TRegistry;
begin
 reg := TRegistry.Create;
 reg.RootKey := HKEY_LOCAL_MACJINE;
 reg.LazyWrite := false;
 reg.OpenKey('SoftwareMicrosoftWindowsCurrentVersionRun', false);
 reg.WriteString('My App', Application.ExeName);
 reg.CloseKey;
 reg.free;
end;


{for Win16}
procedure TForm1.Button2click(Sender : TObject);
var
 WinIni : TIniFile;
 WinIniFileName : array[0..MAX_PATH] of char;
 s : string;
begin
 GetWindowsDirectory(WinIniFileName, sizeof(WininiFileName));
 StrCat(WinIniFileName, 'win.ini');
 WinIni := TIniFile.Create(WinIniFileName);
 s := Winini.ReadString('windows', 'run', '');
 if s = '' then
   s := Application.ExeName else
   s := s + ';'+ Application.ExeName;
 WinIni.WriteString('windows', 'run', s);
 WinIni.Free;
end;

 

 

'Delphi' 카테고리의 다른 글

날짜/시간형식 변경 및 강제 시간세팅  (0) 2014.02.13
Q&A 정리  (0) 2014.02.13
Tip 정리  (0) 2014.02.13
올림 / 내림(버림)  (0) 2011.08.03
델파이의 소숫점 반올림 방식  (2) 2011.08.03
2014. 2. 13. 16:18

날짜/시간형식 변경 및 강제 시간세팅

procedure TForm1.Button1Click(Sender: TObject);
var
  lngLocale, UserLocale, Locate: Cardinal;
  s_time : TSystemTime;
  sysTime : String;
  iDay, iHour : Integer;
begin


  lngLocale := GetSystemDefaultLCID;
  UserLocale := GetUserDefaultLCID;
  Locate := LOCALE_ITIMEMARKPOSN;

 

  If SetLocaleInfo(lngLocale, LOCALE_SSHORTDATE, 'yyyy-MM-dd') Then
    SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0)
  Else
    ShowMessage('날짜형식 변경실패');

  If SetLocaleInfo(UserLocale, LOCALE_STIMEFORMAT, 'tt h:mm:ss') Then
    SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0)
  Else
    ShowMessage('시간형식 변경실패');

 


  // SELECT TO_CHAR(SYSDATE ,'YYYY-MM-DD HH24:MI:SS') SYSTIME FROM DUAL
  sysTime := '2014-02-03 04:40:57';

  s_time.wYear := StrToInt(Copy(sysTime, 1, 4));
  s_time.wMonth := StrToInt(Copy(sysTime, 6, 2));
  iHour := StrToInt(Copy(sysTime, 12, 2));


  If iHour <= 8 Then  // iHour = 0 -> 14시, 23 -> 08시, 24 -> 09시
  Begin
    Inc(iHour, 24);
    iDay := 1;
  End
  Else
    iDay := 0;

 

  s_time.wDay := StrToInt(Copy(sysTime, 9, 2)) - iDay;
  s_time.wHour := iHour - 9;

  s_time.wMinute := StrToInt(Copy(sysTime, 15, 2));
  s_time.wSecond := StrToInt(Copy(sysTime, 18, 2));

  SetSystemTime(s_time);


end;

 

 

'Delphi' 카테고리의 다른 글

델파이 API  (0) 2014.02.13
Q&A 정리  (0) 2014.02.13
Tip 정리  (0) 2014.02.13
올림 / 내림(버림)  (0) 2011.08.03
델파이의 소숫점 반올림 방식  (2) 2011.08.03
2014. 2. 13. 10:23

Q&A 정리

Tform
[Q1] Delphi는 Code나 Form을 어떻게 저장하나요 ?
[A1] Form은 .DFM 화일로, Code는 .PAS로 저장합니다. .DFM 화일은 이진화일이므로 IDE 상태에서 열면 Form 형태로 화면에 나타납니다.

[Q2] Form을 화면에 보이지 않도록 하려면 ?
[A2] 가장 쉬운 방법은 Form의 Left, Top 위치를 -1000 정도의 값(화면에보이지 않을 위치)으로 지정하는 것입니다.

[Q3] 스크린의 resolution에 상관없이 항상 일정한 크기로 폼을 띄우는 방법은 무엇입니까 ?
[A3] 다음과 같이 Form의 height와 width를 실행시에 조정하도록 합니다.

implementation
const
ScreenWidth: LongInt = 800; {800x600 모드에서 설계한 경우}
ScreenHeight: LongInt = 600;

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
scaled := true;
if (screen.width <> ScreenWidth) then

begin
height := longint(height) * longint(screen.height) DIV ScreenHeight;
width := longint(width) * longint(screen.width) DIV ScreenWidth;
scaleBy(screen.width, ScreenWidth);
end;
end;

[Q4] 화면크기에 따라 component의 위치와 크기를 조정하려면 ?
[A4] 다음과 같이 프로그램한 후 테스트로 Form의 크기를 조절해 봅니다.

var oldwidth, oldheight : integer ;

procedure TForm1.FormCreate(Sender: TObject);
begin
oldheight := height ;
oldwidth := width ;
end;

procedure TForm1.FormResize(Sender: TObject);
var i : integer ;
px, py, t : real ;
begin
for i:= 0 to ComponentCount -1 do
if (Components[i] is TControl) then
begin
px := oldwidth / width ;
py := oldheight / height ;
t := (Components[i] as TControl).Top ;
(Components[i] as TControl).Top := trunc(t/py) ;

t := (Components[i] as TControl).Left ;
(Components[i] as TControl).Left := trunc(t/px) ;

t := (Components[i] as TControl).height ;
(Components[i] as TControl).height := trunc(t/py) ;

t := (Components[i] as TControl).width ;
(Components[i] as TControl).width := trunc(t/px) ;
end ;
oldheight := height ;
oldwidth := width ;
end;

[Q5] 사용자가 Form의 크기를 바꾸지 못하게 하려면 ?
[A5] WM_NCHITTEST message를 받아 처리합니다.

TForm1 = class(TForm)
private
{ Private declarations }
procedure WMNCHitTest(var Message : TWMNChitTest) ; message WM_NCHITTEST;
public
{ Public declarations }
end;

procedure WMNCHitTest(var Message:TWMNChitTest) ; message WM_NCHITTEST;
begin
if Message.Result = HTBOTTOM then Message.Result := HTCLIENT ;
end ;

[Q6] 폼이 화면의 중앙에 위치하도록 만들려면 ?
[A6] 프로그램이 처음 시작될 때 중앙에 위치시키려면 폼의 Position Property를PoScreenCenter로 설정하시면 됩니다.
또는 사용자가 폼의 크기를 바꾼 후에 위치를 조정하려면 다음과 같이 합니다.

{Pascal에서는 '/' 기호 대신에 'DIV'를 사용합니다}
Form1.Left := (Screen.Width - Form1.Width) div 2;
Form1.Top := (Screen.height - Form1.height) div 2;

[Q7] Form이 생성되거나, 보여질때 실행되는 Event Handler는 무엇이고 그 순서는 ?
[A7] Form이 생성될 때 OnCreate, OnShow, OnPaint, OnActivate, OnResize,다시 OnPaint Event Handler가 실행됩니다.

[Q8] Run-time시에 프로그램에서 Form을 생성시키려면 ?
[A8] 1. Options/Project에서 Auto-create forms 리스트에 있는 form을Available forms 리스트로 옮긴다.
2. 다음과 같이 프로그램 합니다.

implemetaton
uses unit2 ; {TForm2가 정의되어 있는 unit을 use 시킨다.}

procedure TForm1.Button1Click(Sender : TObject) ;
var f : TForm2 ;
begin
try
f := TFrom2.Create(Self) ;
f.ShowModal ;
finally
f.Free ;
end ;
end ;


Create Method는 새로운 폼을 생성하지만, 이미 생성된 폼은 절대 삭제되지않습니다. 그러므로 폼은 Free Method를 사용하여 자신의 Resource를 Free 시켜야합니다. 그렇지 않으면 위의 Event Handler가 실행될 때 마다 Windows Resource가감소될 것입니 다.

[Q9] Form을 Maximize하려면 ?
[A9] Resize event에서 폼의 크기를 조절하면 됩니다.
만약 이렇게 했을 때 뻔쩍거리는 현상이 나타난다면 다음과 같이 해 보십시오.

Form의 private section에 다음을 추가합니다.
procedure mymax(var m: TWMGETMINMAXINFO); message wm_getminmaxinfo;

다음 procedure를 implemetatoin section에 추가합니다.
procedure yourForm.mymax(var m : TWMGETMINMAXINFO);
begin
m.minmaxinfo^.ptmaxsize.x := screen.width;
m.minmaxinfo^.ptmaxsize.y := screen.height;
m.minmaxinfo^.ptmaxposition.x := 0;
m.minmaxinfo^.ptmaxposition.y := 0;
end;

[Q10] Form의 title bar를 없애려면 ?
[A10] 다음 procedure를 사용해 보십시오.

Procedure TYourFormName.HideTitlebar;
Var
Save : LongInt;
Begin
If BorderStyle=bsNone then Exit;
Save:=GetWindowLong(Handle,gwl_Style);
If (Save and ws_Caption)=ws_Caption then Begin
Case BorderStyle of
bsSingle, bsSizeable :
SetWindowLong(Handle,gwl_Style,Save and (Not(ws_Caption)) or ws_border);
bsDialog :
SetWindowLong(Handle,gwl_Style,Save and (Not(ws_Caption)) or ws_modalframeor ws_dlgframe);
End;
Height:=Height-getSystemMetrics(sm_cyCaption);
Refresh;
End;
end;


Procedure TYourFormName.ShowTitlebar;
Var
Save : LongInt;
begin
If BorderStyle=bsNone then Exit;
Save:=GetWindowLong(Handle,gwl_Style);
If (Save and ws_Caption)<>ws_Caption then Begin
Case BorderStyle of
bsSingle, bsSizeable :
SetWindowLong(Handle,gwl_Style,Save or ws_Caption or ws_border);
bsDialog :
SetWindowLong(Handle,gwl_Style,Save or ws_Caption or ds_modalframe or ws_dlgframe);
End;
Height:=Height+getSystemMetrics(sm_cyCaption);
Refresh;
End;
end;


[Q11] form event(onCreate, onPaint, 등)들이 실행되기 전에 form이 보이도록 하려면 ?
[A11] onCreate event에 "Visible := True"를 추가합니다.

[Q12] 크기 조정이 가능한 multi-split window를 어떻게 만듭니까 ?
[A12] 다음과 같이 합니다.

1) Memo 를 폼에 놓고 그것의 Align 프로퍼티를 alTop 으로 지정합니다.
2) Panel 을 폼에 놓고 Align 프로퍼티를 alTop 으로 지정합니다.
3) Panel의 Height 프로퍼티를 6이나 7쯤으로 둡니다.
4) Panel의 DragMode 프로퍼티를 dmAutomatic으로 둡니다.
5) Panel의 DragCursor 프로퍼티를 crVSplit으로 둡니다.
6) Panel의 Cursor 프로퍼티를 crVSplit으로 둡니다.
7) 또 다른 Memo를 폼에 놓고 Align 프로퍼티를 alClient로 둡니다.
8) Memo 와 Panel을 한꺼번에 선택하고, 다음의 OnDragOver핸들러를 연결합니다.

procedure TForm1.Memo1DragOver(Sender, Source : TObject;
X, Y : Integer; State: TDragState; var Accept: Boolean);
begin
Accept := False;
if Source = Panel1 then begin
Accept := True;
Memo1.Height := Y + (Sender as TControl).Top;
end;
end;

[Q13] Dialog box는 어떻게 사용합니까 ?
[A13] 다음과 같이 사용합니다.

FontDialog1.Font.Assign(Edit1.Font) ;
if FontDialog1.Execute then Edit1.Font.Assign(FontDialog1.Font) ;

[Q14] OnActivate Event에서 Form의 FormStyle 특성을 변경하려면 'CannotChange Visible in OnShow or OnHide' Error가 발 생합니다. 그 이유는 ?
[A14] FormStyle는 Window가 생성될때 결정되며, OnCreate Event에서 일반적인설정이 이루어 집니다. 그러므로 OnShow나 OnHid e, OnActivate event에서 사용될수 없습니다.

[Q15] 윈도우에서 폼이나 Image component를 Byte-Align하는 방법은 ?
[A15] CreateParams Method를 사용합니다.

Procedure TMyForm.CreateParams(Var Params : CreateParams);
Begin
inherited CreateParams(Params);
Style := Style or CS_BYTEALIGNWINDOWS;
End;

모든 고해상의 Video 모드들은 항상 Byte-Align이므로 위의 Code는 Monochrome,EGA, 16Color VGA 모드에서 의미가 있습니다.

[Q16] OnCloseQuery Event는 언제 사용합니까 ?
[A16] 일반적으로 onClose와 onCloseQuery는 해당 form이 close될 때 발생합니다.차이점은 onClose는 해당폼이 close할때 만 발생하지만 OnCloseQuery는 Parentform이 close될때도 발생됩니다.

TMemo
[Q17] TMemo에서 cursor가 있는 line 번호를 알수 있습니까 ?
[A17] EM_LINEFROMCHAR, EM_LINEINDEX 라는 Windows 메세지를 사용하여알 수 있습니다.

procedure GetMemoLine(Memo : TCustomMemo; var MemoLine, MemoCol : integer) ;
var
LineNum : Longint;
CharsBeforeLine : Longint;
begin
LineNum := SendMessage(Memo.Handle, EM_LINEFROMCHAR, Memo.SelStart, 0);
CharsBeforeLine := SendMessage(Memo.Handle, EM_LINEINDEX, LineNum, 0);
MemoLine := LineNum + 1;
MemoCol := Memo.SelStart - CharsBeforeLine + 1;
end;

procedure SetMemoLine(Memo : TCustomMemo; MemoLine, MemoCol : integer );
begin
Memo.SelStart := SendMessage(Memo.Handle,EM_LINEINDEX,MemoLine-1,0)+MemoCol-1;
end ;

[Q18] TMemoField와 TMemo간에 데이타를 주고 받으려면 ?
[A18] TMemo의 내용을 TMemoField로 보내려면 다음과 같이 합니다.

Table.Edit ;
TMemoField.Assign( TMemo.Lines );

반대로 TMemoField의 내용을 TMemo로 보내려면 다음과 같이 합니다.
VAR aBlobStream : TBlobStream;

aBlobStream := TBlobStream.Create(TMemoField, bmRead);
TMemo.Lines.LoadFromStream( aBlobStream );
aBlobStream.Free;

[Q19] TMemo에서 Tab Stop을 설정할 수 있습니까?
[A19] 다중열을 편집할 때 Tab키를 사용하기 위해 Tab Stop을 지정하는정수값 갯수와 Tab Stop 값을 가지고 있는 array po inter를 parameter로 EM_SetTabStops메세지를 TMemo component로 보냅니다.
또한 TMemo의 WantTabs property를 True로 설정하셔야 합니다.

Procedure TForm1.FormCreate(Sender:TObject);
const
TabInc:LongInt = 10;
Begin
SendMessage(Meno1.Handle,EM_SetTabStops,1,Longint(@TabInc));
End;

[Q20] Delphi에서 Memo 필드의 크기는 무엇입니까?
[A20] Delphi의 TEdit와 TMemo component는 MS Windows상의 응용프로그램이사용하는 일반 Edit Control 입니다.
그러므로 Windows가 제공하는 Edit Control은 공통적으로 32KB의 한계를 가지고있습니다.

[Q21] 한번에 TMemo나 TListBox에 여러줄의 데이타를 한번에 채울 수 있는 방법이 있습니까?
[A21] TMemo나 TListbox Component의 SetText Method를 사용할 수 있습니다.
각각을 행을 구분하기 위해 Carriage Return 문자인 #13을 사용합니다.
예를 들어, 다음과 같이 사용합니다.

Memo1.Lines.SetText('aaaaa'#13'bbbbb'#13'ccccc')

그러나 Memo나 Listbox를 채우기 위해서는 Lines나 Items의 method를 사용하여추가하는 것이 무난합니다.

TListBox, TComboBox, TCheckBox
[Q22] 여러개의 CheckBox가 동일한 event handler를 사용할 때 각각의 checkbox에 대해 별개의 작업을 하도록 하려면 ?
[A22] TGroupBox내에 여러개의 checkbox를 위치시킵니다. 설계 또는 실행시에checkbox의 Click event handler를 동일하게 지정한 후에 그 event handler에서는다음과 같이 프로그램하면 됩니다.

for i := 0 to GroupBox1.ControlCount -1 do
if (GroupBox1.Controls[i] as TCheckBox).checked then
begin
if (GroupBox1.Controls[i] as TComponent).name = 'CheckBox1' then
{do something}
else if (GroupBox1.Controls[i] as TComponent).name = 'CheckBox2' then
{do something}
end ;

[Q23] 실행시에 ComboBox 컴포넌트가 초기값을 갖도록 하려면 ?
[A23] ComboBox의 Items에 여러 항목을 추가한 후에 실행중에 ComboBox1.ItemIndex를원하는 index 번호로 지정하면 됩니다 .

[Q24] Add Method를 사용하여 ListBox에 새로운 아이템을 추가할 때, Item이화면에 보이는 것보다 더 많이 있다면 추가된 아이템은 보이지 않습니다. Add와동시에 추가된 항목을 보려면 ?
[A24] 다음과 같이 설정하시면 됩니다.

ListBoxName.Items.ADD('XXX')
ListBoxName.ItemIndex := ListBoxName.Items.Count - 1

[Q25] ListBox에서 오른쪽으로 문자를 정렬하려면 ?
[A25] property로 제공되는 것은 없습니다. 스트링의 앞쪽으로 공백을 채우는형태로 사용할 수 있습니다.

[Q26] Multi-Column Listbox를 만드는 방법은 무엇입니까 ?
[A26] 일반적으로 Listbox에는 하나의 column에 대한 data를 나타낼 수있습니다. 그러나 Listbox의 canvas property와 onD rawItem event를 이용하여여러 column으로 data를 보이게 할 수 있습니다. column구별과 제목 표시를위하여 Header component 를 이용합니다. onDrawItem event procedure에 구현된대로data가 display되도록 하기 위해서는 Listbox의 Style property를 lbO wnerDrawFixed나lbOwnerDrawVariable로 설정해야 합니다.

Listbox의 각 column의 기본 너비를 결정하기 위해 header component의
각 SectionWidth 값을 form의 onCreate event에 정의합니다.

procedure TForm1.FormCreate(Sender: TObject);
begin
Header1.SectionWidth[0] := 80;
Header1.SectionWidth[1] := 100;
Header1.SectionWidth[2] := 100;
end;

다음과 같은 방법으로 Listbox에 data를 입력합니다. column은 3개이며 각 column의구별자는 #9(VK_TAB)를 이용합니다.

ListBox1.Items.Add('1000'+#9+'홍길동'+#9+'연구소');

Listbox의 onDrawItem event에서는 주어진 Header component의 SectionWidth만큼 rect를 구하여서 #9 구분자를 이용하여 data 를 parsing한다음, ListboxCanvas에 해당 data를 display 합니다.

procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;Rect: TRect; State: TOwnerDrawState);
var r1, r2, r3 : TRect;
tmp : string;
ind : byte;
begin
r1 := Rect;
r1.Right := Header1.SectionWidth[0];
r2 := Rect;
r2.left := r1.right + 1;
r2.right := r2.left + Header1.SectionWidth[1];
r3 := Rect;
r3.left := r2.right + 1;
tmp := TListBox(Control).Items[Index];
with TListBox(Control).Canvas do begin
FillRect(Rect);
ind := Pos(#9, tmp);
TextRect(r1, r1.left, r1.top, copy(tmp, 1, ind-1));
tmp := Copy(tmp, ind+1, Length(tmp)-ind+1);
ind := Pos(#9, tmp);
TextRect(r2, r2.left, r2.top, copy(tmp, 1, ind-1));
tmp := Copy(tmp, ind+1, Length(tmp)-ind+1);
TextRect(r3, r3.left, r3.top, tmp);
end;
end;

Listbox의 각 column이 resizing 될 수 있도록 header component를 resize했을경우에는 Listbox를 다시 그릴 수 있도록 합니다 .

procedure TForm1.Header1Sized(Sender: TObject; ASection, AWidth: Integer);
begin
Listbox1.Invalidate;
end;


[Q27] Listbox에 Bitmap(또는 Icon)을 display하는 방법은 무엇입니까 ?
[A27] 이것 역시 Listbox의 canvas property와 onDrawItem event를 이용합니다.
style property도 역시 lbOwnerDrawFixed나 lbOwnerDrawVariable로 설정해야합니다.

Listbox에 bitmap 또는 icon data를 추가하는 방법은 AddObject method를 이용합니다.

ListBox1.Items.AddObject('Bitmap', Image1.Picture.Bitmap);
ListBox2.Items.AddObject('Icon', Image2.Picture);

procedure TForm1.ListBox1DrawItem(Control:TWinControl; Index:Integer; Rect:TRect;State: TOwnerDrawState);
var Bitmap : TBitmap;
begin
with Listbox1.Canvas do begin
FillRect(Rect);
Bitmap := TBitmap(Listbox1.Items.Objects[index]);
BrushCopy(Bounds(Rect.Left + 2, Rect.Top, Bitmap.Width, Bitmap.Height),Bitmap, Bounds(0, 0, Bitmap.Width, Bi tmap.Height), clRed);
TextOut(Rect.Left+50, Rect.Top, Listbox1.Items[Index]);
end;
end;

procedure TForm1.ListBox2DrawItem(Control:TWinControl; Index:Integer; Rect:TRect;State: TOwnerDrawState);
var Pic : TPicture;
begin
with Listbox2.Canvas do begin
FillRect(Rect);
Pic := TPicture(Listbox2.Items.Objects[index]);
Draw(Rect.Left, Rect.Top, Pic.Graphic);
TextOut(Rect.Left+50, Rect.Top, Listbox2.Items[Index]);
end;
end;


[Q28] Listbox에서 특정 index의 font/background color를 어떻게 바꿀 수 있습니까 ?
[A28] canvas property와 onDrawItem event를 이용합니다.

procedure TForm1.ListBox1DrawItem(Control:TWinControl; Index:Integer; Rect:TRect;State: TOwnerDrawState);
begin
with TListBox(Control).Canvas do begin
if Index = 2 then begin
Brush.Color := clYellow;
Font.Color := clBule;
end;
FillRect(Rect);
TextRect(Rect, Rect.left, Rect.top, Listbox1.Items[Inex]);
end;
end;

[Q29] ListBox에서 수평 스크롤바를 표시하기 위해 어떻게 합니까?
[A29] ListBox의 윈도우를 조작하기 위해 LB_SetHorizontalExtent 메세지를보냅니다. 예를 들어 폼의 OnCreate에서 메세지 를 보낼 수 있습니다.

Procedure TForm1.FormCreate(Sender:TObject);
Begin
SendMessage(Listbox1.Handle,LB_SetHorizontalExtent, 1000,Longint(0));
End;

StringGrid
[Q30] StringGrid에서 Options property의 goEditing을 TRUE로 한 후 StringGrid에서직접 편집을 하려고 한다. 그런데 cursor 가 보이지 않습니다. cursor를 보이게 하려면 ?
[A30] DefaultRowHeight property를 조절해 보십시오. 화면의 해상도와글꼴의 크기에 따라 다르긴 하지만 18 또는 22 이상 으로 조정해 보십시오.

[Q31] StringGrid의 Color를 부분적으로 바꾸려면 ?
[A31] DrawCell event handler를 다음과 같이 작성합니다.

procedure TForm1.StringGrid1DrawCell(Sender:TObject; Col,Row:Longint; Rect:TRect;State: TGridDrawState);
begin

{if gdFocused in State then}
if (Col >= StringGrid1.FixedCols) and (Row >= StringGrid1.FixedRows)then
with (Sender as TStringGrid).Canvas do
begin
if (Row = 1) and (Col = 1)then
Brush.Color := clRed
else Brush.Color := clBlue ;
FillRect(Rect) ;
TextOut(Rect.Left, Rect.Top, StringGrid1.Cells[Col,Row]) ;
end ;
end;

[Q32] StringGrid에서 입력된 데이타의 종류에 따라 정렬하는 방법은 무엇입니까?
[A32] StringGrid의 DrawCell event를 이용합니다.

procedure TForm1.StringGrid1DrawCell(Sender:TObject; Col,Row:Longint; Rect:TRect;State: TGridDrawState);
var
Left,code, V : integer;
ConvertString : String;
DataInCell : string;
begin
DataInCell := StringGrid1.Cells[col,row];
if DataInCell = '' then exit;
with StringGrid1.Canvas do begin
FillRect(Rect);
if (row = 0) or (col = 0) then
Left := Rect.Left + ((Rect.Right-Rect.Left) - TextWidth(DataInCell)) div2
else begin
val(DataInCell, V, code);
if (code = 0) and (col <> 0) then begin
DataInCell := FormatFloat('\#,##0', StrToInt(DataInCell));
Left := Rect.Right - TextWidth(DataInCell) - 3;
end
else Left := Rect.Left + 3;
end;
TextRect(Rect, Left, Rect.Top, DataInCell);
end;
end;

 

[Q33] StringGrid의 값을 오른쪽으로 정렬하려면 ?
[A33] DrawDell event handler를 다음과 같이 작성합니다.

procedure TForm1.StringGrid1DrawCell(Sender:TObject; Col,Row:Longint, Rect:TRect;State: TGridDrawState);
var oldalign : word;
begin
if (row=0) or (col<2) then {set the headings in bold}
StringGrid1.canvas.font.style := StringGrid1.canvas.font.style + [fsbold];

if col<>1 then
begin
oldalign:=settextalign(StringGrid1.canvas.handle,ta_right);
StringGrid1.canvas.textrect(rect,rect.right-2,rect.top+2,
StringGrid1.cells[col,row]);
settextalign(StringGrid1.canvas.handle,oldalign);
end
else
StringGrid1.canvas.textrect(rect,rect.left+2,rect.top+2,
StringGrid1.cells[col,row]);

StringGrid1.canvas.font.style:=StringGrid1.canvas.font.style-[fsbold];
end;


[Q34] TStringGrid에서 wrap을 지원하려면 ?
[A34] 다음과 같이 TStringGrid로 부터 새로운 component를 만듭니다.

TWrapGrid = class(TStringGrid)
private
{ Private declarations }
protected
{ Protected declarations }
{ This DrawCell procedure wraps text in the grid cell }
procedure DrawCell(ACol, ARow : Longint; ARect : TRect; AState : TGridDrawState);override;
public
{ Public declarations }
{ The Create procedure is overriden to use the DrawCell procedure by
default }
constructor Create(AOwner : TComponent); override;
published
{ Published declarations }
end;


constructor TWrapGrid.Create(AOwner : TComponent);
begin
{ Create a TStringGrid }
inherited Create(AOwner);

{ Make the drawing use our DrawCell procedure by default }
DefaultDrawing := FALSE;
end;


{ This DrawCell procedure wraps text in the grid cell }
procedure TWrapGrid.DrawCell(ACol, ARow : Longint; ARect : TRect;
AState : TGridDrawState);
var
Sentence, { What is left in the cell to output }
CurWord : String; { The word we are currently outputting }
SpacePos, { The position of the first space }
CurX, { The x position of the 'cursor' }
CurY : Integer; { The y position of the 'cursor' }
EndOfSentence : Boolean; { Whether or not we are done outputting the cell}
begin
{ Initialize the font to be the control's font }
Canvas.Font := Font;

with Canvas do begin
{ If this is a fixed cell, then use the fixed color }
if gdFixed in AState then begin
Pen.Color := FixedColor;
Brush.Color := FixedColor;
end
else begin { else, use the normal color }
Pen.Color := Color;
Brush.Color := Color;
end;

{ Prepaint cell in cell color }
Rectangle(ARect.Left, ARect.Top, ARect.Right, ARect.Bottom);
end;

{ Start the drawing in the upper left corner of the cell }
CurX := ARect.Left;
CurY := ARect.Top;

Sentence := Cells[ACol, ARow]; { Here we get the contents of the cell }

{ for each word in the cell }
EndOfSentence := FALSE;
while (not EndOfSentence) do begin
{ to get the next word, we search for a space }
SpacePos := Pos(' ', Sentence);
if SpacePos > 0 then begin
{ get the current word plus the space }
CurWord := Copy(Sentence, 0, SpacePos);

{ get the rest of the sentence }
Sentence := Copy(Sentence, SpacePos + 1, Length(Sentence) - SpacePos);
end
else begin
{ this is the last word in the sentence }
EndOfSentence := TRUE;
CurWord := Sentence;
end;

with Canvas do begin
{ if the text goes outside the boundary of the cell }
if (TextWidth(CurWord) + CurX) > ARect.Right then begin
{ wrap to the next line }
CurY := CurY + TextHeight(CurWord);
CurX := ARect.Left;
end;

{ write out the word }
TextOut(CurX, CurY, CurWord);
{ increment the x position of the cursor }
CurX := CurX + TextWidth(CurWord);
end;
end;
end;


메뉴
[Q35] Help 메뉴를 메뉴바 우측 가장자리로 정렬시키려면 ?
[A35] 설계시에는 할 수 없습니다. MenuItem의 Name property를 Help 라고할 때 실행시에 폼의 'OnCreate handler'에 다음 과 같이 추가합니다.

Help.Caption := #8 + Help.Caption;

단, 윈도우 95에서는 실행되지 않을 수 있습니다.

[Q36] Copy, Cut, Paste와 Undo에 대한 CTRL-C, CTRL-X, CTRL-Y, CTRL-Z키는 그냥 사용할 수 있습니다. 그러나 이들을 메뉴바에서 선택하게 하려면?
[A36] 예를 들면 다음과 같이 합니다.

procedure TForm1.Menu1Click(Sender: TObject);
begin
if ((ActiveControl) is TCustomEdit) then TEdit(ActiveControl).CutToClipBoard;
end;

procedure TForm1.Menu2Click(Sender: TObject);
begin
if ((ActiveControl) is TCustomEdit) then TEdit(ActiveControl).ClearSelection;
end;

[Q37] 어떤 component가 Popup 메뉴를 동작시켰는지 아는 방법은 ?
[A37] 다음과 같이 PopupComponent property를 사용합니다.

Procedure TForm1.PopupItem1Click(Sender: TObject);
begin
Label1.Caption := PopupMenu1.PopupComponent.ClassName;
End;

1.5 DDE
[Q38] DDE 기능을 사용하여 다른 응용프로그램으로 Data를 전달하고자 합니다.어떻게 하나요 ?
[A38] TDdeClientConv과 TDdeClientItem component를 사용합니다.

DdeClientItem1의 DdeConv property를 DdeClientConv1로 선택합니다.
그리고 Data를 전달하는 방법은 다음과 같습니다.

var P : array [0..10] of char ;
begin
DDEClientConv1.SetLink('Excel','Sheet1');
try
DDEClientConv1.OpenLink;
DDEClientItem1.DDEItem:= 'R1C1';
DDEClientConv1.PokeData(DDEClientItem1.DDEItem, StrPCopy(P, 'Test')) ;
finally
DDEClientConv1.CloseLink;
end;
end ;

[Q39] Windows 프로그램 Group을 만들고 그 그룹에 item을 추가하려면 ?
[A39] 프로그램 Group을 만드는 방법은다음과 같습니다.

procedure TForm1.CreateButtonClick(Sender: TObject);
var
Name: string;
Macro: string;
Cmd: array[0..255] of Char;
begin
if GroupName.Text = '' then
MessageDlg('Group name can not be blank.', mtError, [mbOK], 0)
else
begin
Name := GroupName.Text;
Macro := Format('[CreateGroup(%s)]', [Name]) + #13#10;
StrPCopy (Cmd, Macro);

DDEClient.OpenLink;
if not DDEClient.ExecuteMacro(Cmd, False) then
MessageDlg('Unable to create group.', mtInformation, [mbOK], 0);
DDEClient.CloseLink;
end;
end;

해당 Group에 item을 추가하는 방법은 다음과 같습니다.

procedure TForm1.Button1Click(Sender: TObject);
var
item,command,dir: string;
Macro: string;
Cmd: array[0..255] of Char;
begin
item := ItemName.text;
command := CmdLine.text;
dir := WorkDir.Text;

Macro := Format('[AddItem(%s,%s)]', [command,item,dir]) + #13#10;
StrPCopy (Cmd, Macro);

DDEClient.OpenLink;
if not DDEClient.ExecuteMacro(Cmd, False) then
MessageDlg('Unable to create item.', mtInformation, [mbOK], 0);
DDEClient.CloseLink;
end;


ReportSmith
[Q40] ReportSmith에서 Server DB에 연결하여 보고서를 작성한 후에 Delphi프로그램에서 Report를 실행시키면 또다시 server l ogin을 위해 Dialog가 나타납니다.이 과정을 매번 하지 않으려면 ?
[A40] ReportSmith component의 connect method를 사용합니다.

Report1.Connect(ctOracle, 'T:lambda:ORA7', 'scott', 'tiger', '') ;
Rpoert1.Run ;

위의 ctOracle과 같은 Server Type을 정의하는 상수는 DELPHI\SOURCE\VCL\REPORT.PAS화일에 정의되어 있습니다.

[Q41] ReportSmith에서 테이블의 특정 필드를 다른 문자열로 대치하고자합니다. 어떻게 하면 좋을까요 ?
[A41] Derived Field를 macro를 사용하도록 정의합니다.
그리고 다음과 같이 macro를 작성하면 Derived Field가 추가됩니다.

Sub Test()
if Field$("필드명") = "TRUE" then
DerivedField "참값"
else
DerivedField "거짓값"
end if
End Sub

[Q42] Report Variable로 값을 넘겨주는 방법은 ?
[A42] Report component의 ReportName property에 ReportSmith에서 작성된보고서를 선택합니다. 그리고 나서 다음과 같이 프로그램 합니다.

Report1.InitialValues.Clear ;

{integer형 변수}
Report1.InitialValues.Add('@empno=<''' + Edit1.Text + '''>') ;

{string형 변수}
Report1.InitialValues.Add('@enddate=<''' + Edit2.Text + '''>') ;

{date형 변수}
{ReportSmith에서 Date Type의 variable을 정의할 때 Format을 mm/dd/yy로 설정하고,Edit3.Text 에는 월/일/년의 순서로 입력 되었다고 가정한다.}
Report1.InitialValues.Add('@saledate=<''' + Edit3.Text + '''>') ;

{ReportSmith Run-Time 구동}
Report1.Run ;

ChartFX
[Q43] Chart에 Value를 assign 하는 방법은 ?
[A43] 다음과 같이 프로그램 합니다.

{MAKELONG의 1st parameter:series 갯수, 2nd parameter:value 갯수}
ChartFX1.OpenData[COD_VALUES] := MAKELONG(2, 3);

ChartFX1.ThisSerie := 0;
ChartFX1.Value[0] := 30;
ChartFX1.Value[1] := 20;
ChartFX1.Value[2] := 40;

ChartFX1.ThisSerie := 1;
ChartFX1.Value[0] := 45;
ChartFX1.Value[1] := 60;
ChartFX1.Value[2] := 30;

ChartFX1.CloseData[COD_VALUES] := 0;

[Q44] Chart의 Title, Legend, Series Legend 추가하는 방법은 ?
[A44] 다음과 같이 프로그램 합니다.

ChartFX1.pType := ChartFX1.pType or CT_LEGEND or CT_SERLEGEND ;

ChartFX1.Title[CHART_BOTTOMTIT] := 'Person'; {X축 Title}
ChartFX1.Title[CHART_LEFTTIT] := 'Sales'; {Y축 Title}

ChartFX1.YLeg[0] := 'Really Bad';
ChartFX1.YLeg[1] := 'Bad';
ChartFX1.YLeg[2] := 'Regular';
ChartFX1.YLeg[3] := 'Good';
ChartFX1.YLeg[4] := 'Excellent';

{ Tell Chart FX how to use the legends (GAP) }
ChartFX1.Adm[CSA_YLEGGAP] := 20;

{ Set the legends }
ChartFX1.Legend[0] := 'Peter Gabriel';
ChartFX1.KeyLeg[0] := 'PG';
ChartFX1.Legend[1] := 'Phil Collins';
ChartFX1.KeyLeg[1] := 'PC';
ChartFX1.Legend[2] := 'Bruce Springsteen';
ChartFX1.KeyLeg[2] := 'BS';
ChartFX1.Legend[3] := 'Tracy Chapman';
ChartFX1.KeyLeg[3] := 'TC';
ChartFX1.Legend[4] := 'Big Mamma Thornton';
ChartFX1.KeyLeg[4] := 'BM';
ChartFX1.Legend[5] := 'Paul Simon';
ChartFX1.KeyLeg[5] := 'PS';
ChartFX1.Legend[6] := 'Louis Armstrong';
ChartFX1.KeyLeg[6] := 'LA';
ChartFX1.Legend[7] := 'John Lennon';
ChartFX1.KeyLeg[7] := 'JL';

{ Series Legends }
ChartFX1.SerLeg[0] := 'First Test';
ChartFX1.SerLeg[1] := 'Second Test';

ChartFX1.LeftGap := 70;


[Q45] Chart를 3차원으로, 배경 Color, Font 정보를 바꾸는 방법은 ?
[A45] 다음과 같이 프로그램 합니다.

ChartFX1.View3D := True;
ChartFX1.Angles3D := MAKELONG(30, 60);

ChartFX1.Grid := CHART_HORZGRID;

ChartFX1.RGBBk := RGB(0, 255, 0);
ChartFX1.RGB2DBk := RGB(200, 20, 90);
ChartFX1.RGB3DBk := RGB(200, 20, 90);

ChartFX1.Title[CHART_BOTTOMTIT] := 'Times Font';
ChartFX1.Font[CHART_BOTTOMFT] := CF_TIMES OR CF_BOLD OR 12;
ChartFX1.RGBFont[CHART_BOTTOMFT] := RGB(255, 0, 0);


[Q46] Chart의 Status Line을 그리는 방법은 ?
[A46] 다음과 같이 프로그램 합니다.

ChartFX1.OpenData[COD_STATUSITEMS] := 4;
l:= chart_SetStatusItem(ChartFX1.Handle,0,True,101,True,100,50,4,CHART_STLEFT);
l:= chart_SetStatusItem(ChartFX1.Handle,1,True,102,False,80,80,5,CHART_STCENTER);
l:= chart_SetStatusItem(ChartFX1.Handle,2,False,0,True,40,40,10,0);
l:= chart_SetStatusItem(ChartFX1.Handle,3,True,103,True,50,30,4,CHART_STRIGHT);
ChartFX1.CloseData[COD_STATUSITEMS] := 4;

ChartFX1.StatusText[101] := 'Text 1';
ChartFX1.StatusText[102] := 'Text 2';
ChartFX1.StatusText[103] := 'Text 3';
ChartFX1.ShowStatus := True;


[Q47] Chart에서 Y축 계열값의 특정 범위를 구별되게 표시하려면 ?
[A47] 다음과 같이 프로그램 합니다.

procedure TForm1.FormCreate(Sender: TObject);
begin
ChartFX1.OpenData[COD_STRIPES] := 1;
chart_SetStripe(ChartFX1.Handle,0,25,50,RGB(128,0,128));
ChartFX1.CloseData[COD_STRIPES] := 0;
end ;

procedure TForm1.ChartFX1LButtonDblClk(Sender: TObject; var X, Y, nSerie,
nPoint, nRes: Integer);
var
sx,sy,sPoint,sSerie: String;
dValue: Double;
begin
Str(X, sX);
Str(Y, sY);
Str(nPoint, sPoint);
Str(nSerie, sSerie);

If (nSerie = -1) OR (nPoint = -1) Then
MessageDlg('Empty DobleClick X:' + sX + ' Y:' + sY, mtWarning, [mbOK],0)
Else
begin
ChartFX1.ThisSerie := nSerie;
dValue := ChartFX1.Value[nPoint];
If (dValue < 25) Then
nRes := 1
Else
If (dValue < 50) Then
ChartFX1.HText := 'Value between 25 and 50'
end
end;


[Q48] Chart의 각 Point에서 Menu를 사용하게 하려면 ?
[A48] Chart의 OnMenu event handler를 다음과 같이 작성합니다.

procedure TForm1.ChartFX1Menu(Sender: TObject; var wParam, nSerie, nPoint,
nRes: Integer);
var
s1, s2, s3 : string[10];
begin
Str(wParam-1, s1);
Str(nPoint, s2);
Str(nSerie, s3);
MessageDlg('Menu Option:'+s1+' nPoint:'+s2+' nSerie:'+s3, mtWarning, [mbOK],0);
end;

단, 다음과 같이 Chart의 property에 보이고자 하는 Popup 메뉴를 지정해야합니다.

ChartFX1.RigClk[CHART_MENUCLK] := PopupMenu1.Handle;

1.8 VBX
[Q49] VBX datatype(예를 들면 TBasicString)의 선언과 이들 Datatype을 다루기 위한 기능은 어디에 있습니까?
[A49] 모든 VBX와 관련된 datatype과 기능은 \DELPHI\DOC 디렉토리에 있는VBXCTRL.INT라는 화일에 Interface 부분이 준비 되어 있습니다. VBXCtrl Unit의내용에 있는 정보는 완전한 실제 Source입니다.

[Q50] application에서 VBX를 사용할 때 어떤 file을 배포해야 합니까 ?
[A50] 사용된 VBX file과 Windows\System directory에 있는 BIVBX11.Dllfile을 배포하면 됩니다.

[Q51] 가지고 있는 VBX를 Delphi에 load할려고 했으나 되지가 않습니다.왜 그렇습니까 ?
[A51] Delphi는 VBX 1.0 버전만 지원합니다. 가지고 있는 VBX가 2.0 또는3.0일 경우는 사용할 수가 없습니다.

1.9 기타 component
[Q52] 응용프로그램의 icon을 가져와서 특정 SpeedButton에 보여주려면 ?
[A52] 다음과 같이 프로그램 합니다.

procedure TForm1.Button1Click(Sender: TObject);
var
imgIcon: TIcon;
imgRect: TRect;
begin
imgIcon := TIcon.Create;
imgIcon.Handle := ExtractIcon(handle, 'project1.exe', 0 );

with SpeedButton1.Glyph do begin
Width := imgIcon.Width;
Height := imgIcon.Height;
imgRect := Rect( 0, 0, Width, Height );
Canvas.Draw(0,0, imgIcon);
end;
end ;

[Q53] Bitmap을 다른 component에 투명하게 보이도록 만들려면 ?
[A53] 아래의 DrawTransparent procedure를 사용합니다.
이 procedure는 bitmap에서 투명하게 보이고자 하는 부분의 색을 지정하면 그부분은 바탕의 다른 component 색을 그대로 유지 시킵니다.

t = 대상 canvas
x,y = bitmap을 write할 위치
s = 그리고자 하는 bitmap
TrCol = 그리고자 하는 bitmap에서 투명하게 보일 부분의 색

주의: 대상 component를 반드시 다시 그려야 함. (즉 Image1.Invalidate)

procedure DrawTransparent(t: TCanvas; x,y: Integer; s: TBitmap; TrCol:TColor);
var
bmpXOR, bmpAND, bmpINVAND, bmpTarget: TBitmap;
oldcol: Longint;
begin
try
bmpAND := TBitmap.Create;
bmpAND.Width := s.Width;
bmpAND.Height := s.Height;
bmpAND.Monochrome := True;
oldcol := SetBkColor(s.Canvas.Handle, ColorToRGB(TrCol));
BitBlt(bmpAND.Canvas.Handle, 0,0,s.Width,s.Height, Canvas.Handle, 0,0,SRCCOPY);
SetBkColor(s.Canvas.Handle, oldcol);

bmpINVAND := TBitmap.Create;
bmpINVAND.Width := s.Width;
bmpINVAND.Height := s.Height;
bmpINVAND.Monochrome := True;
BitBlt(bmpINVAND.Canvas.Handle, 0,0,s.Width,s.Height, bmpAND.Canvas.Handle,0,0, NOTSRCCOPY);

bmpXOR := TBitmap.Create;
bmpXOR.Width := s.Width;
bmpXOR.Height := s.Height;
BitBlt(bmpXOR.Canvas.Handle, 0,0,s.Width,s.Height, s.Canvas.Handle, 0,0,SRCCOPY);
BitBlt(bmpXOR.Canvas.Handle, 0,0,s.Width,s.Height, bmpINVAND.Canvas.Handle,0,0, SRCAND);

bmpTarget := TBitmap.Create;
bmpTarget.Width := s.Width;
bmpTarget.Height := s.Height;
BitBlt(bmpTarget.Canvas.Handle, 0,0,s.Width,s.Height, t.Handle, x,y, SRCCOPY);
BitBlt(bmpTarget.Canvas.Handle, 0,0,s.Width,s.Height, bmpAND.Canvas.Handle,0,0, SRCAND);
BitBlt(bmpTarget.Canvas.Handle, 0,0,s.Width,s.Height, bmpXOR.Canvas.Handle,0,0, SRCINVERT);
BitBlt(t.Handle, x,y,s.Width,s.Height, bmpTarget.Canvas.Handle, 0,0, SRCCOPY);
finally
bmpXOR.Free;
bmpAND.Free;
bmpINVAND.Free;
bmpTarget.Free;
end;{End of TRY section}
end;


[Q54] Clipboard의 자료를 가져오는 방법은 ?
[A54] 다음과 같이 프로그램 합니다.

var
Buffer: PChar;
MyHandle : THandle;
TextLength : intger ;
begin
MyHandle := Clipboard.GetAsHandle(CF_TEXT);
Buffer := GlobalLock(MyHandle);
If Buffer = Nil then
begin
GlobalUnlock(MyHandle);
exit;
end;

{since buffer is of type PChar, all the functions applicable to PChar canbe applied}
TextLength := StrLen(buffer);

단, Windows의 Clipboard에 담을 수 있는 자료는 64K로 제한됩니다.

[Q55] Canvas 를 가장 빠르게 다시 그리는 방법은 ?
[A55] InValidateRect(Canvas.handle,NIL,True);

[Q56] TPanel로부터 새로운 component를 만들었습니다. constructor에 BevelWidthproperty를 보면 설계시 정한 값과는 무관하게 항상 1로 setting되어 있습니다.constructor가 실행된 다음 설계시에 지정한 값으로 수정될 것인데 이 작업은 언제 일어납니까?
[A56] component들이 읽혀지고, 각 component가 create된 다음에 property값들이 다시 읽혀집니다. 모두 다 읽은 후에는 c omponent의 Loaded method가실행되므로 그 component에 대해서 무엇인가 작업을 하려면 Loaded method를자신의 procedure로 대 치시키면 됩니다.

[Q57] TMediaPlayer를 사용하여 Avi 화일을 동작시킬 수 있습니까?
[A57] TMediaPlayer를 사용하여 Avi 화일들을 동작시킬 수 있습니다.
TMediaPlayer component의 Filename property에 AVI 화일이름을 주고, Displayproperty를 TPanel로 설정한후 Open Method를 사 용합니다.
AVI 화일들을 동작하기 위해 사용자의 시스템는 Video for Windows의 정식 버젼이설치되어 있어야 합니다. 또한 WAV 화일도 마 찬가지로 동작시킬 수 있습니다.

[Q58] Password에 해당되는 자료를 입력할 때 화면에 보이지 않도록 하려면?
[A58] TEdit component의 PasswordChar property를 사용합니다.
실행시에 TEdit control에 입력되는 data는 PasswordChar property에서 주어진문자로 표시됩니다.

[Q59] 대화상자내의 특정 control을 enable/disable 시키는 방법은?
[A59] EnableWindow(Wnd: Hwnd, Enable: Bool) API 함수를 사용하십시오.
두개의 parameters중에 하나는 원하는 control의 window handle이고, Enableflag는 True이면 enable, False이면 disable 됩니 다.

[Q60] TDBNavigator component의 각각의 button이 enable 되었는지 알 수 있는 방법이 있습니까 ?
[A60] 다음과 같이 하면 됩니다.

type
TDBNavCracker = class(TDBnavigator);
...
if TDBNavCracker(DBNavigator1).Buttons[nbEdit].Enabled then
{your code}

[Q61] TEdit Component의 OnExit event는 사용자가 Speed Button에서 마우스를 클릭했을 경우 왜 실행되지 않습니까? Speed Button이 눌려졌을때 OnExit event를실행하기 위해 어떤 방법이 있습니까?
[A61] Speed Button은 동적인 Focus를 결코 갖지 않습니다. 그래서 Speedbutton이눌려지기 전에 Active 상태인 control에 서는 Focus를 잃어 버리지 않습니다.즉, Control의 OnExit event는 발생하지 않습니다.

OnExit event handler를 실행하도록 하는 한가지 방법은 SpeedButton의 OnClick에서명확하게 호출하는 것입니다.

Procedure TForm1.SpeedButton1Cliek(Sender:TObject);
Begin
if ActiveControl is TEdit then (ActiveControl as TEdit).OnExit(ActiveControl);
End;

[Q62] TEdit가 Focus를 가지고 있는지 알 수 있는 방법은 ?
[A62] ActiveControl이 TEdit형식 인지 다음과 같이 확인할 수 있고 TEditcomponent의 일반적인 method를 사용할 수 있습 니다.

procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
If (ActiveControl is TEdit) Then TEdit(ActiveControl).CopyToClipboard;
end;

[Q63] Runtime시에 TTabbedNoteBook의 원하는 페이지에 새로운 Component를추가할 수 있습니까? 새로운 Component에 대한 부모가 무엇인지 어떻게 결정합니까?
[A63] Runtime시에 TTabbedNoteBook의 원하는 페이지에 Component를 추가하기위해서는 새로운 Component의 부모 특성을 지 정해야 합니다.

Runtime시에 TTabbedNotebook의 모든 페이지에 접근하기 위한 방법은 TabbedNotebook의Page 개체의 Object property 의 개체 배열 특성을 사용하는 것입니다.

다른 방법으로는 Pages Component는 Pages 문자열 목록 특성에서 Page 이름들과연결되어 있는 개체들이 저장되어 있습니다.

다음은 TabbedNotebook1의 두번째 페이지에 새로운 Button을 생성하는 방법입니다.

var
NewButton:TButton;
Begin
NewButton := TButton.Create(Self);
NewButton.Caption := 'New' ;
NewButton.Parent := TWinControl(TabbedNotebook1.Pages.Objects[1])
...

다음은 TTabSet Tab Page의 해당 Tab Page위에 새로이 생성된 Component에 부모를어떻게 사용하는지에 대한 것입니다.

NewButton.Parent := TWinControl(NoteBook1.Pages.Objects[1])

[Q64] 특정 component가 존재하는지 알 수 있는 방법은 ?
[A64] 다음과 같이 FindComponent를 사용합니다.

Procedure TForm1.Button1Cliek(Sender:TObject);
var FormExists: Boolean;
Begin
FormExists := FindComponent('Button2') <> nil;
end ;

[Q65] 실행시에 component의 총 갯수를 알 수 있는 방법은 ?
[A65] 각 Form은 Screen.Forms 라는 array를 통해서 access 할 수 있고,각 Form의 component수는 ComponentCount 값에 있 습니다.
즉, 다음과 같이 프로그램 합니다.

function GetTotalComponents : Integer;
var
TotalComps, CurForm : Integer;
begin
TotalComps := 0;

for CurForm := 0 to (Screen.FormCount - 1) do begin
TotalComps := TotalComps + Screen.Forms[CurForm].ComponentCount;
end;

Result := TotalComps;
end;

이 코드는 실행시에 생성된 component에 대하여 특별한 작업을 하지 않아도이상 없이 작동됩니다.
또한 Application.ComponentCount는 프로그램의 Form 또는 windows 갯수를 돌려줍니다.단, 보이지 않는 application window 하 나를 포함한 갯수 입니다.

[Q66] component를 배열 형태로 사용하려면 ?
[A66] component의 Tag property를 사용합니다.
설계시에 component의 Tag property에 유일한 번호를 할당한 후에 다음과 같이프로그램합니다.

procedure TForm1.Button1Click(Sender: TObject);
var i : integer ;
begin
for I := 0 to ComponentCount -1 do
if Components[I] is TRadioButton then
if TRadioButton(Components[i]).checked then
case TRadioButton(Components[I]).Tag of
1 : Edit1.Text := 'RadioButton1' ;
2 : Edit1.Text := 'RadioButton2' ;
3 : Edit1.Text := 'RadioButton3' ;
4 : Edit1.Text := 'RadioButton4' ;
end ;
end;

[Q67] 새로운 component를 install했을 때 component palette에 원하는 icon이 보여지도록 하려면 ?
[A67] Component Writer's Guide 8장(Registering components)의 "Addingpalette bitmaps"를 참조합니다.

Image Editor에서 component resource(.DCR)를 만들어 24*24 bitmap을 추가합니다.이 때 주의할 것은 bitmap의 이름은 반드시 대문자로 적어야 한다는 것입니다.

 

[Q1] VCL 소스 코드를 구입할 수가 있습니까 ?
[A1] 컴포넌트 설계에 관심이 있다면 얼만든지 구입이 가능합니다. VCL소스 코드를 가지고 있다면, 개인적으로 컴포넌트 생성 을 정확하게 시험할수가 있습니다. 이것은 자기소유의 사용자정의 컴포넌트를 생성하려고 할 때매유 유용한 방법입니다. 또한 디버거를 사용하여 소스 코드를 분석할 수가있습니다.

[Q2] tabbed 콘트롤(예, TTabbedNotebook 등)에 대한 소스 코드는 어디에있습니까 ?
[A2] tabbed 콘트롤에 대한 소스는 법적인 문제로 인하여 소스에 포함되어있지 않습니다.
그러나, 인터페이스 소스는 DELPHI\DOC 디렉토리 밑에 INT 확장자로서 제공됩니다.
참고: Delphi RTL 소스 코드 등록자는 Borland Corporate로 부터 TTabSet과TTabbedNotebook에 대한 소스를 요청할 수 있습니다 .

[Q3] TString 리스트에 문자열에 붙여서 object나 property로서 정수값을저장할 수 있는 방법이 있읍니까?
[A3] 그렇습니다만 약간의 type 변환이 필요합니다. TString component는String array에 따라 같이 붙여 쓰도록 되어있는 Object array가 있습니다.이 Object array를 정수 데이타를 저장하는 목적으로 사용하면 됩니다. Objectarray가 가지는 자료형 은 TObject 입니다. 이것은 실제로는 4바이트의 포인터값입니다. 따라서 정수값을 여기 저장하려면 형변환(Type cast)이 필요합 니다.다음의 코드는 ListBox component의 items property(TString 개체)에 문자열과정수값 100을 저장합니다.

ListBox1.Items.AddObject('Text string', TObject(100));

이 값을 얻으려면 다음과 같이 합니다. (Result 가 Longint형이고 방금 추가된개체의 index 위치가 0이라고 가정하면)
Result := LongInt ( ListBox1.Items.Objects[0]);

주의 : 이것이 동작한다고는 하더라도 내부적 동작까지 완전히 믿어서는 안됩니다.이것은 트릭일 뿐이므로 꼭 주의해야합니다.

만약 하나의 값 이상을 넣어야 한다면 다음과 같이 TObject 클래스를 베이스로두 개의 정수를 갖는 다음과 같은 클래스를 새로 정의하면 됩니다.

type
ManyValues = class(TObject)
Value1 : Integer;
Value2 : Integer;
end;

[Q4] TStrings, TStringList의 차이는 무엇입니까 ?
[A4] TStrings는 create되더라도 자체적으로 저장할 공간을 가지고 있지않습니다.
예를들면, TListbox의 Items의 type은 TStrings 입니다. 그러나 create 시에는TListboxStrings의 type으로 create 합니다. 따 라서 다음과 같은 방법으로는TStrings를 사용할 수 없습니다.
ItemString = TStrings.Create;
ItemString.Add('test');

TStrings를 사용하고자 할 경우에는 다음과 같은 방법등으로 쓸 수 있습니다.
ItemString = TStringList.Create;
ItemString.Add('test');

그러나 TStringList에서는 자체적으로 저장할 공간을 가지고 있기 때문에 create한후에 Add Method를 사용할 수 있습니다.

[Q5] component를 그것의 name property를 가지고 참조하는 것이 가능합니까?
[A5] 가능합니다. 다음 예는 Form1의 FindComponent method를 가지고 처음부터10번째 까지의 SpeedButton들의 Enable prop erty를 FALSE로 만듭니다.

for I := 1 to 10 do
with Form1.FindComponent('SpeedButton' + IntToStr(i)) as TSpeedButton do
Enable := False;

[Q6] component에 나오는 font의 default 크기를 변경할 수 있읍니까?
[A6] 일단 폼의 font proerty를 원하는 크기로 변경한 다음 그 폼을 gallery에추가하면 됩니다.
component는 기본적으로 그것의 parent의 font를 반영하도록 되어 있으므로,이후로 그 폼에 추가하는 component는 폼의 font 크기를 따르게 될 것입니다.
Options | Gallery 명령을 통해 원하는 폼을 default mainform이나 defaultnewForm으로 지정할 수 있습니다.

[Q7] font property의 값을 Canvas.Font.Style := [fsBold] 와 같이 지정한뒤에 그것을 다시 보통 상태로 되돌리려면 어떻 게 합니까? 온라인 도움말에서는[fsBold],[fsItalic] 같은 것은 나와있지만 보통상태에 대한 기호는 없던데요?
[A7] 간단합니다. 빈 집합을 지정하면 됩니다.
Canvas.Font.Style := [];

또는 fsBold 만을 없애고 싶다면 다음과 같이 합니다.
Canvas.Font.Style := Canvas.Font.Style - [fsBold];

[Q8] 각각의 내장된 component가 사용하는 GDI resource의 양은 얼마나 됩니까?
[A8] TGraphicControl에서 계승된 TLabel이나 TBevel 같은것들은 systemresource를 전혀 사용하지 않습니다. 그러나 TWinC ontrol 에서 계승된 TEdit이나TPanel 같은것들은 resource를 사용합니다. TRadioGroup 안의 각각의 radiobutton들 또한 윈도우 이며 따라서 윈도우 핸들을 가지게 됩니다.

[Q9] TTabbedNotebook은 한 번에 한 페이지만이 보여지는데도 system resource들을왜 그렇게 많이 사용하는지 알고싶습니다 .
[A9] 한 번에 하나의 페이지만이 보여지고 있다고는 해도 모든 페이지의각각의 component는 이미 모두 생성되어있기 때문 에 resource를 사용합니다.이 문제를 해결하려면 notebook을 사용하는 대신에 페이지마다 각각의 분리된폼을 사용하여 user가 tab을 클릭하면 현재의 페이지를 파괴하고 새로운 것을생성하는 것입니다. 이렇게 하려면 다음과 같이 합니다.

각각의 child 폼은 어떤 방법으로든 CreateParams setup이 필요합니다.

...
private
{ Private declarations }
PRODCEDURE CreateParams(VAR Params: TCreateParams); override;
...

procedure TForm2.CreateParams(VAR Params: TCreateParams);
begin
Inherited CreateParams(Params);
with Params do begin
WndParent:= Application.MainForm.Handle;
Style := (Style OR WS_CHILD) AND NOT (WS_POPUP);
end;
end;

child 폼의 BorderStyle은 반드시 bsNone 으로 되어있어야 합니다. 메인폼에서TForm 형으로 된 Child 라는 private 데이타 필 드를 정의합니다. 그리고 OnCreate가아닌 OnActivate 이벤트에서 그것을 초기화 합니다. 페이지를 바꾸기 위해 tab이클릭될 때 마다 가지고 있던 child를 해제하고 새로운 것을 OnActivate event에서했듯이 원하는 타입으로 다시 초기화 합니다.

Child := TForm2.Create(Self);
with Child do begin
Parent := Self;
Align := alClient;
Visible := True;
end;

tab이 바뀜에 따라 child 페이지를 생성할 때 위에 보여진 것과 같이 하십시오.물론 child window가 해제될 때 그 child windo w에 있던 데이타는 사라져 버리기때문에 주어진 child window의 상태를 유지하기 위해 필요한 데이타는 main폼에 저장해야 할 것입니다.

[Q10] 새로운 component를 만들고자 하는데 Parent class를 무엇으로 해야하나요 ?
[A10] 가장 쉬운 방법은 특성을 알기 쉬운 component를 선택하는 방법입니다.

TComponent - non-visual component를 만들때의 기본입니다.
TWinControl - window handle이 필요할 때의 기본입니다.
TGraphicControl - window handle에 대한 overhead가 필요없는 visual component를
만들때의 좋은 기본입니다. 이 class는 paint method를
가지고 있습니다.
TCustomControl - Visual component에 대한 가장 일반적인 기본입니다.
이 class는 Window handle과 일반적인 event, property를
가지고 있으며, paint() method에 대한 canvas를 가지고
있습니다.

[Q11] TPanel로부터 derive된 component를 하나 만들었습니다. constructor에는BevelWidth 값이 항상 1로 되어있습니다. pr operty는 constructor가 끝나고나서 설계시 update되는 것으로 알고 있습니다. 언제 이것이 일어납니까? 그리고component의 초 기화 값을 위치시키는 위치는 어디입니까 ?
[A11] Component가 stream으로부터 읽혀질 때, 각각의 component는 먼저construct되고, property 값이 stream으로부터 읽 혀집니다. component의 로드된method는 모든 stream 과정이 끝났을 때 불려집니다. component가 stream으로부터load된 후에 어 떤것을 override Load할 수 있습니다.

[Q12] publish에 array property를 설정하였는데 #202 error가 발생합니다.무엇때문에 publish 될 수가 없습니까 ?
[A12] online help의 "published parts"를 보면 어떤 property와field가 publish될 수 있는지 나와있습니다. no n-standard data type (arrayproperty 포함) 데이타만 stream할 수있습니다. 참고적으로 TStringList source를참고 하십시오.

[Q13] 특수한 font를 사용한후 문자의 fixel에서 길이를 어떻게 결정해야합니까?
[A13] 픽셀에서 문자열의 문자 높이와 넓이를 결정하기 위해 TextHeight와TextWidth인 Canvas Method를 사용합니다. 그리 거나, 크기를 결정하기 전에Canvas에서 font를 지정해야만 합니다.

[Q14] Release/Free와 Close method의 다른점은 무엇입니까 ?
[A14] release와 free method는 본질적으로 기능이 같습니다. 따라서 발생하는event도 동일하며 아래와 같습니다. 특징은 close event가 발생하지 않는 다는것입니다.

Hide, Destroy

Close method를 사용했을 경우에는 Destroy가 발생하지 않습니다.

[Q15] 표준 Delphi controls의 용량 한계는 무엇입니까?
[A15] 정보를 저장하기 위해 TList를 사용하는 component는 16368 아이템이상을 넘을 수 없습니다. 예를 들어 TTabControl 은 16368개의 tab을 포함할수있으며, Delphi의 component pallete는 16368개의 pallete 페이지를 포함할수 있습니다.

Dephi Standard component의 숫자는 표준 윈도우 control을 포함할 수 있습니다.
Windows 3.1은 이들 component 내의 한계를 지우고 있습니다. 예를 들어: TComboBox나TListBox는 5440개의 아이템을 포함할 수 있으며, TMemo나 TEdit (또는 연관된컴포넌트)는 32KB의 문자를 포함할 수 있습니다.

Windows 3.1 Resource 공간은 TNoteBook component에서 570 페이지의 한계를가지고 있습니다.(이것은 다른 Windows 어플리케이 션에서 500 Window Handle이상을할 수 있는 것과는 다릅니다.)

주의 1 : 이 한계를 넘을 경우 Exception이 발생하거나, Windows가 이상한 행동을하는 원인이 될 수 있습니다.
주의 2 : Windows에 기초된 많은 것들의 용량 한계는 Windows NT와 Windows95의 16-bit WOW Box에서 보다 많을 수 있습니다. D elphi의 32Bit version은이런 한계의 가정된 모든것이 발생하지 않습니다.

[Q16] TPanel과 TEdit 같은 어떤 visual component는 왜 Canvas 특성을 가지고있지 않습니까?
[A16] 모든 TCustomControl의 상속은 Canvas 특성을 가지고 있습니다. 그렇지만,대부분은Component에 그려지는것을 '외부' 로 제한하기 위해 보호되고 있습니다.하나의 Component의 상속들은 항상 Component(Canvas와 같은)로 부터 상속받은특성이 보 호된채 접근할 수 있습니다. 그러므로 다음과 같이 Canvas를 publicproperty로 만들어 줍니다.

Type
TCanvasPanel = calss(TPanel)
public
Property Canvas;
End;

[Q17] Delphi가 Currency/money 컴포넌트를 가지고 있습니까?
[A17] 아니오. 그러나 천리안의 Delphi Forum이나 internet 등에서 CurrencyEdit Component를 다운로드 받아서 사용할 수 있습니다.

[Q18] Component들을 오목과 볼록으로 보이게 만들 수 있습니까?
[A18] TBevel이나 TPanel Component의 Frame특성인 raise나 lower특성을사용하여 오목과 볼록으로 보이게 할 수 있습니다.

[Q19] Visual Basic에서 Control Array와 같은 것을 생성하는게 가능합니까?
[A19] 이것을 하기 위해 Sender의 Tag field에서 보이는 공통적인 OnClickevent handler를 생성하거나, 다른 번호로 각각 의 버튼에 대한 Tag field를설정하는 방법이 있습니다.
그룹되어진 모든 버튼에게 같은 OnClick event handler를 지정합니다. 그리고이렇게 OnClick event handler를 지정하면 됩니다 .

Procedure TForm1.Button1Click(Sender:TObject);
Begin
case TButton(Sender).Tag of
1:ShowMessage('1st Button Pressed');
2:ShowMessage('2nd Button Pressed');
3:ShowMessage('3rd Button Pressed');
end;
end;

[Q20] 가로(페이지의 옆면에) Tab Components가 가능한, 상업적인, Shareware나Freeware가
있는곳은 어디 입니까?
[A20] TurboPower's Orpheus Product가 이것을 지원할 것입니다. 추가적인정보는 compuserve의
'GO TURBOPOWER'로 하시기 바랍니다.

[Q21] non-visual component를 만들려고 할 때, 하나의 property를 FileNameproperty로 하려고 합니다. 설계시에 사용자가 object inspector에서 생략(...)버튼을 눌렀을 경우에OpenDialogbox을 띄워서 선택한 filename이 property 값으로assign되게 하는 방법은 무엇입니까 ?
[A21] 다음과 같이 하면 됩니다.

TFileNameProperty = class (TStringProperty)
public
function getattributes: TPropertyattributes; override;
procedure Edit; override;
end;

RegisterPropertyEditor(Typeinfo(String),
TMyComponent, 'Filename', TFileNameProperty);

function TFileNameProperty.GetAttributes;
begin
Result := [paDialog];
end;

Procedure TFilenameProperty.edit;
var
MFileOpen: TOpenDialog;
begin
MFileOpen := TOpenDialog.Create(Application);
MFileOpen.Filename := GetValue;
MFileOpen.Filter := 'The Right Kind Of Files|*.*';
MFileOpen.Options := MFileOpen.Options + [ofPathMustExist,ofFileMustExist];
try
if MFileOpen.Execute then SetValue(MFileOpen.Filename);
finally
MFileOpen.Free;
end;
end;

[Q22] Delphi는 Serial 통신을 지원하는 Component를 가지고 있습니까?
[A22] 없습니다. 그러나, TurboPower, SaxComm와 같은 Third-Party 회사들로부터Delphi에서 사용가능한 Serial Communicat ions Libraries가 있습니다.

Database

[Q1] IDAPI의 정의는 무엇입니까? 그리고 SQL Links는 무엇입니까?
[A1] IDAPI는 Integrated Database Application Program Interface의 약어입니다.BDE는 일관된 API 를 가지고 복수개의 data source들과 접속하기 위한 한 방법입니다.IDAPI는 바로 BDE에 대한 API입니다. 그것은 데이타를 액세스하고 조작하는등의 필요한 모든 function들이 포함되어 있습니다. Delphi, dBASE for Windows,Paradox for Windows등이 data를 액세스하기 위해 이들 function들을 사용합니다.개발자는 스스로 자신의 프로그램들에 이들을 사용할 수가 있습니다.
BDE를 구입하여 이들 관련 문서를 얻을 수 있고, 제품에는 모든 가용한 function들이리스트되어 있고 이용할 수 있습니다. Del phi source를 찾아보면 사용된 이들function들을 볼 수가 있을 것입니다. 그것들은 "Dbi"로 시작되어집니다.(예를들면, DbiCreateTable) SQL Links는 remote database server에 연결하기 위해서사용할 수 있는 선택 가능한 내장 드라이버들입 니다.

[Q2] SQL Links가 지원하는 Informix(Online, I-NET)의 버전은?
[A2] SQL Links는 DELPHI 1.02 버전이상 부터는 Informix server의 모든버전들과 잘 동작합니다.

[Q3] Delphi에서 data 접속을 위해 IDAPI가 필요합니까? 배포되는 어플리케이션이사용자의 컴퓨터들에 IDAPI를 설치할 필 요 없도록 Delphi EXE내에 IDAPI를내장할 수 있습니까?
[A3] IDAPI는 Delphi에서 data 접속을 위해 필요합니다. Delphi는 IDAPI를설치하는 BDE 재분 배 가능한 디스켓과 함께 따 라옵니다.

[Q4] 제가 가지고 있는 SQL Link 구 버젼을 Delphi와 호환성있는 IDAPI와같이 사용할 수 있습니까?
[A4] 구 버젼의 SQL Link는 사용하지 못합니다. Client/Server에는 모든것이 포함되어 있으며, Delphi와 새로운 SQL Lin k만이 가능합니다.

[Q5] Quattro Pro 6.0과 IDAPI 를 네트웍에 가지고 있읍니다. 델파이와 새로운IDAPI를 네트웍에 설치한 뒤에 Quattro Pro 를 다른 기계에서 실행시키면 언어드라이버를읽어들일 수 없다는 에러가 납니다.
[A5] WIN.INI 파일에 IDAPI/LANGDRV 디렉토리를 지칭하기 위해 [BorlandLanguage Drivers] 섹션을 추가합니다. 예를들면 다음과 같습니다.

[Borland Language Drivers]
LDPATH=C:\IDAPI\LANGDRV

[Q6] ReportSmith, Interbase, SQL Links/ODBC 연결성에 대한 도움은 어디서얻을 수 있읍니까?
[A6] 볼랜드 개발 툴 포럼(Borland Development Tools forum : BDEVTOOLS)에 가십시오. ReportSmith, InterBase, Borland Database Engine, SQL Links/ODBC연결성에 대한 섹션이 있읍니다.

[Q7] IDAPI.CFG 화일에 한 alias를 추가하기 위한 프로그램적인 방법이 있습니까?
[A7] BDE는 DbiAddAlias()라고 하는 함수를 포함합니다. Specification들은AddAlias.txt 화일의 Section 6(Database) library에서 확인할 수 있습니다.또한, AliasManager라고 하는 Delphi component도 Section 6(Database) library에서가능합 니다.

[Q8] 'IDAPI error $2C08' 이 무슨뜻입니까?
[A8] IDAPI01.DLL을 읽어들일 수 없다는 뜻입니다. WIN.INI 파일의 다음섹션에 DLLPATH 가 정확한 위치를 지칭하고 있는지 를 확인하십시오.

[IDAPI]
DLLPATH=C:\IDAPI
CONFIGFILE01=C:\IDAPI\IDAPI.CFG

[Q9] 데이터베이스 응용프로그램을 델파이에서 실행시키려고 하자 EDatabaseError예외와 함께 'An Error occurred while at tempting to initialize the BorlandDatabase Engine (Error $2C09)' 라는 에러가 발생했읍니다.
[A9] SHARE.EXE /F4096 /L40 를 AUTOEXEC.BAT 에 추가하거나 SYSTEM.INI파일의 [386Enh] 섹션에 DEVICE = VSHARE.386을 넣고 다시 부트하세요.

[Q10] 프로그램에서 서버 데이타베이스(즉, Informix, Oracle, Sybase등)를연결하고자 할 때 해야 할 것은 ?
[A10] Delphi를 사용하여 데이타베이스 프로그램을 작성하려면 우선 해당Server 데이타베이스에 해당되는 Client Module이 개발자 PC에 설치되어 있어야합니다.
예를 들면 Informix의 경우에는 I*Net for windows, Oracle의 경우에는 SQL*Net을말합니다.
이것이 설치되어 설정사항이 모두 정확하여 데이타베이스로의 Ping이 성공적으로이루어 지면 다음과 같이 합니다. 이것이 우선 되지 않으면 서버 데이타베이스로접속하실 수 없습니다.

Delphi C/S Version에서 제공되는 IDAPI driver를 사용하는 경우에는,
IDAPI Configuration Utility에서 해당 driver로 부터 하나의 Alias를 추가시킵니다.
그리고 나서 그 Alias에 적절한 Parameter를 설정하면 Delphi IDE 환경에서각종 데이타베이스에 관련된 component를 사용할 수 있습니다.
Informix의 경우에는 Alias Parameter중 SERVER NAME, DATABASE NAME, USERNAME을 반드시 명시합니다.
또한 Oracle의 경우에는 Driver Parameter중 VENDOR INIT과 Alias Parameter중SERVER NAME, USER NAME, NET PROTOCOL을 반드시 명시합니다. 예를 들어 SERVERNAME은 @T:lambda:ORA7 과 같이 작성합니다. 여기에서 IDAPI의 경우 @를 빼면접속되지 않음을
유의하여 주십시오.

또한 Delphi가 제공하는 IDAPI driver로 접속할 수 없는 다른 종류의 데이타베이스를사용하려면 우선 ODBC driver를 구입하십 시오.
데이타베이스 vendor가 제공하거나 또는 3rd party 회사로 부터 구입한 ODBCdriver를 설치한 후에 제어판에서 ODBC driver를 s etup합니다.
사용할 데이타베이스 이름, 서버명 등 접속에 필요한 모든 정보는 ODBC driversetup 화면에서 설정해야 합니다.
이들 설정이 완성되지 않으면 마찬가지로 다음 Configuration 작업은 무의미합니다.
ODBC Driver 설정을 마친후에 IDAPI Configuration Utility에서 해당 ODBC driver의정보를 사용하는 새로운 driver를 추가시킵 니다.
또한 새로 추가한 driver로 부터 새로운 Alias를 추가합니다. 이 때 ODBC 제어판에서설정사항을 맞추었던 Data Source 이름을 ODBC DSN이라는 Parameter에서 확인할수 있으므로 이것이 올바르게 지정되었는지 살펴보십시오.

위의 작업이 끝나고 Configuration 화일이 저장되면 Delphi IDE 환경에서 각종데이타베이스에 관련된 component를 사용하여 프 로그램 하실 수 있습니다.

[Q11] database component를 이용하여 login prompt 없애는 방법?
[A11]
1.database component의 popupmenu인 database editer 선택
2.default button를 누른후에 'password ='에 사용자password 입력
3.login prompt를 check 안함

[Q12] 새로운 Table을 하나 만들고 Index를 정의하려고 합니다. 어떻게 합니까?
[A12] 그방법은 NewTable에서 index를 정의하는 정확한 방법입니다. 그러나아마도 Table의 IndexDefs property가 update 되지 않았을 것입니다. 그러므로,아래와 같이 Update method를 사용할 필요가 있습니다.

with NewTable do begin
Active := False;
DatabaseName := 'DBDEMOS';
TableName := 'Temp';
TableType := ttParadox;
FieldDefs.Assign(Table1.FieldDefs);
Table1.IndexDefs.Update; { Do an update first }
IndexDefs.Assign(Table1.IndexDefs);
CreateTable;
end;

[Q13] transaction 사용법은 ?
[A13]

procedure TForm1.FormCreate(Sender: TObject);
begin
database1.connected := true;
database1.starttransaction;
table1.open;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
table1.close;
database1.rollback;
database1.connected := false;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
database1.commit;
database1.starttransaction;

end;

procedure TForm1.Button2Click(Sender: TObject);
begin
database1.rollback;
database1.starttransaction;
end;

[Q14] 여러table에 대한 작업을 하나의 connection으로 유지하려는 작업은?
[A14] database component를 이용하여 transaction 처리

procedure TForm1.FormCreate(Sender: TObject);
begin
database1.connected := true;
database1.starttransaction;
table1.open;
table2.open;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
table1.close;
table2.close;
database1.rollback;
database1.connected := false;
end;

[Q15] table의 field명을 가져오려면 ?
[A15] fieldcount와 fieldname 사용

procedure TForm1.Button1Click(Sender: TObject);
var i : integer;
begin
with table1 do
begin
for i := 0 to fieldcount -1 do
listbox1.items.add( fields[i].fieldname);
end;
end;

[Q16] field editer에서 editmask를 setting했을때 literal문자를 자료로저장하지않고 단지 display용으로만 사용하려면 ?
[A16] editmask대화창(input mask editor)의 save literal characters option를check 하지 않는다.

editmask에 대한 예제는 DB\Q16 참조

[Q17] 다른 table의 정보를 calculated field로 load 시키려면 ?
[A17]

procedure TForm1.Table1CalcFields(DataSet: TDataset);
begin
if table2.findkey([table1.fields[1].asinteger]) then
table1company.value := table2.fields[1].asstring
else
table1company.value := 'none assign';
end;

예를 들어서 table1의 custno = 1221를 가지고 table2의 custno에서 1221를찾은후 table2의 특정 field내용을(compony)를 tab le1compony(calculated field)에넣는다.

[Q18] datatype field에 대한 조건을 주고 query를 하려는 경우 ?
[A18]

{sql문를 sql property에 editing}
SELECT ORDERS."OrderNo" , ORDERS."CustNo", ORDERS."SaleDate", ORDERS."EmpNo"
FROM "ORDERS.DB" ORDERS WHERE ( ORDERS."SaleDate" >=:dd )

procedure TForm1.Button1Click(Sender: TObject);
begin
Query1.Close ;
Query1.ParambyName('dd').asDatetime := strtodatetime(edit1.text);
query1.open;
end;

[Q19] query에서 outer join 하는 방법은 ?
[A19] 다음과 같이 참조 하십시오.

select proj_id,full_name
from employee left outer join employee_project
on employee.emp_no = employee_project.emp_no;

이것은 interbase용 sql 입니다. 사용하시는 db에 적합한 outer join용 sql문을사용하십시오.

[Q20] onCloseQuery Event는 언제 사용합니까 ?
[A20] 일반적으로 onClose와 onCloseQuery는 해당 form이 close될 때 발생합니다.하지만 차이점은 onClose는 해당폼이 clo se할때만 발생하지만 onCloseQuery는Parent form이 close될때도 발생됩니다.

[Q21] sql문에서 substring format은 ?
[A21] visual query builder의 expression 대화창의 substring(str,st,len)이아니고, substring(from 처음자리수 for 길이 )입니다.

sql문 예제 :
SELECT ANIMALS."NAME", ( substring( ANIMALS.NAME from 1 for 3) ) as Expr__1
FROM "ANIMALS.DBF" ANIMALS

[Q22] record의 특정필드가 비어있는 곳을 찾으려면 ?
[A22] date field의 입력이 안된 부분을 찾고싶을때 사용하는 sql문 입니다.
SELECT * from orders where orders."adate" is null;

[Q23] TQuery와 TDataSource 가 있읍니다. TQuery의 TStrings 프로퍼티에'SELECT * FROM dbo.AnyTable' 을 넣었읍니다. (여 기서 dbo 는 SQL 서버에있는 데이타베이스입니다.) Active 프로퍼티를 TRUE 로 두자 'Token not found.Token : dbo. line numb er : 1'이라는 에러가 발생했읍니다. 뭐가 잘못된 것일까요?
[A23] RequestLive 프로퍼티가 True 로 되어있으면 테이블 이름을 따옴표로둘러싸야합니다.
예) SELECT * FROM "dbo.table"

만약 RequestLive 프로퍼티가 False로 되어있으면 따옴표를 쓰면 안됩니다.
예) SELECT * FROM dbo.table

[Q24] stored procedure를 실행하려면 ?
[A24] storedproc1의 procedure는 input data(dno), output data(tot)이며table의 특정field값을 input data값에 assign하 면, 한 record가 변할때마다output data값이 변하여 label2에 display됩니다.

procedure TForm1.DataSource1DataChange(Sender: TObject; Field: TField);
begin
WITH STOREDPROC1 DO
BEGIN
IF PREPARED = FALSE THEN PREPARE;
params.parambyname('dno').asstring :=
table1.fieldbyname('dept_no').asstring;
execproc;
label2.caption := parambyname('tot').asstring;

END;
end;

[Q25] DBGrid에 나타나지 않게 필드를 만들 수 있습니까?
[A25] Fields Editor의 필드 목록으로 부터 입력된 필드를 제거하거나,Visible 특성을 False로 설정함으로써 할 수 있습니 다.

[Q26] TDBGrid의 현재 레코드와 필드의 위치를 어떻게 알릴 수 있습니까?
[A26] 현재의 Column과 Row의 트랙을 유지하기 위한 Method의 예가 아래에있습니다. 메쏘드 MyDBGridDrawDataCell에서 grid가 다시 그려질 때마다 변수Col과 Row는 매번 갱신되어 집니다. 이 코드를 사용하여 현재의 column과 row에대해 Col과 Ro w 변수가 포인트하는 것으로 가정할 수가 있습니다.

procedure TForm1.DBGrid1DrawDataCell(Sender: TObject; const Rect: TRect;Field: TField; State: TGridDrawState);
var
RowHeight: Integer;
begin
if gdFocused in State then
begin
RowHeight := Rect.Bottom - Rect.Top;
Row := (Rect.Top div RowHeight) - 1;
Col := Field.Index;
edit1.text := inttostr(row);
edit2.text := inttostr(col);
end;
end;

[Q27] TDBGrid에서 현재의 row에 대해 어떻게 선택표시(highlight)할 수있습니까?
[A27] TDBGrid의 Option property에서 dbRowSelect 항목을 enable 로 설정합니다.

[Q28] dbgrid의 각COLUMN별로 색상를 넣는법 ?
[A28]

procedure TForm1.DBGrid1DrawDataCell(Sender: TObject; const Rect: TRect;Field: TField; State: TGridDrawState);
begin
if gdFocused in State then
with(Sender as TDBGrid).Canvas do
begin
Brush.Color := clRed;
FillRect(Rect);
TextOut(Rect.Left,Rect.Top,Field.AsString);
end;
end;

[Q29] Windows상에서 사용자 message를 정의하여 사용하려면 ?
[A29] Windows상에서 사용자 message로 정의하여 쓸 수 있는 message는WM_USER 이후의 숫자로 제한됩니다. 그러므로 다음 과 같이 사용자 message를정의할 수 있습니다.

RequestMsgID = wm_User+1000;
ResponseMsgID = wm_User+1001;

그리고 다른 종류의 Windows message를 처리하는 것과 동일한 방법으로 messageprocedure를 정의합니다.

TForm1 = class(TForm)
private
{ Private declarations }
Procedure RespondToRequest(Var Msg:TMessage);Message RequestMsgID;
Procedure ReceiveData(Var Msg:TMessage);Message ResponseMsgID;
public
{ Public declarations }
end;

Procedure TForm1.RespondToRequest(Var Msg:TMessage);
Begin
{your message procedure}
end ;

[Q30] dbgrid의 last record에서 downkey를 누르면 자동으로 record가 삽입되는데이것을 막고 싶을때는 어떻게 하나요?
[A30]

procedure TForm1.TTable1BeforeInsert(DataSet: TDataset);
begin
Abort;
end;

{table의 before insert event handeler를 발생시킨후 abort 사용 }

[Q31] component의 icon을 만드는 방법은 ?
[A31]

1) tools/image editor선택
2) file/project type(component resource (DCR))선택
3) new resource에서 color를 16color, size in pixels width 24,height 24를설정
4) icon를 그린 후 default로 생긴 bitmap_1를 user가 define한 class명으로변경
(반드시 대문자)
5) save as로 pas 화일명과 동일한 이름으로 dcr화일을 저장(반드시 같은 directory)

[Q32] 데이타 입력을 위하여 Tab 또는 마우스 대신에 Return 키를 사용할수 있습니까 ?
[A32] Edit 컴포넌트의 OnKeyPress 이벤트에 다음과 같은 코드를 사용하면됩니다.

procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
If Key = #13 Then
Begin
SelectNext(Sender as tWinControl, True, True );
Key := #0;
end;
end;

이것은 Enter를 Tab처럼 동작하게 합니다. 폼에 있는 전체의 콘트롤(버튼을제외한)에 대해서 이와같은 동작을 원하면 전체의 콘트롤을 선택한 후에 OnKeyPress핸들러를 Edit1KeyPress로 지정하면 됩니다. 이제 각각의 콘트롤에 대해서 Enter가Tab처럼 작 동됩니다.
만약, 폼 레벨에서 이와같은 동작을 원하면(폼에 있는 전체의 콘트롤의 OnKeyPress핸들러에 전부 지정하기를 원하지 않는다면) 폼의 OnKeyPress에 다음과 같은코드를 사용하면 됩니다. 위의 코드에서 Sender만 ActiveControl로 바꾸고 폼의Property에서 K eyPreview를 true로 바꾸어 주면 됩니다.

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
If Key = #13 Then
begin
SelectNext(ActiveControl as tWinControl, True, True );
Key := #0;
end;
end;

이것은 폼에 있는 각각의 콘트롤에 대해서 Enter가 Tab처럼 작동합니다.

[Q33] 이미지화일을 db의 blob 필드로 load 하는법?
[A33]

procedure TForm2.Button1Click(Sender: TObject);
begin
Table1.Edit ;
DBImage1.Picture := Image1.Picture ;
Table1.Post ;
end;

procedure TForm2.BitBtn1Click(Sender: TObject);
begin
Image1.Picture.LoadFromFile('C:\windows\256color.bmp') ;
end;

[Q34] dbgrid의 원하는 field로 control를 보내는법?
[A34]

procedure TForm1.Button1Click(Sender: TObject);
var i:integer;
begin
for i:= 0 to 5 do
postmessage(dbgrid1.handle,WM_keydown, VK_TAB, 0);
end;

dbgrid의 6번째 field에 control를 보내는법(사실 tab key를 6번 보내준것)

[Q35] memo의 내용을 DBMemo로 put 또는 get 하는 방법은 ?
[A35]

dbmemo1.lines.assign(memo1.lines); (put하는법)
memo1.lines.assign(dbmemo1.lines); (get하는법)

[Q36] 테이블에 저장된 것과 같은 blob 필드의 실제 크기를 어떻게 결정할수 있습니까?
[A36] blob, memo, graphic 필드의 크기를 돌려주는 함수로써 GetBlobSize()를사용해 보십시오.

Function GetBlobSize(Field:TBlobField):LongInt;
var
bi:tblobstream;
begin
bi := TBlobStream.Create(Field,bmRead);
with bi do
try
Result := Seek(0,2);
finally
Free;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
Edit1.Text := IntToStr(GetBlobSize(table1Notes));
end;

[Q37] run time시에 database property를 설정하는 방법은 ?
[A37] datbase component를 사용할때는 다음과 같이 합니다. 이와 같이하면 사용자가 BDE configuration utility에서 Alia s를 추가로 설정할 필요가없습니다.

database1.aliasname := 'dbdemos';
database1.databasename := 'testdb';
database1.connected := true;
table1.databasename := 'testdb';
table1.tablename := 'animals.dbf';

[Q38] 두개의 form에서 처음 form의 table과 datasource를 사용하려면 ?
[A38] 처음 Form이 정의되어 있는 Form의 Unit 명을 uses절에 추가시킵니다.

unit unit2;
interface
{...}
implementation
uses
unit1;

{$R *.DFM}

procedure TForm2.FormActivate(Sender: TObject);
begin
table1.databasename := form1.table1.databasename;
table1.tablename := form1.table1.tablename;
datasource1.dataset := form1.datasource1.dataset;
dbgrid1.datasource := form1.dbgrid1.datasource;
table1.open;
end ;
end.

[Q39] database에 포함된 table list를 얻을 수 있는 방법은 ?
[A39]

procedure TForm1.Listbox1Click(Sender: TObject);
begin
Listbox2.Clear;
Session.GetTableNames(Listbox1.Items[Listbox1.ItemIndex], '', True, False,Listbox2.Items);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
Session.GetDatabaseNames(Listbox1.Items);
end;

[Q40] control의 events에서 예외상항(exceptions)들을 처리할 간단한 방법은?
[A40] 예외처리에 대한 추적을 위해 form의 method를 작성합니다. 이 method는어플리케이션의 OnException method상에 서 호출되어질 것입니다. 이 method에서확인하려는 예외 상황을 check해 봅니다.(예를 들면, EdatabaseError). OnExceptioneve nt에 대한 on-line Help를 확인해 봅니다. 이 event에 대해 만든 method를호출하는 방법에 대한 정보가 설명되어 있습니다.

type
TForm1 = class(TForm)
Table1: TTable;
DataSource1: TDataSource;
Database1: TDatabase;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
Procedure MyExcept(Sender:TObject; E:Exception);
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

Procedure TForm1.MyExcept(Sender:TObject; E:Exception);
{Don't forget to do a forward declaration for this in the class definition}
begin
If E is Edivbyzero then
MessageDlg('zero로 나눌수 없습니다. ',mtInformation, [mbOk],0)
else
{ it's not the error you're looking for, raise it }
end;

procedure TForm1.FormCreate(Sender:TObject);
var i,io : integer;
begin
Application.OnException := MyExcept;
{ Here is how you assign the OnException event to your handler }
io := 0;
i :=i div io;
end;

[Q41] db에 data를 입력할때 error 처리 방법 및 TDBEdit에 대한 mask 생성법은?
[A41]

procedure TForm1.MaskEdit1Exit(Sender: TObject);
begin
MaskEdit1.Text := FormatDateTime('HH:MM', StrToTime(MaskEdit1.Text));
Edit1.Text := FormatDateTime('HHMM', StrToTime(MaskEdit1.Text));
end;

procedure TForm1.MaskEdit2Exit(Sender: TObject);
begin
MaskEdit2.Text := FormatDateTime('HH:MM', StrToTime(MaskEdit2.Text));
Edit2.Text := FormatDateTime('HHMM', StrToTime(MaskEdit2.Text));
if StrToTime(MaskEdit2.text) < StrToTime(MaskEdit1.text) then
ShowMessage('From 시간보다 작습니다.')
else
MaskEdit3.Text := FormatDateTime('HH:MM', StrToTime(MaskEdit2.text) - StrToTime(MaskEdit1.text));
end;

[Q42] dBase 테이블의 expression 인덱스를 가지고 tTable.FindNearest나tTable.FindKey를 사용하면 'Index out of range' 에러가 왜 납니까?
[A42] FindKey 와 FindNearest 는 dBase 의 expression 인덱스에 대해 동작하도록설계되지 않았읍니다. 그러나 tTable 의 GoToKey나 GoToNearest 는 dBase의expression 인덱스에 대해 잘 작동합니다.

[Q43] dBASE 테이블을 pack하기 위한 BED API나 DLL이 있습니까?
[A43] BDE는 dBASE 테이블을 pack하기 위한 함수로써 DbiPackTable()을포함하고 있습니다. 만들고 있는 unit의 USES 절 에 DBITYPES, DBIPROCS, 그리고DBIERRS를 추가하고, 다음과 같이 BDE function을 호출합니다:

DBIPackTable(Table1.DbHandle, Table1.Handle, 'TABLENAME.DBF', szDBASE,TRUE);

주의: 테이블은 property exclusive를 true로 setting 해야합니다.

[Q44] 삭제 표시된 dBASE 레코드들을 어떻게 볼 수 있습니까?
[A44] table의 AfterOpen event 에 다음의 function을 호출합니다. 먼저,DBITYPES, DBIPROCS, DBIERRS를 USES 절에 포 함시킵니다. 그리고 호출하기위해, Ttable의 이름과 삭제된 레코드들을 보이거나 보이지 않도록 하는 TRUE/FALSE를 argument로 서 보냅니다.

주의) dbase table에서만 가능

[Q45] dBASE 테이블에서 레코드들이 삭제를 위한 표시가 되어 있는 것을grid의 column에 어떻게 만들 수 있습니까?
[A45] 계산필드(calculated field)를 만들고, 테이블의 OnCalcField event에대하여 계산필드에 아래와 같이 만들어진 모듈 로 내용을 치환합니다:

{다음 프로그램은 pack된data를 찾아서 calculated field에 표시, 단 dbasetable에 해당됩니다}
procedure SetDelete(oTable:TTable; Value:Boolean);
var
rslt: DBIResult;
szErrMsg:DBIMSG;
begin
try
oTable.DisableControls;
try
rslt := DbiSetProp(hDBIObj(oTable.Handle), curSOFTDELETEON, LongInt(Value));
if rslt <> DBIERR_NONE then
begin
DbiGetErrorString(rslt, szErrMsg);
raise Exception.create(StrPas(szerrmsg));
end;
except
on E: EDBEngineError do ShowMessage(E.Message);
on E: Exception do ShowMessage(E.Message);
end; { except ending}
finally
oTable.Refresh;
oTable.EnableControls;
end; {finally ending}
end; {procedure end}

procedure TForm1.Table1AfterOpen(DataSet: TDataset);
begin
SetDelete(Table1,TRUE);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
table1.open;
end;

procedure TForm1.Table1CalcFields(DataSet: Tdataset);
var
RCProps: RecProps;
Result: DBIResult;
begin
Result :=DbiGetRecord(Table1.Handle, DbiNoLock, Nil, @RCProps);
if RCProps.bDeleteFlag then Table1Del.Value := 'X' else
Table1Del.Value := '';
end;

[Q46] Paradox의 TCursor와 같은것은 Delphi에서 무엇입니까?
[A46] TTable 컴포넌트입니다.

[Q47] Paradox의 Auto Increment형의 필드를 프로그램으로 생성하려면 어떻게해야합니까?
[A47] TQuery를 가지고 SQL의 CREATE TABLE 명령을 사용하십시오.

procedure TForm1.Button1Click(Sender: TObject);
begin
with Query1 do
begin
DatabaseName := 'DBDemos';
with SQL do
begin
Clear;
Add('CREATE TABLE "PDoxTb6.db" (ID AUTOINC,');
Add('Name CHAR(255),');
Add('PRIMARY KEY(ID))');
ExecSQL;
Clear;
Add('CREATE INDEX ByName ON "PDoxTb6.db" (Name)');
ExecSQL;
Clear;
add('select * from "PDoxTb6.db"');
open;
end;
end;
end;

[Q48] Paradox 테이블을 만들때, TTable 컴포넌트의 AddIndex 메쏘드로 index를생성할 때 ixUnique 선택사항을 사용할 수 없는 것은 무엇 때문입니까?"
[A48] TTable 컴포넌트의 AddIndex 메쏘드를 사용할 때의 Index 선택사항은테이블에 특정적입니다. 예를들어 ixUnique 선택사항은 Paradox 테이블에서는사용 못하고 dBASE 테이블에서 사용되는 선택사항입니다. 아래의 표는 dBASE또는 Paradox 테 이블에서 사용할 수 있는 선택사항을 나타냅니다.

Index 선택사항 dBASE Paradox
----------------------------------------------------------
ixUnique *
ixDescending * *
ixNonMaintained * *
ixPrimary *
ixCaseInsensitive *

[Q49] 현재 record 번호를 display하는 방법은 ?
[A49] install component에 rct.pas를 add 시킨후 recordposition component를form에 첨가합니다.

[Q50] Index 되지않은 필드에서 찾을 수 있는 방법은 무엇입니까 ?
[A50] 아래의 Locate() 함수를 사용해 보십시오.

Locate(Table1, Table1LName, '홍길동');

Table1은 table컴포넌트 입니다. Table1LName은 field editor를 통하여 추가된TField이며 찾고자 하는 이름은 '홍길동' 입니다 .

Function Locate( const oTable: TTable; const oField: TField; const sValue:String): Boolean;
var
bmPos : TBookMark;
bFound : Boolean;
begin
Locate := False;
bFound := False;
If not oTable.Active then Exit;
If oTable.FieldDefs.IndexOf( oField.FieldName ) < 0 then Exit;
bmPos := oTable.GetBookMark;

WithoTable do
begin
DisableControls;
First;
While not EOF do
if oField.AsString = sValue then
begin
Locate := True;
bFound := True;
Break;
end
else Next;
end ;

If (Not bFound) then oTable.GotoBookMark( bmPos);
oTable.FreeBookMark( bmPos );
oTable.EnableControls;
end;

[Q51] 패스워드 보호된 테이블을 열때, 패스워드 대화상자을 어떻게 취할수 있습니까?
[A51]
1. database desktop에서 table을 만든 후 table properties의 password security를PASSWORD로 정의합니다.
2. 간단히 다음과 같이 테이블을 열기 전에 추가를 원하는 패스워드와 함께Session object를 지정합니다.

Session.AddPassword('PASSWORD');

일단 테이블을 닫으면 RemovePassword('PASSWORD')로 패스워드를 제거하거나,또는 RemoveAllPasswords로 모든 현재의 패스워 드들을 제거할 수 있습니다.(단,Paradox 테이블일 경우로만 국한됩니다.)

[Q52] 파손된 index들을 rebuild하기 위한 BDE API 나 DLL이 있습니까?
[A52] BDE는 index들을 rebuild하기 위한 함수로써 DbiRegenIndexes()를포함하고 있습니다. USES절에 DBITYPES, DBIPR OCS, 그리고 DBIERRS를 추가하고,다음과 같이 BDE function을 호출합니다:

DBIRegenIndexes(Table1.Handle);

주의: 테이블은 exclusive property가 ture로 설정되어 있고 index는 미리 구성되어있어야 합니다.

[Q53] 어떻게 레코드 포인터가 변할때를 알수 있습니까 ?
[A53] State가 dsBrowse일때 OnDataChanged 이벤트를 사용하십시오.

[Q54] 레코드를 편집할 때 BDEngine 메세지인 'Multiple records found butonly one expected' 가 나오는 데 이것은 무엇을 의미합니까 ?
[A54] 아마도 테이블에 unique index가 생성되어 있을 것입니다. 그러므로먼저 테이블의 unique index를 unique하지 않은 index로 수정하면 중복되는값을 입력할 수가 있습니다. 그러나, 만약 unique index를 원한다면, 중복된레코드를 삭제하여야 합 니다.

[Q55] table로부터 Fixed Length ASCII text table을 만드는 방법은 무엇입니까?
[A55] 다음과 같이 하면 됩니다.
1.아래의 프로그램을 실행시키면 .TXT와 .SCH 화일이 생성됩니다. .SCH 화일은Table의 구조에 대한 정보를 가지고 있습니다.

procedure TForm1.Button1Click(Sender: TObject);
var
t1, t2: tTable; {t1 = PW table; t2 = ASCII version}
begin
t1 := tTable.create(self);
with t1 do
begin
DataBaseName := 'pw'; { Personal Alias for Paradox Directory }
tableName := 'customer.db'; { Source Table }
open;
end;

t2 := tTable.create(self);
with t2 do
begin
DataBaseName := 'pw'; { Personal Alias for Paradox Directory }
tableName := 'asdf.txt';
TableType := ttASCII;

createTable;
open;
edit;
BatchMove(t1, batCopy);
close;
end;

t1.close;
end;

2. ODBC driver를 이용할 수도 있습니다.

1) 제어판에서 Rs_text driver를 load할때 define format(각 column을 정의)을하면 schema.ini화일이 생성됩니다.
2) BDE config에서 ODBC driver와 Alias를 등록합니다.
3) Table의 tabletype property를 ttascii로 선택하고 원하는 Table명을 지정합니다.

[Q56] DBGrid component에click procedure를 추가하는 방법은 ?
[A56] New Component를 만들어 다음과 같이 OnClick event가 published되도록 정의합니다.
이 새로운 Component를 Install Component시키면 OnClick event가 Object Inspector창에 나타납니다.

TMyGrid = class(TDBGrid)
private
{ Private declarations }
protected
{ Protected declarations }
public
{ Public declarations }
published
{ Published declarations }
property OnClick ;
end;

[Q57] BDE Function들과 data type들의 리스트와 설명을 어느곳에서 찾을수 있습니까?
[A57] DELPHI\DOC\ 디렉토리에서 DBIPROCS.INT 화일은 BDE Function들 및필요한 parameter 들, return value, 그리고 각 각의 개략적인 설명이 포함되어있습니다.
DBIPROCS.INT는 BDE function들과 함께 사용되는 type들의 리스트입니다. BDEfunction들을 호출하기 위해서는 USES 절에 다 음의 unit들을 추가합니다: DBITYPES,DBIPROCS, DBIERRS.
IDAPI function들을 사용하는데 있어서 보다 자세한 정보는 Customer Service에서Database Engine User's guide를 얻을 수 있 습니다.

[Q58] 델파이로 만든 DB 프로그램에서의 한글 입력문제 해결 방안.
[A58] 델파이의 DB 에서 한글 문제가 발생하는 이유는대부분이 DatabaseEngine Configuration에서 설정을 잘못하였기 때 문입니다.

환경설정 방법은 다음과 같습니다.

프로그램 매니저의 델파이 그룹에서 Database Engine Configuration 프로그램을실행시킨 후

Ⅰ)왼쪽의 Driver들을 보면 DBASE, PARADOX, INTRBASE 등이 있습니다.

먼저 마우스로 DBASE를 선택하고, 오른쪽의 Prameters를 보면 LANGDRIVER라는란이 있습니다. 여기를 다시 클릭하면 오른쪽에 아랫쪽 화살표 모양의 버튼이생깁니다. 버튼을 누르면 밑에 선택할 수 있는 랭귀지 드라이버 리스트가 나옵니다.

DBASE에 대해서는 dBASE KOR cp949를 선택하시고,
INTRBASE에 대해서는(만약 INTRBASE 가 있다면) 빈칸으로 만드시고,
그 외 나머지 드라이버에 대해서는 모두 Paradox Korea 949로 만드세요.

Ⅱ) 이 프로그램 윈도우의 바닥쪽을 살펴보면 Aliases라는 탭이보입니다. 이탭을 누르시면 페이지가 바뀝니다. 각각의 Alias 에 대해 오른쪽의 Parameters중LANGDRIVER를 INTRBASE인 경우에는 비워놓고 그 외의 것은 모두 Paradox Korea949로 맞추십시오 .

Ⅲ) 프로그램의 System 페이지로 가기 위해 System 탭을 누르시면 여기에도LANGDRIVER란이 있습니다. 이것도 Paradox Korda 9 49로 바꾸십시오.

=====================================================================
이렇게 하면 델파이의 언어드라이버 세팅이 맞춰진 것입니다. 이후에 만들어진테이블에 대해서는 한글 문제가 발생하지 않을 것입니다.
그러나 테이블 마다 정해진 언어드라이버가 있기 때문에 이전에 만들어진 테이블에대해서는 아직도 잘못 정해져 있을 수가 있 습니다. 그런 경우에는 그 테이블에대해 언어 드라이버를 다시 맞춰줘야 합니다.

그 방법은 다음과 같습니다.

Ⅰ) Database Desktop 을 실행합니다. 이것은 프로그램매니저의 델파이 그룹안에있습니다.
Ⅱ) 변경하고자 하는 테이블을 엽니다.
File |Open |Table 하시고, 적절한 파일타입과 알리아스 또는 드라이버를 지정하여테이블을 선택한 후 OK 버튼을 클릭합니다.
Ⅲ)Table |Restructure Table 로써 테이블의 구조를 바꾸는 윈도우로 들어갑니다.
Ⅳ) Restructure... 윈도우에서 오른쪽에 있는 Table Properties 항목에서 TableLanguage 를 선택합니다.
Ⅴ) 아래에 있는 Modify 버튼을 눌러 테이블 형식에 따라 위에서 설명한 대로지정하고 OK 버튼을 누릅니다.

======================================================================
마지막으로, Database Desktop 에서는 한글을 입력할 때에 키보드의 NUMLOCK버튼이 눌러져있어야 합니다. 즉, 오른쪽 키패드의 NUMLOCK에 불이 들어와 있어야합니다. 그렇지 않으면 Database Desktop 에서는 한글을 입력할 수 없습니다.이것은 이 유틸리 티만의 문제이며 델파이
에서는 상관 없이 한글을 입력할 수 있습니다.

참고로 Oracle을 사용하는 경우에 한글이 깨져 보일때는 Windows 디렉토리의ORACLE.INI 화일에NLS_LANG parameter를 DBMS에서 의 설정값과 동일하게 맞추어야합니다.
Oracle 7.X에서는 NLS_DATABASE_PARAMETERS table의 NLS_CHARSET을 확인하면됩니다.

[Q59] TDBGridd의 특정 field에 focus를 주는 방법?
[A59] 다음과 같이 프로그램 합니다.

DBGrid1.SelectedField := Table1SIZE;
DBGrid1.SetFocus;

 


제품 구성
[Q1] Delphi와 Delphi Client/Server 그리고 Delphi WorkGroup의 차이점은 무엇입니까?
[A1] Delphi Client/Server는 Delphi의 모든것에 추가적으로 아래의 것을포함하고 있습니다.

* SQL Links native drivers for Oracle, Sybase, MS SQL Server, Informix,
and InterBase.
* Rights for UNLIMITED redistribution of above drivers.
* Local InterBase Server Deployment Kit.
* Team Development Tools (integrates with existing PVCS installation).
* Visual Component Library source code.
* Visual Query Builder.

Delphi WorkGroup은 Delphi Client/Server에다가 InterSolv사의 PVCS VersionManager 제품이 추가로(포장은 별도로 되어있음) 제공되는 것입니다.

[Q2] 숨겨진 'Methods'를 배우기 위해 구입하거나, 읽어야 할것이 있습니까?
[A2] Component Writer's의 도움말 부분을 숙지하거나, VCL Source코드를구입하여 직접 보는것이 가장 좋습니다.

Project
[Q3] Object Inspector 표시는 무엇을 하는 것입니까 ?
[A3] object inspector는 모든 공개된 Class의 property을 표시합니다.(배열특성은 아니지만 쓰고 읽을 수 있습니다.) obj ect inspector는 Class의 Method에대해서는 표시할 수 없습니다.

[Q4] VB에서 스크린 세이버를 작성하듯이 Delphi에서도 만들 수 있습니까?
[A4]
(1) Project Source에 다음을 삽입합니다.
{$D SCRNSAVE:NameOfScreenSaver}
(2) Project를 컴파일합니다.
(3) .EXE를 .SCR로 이름을 변경하고 윈도우 디렉토리에 복사합니다. Close라고불리는 Mothod를 OnKeyUp과 OnClick에 지정합니 다.

[Q5] 아주 간단한 프로그램인 EXE가 왜그렇게 큰가요 ? (1개의 폼에 1개의버튼만 작성시 200KB)
[A5] Delphi의 VCL은 RTTI와 예외된 것에 기초하고 있습니다. 이것은 공백어플리케이션에 대해 약 120KB의 'footprint'를 요구합니다. 이 200KB는 사용자가디버그 정보를 포함했거나, 컴파일시 최적화를 시키지 않아서 그렇습니다. 버튼두개에 대하여 400KB인 사용자의 .EXE가 되지않지만, 201정도 되는 것을 주의하여보십시요. 데이타/코드 크기의 단지 추가되는 '일반적인'양 이 각각의 추가되는콘트롤과 함께 footprint가 되지 않습니다. 추가적으로 Option/Project 대화상자의Linker Page안에 있는 Ch eckBox는 크기와 읽는 시간를 최적화 합니다.

[Q6] 프로그램이 task list로 부터 없어지지 않은 상태에서 최소화된 icon을숨기는 방법은 무엇입니까 ?
[A6] SetWindowPos나 MoveWindow를 사용하여 icon을 화면 밖으로 이동시키십시오.
이 때 음수좌표를 할당하면 됩니다.

[Q7] 같은 application을 두번이상 실행되지 않게 하는 방법은 무엇입니까?
[A7] HPrevInst variable을 사용하면 됩니다. HPrevInst값이 0이 아니면같은 Application이 현재 Loading되어 있는 상태를 의미합니다. 따라서 .DPRsource에 다음과 같은 방법으로 사용할 수 있습니다.

program Project1;

uses
Forms,
Unit1 in 'UNIT1.PAS' {Form1};

{$R *.RES}

begin
if HPrevInst <> 0 then
Dialogs.ShowMessage('이미 실행중입니다')
else begin
Application.CreateForm(TForm1, Form1);
Application.Run;
end;
end.

[Q8] Splash screen을 보이는 루틴을 프로그램 어디에 포함시키면 좋을까요?
[A8] splash screen은 project source 화일의 첫번 FormCreate와 Run 사이에넣는것이 가장 좋습니다.

Splash unit에 다음과 같이 SplashForm이 정의되어 있습니다.

{$R *.RES}
var
SplashForm : TSplashForm; {in the Splash unit}

응용프로그램의 project source 화일은 다음과 같이 구성합니다.

program Project1;

uses Forms, Unit1 in 'UNIT1.PAS' {Form1}, Splash;
begin
Application.CreateForm(TForm1, Form1);
SplashForm := TSplashForm.Create(Application);
try
SplashForm.Show;
SplashForm.Update;
{
do other CreatForms or anyother processing
before the app is to be opened
}
SplashForm.Close;
finally
SplashForm.Free;
end;
Application.Run;
end.

[Q9] 왜 Unit를 닫으면, Form도 같이 닫히는지요 ?
[A9] Delphi는 사용자가 대화상자로 작업할때 코드를 제어할 수 있도록하기 때문입니다.
폼을 융통성있게 변경하기 위해 사용자의 변경한 점을 연관시켜 작업되기 때문입니다.

[Q10] minimize button이 눌러졌을 때(실제로 form이 작아지기 전에) capture할수 있는 방법이 무엇입니까 ?
[A10] WM_SYSCOMMAND message를 intercept해서 다음과 같이 사용하면 됩니다.

unit Unit1;

interface

uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs;

type
TForm1 = class(TForm)
public
procedure WMSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND;
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.WMSysCommand;
begin
if (Msg.CmdType = SC_MINIMIZE) or (Msg.CmdType = SC_MAXIMIZE) then
MessageBeep(0);
DefaultHandler(Msg);
end;

end.

[Q11] Sub form에서 전체 프로그램을 종료하려면 어떻게 해야 합니까 ?
[A11] 어느 form에서든 간에 MainForm.Close하면 전체 program은 종료됩니다.

[Q12] 실행시에 응용프로그램의 Icon을 다양하게 변경시키려면 ?
[A12] ICON은 Image Editor를 사용하여 Resource 화일에 저장시킵니다.
이 .RES 화일을 load 시키기 위해서 다음과 같이 선언합니다.
implementation
{$R test.res}

그리고 나서 Application.Icon property를 다음과 같이 설정합니다.
if FileExists( 'test.res' ) then
Application.Icon.Handle := LoadIcon( hInstance, 'ICON_NAME' );

[Q13] 프로그램을 실행시킬 때 입력 Parameter를 얻는 방법은 ?
[A13] ParamStr, ParamCount를 다음과 같이 사용하면 됩니다.

Y := 10 ;
for i := 1 to ParamCount do
begin
Canvas.TextOut(5, Y, ParamStr(i)) ;
Y := Y + Canvas.TextHeight(ParamStr(i)) + 5 ;
end ;

Debugger
[Q14] Delphi에서 BP7 프로젝트를 컴파일할 경우, 이것으로 Delphi의 통합된디버거를 사용 할 수 있습니까 ? 또한 무엇이 '주 화일'인지 어떻게 Delphi에전달하나요 ? 전 폼을 가지고 있지 않습니다.
[A14] 예, 통합된 디버거를 사용할 수 있습니다. 주 화일은 프로젝트 화일과같이 Open 하십시오. Open Project를 선택하시 고, 화일 형식을 *.DPR에서 *.PAS로변경한 후 컴파일 하고자 하는 BP7을 선택하시면 됩니다.

[Q15] 디버거 메세지중 "Debugger Is Unable To Stop Due To 'HardMode'"가 의미하는 것은 무엇입니까 ?
[A15] Hard Mode는 메세지 처리를 위치시킬 수 없는 경우 윈도우의 상태를이야기 합니다.
이것은 어떤 Kernel이 동작하거나 메뉴가 동작되는 동안 발생합니다. 이것이의미하는 것은 윈도우의 Lock없이 사용자의 어플리 케이션이 "freeze"할수 없는 Delphi의 상태에 사용자가 있다는 것을 의미 합니다.

[Q16] 나의 Resource Workshop project에서 .RES file 또는 .RC file을 저장할수 있습니까 ?
[A16] .RC file은 ASCII file이므로 debug하기 쉽고, 다른 프로그램에서도사용할 수가 있습니다. 그러므로 그것이 .RC fil e을 저장하고 자동적으로 .RESfile을 create하는 가장 좋은 방법입니다. 그렇게 하기 위해서는 먼저 .RC project를만들고 FILE |Preference에서 "Multi-Save .RES file" checkbox를check해주면 됩니다. 이제는 project를 저장할 때마다 자동적으 로 .RES file이생길 것입니다.

[Q17] WinSpector와 WinSight는 무엇입니까 ?
[A17] WinSpector는 windows application이 General Protection Fault나Unrecoverable Application Error가 발생했을 경우 에 postmortem inspection을실행하는 것을 허용하는 utility 입니다. WinSpector는 아래의 것을 보여줍니다.

* The call stack.
* function and procedures names in the call stack (with a little help fromyou).
* CPU registers.
* A disassembly of the instructions.
* Windows information.

WinSight는 application이 실행되는 동안 window classes, windows, 그리고message에 대한 정보를 보여주는 utility 입니다. 이것을 사용해서 application이어떻게 class와 window를 create하는지 그리고 window가 message를 주고받는것을 배울 수가 있 습니다.

[Q18] Borland Pascal 프로그램 출력을 지켜보기 위해 보조 모니터를 사용할수 있습니까 ?
[A18] 두개의 모니터를 사용하기 위해 하나는 반드시 MDA 모니터를 사용해야하고,(옛날의 Hercules Monochrome 형식) 다른 것은 VGA를(또는 EGA) 사용해야합니다.
이들은 MDA를 위한 $B000과 VGA를 위한 $B800의 2개의 주소 공간을 사용합니다.
Options/Environment/StartUp에서 보조 모니터를 사용하기 위헤 BP IDE에게사용자가 설정할 수 있도록 이들 모니터들을 설치해 야 합니다. 기본적인 모니터는프로그램의 출력을 표시하기 위한 BP IDE에서 설정되는 것입니다. (Delphi가아님)

주의 : Hercules 카드가 설치되었으면, 사용자의 VGA 카드는 8Bit로접근하게됩니다.

Installation
[Q19] Delphi를 install하는 동안 일부 Visual Basic program이 문제를 일으킵니다.왜 그렇습니까 ?
[A19] \Delphi directory에 있는 INSTALL.TXT file을 참고하십시오.
__________________________________________________________
|
| 2. BEFORE YOU RUN SETUP
| -----------------------
| .
| .
| .
| o VBX controls - SETUP installs the following VBX files
| into the \WINDOWS\SYSTEM directory that will
| overwrite any existing VBX files with the same name:
|
| GAUGE.VBX
| SWITCH.VBX
| PICT.VBX
| CHART2FX.VBX
|
| Before running SETUP, check for filename collisions
| and backup your existing copies of these files.
|
| .
| .
| .
| _______________________________________________________

Delphi에서 install하는 VBX file과 Visual Basic application에서 사용하는VBX file의 이름이 같을 경우는 다음과 같이 하십 시오.(GAUGE.VBX를 예로 설명하겠습니다.)

1) Delphi의 component palette에서 GAUGE.VBX를 제거합니다.
a) Options | Install Components를 선택합니다.
b) Installed list에서 GAUGE를 선택합니다.
c) REMOVE button을 클릭합니다.
d) OK Button을 누르면 delphi는 component library를 다시 컴파일 합니다.
e) Delphi를 빠져 나갑니다.

2) GAUGE.VBX를 다른 이름으로 바꿉니다.(예를들어 BIGAUGE.VBX 처럼)

3) 다시 Delphi로 가서 BIGAUGE.VBX를 component palette에 추가합니다.
a) Options | Install Components를 선택합니다.
b) VBX Button을 클릭합니다.
c) VBX File을 선택합니다(BIGAUGE.VBX).
d) OK Button을 누르면 component library를 다시 컴파일 합니다.

4) Visual Basic application에서 사용되었던 원래 GAUGE.VBX file을 \Windows\Systemdirectory로 복사합니다.

위와같이 하면 문제를 해결할 수있습니다.

[Q20] 'Database Desktop'이나 'Database Engine Configuration' 아이콘을클릭할 때, "multiple net files found "라는 error가 나옵니다.
[A20] System에 있는 *.lck file을 찾아서 지우십시오.

[Q21] Delphi에서 Version Control 기능을 사용하려면 어떻게 해야 합니까?
[A21] On-Line Help에서 "Version Control" topic을 참고하십시오.이 기능은 Client/Server 제품에서만 가능합 니다.

[Q22] Delphi를 실행했을 때 "can't open c:\delphi\bin\complib.dcl"이라는 error message가 나옵니다. 어떻게 해야 합니까 ?
[A22] 이러한 error는 여러가지의 경우에 발생합니다. Share 또는 VShare가올라오지 않았거나 또는 parameter가 잘못되어 있을 수도 있습니다. (F:4096L:40 권장)
또는 WIN.INI file에 [IDAPI] section이 빠졌거나 잘못되어 있을 수도 있습니다.아래를 참조하십시오.

[IDAPI]
CONFIGFIL01=C:\IDAPI\IDAPI.CFG
DLLPATH=C:\IDAPI

COMPLIB.DCL이 잘못되었을 경우에는 CD \RunImage\Delphi\Bin directory에 있는COMPLIB.DCL file을 새로 복사하십시오. 경우에 따라서는 windows가 잘못 install되어 있을 수도 있습니다.
아래의 file이 맞는지 확인하십시오.

VER.DLL 9,008
USER.EXE 264,016
KRNL386.EXE 76,400

[Q23] W8LOSS.EXE file은 무엇입니까 ?
[A23] W8LOSS.EXE file은 command line tool 입니다. 이것은 application의size를 optimize 해 주는 것으로써 Delphi의 OP TIONS|PROJECT|LINKER에서 'optimizefor size and load time.'를 선택하는것과 동일합니다.

 

 

'Delphi' 카테고리의 다른 글

델파이 API  (0) 2014.02.13
날짜/시간형식 변경 및 강제 시간세팅  (0) 2014.02.13
Tip 정리  (0) 2014.02.13
올림 / 내림(버림)  (0) 2011.08.03
델파이의 소숫점 반올림 방식  (2) 2011.08.03
2014. 2. 13. 10:22

Tip 정리

<윈도우 캡션 깜박이게 하기>

//---------------------------------------------------------
BOOL FlashWindow(
   HWND hWnd,   // 폼의 Handle속성을 지정
   BOOL bInvert   // 윈도우즈 95에서는 이 변수값을 무시하며,
   // True로 지정된 경우 타이틀바가 활성/비활성 상태가 토글된다
);
//---------------------------------------------------------

procedure TForm1.FormActivate(Sender: TObject);
begin
   Timer1.Enabled := True;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
   FlashWindow(Form1.Handle, True);
end;

 

<윈도우 디렉토리 알아내기>

//---------------------------------------------------------
UNIT GetWindowDirectory(
   LPTSTR lpBuffer, // 시스템 디렉토리를 저장할 버퍼의 포인터
   UINT uSize          // 디렉토리 버퍼의 크기
);
//----------------------------------------------------------

procedure TForm1.Button1Click(Sender: TObject);
var
   Windir : array[0..30] of char;
begin
   GetWindowsDirectory(Windir,sizeof(windir));
   Label1.Caption := Windir;
end;
 


<비퍼(beeper) ON/OFF 시키기>

//----------------------------------------------------
BOOL SystemParametersInfo(
   UINT uiAction,    // 조회하거나 변경할 시스템 파라미터변수
   UINT uiParam,    // 시스템 파라미터 변수에 따라 지정
   PVOID pvParam, // 시스템 파라미터 변수에 따라 지정
   UINT fWinini        // 시스템 파라미터 변수의 내용이 변경될 경우
                            // 사용자프로파일의 변경여부를 지정
);

BOOL MessageBeep(
   UINT uType
);
//-----------------------------------------------------
procedure TForm1.Button1Click(Sender: TObject);
begin
   SystemParametersInfo(SPI_SETBEEP, 1, Pchar(0), 0); // Beeper ON
   Label1.Caption := 'Beep On';
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
   SystemParametersInfo(SPI_SETBEEP, 0, Pchar(0), 0); //Beeper OFF
   Label1.Caption := 'Beep Off';

end;

procedure TForm1.Button3Click(Sender: TObject);
begin
   MessageBeep(MB_OK);
end;

 

<시스템 가동방법 알아내기>

//----------------------------------------------------
int GetSystemMetrics(
   int nIndex;    // 시스템에서 사용하는 정보에대한 변수값
);
//----------------------------------------------------

procedure TForm1.Button1Click(Sender: TObject);
var
   boot : integer;

begin
   boot := GetSystemMetrics(SM_CLEANBOOT);
   case boot of
      0 : Label1.Caption := 'Normal Boot';
      1 : Label1.Caption := 'Fail-safe Boot';
      2 : Label1.Caption := 'Fail-safe with Network Boot';
   end;
end;

 

<마우스버튼 역할 바꾸기>

//----------------------------------------------------
BOOL SystemParametersInfo(
   UINT uiAction,          // 조회하거나 변경할 시스템 파라미터변수
   UINT uiParam,          // 시스템 파라미터 변수에 따라 지정
   PVOID pvParam,       // 시스템 파라미터 변수에 따라 지정
   UINT fWinini             // 시스템 파라미터 변수의 내용이 변경될 경우
                                 // 사용자 프로파일의 변경여부를 지정
);

BOOL MessageBeep(
   UINT uType
);
//------------------------------------------------------
procedure TForm1.Button1Click(Sender : TObject);
begin
   SystemParametersInfo(SPI_SETMOUSEBUTTONSWAP, 1, PChar(0), 0);
   Label1.Caption := 'Left : Popup Right : Pointing and Execute';
end;

procedure TForm1.Button2Click(Sender : TObject);
begin
   SystemParametersInfo(SPI_SETMOUSEBUTTONSWAP, 0, PChar(0), 0);
   Label1.Caption := 'Left : Pointing and Execute Right : Popup';
end;

 

<스크린세이버 ON/OFF시키기>

//-----------------------------------------------------
BOOL SystemParametersInfo(
   UINT uiAction,     // 조회하거나 변경할 시스템 파라미터변수
   UINT uiParam,     // 시스템 파라미터 변수에 따라 지정
   PVOID pvParam,  // 시스템 파라미터 변수에 따라 지정
   UINT fWinini        // 시스템 파라미터 변수의 내용이 변경될 경우
//사용자프로파일의 변경여부를 지정
);

BOOL MessageBeep(
   UINT uType
);
//------------------------------------------------------

procedure TForm1.Button1Click(Sender : TObject);
begin
   SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 1, PChar(0), 0);
   Label1.Caption := 'SCREEN SAVER ON';
end;

procedure TForm1.Button1Click(Sender : TObject);
begin
   SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 0, PChar(0), 0);
   Label1.Caption := 'SCREEN SAVER OFF';
end;

 

<마우스버튼 개수 알아내기>

//--------------------------------------------------
int GetSystemMetrics(
   int nIndex;    // 시스템에서 사용하는 정보에대한 변수값
);
//--------------------------------------------------

procedure TForm1.Button1Click(Sender: TObject);
var
   ButtonNo : integer;

begin
   ButtonNo := GetSystemMetrics(SM_CMOUSEBUTTONS);
   Label1.Caption := IntToStr(ButtonNo)+'개입니다';
end;

 

<WIN.INI파일에 문자열쓰기>

//----------------------------------------------
BOOL WriteProfileString(
LPCTSTR lpszSection, //Win.ini파일 Section명
LPCTSTR lpszKey, //Section에 출력할 Key명
LPCTSTR lpszString //Key에 할당할 문자열
};

// INI파일의 Section, Key, String의 구성형태
// [Section]
// Key = String;
//-----------------------------------------------

procedure TForm1.Button1Click(Sender : TObject);
begin
   WriteProfileString(Edit1.Text, Edit2.Text, Edit3.Text);
   // Win.ini 파일에 Edit 컴포넌트에 입력된문자열을 출력한다.
end;
 


<WIN.INI파일에서 문자열 읽어오기>

//------------------------------------------------------------
DWORD GetProfileString(
   LPCTSTR lpAppName,        // Win.ini파일 Section명
   LPCTSTR lpKeyName,        // Section에 포함되어 있는 Key명
   LPCTSTR lpDefault,            // 함수에러 발생시 되돌려지는 문자열
   LPCTSTR lpReturnedString, // Key에 할당되어 있는 문자열을 읽어오는 문자열의 버퍼의 포인터
   DWORD nSize                    // 문자열 버퍼의 크기
);
//-------------------------------------------------------------

procedure TForm1.Button1Click(Sender : TObject);
var
   retstr : string;
begin
   GetProfileString(Edit1.Text, Edit2.Text, Edit3.Text, retstr,sizeof(retstr));
   Label1.Caption := retstr;
end;
 


<특정 INI 파일에 문자열 쓰기>

//-----------------------------------------------------
BOOL WritePrivateProfileString(
LPCTSTR lpszSection,   // INI파일 Section명
LPCTSTR lpszKey,         // Section에 출력할 Key명
LPCTSTR lpszString,      // Key에 할당할 문자열
LPCTSTR lpszFile          // 문자열을 출력할 INI파일명으로 확장자까지 입력해야한다.
);
//-----------------------------------------------------
procedure TForm1.Button1Click(Sender : TObject);
begin
   WritePrivateProfileString(Edit1.Text, Edit2.Text, Edit3.Text, Edit4.Text);
   // Edit4에서 지정한 파일에 각 Edit컴포넌트에 입력된 문자열을 출력한다.
   // 출력하고자 하는 파일이 없을 경우 새로 만든다.
end;

 

<특정 INI 파일에서 문자열 읽어오기>

//----------------------------------------------------------
DWORD GetPrivateProfileString(
   LPCTSTR lpAppName,      // 특정 INI파일 Section명
   LPCTSTR lpKeyName,      // Section에 포함되어 있는 Key명
   LPCTSTR lpDefault,          // 함수에러 발생시 되돌려지는 문자열
   LPTSTR lpReturnedString, // Key에 할당되어 있는 문자열을 읽어오는 문자열버퍼의 포인터
   DWORD nSize,                 // 문자열버퍼의 크기
   LPCTSTR lpFileName        // INI파일명으로 확장자까지 입력해야한다.
);
//-----------------------------------------------------------
procedure TForm1.Button1Click(Sender : TObject);
var
   retstr : string;
begin
   GetPrivateProfileString(Edit1.Text, Edit2.Text, Edit3.Text, retstr,sizeof(retstr),Edit4.Text);
   // 특정 INI파일의 지정한 Section 및 Key에 할당된 문자열을 읽어온다.
   // GetPrivateProfileString함수에 지정한 Section이나 Key가 없을 경우
   // Default String을 되돌린다.ㅏ
   Label1.Caption := retstr;
end;

 

<현재 실행중인 OS버전 알아내기>

//-------------------------------------------------------
DWORD GetVersion(VOID)

Platform High order bit Low order byte (major version number)
Windows NT zero 3 or 4
Windows 95 1 4
Win32s with Windows 3.1 1 3
//--------------------------------------------------------
procedure TForm1.Button1Click(Sender : TObject);
var
   Version : LongInt;
begin
   Version := GetVersion;
   Label1.Caption := 'Windows ' + IntToStr(LoByte(LoWord(Version))) + '.' +
   IntToStr(HiByte(LoWord(Version)));
   Label2.Caption := 'DOS ' + IntToStr(HiByte(HiWord(Version))) + '.' +
   IntToStr(LoByte(HiWord(Version)));
end;

 

<윈도우 배경화면 바꾸기>

//----------------------------------------------------
BOOL SystemParametersInfo(
   UINT uiAction,    // system parameter to query or set
   UINT uiParam,    // depends on action to be taken
   PVOID pvParam, // depends on action to be taken
   UINT fWinIni       // user profile update flag
);
//----------------------------------------------------
procedure ChangeBatang;
var
   Reg : TRegIniFile;
begin
   Reg := TRegIniFile.Create('Control Panel');
   Reg.WriteString('desktop','Wallpaper','c:\babo.bmp');
   // 바탕화면으로 c:\babo.bmp를 사용함.
   Reg.WriteString('desktop','TitleWallpaper','1');
   Reg.Free;

   SystemParametersInfo(SPI_SETDESKWALLPAPER, 0,
      nil, SPIF_SENDWININICHANGE);
end;

 

<CPU종류 알아내기>

//-------------------------------------------------------------------
VOID GetSystemInfo(
   LPSYSTEM_INFO lpSystemInfo // address of system information structure
);

// SYSTEM_INFO 구조체 내용 - 자세한 사항은 도움말 참조
typedef struct _SYSTEM_INFO { // sinf
   union {
      DWORD dwOemId;
      struct {
         WORD wProcessorArchitecture;
         WORD wReserved;
      };
   };
   DWORD dwPageSize;
   LPVOID lpMinimumApplicationAddress;
   LPVOID lpMaximumApplicationAddress;
   DWORD dwActiveProcessorMask;
   DWORD dwNumberOfProcessors;
   DWORD dwProcessorType;
   DWORD dwAllocationGranularity;
   WORD wProcessorLevel;
   WORD wProcessorRevision;

} SYSTEM_INFO;
//--------------------------------------------------------------------

procedure TForm1.Button1Click(Sender: TObject);
var
   Sysinfo : TSysteminfo;
begin
   GetSystemInfo(Sysinfo);
   case Sysinfo.dwProcessorType of
      386 : Label1.Caption := 'Intel 386 ';
      486 : Label1.Caption := 'Intel 486 ';
      586 : Label1.Caption := 'Intel Pentium';
      4000 : Label1.Caption := 'MIPS R4000';
      21046 : Label1.Caption := 'Alpha 21046'
   end;
end;

 

<메모리상태 알아내기>

//------------------------------------------------------------
BOOL GetDiskFreeSpace(
LPCTSTR lpRootPathName, // 디스크 루트 패스
LPDWORD lpSectorsPerCluster, // 클러스터당 섹터수
LPDWORD lpBytesPerSector, // 섹터당 바이트수
LPDWORD lpNumberOfFreeClusters, // 사용하지 않은 클러스터수
LPDWORD lpTotalNumberOfClusters // 총 클러스터수
);
//------------------------------------------------------------
procedure TForm1.Button1Click(Sender : TObject);
var
   MemStat : TMemoryStatus;

begin
   MemStat.dwLength := sizeof(TMemoryStatus);
   GlobalMemoryStatus(MemStat);
   with MemStat do
   begin
      Label1.Caption := Format('%d KB',[Trunc(dwTotalPhys/1024)]); //총메모리
      Label2.Caption := Format('%d KB',[Trunc(dwAvailPhys/1024)]); //MemAvailable
      Label3.Caption := Format('%d %%',[trunc(dwAvailPhys/dwTotalPhys*100)]); //사용메모리
      Label4.Caption := Format('%d KB',[Trunc(dwTotalPageFile/1024)]); //SwapFileSetting
      Label5.Caption := Format('%d KB',[Trunc((dwTotalPageFile-dwAvailPageFile)/1024)]);      
      // SwapFileSize
     
      Label6.Caption := Format('%d %%',[100-trunc(dwAvailPageFile/dwTotalPageFile*100)]);      
      // SwapFileUsage
   end;
end;

 

<OEM 코드페이지 알아내기>

//-------------------------------------
UINT GetOEMCP(VOID);
// OEM 코드값 리턴

437 MS-DOS United States
708 Arabic (ASMO 708)
709 Arabic (ASMO 449+, BCON V4)
710 Arabic (Transparent Arabic)
720 Arabic (Transparent ASMO)
737 Greek (formerly 437G)
775 Baltic
850 MS-DOS Multilingual (Latin I)
852 MS-DOS Slavic (LatinII)
855 IBM Cyrillic (primarily Russian)
857 IBM Turkish
860 MS-DOS Portuguese
861 MS-DOS Icelandic
862 Hebrew
863 MS-DOS Canadian-French
864 Arabic
865 MS-DOS Nordic
866 MS-DOS Russian (former USSR)
869 IBM Modern Greek
874 Thai
932 Japan
936 Chinese (PRC, Singapore)
949 Korean
950 Chinese (Taiwan, Hong Kong)
1361 Korean (Johab)
//------------------------------------------
procedure TForm1.Button1Click(Sender : TObject);
var
   ret : integer;
begin
   ret := GetOEMCP;
   case ret of
      437 : Label1.Caption := 'MS_DOS United States(CP 437)';
      // 리턴값은 아래 설명 참조
      // .....
      default : Label1.Caption := 'Etc';
   end;
end;

 

<토글키 상태 알아내기>

//-----------------------------
SHORT GetKeyState(
   int nVirtKey // 가상키 코드
);

// 키값
VK_CAPITAL Caps Lock키
VK_NUMLOCK Num Lock키
VK_SCROLL Scroll Lock키
//------------------------------
procedure TForm1.Button1Click(Sender : TObjcet);
begin
   if GetKeyState(VK_INSERT) = 1 then
      Label1.Caption := 'ON'
   else
      Label1.Caption := 'OFF';
      // Insert 키가 눌려졌으면 1, 아니면 0을 리턴
      // 다른 토글키도 마찬가지
end;

 

<윈도우즈 가동시간 알아내기>

procedure TForm1.Button1Click(Sender : TObject);
var
   hh, mm, ss : integer;
   ret : LongInt;
   buff : string;
begin
   ret := GetTickCount/1000;
   hh := ret/3600;   // 시간계산

   ret := ret -(3600*hh);
   mm := ret/60 //분 계산

   ret := ret - (60*mm);
   ss := ret; //초 계산

   strcpy(buff,IntToStr(hh)+'시간 '+IntToStr(mm)+'분 '+IntToStr(ss'+초');
   Label1.Caption := buff;
end;

 

<날짜정보 리셋하기>

//-----------------------------------------------------------------
BOOL SetSystemTime(

   CONST SYSTEMTIME *lpSystemTime     // address of system time to set
);

// SYSTEMTIME 구조체
typedef struct _SYSTEMTIME {     // st
   WORD wYear;
   WORD wMonth;
   WORD wDayOfWeek;
   WORD wDay;
   WORD wHour;
   WORD wMinute;
   WORD wSecond;
   WORD wMilliseconds;
} SYSTEMTIME;
//------------------------------------------------------------------
procedure TForm1.Button1Click(Sender: TObject);
var
   s_time : TSystemTime;
begin
   s_time.wYear := StrToInt(Edit1.Text);
   s_time.wMonth := StrToInt(Edit2.Text);
   s_time.wDay := StrToInt(Edit3.Text);
   SetSystemTime(s_time);

   Label1.Caption := DateToStr(Now);
end;

 

<윈도우즈 종료시키기>

//----------------------------------------------
BOOL ExitWindowsEx(
   UINT uFlags,                  // shutdown operation
   DWORD dwReserved       // reserved
);
//----------------------------------------------
procedure TForm1.Button1Click(Sender: TObject);
begin
   case RadioGroup1.ItemIndex of
      0 : ExitWindowsEx(EWX_FORCE, 0);           // 강제종료
      1 : ExitWindowsEx(EWX_LOGOFF, 0);         // LOG OFF
      2 : ExitWindowsEx(EWX_POWEROFF,0);     // Shut Down & Turn Off
      3 : ExitWindowsEx(EWX_REBOOT, 0);         // Shut Down & Reboot
      4 : ExitWindowsEx(EWX_SHUTDOWN, 0);    // ShutsDown
   end;
end;

 

<환경변수 알아내기>

//---------------------------------------
LPVOID GetEnvironmentStrings(VOID)
//환경변수에 대한 문자포인터를 리턴
//---------------------------------------
procedure TForm1.Button1Click(Sender: TObject);
var
   Dosenv : Pchar;
   len, i : Integer;
begin
   Dosenv := GetEnvironmentStrings;

   while Dosenv <> '\0' do
   begin
      len := StrLen(Dosenv);
      if (len = 0) then break
      else begin
         Memo1.Lines.Add(Dosenv);
         for i := 0 to len do
         Inc(Dosenv);
      end;
   end;
end;

 

<디스크 볼륨정보 알아내기>

//------------------------------------------------------------------------
BOOL GetVolumeInformation(
   LPCTSTR lpRootPathName,                      // 디스크 루트 패스
   LPTSTR lpVolumeNameBuffer,                  // 볼륨이름에 대한 버퍼 포인터
   DWORD nVolumeNameSize,                     // 볼륨이름 버퍼 크기
   LPDWORD lpVolumeSerialNumber,            // 시리얼 넘버
   LPDWORD lpMaximumComponentLength, // 지정 가능한 파일이름의 최대길이
   LPDWORD lpFileSystemFlags,                  // 파일시스템 플래그
   LPTSTR lpFileSystemNameBuffer,            // 파일시스템 네임버퍼 포인터
   DWORD nFileSystemNameSize                // 파일시스템 네임버퍼 크기
);
//------------------------------------------------------------------------
procedure TForm1.Button1Click(Sender: TObject);
var
   RPName : Pchar;
   VolBuf : Pchar;
   VolSNum : Longint;
   MaxLen : Longint;
   FileFlags : Longint;
   FileNameBuf : Pchar;
begin
   GetVolumeInformation(RPName, VolBuf, sizeof(VolBuf), VolSNum, MaxLen,
      FileFlags, FileNameBuf, sizeof(FileNameBuf));

   Label1.Caption := RPName;
   Label2.Caption := VolBuf;
   Label3.Caption := IntToStr(VolSNum);
   Label4.Caption := IntToStr(MaxLen);

end;

 

<현재 작업디렉토리 알아내기/지정하기>

//------------------------------------------------
DWORD GetCurrentDirectory(
   DWORD nBufferLength,  // 디렉토리 버퍼의 크기
   LPTSTR lpBuffer            // 디렉토리 버퍼에 대한 포인터
);
//-----------------------------------------------
procedure TForm1.Button1Click(Sender: TObject);
var
   CurrDir : array[0..200] of char;
begin
   GetCurrentDirectory(sizeof(CurrDir), CurrDir);
   // 현재 지정된 디렉토리를 알아낸다.
   Label1.Caption := CurrDir;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
   SetCurrentDirectory(Pchar(Edit1.Text));
   // 새로운 디렉토리를 지정한다.
end;

 

<해상도 알아내기>

procedure TForm1.Button1Click(Sender: TObject);
begin
   Label1.Caption := IntToStr(GetSystemMetrics(SM_CXSCREEN)) +
      '*' + IntToStr(GetSystemMetrics(SM_CYSCREEN));
end;

 

<Image의 회전>

 "Here's code to rotate a bitmap 90
 degrees"
 
 From: Dave Shapiro
 
 Counterclockwise, that is. This rotates a 640x480 24-bit bitmap 90 degrees in
 about 2/10 of sec on my P133 (4MB video card, 128MB RAM). It works for
 Delphi 2, and should work for 1 and 3, too.
 
 One thing: This does not work for bitmaps that aren't an integral number of colors
 per pixel. If that's the case, you'll have to do some bit twiddling. I'm working on that
 part right now (I need it too), but it'll be a few days. Anyways, suggestions,
 comments, etc., always welcome.
 
 Special thanks to David Ullrich (ooh, I hope I spelled that correctly) for pointing out
 the non-published-but-public-anyway SaveToStream method for the TBitmap class.
 
 Advance apologies for any formatting problems. Netscape's editor is so ridiculously
 crippled that I can't accomplish anything (give me rtin and vim any day).
 
 
 
 procedure RotateBitmap90Degrees(ABitmap: TBitmap);
 
 const
   BITMAP_HEADER_SIZE = SizeOf(TBitmapFileHeader) +
 SizeOf(TBitmapInfoHeader);
 
 var
   { Things that end in R are for the rotated image. }
   PbmpInfoR: PBitmapInfoHeader;
   bmpBuffer, bmpBufferR: PByte;
   MemoryStream, MemoryStreamR: TMemoryStream;
   PbmpBuffer, PbmpBufferR: PByte;
   PbmpBufferRFirstScanLine, PbmpBufferColumnZero: PByte;
   BytesPerPixel, BytesPerScanLine, BytesPerScanLineR: Integer;
   X, Y, T: Integer;
 
 begin
   {
     Don't *ever* call GetDIBSizes! It screws up your bitmap.
     I'll be posting about that shortly.
   }
 
   MemoryStream := TMemoryStream.Create;
 
   {
    To do: Put in a SetSize, which will eliminate any reallocation
    overhead.
   }
 
   ABitmap.SaveToStream(MemoryStream);
 
   {
    Don't need you anymore. We'll make a new one when the time comes.
   }
   ABitmap.Free;
 
   bmpBuffer := MemoryStream.Memory;
 
   { Set PbmpInfoR to point to the source bitmap's info header. }
   { Boy, these headers are getting annoying. }
   Inc( bmpBuffer, SizeOf(TBitmapFileHeader) );
   PbmpInfoR := PBitmapInfoHeader(bmpBuffer);
 
   { Set bmpBuffer to point to the original bitmap bits. }
   Inc(bmpBuffer, SizeOf(PbmpInfoR^));
   { Set the ColumnZero pointer to point to, uh, column zero. }
   PbmpBufferColumnZero := bmpBuffer;
 
   with PbmpInfoR^ do
   begin
     BytesPerPixel := biBitCount shr 3;
     { ScanLines are DWORD aligned. }
     BytesPerScanLine := ((((biWidth * biBitCount) + 31) div 32) * SizeOf(DWORD));
     BytesPerScanLineR := ((((biHeight * biBitCount) + 31) div 32) * SizeOf(DWORD));
 
     { The TMemoryStream that will hold the rotated bits. }
     MemoryStreamR := TMemoryStream.Create;
     {
      Set size for rotated bitmap. Might be different from source size
      due to DWORD aligning.
     }
     MemoryStreamR.SetSize(BITMAP_HEADER_SIZE  + BytesPerScanLineR * biWidth);
   end;
 
   { Copy the headers from the source bitmap. }
   MemoryStream.Seek(0, soFromBeginning);
   MemoryStreamR.CopyFrom(MemoryStream, BITMAP_HEADER_SIZE);
 
   { Here's the buffer we're going to rotate. }
   bmpBufferR := MemoryStreamR.Memory;
   { Skip the headers, yadda yadda yadda... }
   Inc(bmpBufferR, BITMAP_HEADER_SIZE);
 
   {
    Set up PbmpBufferRFirstScanLine and advance it to end of the first scan
    line of bmpBufferR.
   }
   PbmpBufferRFirstScanLine := bmpBufferR;
   Inc(PbmpBufferRFirstScanLine, (PbmpInfoR^.biHeight - 1) * BytesPerPixel);
 
   { Here's the meat. Loop through the pixels and rotate appropriately. }
 
   { Remember that DIBs have their origins opposite from DDBs. }
   for Y := 1 to PbmpInfoR^.biHeight do
   begin
     PbmpBuffer := PbmpBufferColumnZero;
     PbmpBufferR := PbmpBufferRFirstScanLine;
 
     for X := 1 to PbmpInfoR^.biWidth do
     begin
       for T := 1 to BytesPerPixel do
       begin
         PbmpBufferR^ := PbmpBuffer^;
         Inc(PbmpBufferR);
         Inc(PbmpBuffer);
  end;
       Dec(PbmpBufferR, BytesPerPixel);
       Inc(PbmpBufferR, BytesPerScanLineR);
     end;
 
     Inc(PbmpBufferColumnZero, BytesPerScanLine);
     Dec(PbmpBufferRFirstScanLine, BytesPerPixel);
   end;
 
   { Done with the source bits. }
   MemoryStream.Free;
 
   { Now set PbmpInfoR to point to the rotated bitmap's info header. }
   PbmpBufferR := MemoryStreamR.Memory;
   Inc( PbmpBufferR, SizeOf(TBitmapFileHeader) );
   PbmpInfoR := PBitmapInfoHeader(PbmpBufferR);
 
   { Swap the width and height of the rotated bitmap's info header. }
   with PbmpInfoR^ do
   begin
     T := biHeight;
     biHeight := biWidth;
     biWidth := T;
   end;
 
   ABitmap := TBitmap.Create;
 
   { Spin back to the very beginning. }
   MemoryStreamR.Seek(0, soFromBeginning);
   ABitmap.LoadFromStream(MemoryStreamR);
 
   MemoryStreamR.Free;
 end;
 


<조합형 완성형 체크 프로시져>

Function isKs(buf : PChar) : Integer;
var
 Hangul_Code, ks_count, kssm_count : Integer;
 First,Second : Char;
 ptr,ptr2 : PChar;
begin
 ks_count := 0;
 kssm_count := 0;
 ptr := buf;
 ptr2 := buf;
 while ptr^ <> #0 do
 begin
  first := ptr^;
  INC(ptr,1);
  IF (Ord(first) < $80) then Continue;
  second := ptr^;
  if (ptr - ptr2 > 20480) then break;
  hangul_code := (Ord(First) * 256) + Ord(second);
        //  완성형의 특수문자 코드 검사
  if( ( ((hangul_code > $a1a1) And (hangul_code < $a1ff)) OR
        ((hangul_code > $a2a0) And (hangul_code < $a2e6)) OR
        ((hangul_code > $a3a0) And (hangul_code < $a3ff)) OR
        ((hangul_code > $a4a0) And (hangul_code < $a4ff)) OR
        ((hangul_code > $a5a0) And (hangul_code < $a5f9)) OR
        ((hangul_code > $a6a0) And (hangul_code < $a6e5)) OR
        ((hangul_code > $a7a0) And (hangul_code < $a7f0)) OR
        ((hangul_code > $a8a0) And (hangul_code < $a8ff)) OR
        ((hangul_code > $a9a0) And (hangul_code < $a9ff)) OR
        ((hangul_code > $aaa0) And (hangul_code < $aaf4)) OR
        ((hangul_code > $aba0) And (hangul_code < $abf7)) OR
        ((hangul_code > $aca0) And (hangul_code < $acc2)) OR
        ((hangul_code > $acd0) And (hangul_code < $acf2)) OR
        //  1998.2.21 새로 추가(Cherie)
        (hangul_code = $aec2) OR
        //  완성형 한글코드 검사
        Check_HanRange( hangul_code, $b0a0, $b0ff, 16 ) OR
        Check_HanRange( hangul_code, $c0a0, $c0ff, 9  ) OR
        //  완성형 한자코드 검사
        Check_HanRange( hangul_code, $caa0, $caff, 6  ) OR
        Check_HanRange( hangul_code, $d0a0, $d0ff, 16 ) OR
        Check_HanRange( hangul_code, $e0a0, $e0ff, 16 ) OR
        Check_HanRange( hangul_code, $f0a0, $f0ff, 14 ) ) AND
        //  1998.2.23 새로 추가(Cherie)
        //  조합형 일어의 경우 완성형과 동일한 부분이 있는데,
        //  완성형에서는 거의 사용되지 않는 문자이므로,
        //  아래 코드가 있을경우 무조건 조합형으로 인식
        //  만일 조합형 일어 코드가 아니라면...
      ( NOT (( (hangul_code >= $d000) And (hangul_code <= $d3ff) ) OR
          ( (hangul_code >= $dda1) And (hangul_code <= $de98 )) OR
          ( (hangul_code >= $dba1) And (hangul_code <= $dbc8 )) OR
        //  1998.2.27 새로 추가(Cherie)
        //  조합형 선문자일경우도 무조건 조합형으로 인식
        //  만일 조합형 선문자 코드가 아니라면...
          ( (hangul_code >= $d9b0) And (hangul_code <= $d9cf) ) OR
          ( (hangul_code >= $d4b0) And (hangul_code <= $d4cf) ) ) ) ) then
    begin
      INC(ks_count);
      if ks_count >= KS5061_VERIFY_COUNT then
        break;
    end
    else
    begin
      INC(kssm_count);
      if kssm_count >= KS5061_VERIFY_COUNT then
        break;
    end;
    INC(ptr)
  end;
  //  대부분 조합형보다는 완성형 글이 많으므로 카운트 값이
  //  같을 경우 완성형으로 처리하도록 한다.
  if( ks_count >= kssm_count ) then
    isKS := 0
  else
    isKS := 1;
end;
 


<caption에 여러줄 쓰기>

기존에 caption이 여러줄 올 수가 없었습니다.

다음은 caption에 여러줄을 쓰는 간단한 팁입니다.

 unit Newbtn;

 interface

 uses
    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
    stdCtrls;

 type
    TNewButton = class(TButton)

 private
 { Private declarations }
 public
 { Public declarations }
    procedure createParams(var Params: TCreatParams); override
    {생성된 윈도의 형태를 결정하는 메소드를 겹지정합니다.}
 end;

 procedure Register;

 implementation

 {$R *.DFM}

 procedure TNewButton.CreateParams(var Params: TCreatParams);
 begin
    inheritde CreateParams(Params);
    //상위 클래스의 메소드를 먼저 호출한 뒤
    Params.Style := Params.style or BS_TILINE;
    //스타일 형태를 multi-line(다중 라인)으로 설정한다.
 end;

 procedure Register;
 begin
    RegisterComponents('sample',[TNewButton]);
 end;

 end.

 

<파일 다루기>

  파일의 종류를 보면 텍스트 파일과 바이너리 파일이 있다.

 델파이에서는 텍스트 파일은 아주 간단히 액세스가 가능하며, 바이너리 파일도 역시 간단히 액세스를 할 수 있다. 텍스트 파일은 아주 간단하여 초보자도 쉽게 읽고 쓸수 있다는 장점이 있다.

 델파이에서 바이너리 파일은 Typed 파일로 정수나 실수 그리고 레코드 등을 파일로 저장할 수 있도록 한다. 첫 강좌는 파일을 다루는 기본적인 함수와 텍스트 파일을 다루는 방법에 대하여 알아본다.

 1. 파일 변수 선언

 파일 변수란 파일을 제어하기 위한 디스크의 실제적인 파일을 가리키는 변수이며 흔히 파일 핸들이라고 한다. 파일 변수란 복잡한 구성 요소들을 대표하는 변수이며 디스크의 파일과 일단 한 번만 연결해 주면 파일 변수를 통해 간단하게 파일 입출력을 할 수 있다.

 텍스트 파일 타입

 Var
    FH: TextFile;

 FH는 텍스트 파일의 파일 핸들 변수이다.

 

 2. 파일과 핸들 연결

 파일과 핸들을 대응하는 작업은 파일 핸들이 어떤 파일을 가리키는가를 지정해 주는 작업이며 다음의 함수를 사용한다.

 AssignFile(파일핸들, 파일명);

 예: AssignFile(FH, 'C:\autoexec.bat');

 

 3. 파일의 오픈

 파일을 오픈한다는 것은 파일 입출력을 위한 준비 과정이라 하겠다. 파일을 입출력하기 위해서는 파일에서 읽은 내용을 저장할 메모리가 필요하며 또한 파일을 어디쯤 읽고 있는가, 어떤 형태의 파일인가 등의 정보를 기억할 여러가지 내부적인 변수들이 필요하고 에러 처리를 위한 준비가 필요하다. 이런 일체의 작업을 통틀어 파일 오픈이라 한다.

 

 3-1. Rewrite(FileHandle)

 파일로 데이타를 출력하기 위한 파일 오픈 함수이다. 만약 파일이 디스크 상에 없으면 파일을 직접 만들고 파일이 있으면 기존 파일을 삭제한 후 다시 만든다.

 3-2. Reset(FileHandle)

 파일로부터 데이타를 입력하기 위한 파일 오픈 함수이다. 읽기 위해서 오픈한 것이므로 데이터를 출력할 수는 없다. 파일이 디스크상에 존재하지 않으면 에러가 발생한다.

 3-3. Append(FileHandle)

 디스크상의 기존에 있는 파일에 데이터를 추가로 출력하기 위한 파일 오픈 함수이다.

 

 4. 파일 입출력

 파일로부터 데이타를 읽거나 쓸 때 필요한 과정이다.

 ReadLn(FileHandle, Variant);
 WriteLn(FileHandle, Value);

 위의 두 함수가 실제로 텍스트 파일을 읽고 쓰는데 많이 쓰이는 함수이다.

 

 5. 파일 닫기

 입출력을 위하여 파일을 열었으면 원래대로 닫아주어야 한다. 파일을 닫는다는 말은 메모리에서 파일에서 사용된 내용을 제거한다는 것이다.

 CloseFile(FileHandle)

 입출력이 끝난 후에 파일을 닫는 것은 무척 중요한 일이면서도 실수로 빼먹고 안하는 경우가 많은데

 반드시 해 주어야 한다. 그렇지 않으면 말짱하던 파일이 사라진다거나 깨지거나 할 가능성이 있다. 위의 다섯가지 순으로 파일로 작업을 한다.

 

 6. 파일 쓰기

 이제 위의 다섯 가지를 사용하여 파일 쓰기를 하도록 하자.

 Var
    FH: TextFile;

 Begin
    AssignFile(FH, 'C:\DSPF.txt');
    Rewrite(FH);
    WriteLn(FH, '델프동 만세');
    WriteLn(FH, '볼랜드 사용자 그룹 = 델프동');
    CloseFile(FH);
 End;

 FH가 파일 핸들 변수이다 'c:\dspf.txt'파일을 파일 핸들 변수에 할당하고 쓰기 모드로 오픈하였다. WriteLn을 사용하여 파일로 한 라인 출력을 하였다. 마지막으로 파일을 닫는 CloseFile함수가 사용되었다.

 온라인 도움말을 이용하여 WriteLn에 대하여 더 자세히 살펴보기를 바란다.

 

 7. 파일 읽기

 파일로부터 데이터를 읽어 보자. dspf.txt에 저장된 데이터를 읽어 보자.

 Var
    FH: TextFile;
    MyStr: String;

 Begin
    AssignFile(FH, 'c:\dspf.txt');
    Reset(FH);
    While Not Eof(FH) Do Begin
    ReadLn(FH, MyStr);
    ShowMessage(MyStr);
 End;

 CloseFile(FH);

 End;

 파일에서 읽은 데이터를 우리는 스트링 변수에 저장한다. Reset함수는 읽기 모드 오픈이다. Eof(FH)함수는 파일의 끝이다인지를나타낸다. ReadLn을 통하여 MyStr변수에 데이타를 읽어들이고 ShowMessage함수로 화면에 디스플레이하여 주는 것이 파일의 끝일 때까지 반복된다. 마지막에는 CloseFile함수로 파일을 닫는다.

 

 8. 파일 추가

 파일에 데이터를 쓰기에서 발전된 것으로 보면 되겠다... 파일에 데이타가 존재할 때 어떻게 하면 그 파일에 내용을 더할 수 있을까? 그것은 Rewrite대신에 Append함수로 수행할 수 있다.

=======================================================

 델파이는 모든 변수들을 파일로 저장할 수 있도록 하는 기능을 제공하는데 바로 이것이 Typed File이다. 파일로 저장될 때 개별 데이타의 데이터형을 가진다는 것으로 해석하면 될 것이다.

 우선 정수값을 저장하는 파일

 Typed File을 사용하는 방법은 텍스트 파일을 사용하는 방법과 거의 동일하다. 단 타입드 파일 변수를 선언하는 형식적인 차이가 있다.

 선언은

 Var
    TFH: File Of Integer;

 Integer와 같이 어떤 Type이 오는 파일인 Typed File을 선언하는 방법이다.

 

 자 이제 정수형 타입의 파일을 액세스 하자.

 Var
    FH: File Of Integer;
    i : Integer;

 Begin
    AssignFile(FH, 'c:intfile.txt');
    Rewrite(FH);
    For i := 1 To 1000 Do
    Write(FH, i);
    CloseFile(FH);
 End;

 레코드형 Typed File

 위의 예는 단순히 Typed File의 구현은 이렇게 할 수도 있다는 것을 보여주는 예가 되겠다.

 그럼, 레코드를 단위로 파일에 읽고 쓰는 방법에 대하여 알아보자.

 Type
    TMyRec = Record
    Name : String[20];
    Age : Integer;
    Male : Boolean;
 End;

 위의 레코드 선언은 신상의 예가 되는 3개의 필드만을 레코드의 멤버로 선언하였다.

 이런 방법으로 주소록이나 전화번호부, 고객 관리등을 작성한다면 유용하게 쓰일 수 있다.

 아래에서 예를 들어 쉽게 설명하도록 하겠다.

 Var
    MyRec: Array[1..100] Of TMyRec;
    FH: File Of TMyRec;
    i: Integer;

 Begin
    AssignFile(FH, 'c:\recfile.txt');
    Rewrite(FH);
    For i := 1 To 100 Do
       Write(Fh, MyRec[i]);
    CloseFile(FH);
 End;

 TMyRec형의 배열 MyRec을 크기 100으로 선언하고 MyRec 전체를 c:\recfile.txt로 출력한다.

 물론 위의 코드는 출력 예만 보이기 위하여 만든 것이기에 MyRec에는 전혀 쓸모없는 값이 들어 있을 것이다.

 MyRec에 값을 대입해 준 후 파일로 출력하면 레코드 전체가 파일로 저장되며 이 정보는 Read함수를 사용하여 읽어 들일 수 있다.

 

 Random Access

 Typed File에서는 Random Access가 가능하다. 이는 순차 접근(Sequential Access)의 반대의 개념으로 파일에 있는 데이터 중 특정 위치의 데이터를 언제든지 읽을 수 있다.

 파일 입출력은 항상 현재의 위치를 기준으로 수행되며 레코드 하나를 읽으면 현재 위치가 레코드의 길이만큼 증가하여 다음 레코드를 읽을준비를 한다. 현재 위치를 변경하려면 Seek함수를 사용하며 인수로 파일 핸들과 몇번째 레코드를 읽을 것인지 알려주면 된다.

 10번째 레코드를 읽고자 할 때 다음과 같다.

 Seek(FH, 10);
 Read(FH, MyRec[10]);

 파일의 현재 위치를 구하려면 FilePos(FH)함수를 사용하여 파일의 총크기를 구하려면 FileSize(FH)함수를 사용하면 된다.

 

<한, 영 전환하기>

 // 'uses' Clause 에 'Imm' 을 추가함.
 unit Unit1;

 interface

 uses
    Windows,Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Imm, StdCtrls;

 type
    TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    Label1: TLabel;

 procedure Button1Click(Sender: TObject);
 procedure FormCreate(Sender: TObject);

 private
 { Private declarations }

 public
 { Public declarations }

 procedure ConvK_Emode;
 function GetK_Mode: Boolean;

 end;

 var
    Form1: TForm1;

 implementation

 {$R *.DFM}

 var
    K_Emode : HIMC;
    procedure TForm1.ConvK_Emode;     {한/영 모드 전환 }

begin
    K_Emode := ImmGetContext(handle);

    if GetK_Mode then        {한글모드이면 영문모드로}
       ImmSetConversionStatus(K_Emode, IME_CMODE_ALPHANUMERIC,          IME_CMODE_ALPHANUMERIC)

    else       {영문모드이면 한글모드로}
       ImmSetConversionStatus(K_Emode, IME_CMODE_HANGEUL, IME_CMODE_HANGEUL);

 end;

 function TForm1.GetK_Mode: Boolean;     {한/영 모드 얻기}

var
    Conversion, S: DWORD;

 begin
    K_Emode := ImmGetContext(handle);
    ImmGetConversionStatus(K_Emode, Conversion, S);

    if Conversion = IME_CMODE_HANGEUL then
       GetK_Mode := True
    else
       GetK_Mode := False;

 end;

 procedure TForm1.Button1Click(Sender: TObject);

 begin
    ConvK_Emode;

    if GetK_Mode then Label1.Caption := '한글'
    else Label1.Caption := '영문';
 end;

 procedure TForm1.FormCreate(Sender: TObject);

 begin
    if GetK_Mode then Label1.Caption := '한글'
    else Label1.Caption := '영문';
 end;

 end.

 

<키보드의 임의키 발생>

 아래 예제가 있습니다.

 사용법은 Memo1 에 임의의 문장을 작성한 후 E_VirtualKey 콤포넌트에 문자열" BACK"이라고 입력한 후 SpeedButton1 을 누르시면 한 글자씩 지워집니다.

 다른 키의 조합도 사용해 보세요.

 unit Unit1;

 interface

 uses
    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
    Buttons, StdCtrls;

 type
    TForm1 = class(TForm)
    SpeedButton1: TSpeedButton;
    Memo1: TMemo;
    E_VirtualKey: TEdit;
    procedure SpeedButton1Click(Sender: TObject);
  
 private
 { Private declarations }
 public
 { Public declarations }
 end;

 var
    Form1: TForm1;

 implementation {$R *.DFM}

 procedure SimulateKeystroke(VirtualKey: byte; ScanCode: DWORD);
 begin

    // keybd_event 함수를 사용한 키 조합(down, up) 발생
    keybd_event(VirtualKey,     // 키의 down
       ScanCode,  0,  0);

    keybd_event(VirtualKey,     // 키의 up
       ScanCode, KEYEVENTF_KEYUP, 0);

 end;

 procedure SimulateKeyDown(Key : byte);
 begin
    // keybd_event 함수를 사용한 키 down 발생
    keybd_event(Key, 0, 0, 0);
 end;

 procedure SimulateKeyUp(Key : byte);
 begin
    // keybd_event 함수를 사용한 키 up 발생
    keybd_event(Key, 0, KEYEVENTF_KEYUP, 0);
 end;

 procedure TForm1.SpeedButton1Click(Sender: TObject);
 var
    hs: String;
    w : word;

 begin
    Memo1.SetFocus;
    hs := UpperCase(E_VirtualKey.Text);

    if pos('INS',hs)> 0 then SimulateKeystroke(VK_INSERT, 0) else
    if pos('DEL',hs)> 0 then SimulateKeystroke(VK_DELETE, 0) else
    if pos('RT',hs)> 0 then SimulateKeystroke(VK_RETURN, 0) else
    if pos('TAB',hs)> 0 then SimulateKeystroke(VK_TAB, 0) else
    if pos('ESC',hs)> 0 then SimulateKeystroke(VK_ESCAPE, 0) else
    if pos('BACK',hs)> 0 then SimulateKeystroke(VK_BACK, 0) else
    if pos('UP',hs)> 0 then SimulateKeystroke(VK_UP, 0) else
    if pos('DOWN',hs)> 0 then SimulateKeystroke(VK_DOWN, 0) else
    if pos('LEFT',hs)> 0 then SimulateKeystroke(VK_LEFT, 0) else
    if pos('RIGHT',hs)> 0 then SimulateKeystroke(VK_RIGHT, 0) else
    if pos('PGDN',hs)> 0 then SimulateKeystroke(VK_NEXT, 0) else
    if pos('PGUP',hs)> 0 then SimulateKeystroke(VK_PRIOR, 0) else
    if pos('END',hs)> 0 then SimulateKeystroke(VK_END, 0) else
    if pos('HOME',hs)> 0 then SimulateKeystroke(VK_HOME, 0);
    { ... 이하 가상키의 조합을 발생시킬 수 있습니다}

     // 그리고 위의 SimulateKeyDown, SimulateKeyUp 를 사용하여 Shift, Ctrl, Alt 등은
     // down 상태를 유지하고(SimulateKeyDown), 이를 해제(SimulateKeyUp)할 수 있습니다
     // 또한 일반 문자의 ScanCode는 VkKeyScan() 함수로 알 수 있습니다

 end;

 end.

 

<스크린 해상도 변경>

해상도 변경을 위하여 TDevMode 개체를 사용합니다...

 var
    DevMode : TDevMode;

 를 선언하시고...

 구현부에서는 아래와 같죠...

 With DevMode Do Begin
    dmSize := SizeOf(TDevMode);
    dmPelsWidth := 800;
    dmPelsHeight := 600;
    dmFields := DM_PELSWIDTH Or DM_PELSHEIGHT;
 End;

 스크린 해상도의 변경은 좀 신중을 기해야 겠죠...

 

<DELPHI에서 STRING 가지고 놀기>

String Type 의 변수를 가지고 할 수 있는 일 !

 1. Concat (문자열을 합쳐 준다)

    function Concat(str1, str2: String);string;
       str1 = 첫 번째 문자열
       str2 = 두 번째 문자열

 var
    str : String;

 begin
    str := '멍멍이';
    str := concat(str, '강아지');

 실행 결과 : 멍멍이강아지

 //---------------------
 str := '멍멍이;
 str := str + '강아지';
// -----------------------

 위의 문장과 다를게 없다.

 

 2. Copy (원하는 만큼의 문자열을 RETURN 해 준다)

 function Copy(str: String, Index, Counter: integer);string;
    Index = 시작 위치
    Counter = 시작위치부터의 리턴할 문자열까지의 카운터

 var
    str : String;

 begin
    str := '송아지 망아지';
    str := Copy(str, 1, 6);

 실행 결과 : 송아지

 

 3. Insert (원하는 위치의 문자열을 삽입 시킨다)

 procedure Insert(Source: string; var S: string; Index: Integer);
    Source = 원본 문자열
    S = 삽입시킬 문자열
    index = 삽입시킬 위치

 var
    str: string;

 begin
    str := '강지';
    Insert('아', str, 2);
 end;

 실행 결과 : 강아지

 

 4. Delete (원하는 위치의 문자열을 삭제 한다)

 procedure Delete(var S: string; Index, Count:Integer);
    S = 소스 문자열
    index = 삭제를 시작할 위치
    Count = 시작위치부터의 지울위치까지의 카운터

 var
    s: string;

 begin
    s := '강앙아지';
    Delete(s,3, 2);
 end;

 실행 결과 : 강아지

 

 5. Length (문자열의 길이를 반환 해 준다)

 function Length(S: string): Integer;

    s = 소스 문자열

 var
    s : String
    Len : integer;

 begin
    s := '강아지';
    Len := Length('강아지');

 실행 결과 : 6

 

 6. Pos (찾고자 하는 문자열의 위치를 반환하여 준다)

 Pos(Substr: string; S: string): Integer;
    Substr = 찾고자 하는 문자열
    S = 원본 문자열

 var
    str : String;
    sub : String;
    Position : integer;

 begin
    str := '송아지';
    Position := Pos('아', S);
 end;

 실행 결과 : 3

 

<Tray에 아이콘 넣기>

Win95의 오른쪽 귀퉁이에는 스피커의 볼륨조절과 같은 작은 아이콘들이 있습니다.. 자신의 프로그램을 그곳으로 밀어넣는 방법입니다..

 먼저 트레이에서 발생하는 메세지를 받아야 하므로 메세지를 정해야 합니다. 다음줄을 {$R *.DFM} 아랫줄에 넣어주세요.

 물론 그 한참 위에 넣어도 되지만 다른 유닛에서 쓸게 아니니 아랫쪽에 넣는게 좋죠.

    const MY_SHOWFORM_ID = WM_USER+1;

 이제 넣는 부분입니다. 다음의 코드를 FormCreate에 넣어줍니다.

 

 procedure TfmTrayMain.FormCreate(Sender: TObject);
 var
    iconData : TNotifyIconData;

 begin
    // 폼을 트레이에 넣어준다.
    ShowWindow (Application.Handle, SW_HIDE);
    // 폼이 안 보임
    Application.ShowMainForm:= False;
    with IconData do
    begin
       cbSize := SizeOf ( IconData );
       // 델파이에서는 Wnd로 바뀌었음
       Wnd := Handle;
       uID := 100;
       uFlags := NIF_MESSAGE + NIF_ICON + NIF_TIP;
       uCallbackMessage := WM_USER + 1;
       hIcon := Application.Icon.Handle;
       StrPCopy(szTip, Application.Title);
    end;

    Shell_NotifyIcon( NIM_ADD, @IconData );
 end;

 

 넣기만 하면 안되겠죠.. 마우스로 클릭하면 다시 화면에 표시가 되어야 죽이든지 바꾸든지 할테니까요.. 다음과 같이 다시 살릴 수 있습니다.

 

 // 메세지 프로시져
 procedure TfmTrayMain.WndProc;
 begin
    case Message.Msg of
       MY_SHOWFORM_ID:
    case Message.lParam of
       WM_LBUTTONDBLCLK: Self.Show;
 end;

 end;

 inherited;
 end;

 

 WndProc는 구지 설명할 필요는 없을테구, 모르시는 분을 위해 선언부까지 얹어드립니다.

    procedure WndProc ( var Message : TMessage ); override;

 

<다른 프로그램실행 시킨후 Wait하기>

How do I execute a program and have my code wait until it is finished?

 //-------A: Here is the 16 bit version:

 uses Wintypes,WinProcs,Toolhelp,Classes,Forms;

 Function WinExecAndWait(Path : string; Visibility : word) : word;
 var
    InstanceID : THandle;
    PathLen : integer;

 begin
    { inplace conversion of a String to a PChar }
    PathLen := Length(Path);
    Move(Path[1],Path[0],PathLen);
    Path[PathLen] := #00;
    { Try to run the application }
    InstanceID := WinExec(@Path,Visibility);
    if InstanceID< 32 then    { a value less than 32 indicates an Exec error }
    WinExecAndWait := InstanceID

 else begin
    Repeat
       Application.ProcessMessages;
    until Application.Terminated or (GetModuleUsage(InstanceID) = 0);

    WinExecAndWait := 32;
 end;

 end;


 //--------- Here is the 32 bit version:

 function WinExecAndWait32(FileName:String; Visibility : integer):integer;
 var
    zAppName:array[0..512] of char;
    zCurDir:array[0..255] of char;
    WorkDir:String;
    StartupInfo:TStartupInfo;
    ProcessInfo:TProcessInformation;

 begin
    StrPCopy(zAppName,FileName);
    GetDir(0,WorkDir);
    StrPCopy(zCurDir,WorkDir);
    FillChar(StartupInfo,Sizeof(StartupInfo),#0);
    StartupInfo.cb := Sizeof(StartupInfo);
 
    StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
    StartupInfo.wShowWindow := Visibility;
    if not CreateProcess(nil,
       zAppName,   { pointer to command line string }
       nil,                { pointer to process security attributes }
       nil,                { pointer to thread security attributes }
       false,            { handle inheritance flag }
       CREATE_NEW_CONSOLE or   { creation flags }
       NORMAL_PRIORITY_CLASS,
       nil,                { pointer to new environment block }
       nil,                { pointer to current directory name }
       StartupInfo,   { pointer to STARTUPINFO }
       ProcessInfo) then Result := -1    { pointer to PROCESS_INF }

    else begin
       WaitforSingleObject(ProcessInfo.hProcess,INFINITE);
       GetExitCodeProcess(ProcessInfo.hProcess,Result);
    end;
 end;

 

<문자열 대.소문자로 바꾸기>

 EDITBOX 같은데서 키보드 입력 제한을 할때 영문(대.소문자)를 가리기 위해 대부분이 keypress 나 keyup 또는 keydown EVENT에서 처리 하는 것으로 알고 있습니다.

  좀 뭐랄까 ??? 약간 무식한 방법이였지요.... 소스코드도 지저분해 지고.......

  EditChange Event에서 다음과 같은 방법을 권합니다.

 

 procedure _MYForm.WoonoEdit1Change(Sender : TObject);
 begin
        WoonoEdit1.CharCase := clLowerCase;
        // 입력 받을때 무조건 영문 소문자로 받는다.
 end;

 

 ecLowerCase : 모든 영문자를 소문자로 받는다.
 ecUpperCase : 모든 영문자를 대문자로 받는다.
 ecNormal       : 모든 영문자를 보통 상태로 유지한다.

 

<파일정보(생성,변경,접근일자,속성,종류...)>

 아래 소스는 파일의 각종 정보를 읽어오는 루틴인데 완전히 모듈화가 된 것은 아니지만, 파일의 생성,변경,접근일자를 읽는 부분이 있어 올립니다  

  function FileSize(hi,lo: integer) :longint; 
  begin
    Result := (hi * MAXDWORD) + lo;
  end;

  // This function retrieves the last time, the given file was written to disk
 function GetLocalTime(a:tfiletime):string;

 var
      mtm:   TSystemTime;
      at:    TFileTime;
      ds,ts: ShortString;

 begin
      filetimetolocalfiletime(a,at);
      filetimetosystemtime(at,mtm);
      SetLength(ds, GetDateFormat(LOCALE_USER_DEFAULT, 0, @mtm, NIL, @ds[1], 255) - 1);
      SetLength(ts, GetTimeFormat(LOCALE_USER_DEFAULT, time_noseconds, @mtm, NIL,
            @ts[1], 255)  - 1);
      Result:=ds+'  '+ts;
 end;

 procedure TFileInfoForm.GetFileInfo(FileName: String);

 var
    SHFinfo: TSHFileInfo;
    FindData: TWin32FindData;    FindHandle :THandle;

 begin
    L_FileName.Caption := ExtractFileName(FileName); // 파일명(Name)
    ShGetFileInfo(PChar(FileName), 0, SHFinfo, SizeOf(SHFinfo), // 파일종류만 알아낸다
                  SHGFI_TYPENAME);
    L_Filetype.Caption := SHFinfo.szTypeName; // 파일종류(Type)
    FindHandle := Windows.FindFirstFile(PChar(FileName), FindData);

    try
      L_Filesize.Caption := FloatToStr(Trunc(FileSize(FindData.nFileSizeHigh,
         FindData.nFileSizeLow) / 1024))+' KB ('+ IntToStr(FileSize(FindData.nFileSizeHigh,
         FindData.nFileSizeLow))+' Bytes)';

      OldAttributes := FileGetAttr(FileName);  // 파일의 속성(attribute)
      CB_ReadOnly.Checked := (OldAttributes and faReadOnly) = faReadOnly;
      CB_Archive.Checked  := (OldAttributes and faArchive) = faArchive;
      CB_System.Checked   := (OldAttributes and faSysFile) = faSysFile;
      CB_Hidden.Checked   := (OldAttributes and faHidden) = faHidden;
       L_Created.Caption    := GetLocalTime(FindData.ftCreationTime);   // 파일생성일(Created)
      L_Modified.Caption   := GetLocalTime(FindData.ftLastWriteTime);  // 파일변경일(Modified)
      L_LastAccess.Caption := GetLocalTime(FindData.ftLastAccessTime);
      // 파일접근일(LastAccess)

    finally
      Windows.FindClose(FindHandle);
    end;
 end;

 

<JPEG 파일 처리>

우선 uses 에 JPEG 를 추가한다.

procedure TForm1.Button1Click(Sender : TObjcect);
var
   TempImg : TImage;
   Jpg : TJPEGImage;
begin
   TempImg:=TImage.Create(Self);
   with TempImg do   begin
      Width:=PaintBox1.Width;
      TempImg.Height:=PaintBox1.Height;
   end;
   Jpg:=TJPEGImage.Create;
   with PaintBox1 do begin
      BitBlt(TempImg.Canvas.Handle,0,0,Width,Height,Canvas.Handle,0,0,SrcCopy);
   end;
   TempImg.Picture.Bitmap.SaveToFile('TempImg.bmp');
   Jpg.Assign(TempImg.Picture.Bitmap);
     //Bitmap File을 Jpeg파일로
   Jpg.SaveToFile('TestImg.jpg');
   TempImg.Free;
   Jpg.Free;
end;

 

다른 방법(함수 이용 - 천리안 류님께서 올린 함수)
* Source

Implementation
uses
   JPeg;
 
procedure LoadJPeg(FileName:String; PicIn:TPicture);
var
   JPegImage : TJPegImage;
begin
   JPegImage:= TJPegImage.Create;
   JPegImage.LoadFromFile(FileName);
   PicIn.Assign(JPegImage);
   JPegImage.Free;
end;
 
procedure TForm1.Button1Click(Sender : TObject);
begin
  if OpenDialog1.Execute then
     LoadJPeg(OpenDialog1.Filename, Image1.Picture);
      //JPEG파일을 로드하여 Image1에 보여줌
end;

 

<Image 컴포넌트 위에 글씨쓰기>

procedure TForm1.Button1Click(Sender: TObject);
var
   OldBkMode : integer;
begin
   Image1.Picture.Bitmap.Canvas.Font.Color := clRed;
   OldBkMode := SetBkMode(Image1.Picture.Bitmap.Canvas.Handle, TRANSPARENT);
   Image1.Picture.Bitmap.Canvas.TextOut(10, 10, 'Hi, I am Park');
   SetBkMode(Image1.Picture.Bitmap.Canvas.Handle, OldBkMode);
end;

 

<파일의 날짜와 시간을 알아내기>

아래 함수를 이용합니다.
function GetFileDate(TheFileName: string): string;
var
   FHandle: integer;
begin
   FHandle := FileOpen(TheFileName, 0);
   try
      Result := DateTimeToStr(FileDateToDateTime(FileGetDate(FHandle)));
   finally
      FileClose(FHandle);
   end;
end;

 

<드라이브에 디스크 존재여부 알아내기>

function DriveReady(Drive : char):Boolean;
var
   OldErrorMode : word;
   OldDir : string;
begin
   OldErrorMode:= SetErrorMode(SEM_NOOPENFILEERRORBOX);
   GetDir(0, OldDir);
   Result:= True;
   try
      ChDir(Drive + ':\');
   except
      Result:= False
   end;
   ChDir(OldDir);
   SetErrorMode(OldErrorMode);
end;
 
procedure TForm1.Button1Click(Sender: TObject);
begin
   if DriveReady('A') then ShowMessage('Drive is Ready')
   else ShowMessage('Drive not Ready');
end;

 

<화면 캡쳐하여 저장하기>

procedure TForm1.Button1Click(Sender: TObject);
var
   DeskTop : TCanvas ;
begin
   DeskTop := TCanvas.Create ;
   try
   with DeskTop do
      Handle := GetWindowDC (GetDesktopWindow) ;
   with PaintBox1.Canvas do
   CopyRect (Rect (0, 0, Width, Height),   DeskTop, Rect (0, 0, Width, Width))
   finally
      DeskTop.Free
   end;
end;
 
procedure TForm1.Button2Click(Sender: TObject);
var
   MyBmp: TBitmap;
begin
   MyBmp := TBitmap.Create;
   with MyBmp do begin
     Height := PaintBox1.Height;
     Width := PaintBox1.Width;
     Canvas.CopyRect (Rect (0, 0, Width, Height), PaintBox1.Canvas, Rect (0, 0, Width, Height));
     SaveToFile('c:\Grim.bmp');
   end;
      MyBmp.Free;
end;

 

<텍스트 문서 미리보기>

솔직히 미리보기라기 보다는 텍스트 파일의 내용을 Bitmap파일로 변환하여 저장합니다.
procedure TForm1.Button1Click(Sender: TObject);
var
   Bmp : TBitmap;
   Line : string;
   I : integer;
   ch : char;
   F : TextFile;
begin
   I := 0;
   Bmp := TBitmap.Create;
   with Bmp do begin
      Width := ClientRect.Right;
      Height := ClientRect.Bottom;
      AssignFile(F, 'c:\mytext.txt'); {저장하고자 하는 파일명을 삽입}
      Reset(F);
      repeat
        Inc(I);
        Line := '';
        repeat
          Read(F, ch);
          Line := Line+ch;
       until ch= #10;
       Canvas.TextOut(10, I*20, Copy(Line, 1, Length(Line)-2));
      until EOF(F);
   CloseFile(F);
   BitBlt(Canvas.Handle, 0, 0, Width, Height, GetDc(Handle),  ClientRect.Left, ClientRect.Top, SRCCOPY);
   SaveToFile('c:\preview.bmp');
   Free;
   end;
end;

 

<폼의 크기 제한하기>

폼의 크기를 조절할 때 최대, 최소의 크기제한을 두려면
"WM_GETMINMAXINFO"의 메시지 핸들러를 작성해야 한다.
type
   TForm1 = class(TForm)
     procedure FormCreate(Sender: TObjcet);

   private
     MinSize : TPoint;       //최소크기 제한
     MaxSize : TPoint;      //최대크기 제한
     procedure WMGetMinMaxInfo(var Msg: TWMGetMinMaxInfo);
     message WM_GETMINMAXINFO;
     //메시지 WM_GETMINMAXINFO에 반응하는 메소드

   public
end;
 
procedure TForm1.WMGetMinMaxInfo(var Msg: TWMGetMinMaxInfo);
begin
   if visible then begin
   Msg.MinMaxInfo^.PtMinTrackSize := MinSize;
   Msg.MinMaxInfo^.PtMaxTrackSize := MaxSize;
   end;
end;
 
procedure TForm1.FormCreate(Sender: TObject);  //최대,최소 사이즈 지정
begin
   MaxSize.X := 200;   
   MaxSize.Y := 500;
   MinSize.X := 100;
   MinSize.Y := 200;
end;

 

<마우스 동작범위 제한하기>

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
   R : TRect;
begin
   R := BoundsRect;
   InflateRect(R,-30,-30);
   ClipCursor(@R);
end;
 
procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
   ClipCursor(Nil);
end;

 

<스플레시 화면 만들기>

프로그램 시작시 나타나는 로고화면을 제작하는 방법이다. 이는 프로젝트파일(.dpr)를 직접
수정해야만 한다.
Project Option에서 SplashForm을  Available forms로 옮긴다.
program project1;
 
uses
   Forms,
   Unit1 in 'Unit1.pas' {Form1},
   Splash in 'Splash.pas' {SplashForm},
 
{$R *.RES}
begin
  SplashForm := TSplashForm.Create(Application);
  SplashForm.Show;
  SplashForm.Update;
  Application.CreateForm(TForm1, Form1);
  SplashForm.Hide;
  SplashForm.Free;
   Application.Run;
end.

 

<구멍난 폼 만들기>

하나의 폼 위에 다섯개의 판넬을 올려놓고 각각의 속성을  아래의 '표1' 과 같이 설정하고,
폼의 OnResize이벤트 헨들러를 생성 해 아래의 코드를 입력하자.
 
procedure TForm1.FormResize(Sender: TObject);
var
   WindowRgn, HoleRgn : HRgn;
begin
   WindowRgn := 0;
   GetWindowRgn(Handle, WindowRgn);
   DeleteObject(WindowRgn);
   WindowRgn := CreateRectRgn(0,0,Width, Height);
   HoleRgn := CreateRectRgn(Panel3.Width + 6, Panel1.Height + 25,
                   Width - (Panel4.Width + 6), Height - (Panel2.Height + 6));
   CombineRgn(WindowRgn, WindowRgn, HoleRgn, RGN_DIFF);
   SetWindowRgn(Handle, WindowRgn, TRUE);
   DeleteObject(HoleRgn);
end;
 
표1
---------------------------------
Panel1
---------------------------------
Align alTop
BevelOuter bvNone
Caption
Height 17
---------------------------------
Panel2
---------------------------------
Align alBottom
BevelOuter bvNone
Caption
Height 17
---------------------------------
Panel3
---------------------------------
Align alRight
BevelOuter bvNone
Caption
Width 17
---------------------------------
Panel4
---------------------------------
Align alRight
BevelOuter bvNone
Caption
Width 17
---------------------------------
Panel5
---------------------------------
Align alClient
BevelOuter bvLowered
Caption
---------------------------------

 

<원형 폼 만들기>

procedure TForm1.FormCreate(Sender : TObjcet);
var
   MyForm : HRGN;
begin
   MyForm := CreateEllipticRgn(0, 0, Width, Height);  //타원의 폼 설정
   SetWindowRgn(Handle, MyForm, TRUE);
end;
procedure TForm1.FormDestory(Sender : TObject);
begin
   DeleteObject(MyForm);
end;

 

<다각형의 폼 만들기>

다각형의 폼도 마찬가지로 CreatepolygonRgn함수를 사용해 만들 수 있다.
아래와 같이 하면 역삼각형의 폼이 만들어진다.
procedure TForm1.FormCreate(Sender : TObject);
var
   MyForm : HRGN;
   Pixel : array[0..2] of TPoint;
begin
   Pixel[0] := Point(0, 0);        //폼의 좌표를 설정
   Pixel[1] := Point(Width, 0);
   Pixel[2] := Point(Width div 2, Height);
   MyForm := CreatePolygonRgn(Pixel, 3, ALTERNATE);
   SetWindowRgn(Handle, MyForm, TRUE);
end;

 

<힌트의 속성바꾸기>

델파이에서는 힌트속성을 쉽게 구현할 수 있는 반면 힌트의 속성을 바꿀 수 있는 프로퍼티가 없습니다.
아래의 방법을 통해 속성을 바꿔보세요.
....
type
  TUserHint = class(THintWindow)
  constructor Create(AOwner: TComponent); override;
end;                                         //interface부에 삽입
...
constructor TUserHint.Create;
begin
   inherited Create(AOwner);
   Canvas.Font.Name := '궁서체';    // 원하는 폰트의 이름 지정
   Canvas.Font.Size := 10;              // 원하는 폰트의 사이즈 지정   
   Canvas.Brush.Color := clYellow;  // 원하는 바탕색 지정
end;                                             // implementation부에 삽입
 
procedure TForm1.FormCreate(Sender: TObjcet);
var
   OldHint : Boolean;
begin
   OldHint := Application.ShowHint;
   Application.ShowHint := False;
   HintWindowClass := TUserHint;
   Application.ShowHint := OldHint;
end;
end.

 

<상태바에 힌트보이기>

public
{ Public declarations }
   procedure ShowHint(Sender : TObject);  //힌트를 보이기위한 프로시저
end;
 
procedure TForm1.ShowHint(Sender : TObject);
begin
    StatusBar1.Panels[0].Text := Application.Hint;
end;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
    Application.HintPause := 100;  //힌트가 나타나는 속도조절
    Application.OnHint := ShowHint;
end;
또한 힌트와 상태바에 동시에 힌트를 나타내고자 하는 경우에는 Hint속성을 '|'문자를 끊어서
동시에 지정할 수 있다. ("풍선도움말|OnHint이벤트에서 사용할 힌트")

 

<Drive Type을 알아내자>

임의의 드라이브 타입을 알려면, 윈도우 API 함수 중 GetDriveType이라는 함수를 사용하면 된다.

 

procedure TForm1.Button1Click(Sender: TObject);

var
   Drive: Char;
   DriveLetter: String[4];

begin
   for Drive := 'A' to 'Z' do
   begin
      DriveLetter := Drive + ':\';
      //  Syntax
      //  GetDriveType(
      //  lpRootPathName: PChar   {a pointer to the root path string}
      //  ): UINT;                 {returns a value based on the drive type}

      case GetDriveType(PChar(Drive + ':\')) of
         Drive_UnKnown : ListBox1.Items.Add( DriveLetter + ': 알 수 없는 드라이브');
         Drive_Removable: ListBox1.Items.Add( DriveLetter + ' : 플로피 드라이브');
         Drive_Fixed:      ListBox1.Items.Add( DriveLetter + ' : 하드 드라이브');
         Drive_Remote:    ListBox1.Items.Add( DriveLetter + ' : 네트워크 드라이브');
         Drive_Cdrom:     ListBox1.Items.Add( DriveLetter + ' : CD-Rom 드라이브');
         Drive_RamDisk:   ListBox1.Items.Add( DriveLetter + ' : RamDisk 드라이브');
      end;
   end;
end;


[TMemo Component] 현재 라인번호 알아내기

메모에서 현재 Caret이 위치하고 있는 줄이 몇 번째 줄인지를 리턴한다.

Label1.Caption := IntToStr(GetCurrLine(Memo1));

function GetCurrLine(Memo : TMemo) : integer;
begin
      Result := Memo.Perform(EM_LINEFROMCHAR, Memo.SelStart, 0);
end;

 

[TMemo Component] 현재 컬럼번호 알아내기

메모에서 현재 Caret이 위치하고 있는 줄에서 몇 번째 컬럼인지를 리턴한다.

Label1.Caption := IntToStr(GetCurrCul(Memo1));

function GetCurrCul(Memo : TMemo)) : integer;
begin
     Result := Memo.SelStart - Memo.Perform(EM_LINEINDEX, GetCurrLine(Memo), 0);
end;

 

[TMemo Component] Caret를 원하는 라인으로 이동하기

Caret을 원하는 위치로 이동시키는데 이때 넘겨주는 값이 라인의 한계를 벗어나면 그 안 범위로 위치시킨다.

만약 라인의 맨끝으로 이동시키고 싶다면 아주 큰값을 주면된다.

SetCurrLine(Memo1. 10);

procedure SetCurrLine(Memo : TMemo; Value : integer);
begin
   if Value < 0 then Value := 0;
   if Value > Memo.Lines.Count then Value := Memo.Lines.Count;
   Memo.SelLength := 0;
   Memo.SelStart := Memo.Perform(EM_LINEINDEX, Value, 0);
end;

[TMemo Component] Caret을 원하는 컬럼으로 이동하기

SetCurrCul(Memo1. 10);

procedure SetCurrCul(Memo : TMemo; Value : integer);
var
   CurrLine : integer;
begin
   CurrLine := GetCurrLine(Memo);
   if Value < 0 then Value := 0;
   if (Value > Length(Memo.Lines[CurrLine])) then
      Value := Length(Memo.Lines[CurrLine]);
   Memo.SelLength := 0;
   Memo.SelStart := Memo.Perform(EM_LINEINDEX, CurrLine, 0) + Value;
end;

 

[TMemo Component] Text가 쓰여지는 영역 알아내기

현재 Text가 쓰여지는 영역을 TRect형으로 리턴한다.

즉 글자의 높이가 10이고 메모의 높이가 25라면 2라인만이 그려지게 된다.

따라서 글자가 그려지는 정확한 영역을 알아내기 위해서는 아래 함수를 사용한다.

Rect := GetTextRect(Memo1);

function GetTextRect(Memo : TMemo) : TRect;
var
   lParam : TRect;
begin
   Memo.Perform(EM_GETRECT, 0, Integer(@lParam));
   Result := lParam;
end;

 

[TMemo Component] 메모에서 현재 보이는 라인수 알아내기

Label1.Caption := IntToStr(GetVisibleLine(Memo1));

function GetVisibleLine(Memo : TMemo) : integer;
var
   Metric : TTextMetric;
   DC : hDC;
begin
   DC := GetWindowDC(Memo.Handle);
   GetTextMetrics(DC, Metric);
   Result := (GetTextRect(Memo).Bottom div Metric.tmHeight);
end;

 

[TMemo Component] 원하는 라인만큼 스크롤하기

현재상태에서 원하는 x, y만큼 스크롤한다.

DoScroll(Memo1, 10, 10);

procedure DoScroll(Memo : TMemo; x : integer; y : integer);
begin
   Memo.Perform(EM_LINESCROLL, x, y);
end;

 

[TRichEdit Component] 블록설정부분 폰트 변경하기

리치에디트컴포넌트는 메모컴포넌트와는 달리 설정부분만 폰트를 변경한다던가, 정렬상태를 바꾸는게 가능하다.

procedure TForm1.FontBtnClick(Sender : TObject);

begin
   if RichEdit1.SelLength > 0 then
   begin
      FontDialog1.Font.Assign(RichEdit1.DefAttributes);
     if FontDialog1.Execute then
         RichEdit1.SelAttributes.Assign(FontDialog1.Font);
   end

   else
     ShowMessage('No Text Selected');
end;

  

[TRichEdit Component] 블록설정부분 속성 변경하기

아래의 소스는 굵게(Bold) 속성을 지정한다.

이탤릭(fsItalic), 밑줄(fsUnderLine) 등의 속성도 마찬가지로 바꿀 수 있다.

procedure TForm1.BoldBtn(Sender : TObject);
begin
   if BoldBtn.Down then
      RichEdit1.SelAttributes.Style := RichEdit1.SelAttributes.Style + [fsBold]
   else
      RichEdit1.SelAttributes.Style := RichEdit1.SelAttributes.Style - [fsBold];
end;

 

[TRichEdit Component] 블록설정부분 복사, 삭제, 잘라우기, 붙이기 설정방법

interface부의 uses절에 Clipbrd를 추가한다.

procedure TForm1.CopyBtnClick(Sender : TObject);
begin
   RichEdit1.CopyToClipboard;  {복사}
   RichEdit1.CutToClipboard;   {잘라두기}
   RichEdit1.ClearSelection;  {지우기 - 클립보드에 저장되지 않는다}
   if Clipboard.HasFormat(CF_TEXT) then begin
      PasteBtn.Enabled := True;   {복사가 되었으면붙이기 버튼을 활성화}
   end;
end;

procedure TForm1.PasteBtnClick(Sender : TObject);
begin
   RichEdit1.PasteFromClipboard;
end;

 

[TRichEdit Component] Insert 키 상태 알아내기

이 소스는 RichEdit 컴포넌트에서만 사용할 수 있다.(메모컴포넌트는 삽입, 수정의 개념이 없음)

procedure TForm1.RichEdit1Key(Sender: TObject; var Key: Word; Shift: TShiftState);
var
  ret : integer;
begin
   ret := GetKeyState(45);
   if ret=1 then
      Label1.Caption := 'Overwrite'
   else
      Label1.Caption := 'Insert';
end;

 

[Find Dialog Component] 리치에디트에서 문자열찾기

먼저 폼에 Memo, FindDialog컴포넌트를 배치합니다. 델파이 도움말에서 참조했습니다.

procedure TForm1.FindBtnClick(Sender : TObject);
begin
   FindDialog1.Execute;
   { or ReplaceDialog1.Execute;}
end;

procedure TForm1.FindDialog1Find(Sender: TObject);
var
   SelPos: Integer;
begin
   with TFindDialog(Sender) do
   begin
      { Perform a global case-sensitive search for FindText in Memo1 }
      SelPos := Pos(FindText, Memo1.Lines.Text);
      if SelPos > 0 then 
      begin
         Memo1.SelStart := SelPos - 1;
         Memo1.SelLength := Length(FindText);
       end
     
      else MessageDlg(Concat('Could not find "', FindText, '" in Memo1.'),
          mtError,[mbOk], 0);
   end;
end;

procedure TForm1.ReplaceDialog1Replace(Sender: TObject);
var
   SelPos: Integer;
begin
   with TReplaceDialog(Sender) do
   begin
     { Perform a global case-sensitive search for FindText in Memo1 }
     SelPos := Pos(FindText, Memo1.Lines.Text);
     if SelPos > 0 then
     begin
        Memo1.SelStart := SelPos - 1;
        Memo1.SelLength := Length(FindText);
        { Replace selected text with ReplaceText }
        Memo1.SelText := ReplaceText;
      end
   
     else MessageDlg(Concat('Could not find "', FindText, '" in Memo1.'),
          mtError,[mbOk], 0);

   end;
end;

 

<System Modal 폼을 만들려면>

Windows API 함수인 SetSysModalWindow를 사용하면 가능합니다.

다음은 System Modal 창을 보여주는 간단한 예제입니다.

procedure TMainForm1.Create(Application) do
begin
   SetSysModalWindow(Handle);
end;

 

<.RES 화일에서 비트맵을 불러오려면>

다음과 같이 선언합니다.

implementation
{$R C:\Delphi\MyDir\MyRes.Res} <- .RES 화일이 있는 경로명과 파일명

위와 같이 선언한 후에 사용시에는 다음과 같이 Windows API함수를 이용합니다.

Image1.Picture.Bitmap.Handle := LoadBitmap(HInstance, 'BITMAP1');

 

<Win95 와 W3.X 를 구별하는 법>

Windows API 함수인 GetVersion 을 쓰시면 가능합니다.

다음은 버튼을 누르면 윈도우의 버전을 보여줍니다.

procedure TForm1.Button1Click(Sender: TObject);
Var
   x :longint;
   y,z :integer;
begin
   x := GetVersion;
   y := integer(x and $ff);
   z := integer((x shr 8) and $ff);
   Edit1.Text := IntToStr(y);
   Edit2.Text := IntToStr(z);
end;

 

<마우스 커서를 보이지 않게 하려면>

Window API함수인 ShowCursor 에서 값을 False로 줍니다.

 

<정의된 message handler에 다른 작업을 추가하려면>

예를 들어 CM_DIALOGKEY message가 발생되었을 때 원하는 작업을 추가하려고한다면 public section에 다음과 같이 선언합니다.

Procedure CMDialogKey(var Message: TCMDialogKey);message CM_DIALOGKEY;

procedure이름을 message 이름에서 _(밑줄) 표시를 뺍니다. procedure의 정의는 다음과 같습니다.

Procedure TForm1.CMDialogKey(var Message: TCMDialogKey);
begin
   if CharCode = VK_TAB then begin
      {Process the Alt+Tab key here}
      result := 1;
      exit;
   end;
   inherited;
end;

result를 1로 setting하면 더 이상 실행시키지 않고 중단시키겠다는 뜻이고, inherited문은 parent handler로 제어를 보냄을 의미합니다. 모든 작업을 일일이 처리하고자 하지 않으면 inherited문을 사용하십시오.

 

<Run-Time시에 DLL을 Load하고 Free 시키는 방법>

Windows API 함수인 LoadLibrary를 쓰면 Load가 가능합니다. 또한 FreeLibrary를 쓰면 메모리에서 제거할 수 있습니다.

 

<비정상적으로 종료된 DLL 프로그램을 강제적으로 unload 하는 방법>

Windows API 함수인 GetModuleHandle은 DLL의 handle을 돌려주므로ModuleHandle이 0을 리턴할 때 까지 freelibrary를 call한다. 만약에 DLL이 다른 DLL을 Load 했다면 child DLL을 먼저 free시킨다.

 

<DLL의 data segment를 fixed에서 movable로 바꾸는 방법>

DLL 외부에서 GlobalPageUnlock(DSEG)를 부르면 됩니다. 이 함수는DLL 소스에서 Pointer등을 이용하지 않는다면 정상적으로 실행될 것입니다.

 

<최소화되어 있는 Icon을 안보이게 하는 방법>

SetWindowPos나 MoveWindow를 이용하여 좌표값을 음수로 주면 됩니다.

 

<외부의 Exe 화일 호출하는 방법>

Windows API 함수인 WinExec 를 사용하면 됩니다. 다음은 간단한 예제 코드입니다.

WinExec('프로그램명', SW_SHOW);

 

<Title Bar가 없는 Form을 움직이게 하려면>

폼위에서 마우스 커서가 움직이면, 윈도우는 폼에 WM_NCHitTest 메시지를보냅니다. 이 때 폼은 마우스가 폼의 어느 위치에 있는지를 메시지로 주게 됩니다. 마우스의 버튼을 누르는 것과 같은 event가 발생하면 윈도우는 이 정보를 써서 특정행동을 수행하게 되는 것입니다.

다음은 WM_NCHitTest 메시지가 특정한 값을 주는 예제 코드입니다.

procedure TNoCapForm.WMNCHitTest(var Msg: TMessage);
begin
   if GetAsyncKeyState(VK_LBUTTON) < 0 then
      Msg.Result := HTCAPTION
   else
      Msg.Result := HTCLIENT;
end;

 

<Resource를 동적으로 load/free 하는 방법>

Windows가 제공하는 LoadResource(), FreeResource() API 함수를사용합니다.

 

<System 또는 User resource, memory 상태를 구하는 방법>

Windows API를 이용하면 됩니다. GetFreeSystemResource 함수를 참고하시면 됩니다.

다음은 버튼을 누르면 시스템 자원을 보여주는 간단한 코드입니다.

procedure TForm1.Button1Click(Sender: TObject);
begin
   Label1.Caption := IntToStr(GetFreeSystemResources(GFSR_SYSTEMRESOURCES));
   Label2.Caption := IntToStr(GetFreeSystemResources(GFSR_USERRESOURCES));
   Label3.Caption := Formatfloat('#,##0', (GetFreeSpace(0) div 1000));
end;

 

<Visual Basic의 DoEvent와 같은 기능을 사용하려면>

다음과 같이 함수를 만드실 수 있습니다.

function DoEvents: Boolean;
var msg: TMsg;

begin
   while PeekMessage(msg, 0, 0, 0, PM_REMOVE) do
   begin
      if msg.message = WM_QUIT then
      begin
         PostQuitMessage(msg.wParam);
         DoEvents := true;
         exit;
      end
     
      else
      begin
         TranslateMessage(msg);
         DispatchMessage(msg);
      end;
   end;
   DoEvents := false;
end;

 

<프로그램의 실행이 끝나기를 기다리는 법>

WinExec 함수는 핸들을 돌려주므로, 이것을 이용합니다.

procedure SomeProc;
var
   ProgramHandle : THandle;
begin
   ProgramHandle := WinExec('C:\Program.exe', SW_SHOWNORMAL);

   {프로그램이 종료될 때까지 반복}
   while GetModuleusage(ProgramHandle) <> 0 do application.processmessages;
end;

 

<프로그램 실행중에 잠시 멈추고 다른 프로세스를 실행시키려면>

다음과 같은 코드를 작성하실 수 있습니다.

procedure TForm1.Delay(msecs:integer);
var
   FirstTickCount:longint;
begin
   FirstTickCount:=GetTickCount;

   repeat
   {실행을 잠시 중지하고 다른 프로세스를 실행합니다.}
      Application.ProcessMessages;
      until ((GetTickCount-FirstTickCount) >= Longint(msecs));
end;

참고로 Application.ProcessMessage 는 메시지 큐에 쌓여있는 메시지중 하나를처리하고 메시지가 큐에 없으면 false를 리턴합 니다.

 

<control의 handle이나 ID를 얻는 방법>

control object의 pointer를 알고 있다면 PointerToMyControl^.HWindow가 바로 window handle입니다.

만약, control의 handle을 알고 있다면 GetDlgCtrlID() API 함수는 ID를 돌려줍니다.

ControlID := GetDlgCtrlID(ControlHandle);

만약 contorl의 pointer를 모르고 ID만 알고 있다면, GetDlgItem() API 함수는handle을 돌려줍니다.

ControlHandle := GetDlgItem(DialogHandle, ControlID);

 

<프로그램이 실행된 디렉토리를 알 수 있는 방법>

다음의 함수는 Application이라는 개체의 ExeName 속성으로부터 디렉토리 경로를 추출해 냅니다.

function GetExePath : String;
var
   LastBackSlashPos, Index : Integer;
begin
   Result := Application.ExeName;
   for Index := 1 to length(Result) do
   if Result[Index] = '\' then LastBackSlashPos := Index;

   {'\' 기호가 붙지 않도록 하려면 LastBackSlashPos 에서 1을 빼야합니다. }
   Result[0] := chr(LastBackSlashPos - 1);
end;

 

<Directory를 만드는 방법>

MKDIR procedure를 이용하면 됩니다.

MkDir('C:\Delphi\MyDir');

 

<MediaPlayer를 이용하지 않고 sound를 발생할 수 있는 방법>

mmSystem에 있는 SndPlaySound Function을 이용하면 됩니다.

SndPlaySound('C:\Windows\Ding.WAV', snd_Async);

 

<Windows의 Message를 처리하는 방법>

다음 Windows 메시지를 처리하는 procedure를 참고하십시오.

procedure YieldToOthers ;
var MSG : TMSG ;
begin
   while PeekMessage(MSG, 0,0,0,PM_REMOVE) do begin
      if Msg.Message = WM_QUIT then exit ;
      TranslateMessage(Msg) ;
      DispatchMessage(Msg) ;
   end ;
end ;

 

<Windows의 Main Message Procedure를 만드는 방법>

다음 예제 procedure를 참고하십시오.

procedure TForm1.ClientWndProc(VAR Message: TMessage);
begin
   with Message do
   case Msg of
      WM_MOUSEMOVE : Memo1.Lines.Add('Mouse Move') ;
      WM_LBUTTONDOWN : Memo1.Lines.Add('LeftButton Down') ;
   else
      Result := CallWindowProc(FPrevClientProc, Handle, Msg, wParam, lParam);
   end;
end;

 

<다른 Application의 메뉴 기능을 실행하도록 하려면>

다음 예제 procedure를 참고하십시오.

CurrWnd := GetWindow(application.handle, gw_hwndfirst);
length := GetWindowText(Currwnd, tmpstr, 255);

if length > 0 then
begin
   if (pos('훈민정음', strpas(tmpstr)) > 0) and (strpas(pAttach^.filepath.tmpstr)<> nil) then
      CurrWnd := 0;
end;

tmpname := ExtractFilename(strpas(pAttach^.filepath));

While CurrWnd <> 0 do
begin
   length := GetWindowText(Currwnd, tmpstr, 255);

   if (length > 0) and (pos('훈민정음', strpas(tmpstr) > 0) and (pos(tmpname,StrPas(tmpstr)) > 0) then
   break;

   CurrWnd := GetWindow(CurrWnd, GW_HWNDNEXT);
   Application.ProcessMessages;
end;

Handle := CurrWnd;

if Handle <> 0 then
begin
   SendMessage(Handle, WM_COMMAND, 4005, 0);
   SendMessage(Handle, WM_SYSCOMMAND, SC_CLOSE, 0);
end;

 

<폼이 최소화 되지 못하도록 하려면>

다음과 같이 WM_SYSCOMMAND 메시지를 처리하면 됩니다.

type
   TForm1 = class(TForm)
public :
   procedure WMSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND;
end;

procedure TForm1.WMSysCommand(var Msg:TWMSysCommand) ;
begin
   {최소화/최대화 버튼을 누를때 아무 작용을 하지 않게 합니다}
   if (Msg.CmdType = SC_MINIMIZE) or (Msg.CmdType = SC_MAXIMIZE) then
      Msg.CmdType := SC_RESTORE;

   DefaultHandler(Msg);
end;

 

<DPR 화일의 Application.Run이 실행되기 전에 Windows 메시지를 가로채는방법>

다음과 같이 새로운 Windows Message procedure를 정의하고 그것을Main Windows procedure로 설정합니다. 다음 예제 procedure를 참고하십시오.

program Project1;

uses
   Forms, messages, wintypes, winprocs,
   Unit1 in 'UNIT1.PAS';

{$R *.RES}

var
   OldWndProc: TFarProc;

function NewWndProc(hWndAppl: HWnd; Msg, wParam: Word; lParam: Longint):Longint; export;
begin
   result := 0; { Default WndProc return value }

   {message 처리 루틴이 들어갈 곳}

   result := CallWindowProc(OldWndProc, hWndAppl, Msg, wParam, lParam);
end;

begin
   Application.CreateForm(TForm1, Form1);
   OldWndProc := TFarProc(GetWindowLong(Application.Handle, GWL_WNDPROC));
   SetWindowLong(Application.Handle, GWL_WNDPROC, longint(@NewWndProc));
   Application.Run;
end.

 

<Task Handling 방법>

ToolHelp unit에 정의되어 있는 함수들을 이용하면 됩니다. 다음은 TaskFirst, TaskNext 등을 이용한 예제입니다.

function isTaskInstance(HInst : Longint) : Boolean;
var CurrentTask : TTaskEntry;
   Success : boolean;
begin
   Result := false;
   Yield;
   CurrentTask.dwSize := SizeOf(CurrentTask);
   Success := TaskFirst(@CurrentTask);
   while Success do begin
      if CurrentTask.HInst = HInst then begin
         Result := true;
         exit;
      end;
      Success := TaskNext(@CurrentTask);
   end;
end;

 

<MDI 어플리케이션에서 focus를 가지고 있는 form이 어느 것인지 알수 있는 방법>

TForm의 ActiveMDIChild property를 이용합니다.

if Application.MainForm.ActiveMDIChild as TEditForm then
TEditForm(ActiveMDIChild).Save1Click(Sender);

 

<Delphi의 MDI에서 title bar가 없는 child form 을 만드는 방법>

다음과 같이 MDI Parent Form에 코드를 입력하시면 가능합니다.

type
   TForm1 = class(TForm) {TForm1 는 child form의 이름입니다.}
   procedure CreateParams(var Params: TCreateParams);
   override;
end;

procedure TForm1.CreateParams(var Params: TCreateParams);
begin
   inherited CreateParams(Params);
   Params.Style := Params.Style and not WS_OVERLAPPEDWINDOW or WS_BORDER ;
end;

 

<MDI application에서 특정 child를 항상 일정한 크기/위치로 고정하는방법>

Child Form의 onActivate event에서 다음과 같이 크기와 위치를 정해주면됩니다.

procedure TEditForm.FormActivate(Sender: TObject);
begin
   Left := 200;
   Height := 140;
end;

단, 이 이후에 생성하는 child form은 윈도우의 기본 특성에 따라 다른 위치로생성됩니다.

 

<MDI에서 차일드 윈도우의 위치 지정>

사용자가 Run-Time시에 Child Windows를 열면 각각은 이전 윈도우의 약간 우측 아래에 위치하게 됩니다. 이렇게 하고 싶지 않을 경우 어떻게 해야 합니까?


이것은 MDI 윈도우가 어떻게 작업하느냐 입니다. VCL은 이 상황에서윈도우의 기본적인 행동을 무시하진 못합니다.

단, Position Property 에서 poScreenCenter 값을 사용할 수 있습니다. 그러나 이 속성을 선택하면 child form이 항상 Parent Form의 가운데에 위치합니다.

 

<Caps Lock 키 조절>

어떻게 Caps Lock 키를 조절할 수 있습니까?

SetKeyboardState 함수를 사용하면 됩니다.

다음은 버튼을 누를 때 마다 Caps Lock 키의 상태가 변하도록 하는 코드입니다.

procedure TForm1.Button1Click(Sender: TObject);
   var
      Level : Integer;
      KeyState : TKeyBoardState;
      begin
         Level := GetKeyState(VK_CAPITAL); {Caps Lock 키를 체크한다}
         GetKeyboardState(KeyState);
         If Level = 0 then
         begin
            KeyState[VK_CAPITAL] := 1;
            setKeyboardState(KeyState);
        end
        else if Level = 1 then
        begin
           KeyState[VK_CAPITAL] := 0;
         setKeyboardState(KeyState);
   end;
end;

 

<눌려진 Key가 무엇인지 확인하는 방법>

Form의 KeyPreview 속성을 True 로 하고, KeyDown 이벤트에서 처리하면됩니다.

다음은 Key를 처리하는 예제 procedure 입니다.

procedure TForm1.Edit3KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
var
tempstr: string; {used to spell out keys typed}
begin

{be sure to set Form.KeyPreview to True}
Edit4.Text := '';
if (Shift = ([ssShift])) then Edit4.Text := Edit4.Text + 'Shift';
if (Shift = ([ssShift, ssAlt])) then Edit4.Text := Edit4.Text + 'Shift+Alt';
if (Shift = ([ssShift, ssCtrl])) then Edit4.Text := Edit4.Text + 'Shift+Ctrl';
if (Shift = ([ssShift, ssAlt, ssCtrl])) then Edit4.Text := Edit4.Text +'Shift+Ctrl+Alt';
if (Shift = ([ssAlt])) then Edit4.Text := Edit4.Text + 'Alt';
if (Shift = ([ssAlt, ssCtrl])) then Edit4.Text := Edit4.Text + 'Ctrl+Alt';
if (Shift = ([ssCtrl])) then Edit4.Text := Edit4.Text + 'Ctrl';

tempstr := '';

case Key of
VK_CANCEL: tempstr := 'CANCEL';
VK_BACK: tempstr := 'BACKSPACE';
VK_TAB: tempstr := 'TAB';
VK_CLEAR: tempstr := 'CLEAR';
VK_RETURN: tempstr := 'ENTER';
VK_PAUSE: tempstr := 'PAUSE';
VK_CAPITAL: tempstr := 'CAPS LOCK';
VK_ESCAPE: tempstr := 'ESC';
VK_SPACE: tempstr := 'SPACEBAR';
VK_PRIOR: tempstr := 'PAGE UP';
VK_NEXT: tempstr := 'PAGE DOWN';
VK_END: tempstr := 'END';
VK_HOME: tempstr := 'HOME';
VK_LEFT: tempstr := 'LEFT ARROW';
VK_UP: tempstr := 'UP ARROW';
VK_RIGHT: tempstr := 'RIGHT ARROW';
VK_DOWN: tempstr := 'DOWN ARROW';
VK_SELECT: tempstr := 'SELECT';
VK_EXECUTE: tempstr := 'EXECUTE';
VK_SNAPSHOT: tempstr := 'PRINT SCREEN';
VK_INSERT: tempstr := 'INS';
VK_DELETE: tempstr := 'DEL';
VK_HELP: tempstr := 'HELP';

{VK_1..VK_0 and VK_A..VK_Z are not defined so you have to use the Ord()
function instead which yields the equivilent VK code}

Ord('0'): tempstr := '0';
Ord('1'): tempstr := '1';
Ord('2'): tempstr := '2';
.
.
Ord('A'): tempstr := 'A';
Ord('B'): tempstr := 'B';
Ord('C'): tempstr := 'C';
.
.
VK_NUMPAD0: tempstr := 'Numeric keypad 0';
VK_NUMPAD1: tempstr := 'Numeric keypad 1';
VK_NUMPAD2: tempstr := 'Numeric keypad 2';
.
.
VK_MULTIPLY: tempstr := 'Multiply';
VK_ADD: tempstr := 'Add';
VK_SEPARATOR: tempstr := 'Separator';
VK_SUBTRACT: tempstr := 'Subtract';
VK_DECIMAL: tempstr := 'Decimal';
VK_DIVIDE: tempstr := 'Divide';
VK_F1: tempstr := 'F1';
VK_F2: tempstr := 'F2';
VK_F3: tempstr := 'F3';
.
.
VK_NUMLOCK: tempstr := 'NUM LOCK';
VK_SCROLL: tempstr := 'SCROLL LOCK';
end;
if Edit4.Text = '' then Edit4.Text := tempstr
else if tempstr <> '' then Edit4.Text := Edit4.Text + '+' + tempstr;
Key := 0; {set key to 0 to send no key stroke}
end;

 

<특정 component에서 Enter 키를 눌렀을 때 원하는 처리 추가 방법>

[A8] KeyDown event handler에서 Key가 VK_Return 값인지 체크하면 됩니다.
다음은 그러한 event handler의 간단한 예제입니다.

procedure TForm1.Edit1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
if Key = VK_Return then
Edit2.Text := FormatFloat('###.###',StrToFloat(Edit1.Text)) ;
end;

 

<Enter키에 Tab키 효과를 주려면>

Edit 컴포넌트의 OnKeyPress 이벤트에 다음과 같은 코드를 사용하면됩니다.

procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
If Key = #13 Then
Begin
SelectNext(Sender as TWinControl, True, True );
Key := #0;
end;
end;

이것은 Enter를 Tab처럼 동작하게 합니다. 폼에 있는 전체의 콘트롤(버튼을제외한)에 대해서 이와같은 동작을 원하면 전체의 콘트롤을 선택한 후에 OnKeyPress핸들러를 Edit1KeyPress로 지정하면 됩니다.
이제 각각의 콘트롤에 대해서 Enter가 Tab처럼 작동됩니다.
만약, 폼 레벨에서 이와같은 동작을 원하면(폼에 있는 전체의 콘트롤의 OnKeyPress핸들러에 전부 지정하기를 원하지 않는다면) 폼의 OnKeyPress 에 다음과 같은코드를 사용하면 됩니다. 위의 코드에서 Sender만 ActiveControl로 바꾸고 폼의Property에서 KeyPreview를 true로 바꾸어 주면 됩니다.

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
If Key = #13 Then
begin
SelectNext(ActiveControl as TWinControl,True, True );
{Perfome(wm_NextDlgCtl,0,0); 라는 명령문도 가능합니다.}
Key := #0;
end;
end;

이것은 폼에 있는 각각의 콘트롤에 대해서 Enter가 Tab처럼 작동합니다.

 

<Task 전환키인 ALT+TAB 키를 disable 시키려면>

WM_KeyDown message를 처리하거나 Form의 KeyDown event handler를작성합니다.

다음은 간단한 예제 코드입니다.

procedure TForm1.WMKEYDOWN(var Message : TWMKEYDOWN); message WM_KEYDOWN;
begin
if ssAlt in KeyDataToShiftState(Message.KeyData) then
if Message.CharCode = VK_TAB then
begin
Message.CharCode := 0 ;
exit ;
end ;
end;

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
if ssAlt in Shift then
if Key = VK_TAB then
begin
Key := 0 ;
exit ;
end ;
end;

 

<Keyboard 명령을 사용하여 TForm component에서 스크롤 기능 사용하기>

예를 들어, 폼을 위/아래로 스크롤 하기 위해 PgUp과 PgDn키를 사용하고 싶습니다.

다음과 같이 프로그램 합니다.

procedure TForm1.FormCreate(Sender: TObject);
begin
with VertScrollBar do
begin
Range := 500;
Visible := True;
end;
end;

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
Const
PageDelta = 100;
Begin
With VertScrollBar do
If Key = VK_NEXT then Position := Position + PageDelta
Else If Key = VK_PRIOR then Position := Position - PageDelta;
End;

주의) TMemo와 같은 component에서는 동작하지 않을 수도 있습니다.

 

<화일 크기를 알고 싶다면>

다음과 같이 프로그램 합니다.

이것은 특정화일의 크기를 에디트박스에 보여주는 예제입니다.

Function FileGetSize(YourFile : String) : LongInt;
Var
   F : Integer;
   Begin
   F:=FileOpen(YourFile,0); { ReadOnly Mode }
   FileGetSize := FileSeek(F,0,2);
   FileClose(F)
End;

procedure TForm1.Button1Click(Sender: TObject);
begin
   Edit1.Text := IntToStr(FileGetSize('c:\bin\q.exe'));
end;

 

<화일을 복사 하려면>

다음 FileCopy 함수를 사용해 보십시오.

function FileCopy(source,dest: String): Boolean;
var
   fSrc,fDst,len: Integer;
   size: Longint;
   buffer: packed array [0..2047] of Byte;
   begin
      Result := False; { Assume that it WONT work }
      if source <> dest then begin
      fSrc := FileOpen(source,fmOpenRead);
      if fSrc >= 0 then begin
         size := FileSeek(fSrc,0,2);
         FileSeek(fSrc,0,0);
         fDst := FileCreate(dest);
         if fDst >= 0 then begin
         while size > 0 do begin
            len := FileRead(fSrc,buffer,sizeof(buffer));
            FileWrite(fDst,buffer,len);
            size := size - len;
         end;
         FileSetDate(fDst,FileGetDate(fSrc));
         FileClose(fDst);
         FileSetAttr(dest,FileGetAttr(source));
         Result := True;
      end;
      FileClose(fSrc);
   end;
end;
end;

 

<화일의 날짜와 시간을 설정하려면>

SetFTime 함수를 사용합니다.

다음은 화일의 날짜와 시간을 바꾸는 간단한 예제 코드입니다.

var
   f: file;
   begin
      Assign(f, DirInfo.Name);
   Reset(f);
   SetFTime(f, Time);
   Close(f);
end;

 

<INI file을 어떻게 처리합니까>

TIniFile Object를 이용하면 응용프로그램에서 .INI화일을 생성하여조작할 수 있습니다.
중요한 method로는 Create, ReadString, WriteString 등이 있습니다.

다음은 그러한 method 들의 간단한 예제 코드입니다.

var
   IniFile: TIniFile;
   begin
      IniFile := TIniFile.Create('C:\Windows\Delphi.INI');
      IniFile.ReadString('Library', 'SearchPath', 'C:\Delphi\Bin');
      IniFile.WriteString('Library', 'SearchPath', 'C:\Delphi\Bin;C:\MyDir');
      IniFile. Free;
end;

 

<특정 디렉토리에 있는 모든 화일을 다루는 방법>

FindFirst와 FindNext 함수를 사용합니다.

다음은 특정 디렉토리에 있는 화일의 이름과 크기를 보여주는 간단한 예제입니다.

var
   SearchRec: TSearchRec;

procedure TForm1.Button1Click(Sender: TObject);
begin
   FindFirst('c:\dl\bin\*.*', faAnyFile, SearchRec);
   Label1.Caption := SearchRec.Name + ' is ' + IntToStr(SearchRec.Size) +'bytes in size';
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
   FindNext(SearchRec);
   Label1.Caption := SearchRec.Name + ' is ' + IntToStr(SearchRec.Size) +'bytes in size';
end;

 

<인쇄관리자에서 표시되는 인쇄작업의 제목을 주고 싶을때>

다음과 같은 코드를 쓰시면 가능합니다.

Printer.Title := 'your title';

 

<프린터의 인치당 픽셀 구하기>

Windows API 함수인 GetDeviceCaps 을 사용하면 가능합니다.
다음은 에디트박스에 프린터의 가로, 세로 인치당 픽셀을 보여주는 간단한 코드입니다.

procedure TForm1.Button2Click(Sender: TObject);
begin
   Edit1.Text := IntToStr(GetDeviceCaps(Printer.Handle, LogPixelsX));
   Edit2.Text := IntToStr(GetDeviceCaps(Printer.Handle, LogPixelsY));
end;

 

<프린터에 escape 코드를 전달하는 방법>

다음은 삼보 KSSM 모드에서 축소 escape 코드를 사용하는 예제입니다.

procedure TForm1.Button1Click(Sender: TObject);
var
   MyFile: Textfile ;
   s, s1 : string ;
   ff : string ;

begin
   {삼보 KSSM Mode}
   s[0] := #1 ; {축소 지정}
   s[1] := #15 ;
   s1[0] := #1 ; {축소 해제}
   s1[1] := #18 ;
   ff[0] := #1 ; {Form Feed}
   ff[1] := #12 ;

   AssignFile(MyFile,'PRN') ;
   Rewrite(MyFile);
   s := 'Normal font size' + s + 'small font' + s1 + 'Normal font size' +ff ;
   Writeln(MyFile, s);
   System.CloseFile(MyFile);
end;

또는 Windows API 함수 Escape()를 참고 하십시오.

 

<특정 어드레스에 데이타를 저장하려면>

Object Pascal에서는 사용자가 직접 메모리를 다룰 수 있도록 다음과같은 함수를 제공합니다.

Mem
MemW
MemL

Mem의 각 요소는 Byte이고, MemW의 각 요소는 Word이며 MemL의 요소들은 Longint입니다.
Mem 배열함수는 인덱스로 특정한 형식을 취합니다.

다음은 예제 코드입니다:

Mem[$0040:$0049] := 7; {7 을 $0040:$0049에 저장한다}
Data := MemW[Seg(V):Ofs(V)]; {변수 V의 첫 2바이트에 저장된 워드 값을 변수데이타로 옮긴다.}

 

<TPrinter Object를 사용하려면>

다음 예제를 참고하십시오.

var Printer : TPrinter ;

FontDialog1.Font.Assign(Edit1.Font);
if Font1.Dialog.Execute then Edit1.Font.Assign(FontDialog1.Font);

Printer.Canvas.TextOut(X, Y, '문자열');
Printer.Canvas.TextRect(TRect, X, Y, '문자열');
Printer.Canvas.TextHeight('문자열');
GetDeviceCaps(Printer.Handle, LOGPIXELSX);
GetDeviceCaps(Printer.Handle, LOGPIXELSY);

Printer.NewPage;

 

<RES파일 추가후 Resource를 찾지 못할 경우>

사용자가 .RES화일을 추가 했어도 왜 사용자의 프로그램은 Resource의어느것도 찾지 못하는지요? 만약 사용자의 폼에 Unit 이름과 .RES가 같아서그럴까요?

만약 포함된 .RES화일의 이름이 .DPR화일 이름과 같다면 Delphi는자신의 .RES 화일로 덮어쓰기를 할 것입니다. 추가적으로, Project RES 화일은단지 Delphi Project 관리에 대한 것입니다.이 RES 화일에 Resources를 추가하거나,편집할 수 없습 니다.

 

<RC file을 컴파일하는 방법과 Bitmap, Cursor, Icon등을 사용하려면>

DOS Prompt에서 Delphi\Bin directory에 있는 BRCC.EXE를 이용하여컴파일하면 됩니다. 컴파일된 RC file은 .RES 형 태의 binary file로 생성됩니다.
생성된 .RES file을 다음과 같이 선언하여 program에서 사용하면 됩니다.

implementation

{$R C:\Delphi\MyDir\MyRes.Res}

위와같이 선언한 후 사용시에는 Windows API를 이용하면 됩니다.

Image1.Picture.Bitmap.Handle := LoadBitmap(HInstance, 'BITMAP1');
Screen.Cursors[1] := LoadCursor(HInstance, 'CURSOR1');
Image1.Picture.Icon.Handle := LoadIcon(HInstance, 'ICON1');
LoadString(HInstance, 1000, Buffer, 255);

 

<사용자에게 에러를 보여주기 전에 가로채기>

그러한 역할을 하는 새로운 Exception을 다음과 같이 만들 수 있습니다.
다음에 프로시져를 main 폼에 선언해줍니다.

type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);

{Exception처리를 하기 위한 procedure를 선언한다}
procedure MyException(Sender:TObject; E:Exception);
private
{ Private declarations }
public
{ Public declarations }
end;

procedure TMyForm.MyException(Sender:TObject; E:Exception);
begin
   if (E.ClassType.ClassName='EConvertError') then
begin
   {사용자가 원하는 처리 내용}
end
else Application.ShowException(E);
end;

procedure TMyForm.FormCreate(Sender: TObject);
begin
   Application.OnException := MyException;
end;

 

<Delphi는 Run-Time 오류를 어떻게 조정합니까>

Delphi에서 Run-Time 오류가 발생할때에 Exception이 생성됩니다.Delphi에서 사용자의 프로그램이 실행되는 동안 Ex ception이 발생할때, 개발환경에서특수한 옵션이 설정된다면, Delphi는 발생한 Line에 커서를 위치시킬 것입니다.그러면서도, 프로그램은 종료되지 않습니다. 따라서 Exception이 생성되면 사용자의어플리케이션은 자동적으로 종료되지 않습니다.

 

<'Stream Read Error'을 조정할 수 있는 방법>

*.DSM을 삭제한후 다시 Project를 컴파일합니다.

 

<WinPrn Unit 컴파일시 에러>

[Q] WinPrn Unit라 불리우는 코드를 컴파일할때, Delphi는 'It can't findWinPrn.DCU'를 나타냅니다.

[A] Option/Project의 search path에 \Delphi\Source\Rtl70'을 추가 합니다.

 

<새로운 커서를 만들어 사용하려면>

다음과 같이 RES 화일을 project에 포함시킵니다.

{$R c:\dl\testcur.res} {RES 화일의 이름과 경로를 명시}

procedure TForm1.Button1Click(Sender: TObject);
Var
   ddd: PChar;
begin
   GetMem(ddd, 8);
   ddd := 'Cursor_1';
   SetClassWord(Form1.handle, GCW_HCURSOR, LoadCursor(hinstance, ddd));
end;

 

<Cursor 모양을 바꾸려면>

다음은 어떤 작업시에 HourGlass 커서를 보여주고, 다시 정상적인커서를 보여주는 예제입니다.

Begin
Try
Screen.Cursor:=crHourGlass;
ReportForm := TReportForm.Create(Application);
Screen.Cursor:=crDefault;
ReportForm.ShowModal;
ReportForm.Free;
Finally
Screen.Cursor:=crDefault;
end;
end;

 

<이미지의 크기를 조절하여 보려주려면>

다음 예제를 참고하십시오.

procedure TForm.ZoomImage;
var Bitmap: TBitmap;
   DstRect: TRect;
begin
      Bitmap := TBitmap.Create;
      Bitmap.Width := { 원하는 길이 }
      Bitmap.Height := { 원하는 높이 }
      Bitmap.Canvas.StretchDraw(Bitmap.Canvas.ClipRect,{원하는 이미지});

      Image1.Picture.Graphic := Bitmap;
      Image1.Invalidate;
end;

 

<아이콘을 Glyphs으로 바꾸려면>

다음을 프로그램 하여 보십시오.

unit Procs;

interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms,StdCtrls, Buttons, ExtCtrls, ShellAPI;

procedure LlenaBoton(boton: TSpeedButton; Programa: string);
procedure LimpiaBoton(boton: TSpeedButton);

var
{Botones de programas}
Pic: TPicture;
Fname : String;
TempFile: array[0..255] of Char;
Icon : TIcon;

implementation
uses ttotro;

procedure LlenaBoton(boton: TSpeedButton; Programa: string);
var
NumFiles, NameLength : integer;
nIconsInFile : word;
rBoton : TRect;
oBitmap : TBitmap;
oBitmap2: TBitmap;
NombreBitmap: string;

begin

try
screen.cursor := crHourglass;

{Extrae el Icono}
Icon := TIcon.Create;
StrPCopy(TempFile, Programa);
Icon.Handle := ExtractIcon(HInstance, TempFile, 0);

{Crea una instancia de TPicture}
Pic := TPicture.Create;
{Asigna el icon.handle a la propiedad Pic.icon}

Pic.Icon := Icon;

{Configura el tamano del bitmap como el del icono y el del segundo bitmapcon el tamano del boton}
oBitmap := TBitMap.create;
oBitmap2 := TBitMap.create;
oBitmap2.Width := Icon.Width;
oBitmap2.Height := Icon.Height;
oBitmap.Width := boton.Width-4;
oBitmap.Height := boton.Height-4;

{ Dibuja el icono en el bitmap }
oBitmap2.Canvas.Draw( 0, 0, Pic.Graphic );
rBoton.left := 1;
rBoton.Top := 1;
rBoton.right:= boton.Width-6;
rBoton.Bottom := boton.Height-6;
oBitmap.Canvas.StretchDraw(rBoton, oBitmap2);

Boton.Hint := Programa;

NombreBitmap := Copy(programa, 1, Length(programa)-3)+'BMP';
{Salva el bitmap en un fichero}
If Not FileExists(NombreBitmap) Then
begin
oBitmap.SaveToFile(ExtractFilePath(Application.ExeName)+ExtractFileName(NombreBitmap));
Boton.Glyph := oBitmap;
end
else
{Carga el BMP en el boton}
Boton.Glyph.LoadFromFile(ExtractFilePath(Application.ExeName)+ExtractFileName(NombreBitmap));

finally
Icon.Free;
oBitmap.Free;
oBitmap2.Free;
screen.cursor := crDefault;
end;
end;

procedure LimpiaBoton(boton: TSpeedButton);
var
oBitmap : TBitmap;
rBoton : TRect;
begin

try
{Configuara el tamano del bitmap como el del icono y el del segundo
bitmap con el tamano del boton}
oBitmap := TBitMap.create;
oBitmap.Width := boton.Width-4;
oBitmap.Height := boton.Height-4;
Boton.Glyph := oBitmap;
finally
oBitmap.Free;
end;
end;

end.

 

<image component에 특정 application의 icon을 보이게 하는 방법>

Windows API인 ExtractIcon function을 이용하면 됩니다.

uses SHELLAPI;

Image1.Picture.Icon.Handle := ExtractIcon(Handle, 'C:\Delphi\Bin\Delphi.exe',0);

 

<날짜와 시간의 형식을 DD/MM/YY 에서 DDMMYYYY 로 바꾸려면>

다음 예제를 참고하십시오.

LongDate := FormatDateTime('ddmmyyyy', StrToDate(ShortDate));

위의 코드는 DD/MM/YY 와 같은 제어판의 날짜 형식을 형식문자열(여기서는 DDMMYYYY)로바꾸어줍니다.

 

<Date 또는 시간차이 구하는 법>

다음은 시간차이를 구하는 예제입니다.

procedure TForm1.MaskEdit2Exit(Sender: TObject);
begin
   MaskEdit2.Text := FormatDateTime('HH:MM', StrToTime(MaskEdit2.Text));
   Edit2.Text := FormatDateTime('HHMM', StrToTime(MaskEdit2.Text));
   if StrToTime(MaskEdit2.text) < StrToTime(MaskEdit1.text) then
      ShowMessage('From 시간보다 작습니다.')
   else
      MaskEdit3.Text := FormatDateTime('HH:MM', StrToTime(MaskEdit2.text) - StrToTime(MaskEdit1.text));
end;

다음은 날짜차이를 구하는 예제입니다.

procedure TForm1.MaskEdit5Exit(Sender: TObject);
begin
   MaskEdit5.Text := FormatDateTime('YYYY-MM-DD', StrToDate(MaskEdit5.Text));
   Edit5.Text := FormatDateTime('MMDDYYYY', StrToDate(MaskEdit5.Text));
   if StrToDate(MaskEdit5.text) < StrToDate(MaskEdit4.text) then
      ShowMessage('From 날짜보다 작습니다.')
   else begin
      MaskEdit6.Text := FormatDateTime('YYYY-MM-DD', StrToDate(MaskEdit5.text)- StrToDate(MaskEdit4.text));
      Edit6.Text := FloatToStr(StrToDate(MaskEdit5.text) - StrToDate(MaskEdit4.text));
   end;
end;

 

<number를 천단위로 분리해서 comma를 찍어주는 방법>

다음과 같이 하면 됩니다.

function FormatNumber(l: longint): string;
begin
   FormatNumber := FormatFloat('#,##0', StrToFloat(IntToStr(l)));
end;

 

<Application에서 사용되는 날짜형식을 특정한 format으로 고정하는 방법>

SysUtils Unit에 선언된 변수들을 원하는 특정값으로 주면 됩니다.
Application 전체에 원하는 형태로 날짜 format을 지정하려면 main form의 onCreateEvent에 다음과 같이 하면 됩니다.

ShortDateFormat := 'YY-MM-DD';
LongDateFormat := 'YYYY-MM-DD';

 

<윈도우/대화상자의 크기를 재지정 했을때, 버튼을 윈도우내의 하단에 자동적으로 정렬할 수 있는 방법>

TPanel을 생성한후, TPanel의 Align특성을 사용하여 하단에 정렬하십시오.
그리고 나서 이 Panel 위에 버튼을 위치 시키면 됩니다. 만약 Button만 나타내고싶은 경우 Panel의 특성중 Ctl3D를 'Off'로 설 정하시고, Bevels를 none' 으로Parentcolor를 True로 설정하면 됩니다.

 

<파라독스의 계산 필드에서 25.55 가 24.499999 가 되는 이유>

숫자의 소수점 자리수가 틀리면 그러한 잘못된 값을 줍니다.
다음과 같이 Round 함수나 str함수를 써서 자리수를 맞춰서 계산하시기 바랍니다.

SalesIncVAT:=round(SalesIncVAT*100)/100; {소숫점 둘째자리 수}

혹은

var
s : string;
begin
str(SalesIncVat:10:2,s); {10 자리수와 소수점 둘째짜리}
Label1.Caption:=s;
end ;

 

<금주가 몇번째 주인지 구하는 법 (윤년 계산법)>

다음 함수를 사용해 보십시오.

윤년을 계산하는 함수 :
function kcIsLeapYear( nYear: Integer ): Boolean;
begin
Result := (nYear mod 4 = 0) and ((nYear mod 100 <> 0) or (nYear mod
400 = 0));
end;


한달에 몇일이 있는지를 계산하는 함수 :
function kcMonthDays( nMonth, nYear: Integer ): Integer;
const
DaysPerMonth: array[1..12] of Integer = (31, 28, 31, 30, 31, 30, 31, 31,30, 31, 30, 31);
begin
Result := DaysPerMonth[nMonth];
if (nMonth = 2) and kcIsLeapYear(nYear) then Inc(Result);
end;


위의 두 함수를 써서 몇번째 주인지 계산하는 함수 :
function kcWeekOfYear( dDate: TDateTime ): Integer;
var
X, nDayCount: Integer;
nMonth, nDay, nYear: Word;
begin

nDayCount := 0;
deCodeDate( dDate, nYear, nMonth, nDay );
For X := 1 to ( nMonth - 1 ) do
nDayCount := nDayCount + kcMonthDays( X, nYear );

nDayCount := nDayCount + nDay;
Result := ( ( nDayCount div 7 ) + 1 );
end;

 

<Hint가 나타나는 속도를 빠르게 하는 방법>

TApplication의 property중 HintPause property를 이용하면 됩니다.기본값은 800 millisecond 입니다.

Application.HintPause := 100;

 

<실행중 Component를 생성하고 property를 주려면>

다음의 코드를 참고하십시오.

{component를 만듭니다.}
procedure TForm1.Button1Click(Sender: TObject);
begin
   SomeComponent:= TComponentClass(FindClass(Edit1.Text)).Create(Self);
   (SomeComponent as TControl).Parent := Self;
end;

{만들 수 있는 component의 유형}
procedure TForm1.FormCreate(Sender: TObject);
begin
   RegisterClasses([TButton, TEdit, TMemo, TLabel]);
end;

{component의 property를 주는 방법}
procedure TForm1.Button2Click(Sender: TObject);
var
   PropType: pTypeInfo;
   PropInfo: pPropInfo;
begin
   PropInfo := GetPropInfo(SomeComponent.ClassInfo, Edit2.Text);
   PropType := PropInfo^.PropType;
   case PropType^.Kind of
      tkInteger:
      SetOrdProp(SomeComponent, PropInfo,StrToInt(Edit3.Text));
      tkChar:
      SetOrdProp(SomeComponent, PropInfo, Ord(Edit3.Text[1]));
      tkEnumeration:
      SetOrdProp(SomeComponent, PropInfo, GetEnumValue(PropType,Edit3.Text));
      tkFloat:
      SetFloatProp(SomeComponent, PropInfo,StrToFloat(Edit3.Text));
      tkString:
      SetStrProp(SomeComponent, PropInfo, Edit3.Text);
   end;
end;

 

<실행 중 만든 컴포넌트에 설정한 기본값이 설정되지 않은 경우>

[Q] 실행중에 component 하나를 만들었습니다. 그런데 제가 사용한 기본값이 설정되지 않은 것 같습니다. 어떻게 해야 합니까?

[A] 그 component의 Create constructor에서 property의 기본값을 설정했는지 확인하십시오. 기존 property의 기본값은 실행중에 만든 component에는 적용되지않습니다.

 

<Run-Time시에 VCL 컴포넌트의 개체를 생성하려면>

다음의 코드는 Runtime시에 Form을 생성하는 것입니다.

with TPasswordForm.Create(Application) do
Begin { i.e TForm1, TPasswordForm etc. }
ShowModal; { Diaplay form as a modal window }
Free; { Free the form when it is closed }
end;

다음의 코드는 Button을 생성하는 것입니다.

Var
TempButton : TButton; {This is only a pointer to a TButton }
Begin
TempButton := TButton.Create(Self);
TempButton.Parent := Self; { Must assign the Parent }
TempButton.Caption := 'Run-time';{ Assign properties new }
TempButton.Visible := True; { Show to button }
End;

이 개체는 사용후에 반드시 Free 시켜야 합니다.

 

<'Tab Order 설정방법>

Control을 정하기위해 Form에서 클릭한후 Object Inspector에서 TabOrderproperty를 설정해 줍니다.

 

<이름에 의해서 component를 access 하기>

FindComponent method를 사용하면 됩니다.

for I := 1 to 10 do
with Form1.FindComponent('SpeedButton' + IntToStr(i)) as TSpeedButton do
Enabled := False;

 

<Lasso 제어>

다음을 참고하십시오.

1. 폼의 OnMouseDown 이벤트:
bMarquee := True; {bMarquee는 Boolean변수}
ptOrigin := Point( X, Y );
ptMove := Point( X, Y );{ptOrigin, ptMove는 Point변수}

Canvas.Pen.Color := clBlack;
Canvas.Pen.Width := 1;
Canvas.Pen.Style := psDash;
Brush.Style := bsClear;

DrawMarquee(ptOrigin, ptMove, pmNotXor );

2. 폼의 OnMouseMove 이벤트
if bMarquee = True then begin
   DrawMarquee(ptOrigin, ptMove, pmNotXor );
   DrawMarquee(ptOrigin, Point( X, Y ), pmNotXor );
   ptMove := Point( X, Y );
   Canvas.Pen.Mode := pmCopy;
end;

3. 폼의 OnMouseUp 이벤트
if bMarquee = True then begin
   bMarquee := False;
   DrawMarquee(ptOrigin, Point( X, Y ), pmNotXor );
   ptMove := Point( X, Y );
end;

4. DrawMarquee procedure

procedure myForm.DrawMarquee( mStart, mStop : TPoint; AMode : TPenMode);
begin
   Canvas.Pen.Mode := AMode;
   Canvas.Rectangle( mStart.X, mStart.Y, mStop.X, mStop.Y );
end;

 

<inline Assembler 코드를 사용하려면>

다음은 시스템의 시간을 맞추는 예제입니다.

procedure TForm1.Button1Click(Sender: TObject);
begin
   {set system time}
   asm
      mov Ah,2dh { function number}
      mov ch,1 { hours }
      mov cl,10 { minutes }
      mov dx,0 { seconds }
      INT 21h
   end ;
end;

 

'Delphi' 카테고리의 다른 글

날짜/시간형식 변경 및 강제 시간세팅  (0) 2014.02.13
Q&A 정리  (0) 2014.02.13
올림 / 내림(버림)  (0) 2011.08.03
델파이의 소숫점 반올림 방식  (2) 2011.08.03
동적 체크박스 생성  (0) 2010.03.24
2014. 2. 6. 18:54

Windows 열려있는 포트 확인법

netstat 확인하기

 

1. 시작 - 실행에 cmd를 입력하고 확인을 클릭합니다.

 

2. 명령 프롬프트 창이 뜨면 netstat -an이라고 입력을 하고 엔트를 칩니다.

 

3. 그러면 아래와 같은 화면이 나오는데 Local Address는 현재 내PC의 아이피와 포트를 의미하고 Foreign Address는 외부 사이트의 아이피와 포트번호 입니다.

 

4. 아이피번호 다음에 있는 : 로 아이피주소와 포트번호가 구분이 됩니다.

 

 

 

 telnet 확인하기

 

윈도우에서 직접 커맨드 창으로 알아보실 수도 있습니다.

 

특정 포트(PORT)가 열려있는지 확인하는 방법입니다.

윈도우즈면 커맨트창(명령어프롬프트), 리눅스면 쉘이 되겠습니다.

 

사용법 : telnet [아이피주소] [포트번호]

예)
#] telnet XXX.XXX.XXX.XXX port

위의 XXX.XXX.XXX.XXX 부분에 해당 서버(컴퓨터)의 실제 아이피를 입력해 주시면 됩니다.


 

CurrPorts 확인하기

 

CurrPorts 같은 프로그램을 사용해서 확인