2011년 4월 6일 수요일

DevExpress 6.xx 버젼의 Skinres 파일 사용하기

DevExpress 6.50 부터는 스킨 파일(*.Skinres)을 별도로 제공합니다.
이전에도 SkinEditor를 사용해서 별도로 저장해서 사용하기도 했지만, 제공해주니 편하네요.

퀀텀의 스킨은 스킨이 Uses문에 추가되어 실행화일의 크기가 증가합니다.
따라서, 많은 스킨을 사용자에게 제공하려 하는 경우 실행화일이 조금 커집니다.
( 실제로 타 Skin보다 용량이 크긴 합니다. )

이를 위한 해결방법으로 UserSkin을 사용하는데...

일단 SkinRes화일이 있어야 합니다.

6.50은 아래와 같은 경로에 파일이 있습니다.

1.const
2. sFileName = 'C:\Delphi\My_Components\DevExpress\ExpressSkins Library\Binary Skin Files\AllSkins.skinres';


이 화일에는 모든 스킨이 다 들어 있는 바이너리 화일입니다.
따라서 여기서 스킨을 불러오려면 아래와 같은 코드를 사용합니다.

01.// 화일에서 스킨명을 읽어 오기.
02. dxSkinsUserSkinPopulateSkinNames( sFileName , ListBox1.Items );
03.// 스킨 명을 적용하기..
04.procedure TForm2.ListBox1Click(Sender: TObject);
05.var
06. AIndex: Integer;
07. ASkinName: string;
08.begin
09. AIndex := ListBox1.ItemIndex;
10. ASkinName := ListBox1.Items[AIndex];
11. if dxSkinsUserSkinLoadFromFile (sFileName, ASkinName ) then
12. begin
13. dxSkinController1.NativeStyle := false;
14. dxSkinController1.SkinName := 'UserSkin';
15. dxSkinController1.UseSkins := true;
16. end;
17.end;

2011년 3월 22일 화요일

내 홈피에 싸이월드 공감달기

http://devsquare.nate.com/openApi/empathyButton

에서 url만 넣으면 공감 경로를 받을 수 있습니다.

<img style="cursor: pointer;" onclick="window.open('http://csp.cyworld.com/bi/bi_recommend_pop.php?url=http://agent.ucczone.co.kr/', 'recom_icon_pop', 'width=400,height=364,scrollbars=no,resizable=no');" src="http://csp.cyworld.com/images/ico_clog.gif" alt="싸이월드 공감" title="싸이월드 공감" >

이런씩인데 실제 자신의 url만 자동으로 하면 따로 받지 않고도 가능하네요

2011년 3월 15일 화요일

Indy10 재설치 (버전10)

Indy를 재설치하려면 먼저 Indy사이트에 간다.
Indy 설치 환경 : Delphi 2006 환경에서의 설치
http://www.indyproject.org/ : Indy 사이트

최신판 Indy Download

Indy 사이트에 첫페이지에서 아래 링크를 클릭하면
델파이 관련 컴포넌트를 받을 수 있는 곳으로 들어간다.

Indy.Sockets (VCL)

위 페이지의 맨밑에 보면 [Downloads]가 나오고
거기를 클릭하면 몇가지 버전이 나온다.
여기서는 버전 10을 클릭한다.
[Development Snapshot]을 선택한다.

밑의 사이트에 가면 최신판을 업데이트 한다고 한다.
indy.Fulgan.com/zip/
위 사이트에서 indy10.zip을 다운 받는다.

위사이트에서 받지않으면 SubVersion이라고 해서
버전 관리 툴(?)을 설치해서 최신판을 받을 수 있는데
버전 관리 툴을 설치하고 사용법을 익히는 등 좀 귀찮다.
혹시라도 버전 관리툴을 깔아서 사용하고 싶은 사람은
아래 사이트를 참조하면 된다.
Indy via SVN

여하튼 어떻게든 최신판을 다운받는다.

기존 버전 Indy삭제
01) Component 메뉴에서 Intall Packages...를 선택한다.


02) 그러면 아래와 같은 Install Packages 창이 뜬다.
Design packages에서 "Indy 10 Protocol Design Time"을 선택하고
[Remove]버튼을 클릭한다.


그러면 아래의 Uninstall 확인 창이 뜬다.
[Yes]버튼을 클릭하고 Uninstall을 진행한다.

03) 같은 방법으로 Design packages에서 "Indy 10 Core Design Time"을 선택하고
[Remove]버튼을 클릭하여 Uninstall한다.

04) 익스플로러로 Delphi가 설치된 폴더를 찾아 폴더를 클릭한다.
C:\Program Files\Borland\BDS

05) 이 폴더에서 오른쪽 클릭을 하고 검색을 클릭한다.
검색 결과 창이 뜨면 전체 또는 일부 파일 이름에 아래의 파일들을 검색하여 지운다.
dclIndy*.bpl
Indy*.bpl
Id*.pas
Id*.dcu
지울때는 Shift키를 누르고 Delete키를 눌러서 지우면 잘못 지웠을 경우 곤란함으로
그냥 Delete키만 눌러 지운다.

이렇게 하면 Delphi에서 기존 버전의 Indy가 삭제된다.

최신 버전 Indy 설치
01) 다운 받은 최선 Indy 소스를 적당한 장소에 둔다.
C:\Program Files\Borland\BDS\4.0\lib\indy10

02) 델파이에서 File 메뉴에서 Open Project를 선택한다.
Indy 소스가 위치한 곳에 가서 IndySystemX0.dpk를 연다.
(IndySystem dpk파일을 Lib폴더 밑의 System에 있다.)


03) dpk를 열면 Project Manager에 dpk 프로젝트가 아래와 같이 표시된다.


04) 추가한 IndySystemX0 프로젝트에서 오른쪽 클릭을 해서 Compile을 한다.


05) IndySystem을 Compile한 것과 같은 방법으로 아래의 dpk파일도
동일한 방법(02~04의 방법)으로 차례대로 Compile한다.

IndyCore110.dpk (Lib\Core)
IndyProtocols110.dpk (Lib\Protocols)

06) 위 세 dpk파일을 컴파을 마치면 Core폴더 밑의 dclIndyCore110.dpk를 연다.
그러면 아래와 같이 표시되고 이번에는 Install을 클릭한다.


그러면 아래와 같은 창이 떠서 Install된 것을 알려준다.


07) 이번에는 dclIndyProtocols110.dpk를 열어 위와 동일한 방법으로 Install을 한다.
그러면 아래와 같이 Install된 것을 알려준다.


08) Tools 메뉴에서 Options...를 선택한다.


09) Options창의 Environment Options > Delpji Options > Library - Wind32에서
Library path와 Debug DCU path를 설정 한다.
DCU파일들이 있는 아래의 폴더들을 설정된 것들을
Library path와 Debug DCU path에 입력하고 [OK] 버튼을 클릭한다.

;$(BDS)\Lib\indy10\Core
;$(BDS)\Lib\indy10\Protocols
;$(BDS)\Lib\indy10\System;




이렇게 하면 INDY의 설치가 완료된다.

시간차 : 0002.010 (시간차를 실수로 표현하고 싶습니다. 분초.밀리초) 구하기

function TForm1.GetTimeDif(Time1 , Time2 : TTime) : Double;
var
TimeDif : TTime;
Hour, Sec, Min, mSec : Word;
begin
TimeDif := Time2 - Time1;
DecodeTime(TimeDif, Hour, Min,Sec, mSec);
Sec := Hour*3600+Min*60+Sec;
Result := Sec+(mSec/1000);
end;

procedure TForm1.Button3Click(Sender: TObject);
var
time1, Time2 : TTime;
res : Double;
begin
Time1 := EncodeTime(07,08,00,000);
Time2 := EncodeTime(07,08,02,010);
Res := GetTimeDif(Time1, Time2);
ShowMessage(FormatFloat('0000.0000',Res));
end;

hook를 이용한 textout 하기

"캡쳐"실현 //------------------------------------------------ ----------------- 1 SetWindowsHookEx ()를 마우스 후크를 MouseProc 설치; 2, 움직임은 화면에 마우스 시스템은 마우스 후크 MouseProc 전화 것이다; 3 MouseProc로, 마우스 (좌표를 얻을 엑스, y를), 설정 TextOut (), ExtTextOut () 및 기타 추적 절차에 invalidateRect ()와 요점은 (여기서 x, y를) "실패"로 시스템을 알려줍니다; 4 보내기 WM_PAINT 메시지 시스템, 포인트 (엑스, y를)는 Office 응용 프로그램이 지역의 "실패"를 다시 그리기 나타냅니다. 5 WM_PAINT 메시지에 의해 응용 프로그램에서 지점을 () 그리기에 대한 책임, 기회를 호출해야합니다 TextOut (), ExtTextOut () 및 기타 기능을합니다. 6, 함수 호출을 추적하는 과정으로 차단됩니다 : 추적 프로그램을 두 번째 통화를 도청 설정, 는 응용 프로그램 밖으로 포인트 (스택에서 x를 y를) "텍스트"포인터; "" "화면을 완성 포인터의 내용을 서면으로 7 응용 프로그램의 데이터 세그먼트의 수 단어를 파악하는 것이지 "; MouseProc 마우스 후크로 반환 절차를 추적 8 아웃; 9 MouseProc TextOut () ExtTextOut () 트랙의 리프팅; MouseProc 마우스 후크 프로 시저 10 밖으로, 시스템을 제어할 수 있습니다. 11 화면에 다음 "화면"라는 단어를 파악하고 2 단계로 돌아갑니다 시작하는 마우스를 이동합니다.


1。新建dll项目GetWordDll.dpr,代码如下
library GetWordDll;
uses
Windows,
SysUtils,
Classes,
UnitHookDll in ‘UnitHookDll.pas’,
UnitNt2000Hook in ‘UnitNt2000Hook.pas’,
UnitHookType in ‘UnitHookType.pas’;

exports
StartHook,
StopHook;
// MouseWndProc,
{以下导出列表都是必须的,
不能少,因为程序要取其地址}
{ NewBeginPaint,
NewCreateCompatibleDC,
NewTextOutA,
NewTextOutW,
NewExtTextOutA,
NewExtTextOutW,
NewDrawTextA,
NewDrawTextW; }
begin
end.

2。新建3个单元UnitHookDll.pas,UnitHookType.pas,UnitNt2000Hook.pas具体代码如下
unit UnitHookDll;
interface
uses Windows, SysUtils, Classes, math, messages, dialogs, UnitNt2000Hook,
UnitHookType;

const
COLOR1=255;
COLOR2=0;
COLOR3=255;
Trap=true; //True陷阱式,False表示改引入表式

procedure StartHook; stdcall; {开始取词}
procedure StopHook; stdcall; {停止取词}

implementation
var
MouseHook: THandle;
pShMem: PShareMem;
hMappingFile: THandle;
FirstProcess:boolean;{是否是第一个进程}
Hook: array[fBeginPaint..fDrawTextW] of THookClass;{API HOOK类}
i:integer;

{自定义的BeginPaint}
function NewBeginPaint(Wnd: HWND; var lpPaint: TPaintStruct): HDC; stdcall;
type
TBeginPaint=function (Wnd: HWND; var lpPaint: TPaintStruct): HDC; stdcall;
begin
Hook[fBeginPaint].Restore;
result:=TBeginPaint(Hook[fBeginPaint].OldFunction)(Wnd,lpPaint);
if Wnd=pshmem^.hHookWnd then{如果是当前鼠标的窗口句柄}
begin
pshmem^.DCMouse:=result;{记录它的返回值}
end
else pshmem^.DCMouse:=0;
Hook[fBeginPaint].Change;
end;

{自定义的GetWindowDC}
function NewGetWindowDC(Wnd: HWND): HDC; stdcall;
type
TGetWindowDC=function (Wnd: HWND): HDC; stdcall;
begin
Hook[fGetWindowDC].Restore;
result:=TGetWindowDC(Hook[fGetWindowDC].OldFunction)(Wnd);
if Wnd=pshmem^.hHookWnd then{如果是当前鼠标的窗口句柄}
begin
pshmem^.DCMouse:=result;{记录它的返回值}
end
else pshmem^.DCMouse:=0;
Hook[fGetWindowDC].Change;
end;

{自定义的GetDC}
function NewGetDC(Wnd: HWND): HDC; stdcall;
type
TGetDC=function (Wnd: HWND): HDC; stdcall;
begin
Hook[fGetDC].Restore;
result:=TGetDC(Hook[fGetDC].OldFunction)(Wnd);
if Wnd=pshmem^.hHookWnd then{如果是当前鼠标的窗口句柄}
begin
pshmem^.DCMouse:=result;{记录它的返回值}
end
else pshmem^.DCMouse:=0;
Hook[fGetDC].Change;
end;

{自定义的CreateCompatibleDC}
function NewCreateCompatibleDC(DC: HDC): HDC; stdcall;
type
TCreateCompatibleDC=function (DC: HDC): HDC; stdcall;
begin
Hook[fCreateCompatibleDC].Restore;
result:=TCreateCompatibleDC(Hook[fCreateCompatibleDC].OldFunction)(DC);
if DC=pshmem^.DCMouse then{如果是当前鼠标的窗口HDC}
begin
pshmem^.DCCompatible:=result;{记录它的返回值}
end
else pshmem^.DCCompatible:=0;
Hook[fCreateCompatibleDC].Change;
end;

function NewTextOutA(theDC: HDC; nXStart, nYStart: integer; str: pchar; count: integer): bool;
stdcall;
type
TTextOutA=function (theDC: HDC; nXStart, nYStart: integer; str: pchar; count: integer): bool;stdcall;
var
dwBytes: DWORD;
poOri, poDC, poText, poMouse: TPoint;
Size: TSize;
Rec:TRect;
faint:boolean;
begin
Hook[fTextOutA].Restore;{暂停截取API,恢复被截的函数}
try
if pShMem^.bCanSpyNow then{是否开始取词}
begin
GetDCOrgEx(theDC, poOri);{HDC的坐标}
poDC.x := nXStart;{显示的相对坐标}
poDC.y := nYStart;
if(poOri.X=0)and(poOri.Y=0)then{如果HDC的坐标为(0,0)}
begin
if (theDC=pShmem^.DCCompatible)then
faint:=false{精确匹配,就是指定的内存HDC}
else faint:=true;{模糊匹配,"可能"是内存HDC}
{取鼠标当前处的窗口(等效于Delphi的控件)坐标}
GetWindowRect(pShMem^.hHookWnd,Rec);
poOri.X:=Rec.Left;{把窗口坐标作为HDC的坐标}
poOri.Y:=Rec.Top;
end
else begin{如果是普通HDC}
{局部逻辑坐标转化为设备相关坐标}
LPToDP(theDC, poDC, 1);
faint:=false;{精确匹配,是普通HDC}
end;
{计算显示文字的屏幕坐标}
poText.x := poDC.x + poOri.x;
poText.y := poDC.y + poOri.y;
{获取当前鼠标的坐标}
GetCursorPos(poMouse);
{如果对齐属性是居中}
if (GetTextAlign(theDC) and TA_UPDATECP) <> 0 then
begin
GetCurrentPositionEx(theDC, @poOri);
poText.x := poText.x + poOri.x;
poText.y := poText.y + poOri.y;
end;
{显示文字的长和宽}
GetTextExtentPoint(theDC, Str, Count, Size);
{鼠标是否在文本的范围内}
if (poMouse.x >= poText.x) and (poMouse.x <= poText.x + Size.cx)
and (poMouse.y >= poText.y) and (poMouse.y <= poText.y + Size.cy)
then
begin
{最多取MaxStringLen个字节}
dwBytes := min(Count, MaxStringLen);
{拷贝字符串}
CopyMemory(@(pShMem^.Text), Str, dwBytes);
{以空字符结束}
pShMem^.Text[dwBytes] := Chr(0);
{发送WM_MOUSEPT成功取词的消息给主程序}
postMessage(pShMem^.hProcWnd, WM_MOUSEPT, fTextOutA, 2);
{如果输出的不是Tab键,而且是精确匹配的}
if (string(pShMem^.Text)<>#3)and(not faint) then
pShMem^.bCanSpyNow := False;{取词结束}
end;
end;
finally
{调用被截的函数}
result := TTextOutA(Hook[fTextOutA].OldFunction)(theDC, nXStart,
nYStart, str, count);
end;
Hook[fTextOutA].Change;{重新截取API}
end;


function NewTextOutW(theDC: HDC; nXStart, nYStart: integer; str: pWidechar; count: integer): bool; stdcall;
type
TTextOutW=function (theDC: HDC; nXStart, nYStart: integer; str: pWidechar; count: integer): bool; stdcall;
var
dwBytes: DWORD;
poOri, poDC, poText, poMouse: TPoint;
Size: TSize;
Rec:TRect;
faint:boolean;
begin
Hook[fTextOutW].Restore;{暂停截取API,恢复被截的函数}
// SetTextColor(thedc,RGB(COLOR1,COLOR2,COLOR3));
try
if pShMem^.bCanSpyNow then{是否开始取词}
begin
GetDCOrgEx(theDC, poOri);{HDC的坐标}
poDC.x := nXStart;{显示的相对坐标}
poDC.y := nYStart;
if(poOri.X=0)and(poOri.Y=0)then{如果HDC的坐标为(0,0)}
begin
if (theDC=pShmem^.DCCompatible)then
faint:=false{精确匹配,就是指定的内存HDC}
else faint:=true;{模糊匹配,"可能"是内存HDC}
{取鼠标当前处的窗口(等效于Delphi的控件)坐标}
GetWindowRect(pShMem^.hHookWnd,Rec);
poOri.X:=Rec.Left;{把窗口坐标作为HDC的坐标}
poOri.Y:=Rec.Top;
end
else begin{如果是普通HDC}
{局部逻辑坐标转化为设备相关坐标}
LPToDP(theDC, poDC, 1);
faint:=false;{精确匹配,是普通HDC}
end;
{计算显示文字的屏幕坐标}
poText.x := poDC.x + poOri.x;
poText.y := poDC.y + poOri.y;
{获取当前鼠标的坐标}
GetCursorPos(poMouse);
{如果对齐属性是居中}
if (GetTextAlign(theDC) and TA_UPDATECP) <> 0 then
begin
GetCurrentPositionEx(theDC, @poOri);
poText.x := poText.x + poOri.x;
poText.y := poText.y + poOri.y;
end;
{显示文字的长和宽}
GetTextExtentPointW(theDC, Str, Count, Size);
{鼠标是否在文本的范围内}
if (poMouse.x >= poText.x) and (poMouse.x <= poText.x + Size.cx)
and (poMouse.y >= poText.y) and (poMouse.y <= poText.y + Size.cy)
then
begin
{最多取MaxStringLen个字节}
dwBytes := min(Count*2, MaxStringLen);
{拷贝字符串}
CopyMemory(@(pShMem^.Text), Pchar(WideCharToString(Str)), dwBytes);
{以空字符结束}
pShMem^.Text[dwBytes] := Chr(0);
{发送WM_MOUSEPT成功取词的消息给主程序}
postMessage(pShMem^.hProcWnd, WM_MOUSEPT, fTextOutW, 2);
{如果输出的不是Tab键,而且是精确匹配的}
if (string(pShMem^.Text)<>#3)and(not faint) then
pShMem^.bCanSpyNow := False;{取词结束}
end;
end;
finally
{调用被截的函数}
result := TTextOutW(Hook[fTextOutW].OldFunction)(theDC, nXStart, nYStart, str, Count);
end;
Hook[fTextOutW].Change;{重新截取API}
end;

function NewExtTextOutA(theDC: HDC; nXStart, nYStart: integer; toOptions:Longint;
rect: PRect; Str: PAnsiChar; Count: Longint; Dx: PInteger): BOOL; stdcall;
type
TExtTextOutA=function (theDC: HDC; nXStart, nYStart: integer; toOptions:Longint;
rect: PRect; Str: PAnsiChar; Count: Longint; Dx: PInteger): BOOL; stdcall;
var
dwBytes: DWORD;
poOri, poDC, poText, poMouse: TPoint;
Size: TSize;
Rec:TRect;
faint:boolean;
begin
Hook[fExtTextOutA].Restore;{暂停截取API,恢复被截的函数}
// SetTextColor(thedc,RGB(COLOR1,COLOR2,COLOR3));
try
if pShMem^.bCanSpyNow then{是否开始取词}
begin
GetDCOrgEx(theDC, poOri);{HDC的坐标}
poDC.x := nXStart;{显示的相对坐标}
poDC.y := nYStart;
if(poOri.X=0)and(poOri.Y=0)then{如果HDC的坐标为(0,0)}
begin
if (theDC=pShmem^.DCCompatible)then
faint:=false{精确匹配,就是指定的内存HDC}
else faint:=true;{模糊匹配,"可能"是内存HDC}
{取鼠标当前处的窗口(等效于Delphi的控件)坐标}
GetWindowRect(pShMem^.hHookWnd,Rec);
poOri.X:=Rec.Left;{把窗口坐标作为HDC的坐标}
poOri.Y:=Rec.Top;
end
else begin{如果是普通HDC}
{局部逻辑坐标转化为设备相关坐标}
LPToDP(theDC, poDC, 1);
faint:=false;{精确匹配,是普通HDC}
end;
{计算显示文字的屏幕坐标}
poText.x := poDC.x + poOri.x;
poText.y := poDC.y + poOri.y;
{获取当前鼠标的坐标}
GetCursorPos(poMouse);
{如果对齐属性是居中}
if (GetTextAlign(theDC) and TA_UPDATECP) <> 0 then
begin
GetCurrentPositionEx(theDC, @poOri);
poText.x := poText.x + poOri.x;
poText.y := poText.y + poOri.y;
end;
{显示文字的长和宽}
GetTextExtentPoint(theDC, Str, Count, Size);
{鼠标是否在文本的范围内}
if (poMouse.x >= poText.x) and (poMouse.x <= poText.x + Size.cx)
and (poMouse.y >= poText.y) and (poMouse.y <= poText.y + Size.cy)
then
begin
{最多取MaxStringLen个字节}
dwBytes := min(Count, MaxStringLen);
{拷贝字符串}
CopyMemory(@(pShMem^.Text), Str, dwBytes);
{以空字符结束}
pShMem^.Text[dwBytes] := Chr(0);
{发送WM_MOUSEPT成功取词的消息给主程序}
postMessage(pShMem^.hProcWnd, WM_MOUSEPT, fExtTextOutA, 2);
{如果输出的不是Tab键,而且是精确匹配的}
if (string(pShMem^.Text)<>#3)and(not faint) then
pShMem^.bCanSpyNow := False;{取词结束}
end;
end;
finally
{调用被截的函数}
result := TExtTextOutA(Hook[fExtTextOutA].OldFunction)(theDC, nXStart, nYStart, toOptions, rect, Str,
Count, Dx);
end;
Hook[fExtTextOutA].Change;{重新截取API}
end;

function NewExtTextOutW(theDC: HDC; nXStart, nYStart: integer; toOptions:
Longint; rect: PRect;
Str: Pwidechar; Count: Longint; Dx: PInteger): BOOL; stdcall;
type
TExtTextOutW=function (theDC: HDC; nXStart, nYStart: integer; toOptions:Longint;
rect: PRect; Str: Pwidechar; Count: Longint; Dx: PInteger): BOOL; stdcall;
var
dwBytes: DWORD;
poOri, poDC, poText, poMouse: TPoint;
Size: TSize;
Rec:TRect;
faint:boolean;
begin
Hook[fExtTextOutW].Restore;{暂停截取API,恢复被截的函数}
// SetTextColor(thedc,RGB(COLOR1,COLOR2,COLOR3));
try
if pShMem^.bCanSpyNow then{是否开始取词}
begin
GetDCOrgEx(theDC, poOri);{HDC的坐标}
poDC.x := nXStart;{显示的相对坐标}
poDC.y := nYStart;
if(poOri.X=0)and(poOri.Y=0)then{如果HDC的坐标为(0,0)}
begin
if (theDC=pShmem^.DCCompatible)then
faint:=false{精确匹配,就是指定的内存HDC}
else faint:=true;{模糊匹配,"可能"是内存HDC}
{取鼠标当前处的窗口(等效于Delphi的控件)坐标}
GetWindowRect(pShMem^.hHookWnd,Rec);
poOri.X:=Rec.Left;{把窗口坐标作为HDC的坐标}
poOri.Y:=Rec.Top;
end
else begin{如果是普通HDC}
{局部逻辑坐标转化为设备相关坐标}
LPToDP(theDC, poDC, 1);
faint:=false;{精确匹配,是普通HDC}
end;
{计算显示文字的屏幕坐标}
poText.x := poDC.x + poOri.x;
poText.y := poDC.y + poOri.y;
{获取当前鼠标的坐标}
GetCursorPos(poMouse);
{如果对齐属性是居中}
if (GetTextAlign(theDC) and TA_UPDATECP) <> 0 then
begin
GetCurrentPositionEx(theDC, @poOri);
poText.x := poText.x + poOri.x;
poText.y := poText.y + poOri.y;
end;
{显示文字的长和宽}
GetTextExtentPointW(theDC, Str, Count, Size);
{鼠标是否在文本的范围内}
if (poMouse.x >= poText.x) and (poMouse.x <= poText.x + Size.cx)
and (poMouse.y >= poText.y) and (poMouse.y <= poText.y + Size.cy)
then
begin
{最多取MaxStringLen个字节}
dwBytes := min(Count*2, MaxStringLen);
{拷贝字符串}
CopyMemory(@(pShMem^.Text), Pchar(WideCharToString(Str)), dwBytes);
{以空字符结束}
pShMem^.Text[dwBytes] := Chr(0);
{发送WM_MOUSEPT成功取词的消息给主程序}
postMessage(pShMem^.hProcWnd, WM_MOUSEPT, fExtTextOutW, 2);
{如果输出的不是Tab键,而且是精确匹配的}
if (string(pShMem^.Text)<>#3)and(not faint) then
pShMem^.bCanSpyNow := False;{取词结束}
end;
end;
finally
{调用被截的函数}
result := TExtTextOutW(Hook[fExtTextOutW].OldFunction)(theDC, nXStart, nYStart, toOptions,Rect, Str, Count, Dx);
end;
Hook[fExtTextOutW].Change;{重新截取API}
end;

function NewDrawTextA(theDC: HDC; lpString: PAnsiChar; nCount: Integer;
var lpRect: TRect; uFormat: UINT): Integer; stdcall;
type
TDrawTextA=function (theDC: HDC; lpString: PAnsiChar; nCount: Integer;
var lpRect: TRect; uFormat: UINT): Integer; stdcall;
var
poMouse,poOri,poDC: TPoint;
dwBytes: integer;
RectSave,rec:TRect;
faint:boolean;
begin
Hook[fDrawTextA].Restore;{暂停截取API,恢复被截的函数}
// SetTextColor(thedc,RGB(COLOR1,COLOR2,COLOR3));
try
if pShMem^.bCanSpyNow then{是否开始取词}
begin
GetDCOrgEx(theDC, poOri);{HDC的坐标}
poDC.x := 0;{局部逻辑坐标初始化为(0,0)}
poDC.y := 0;
if(poOri.X=0)and(poOri.Y=0)then{如果HDC的坐标为(0,0)}
begin
if (theDC=pShmem^.DCCompatible)then
faint:=false{精确匹配,就是指定的内存HDC}
else faint:=true;{模糊匹配,"可能"是内存HDC}
{取鼠标当前处的窗口(等效于Delphi的控件)坐标}
GetWindowRect(pShMem^.hHookWnd,Rec);
poOri.X:=Rec.Left;{把窗口坐标作为HDC的坐标}
poOri.Y:=Rec.Top;
end
else begin{如果是普通HDC}
{局部逻辑坐标转化为设备相关坐标}
LPToDP(theDC, poDC, 1);
faint:=false;{精确匹配,是普通HDC}
end;
RectSave := lpRect;{显示的矩形}
OffsetRect(RectSave, poOri.x+poDC.x, poOri.y+poDC.y);{显示的矩形加上偏移}
{获取当前鼠标的坐标}
GetCursorPos(poMouse);
{鼠标是否在文本的范围内}
if PtInRect(RectSave, poMouse) then
begin
if nCount=-1 then
begin
strcopy(@(pShMem^.Text[0]), lpString);
end
else begin
{最多取MaxStringLen个字节}
dwBytes := min(nCount, MaxStringLen);
{拷贝字符串}
CopyMemory(@(pShMem^.Text[0]), lpString, dwBytes);
{以空字符结束}
pShMem^.Text[dwBytes] := Chr(0);
end;
{发送WM_MOUSEPT成功取词的消息给主程序}
postMessage(pShMem^.hProcWnd, WM_MOUSEPT, fDrawTextA, 2);
{如果输出的不是Tab键,而且是精确匹配的}
if (string(pShMem^.Text)<>#3)and(not faint) then
pShMem^.bCanSpyNow := False;{取词结束}
end;
end;
finally
{调用被截的函数}
result := TDrawTextA(Hook[fDrawTextA].OldFunction)(theDC, lpString, nCount, lpRect, uFormat);
end;
Hook[fDrawTextA].Change;{重新截取API}
end;

function NewDrawTextW(theDC: HDC; lpString: PWideChar; nCount: Integer;
var lpRect: TRect; uFormat: UINT): Integer; stdcall;
type
TDrawTextW=function (theDC: HDC; lpString: PWideChar; nCount: Integer;
var lpRect: TRect; uFormat: UINT): Integer; stdcall;
var
poMouse,poOri,poDC: TPoint;
dwBytes: integer;
RectSave,rec:TRect;
faint:boolean;
begin
Hook[fDrawTextW].Restore;{暂停截取API,恢复被截的函数}
// SetTextColor(thedc,RGB(COLOR1,COLOR2,COLOR3));
try
if pShMem^.bCanSpyNow then{是否开始取词}
begin
GetDCOrgEx(theDC, poOri);{HDC的坐标}
poDC.x := 0;{局部逻辑坐标初始化为(0,0)}
poDC.y := 0;
if(poOri.X=0)and(poOri.Y=0)then{如果HDC的坐标为(0,0)}
begin
if (theDC=pShmem^.DCCompatible)then
faint:=false{精确匹配,就是指定的内存HDC}
else faint:=true;{模糊匹配,"可能"是内存HDC}
{取鼠标当前处的窗口(等效于Delphi的控件)坐标}
GetWindowRect(pShMem^.hHookWnd,Rec);
poOri.X:=Rec.Left;{把窗口坐标作为HDC的坐标}
poOri.Y:=Rec.Top;
end
else begin{如果是普通HDC}
{局部逻辑坐标转化为设备相关坐标}
LPToDP(theDC, poDC, 1);
faint:=false;{精确匹配,是普通HDC}
end;
RectSave := lpRect;{显示的矩形}
OffsetRect(RectSave, poOri.x+poDC.x, poOri.y+poDC.y);{显示的矩形加上偏移}
{获取当前鼠标的坐标}
GetCursorPos(poMouse);
{鼠标是否在文本的范围内}
if PtInRect(RectSave, poMouse) then
begin
if nCount=-1 then
begin
strcopy(@(pShMem^.Text[0]), Pchar(WideCharToString(lpString)));
end
else begin
{最多取MaxStringLen个字节}
dwBytes := min(nCount*2, MaxStringLen);
{拷贝字符串}
CopyMemory(@(pShMem^.Text[0]), Pchar(WideCharToString(lpString)), dwBytes);
{以空字符结束}
pShMem^.Text[dwBytes] := Chr(0);
end;
{发送WM_MOUSEPT成功取词的消息给主程序}
postMessage(pShMem^.hProcWnd, WM_MOUSEPT, fDrawTextW, 2);
{如果输出的不是Tab键,而且是精确匹配的}
if (string(pShMem^.Text)<>#3)and(not faint) then
pShMem^.bCanSpyNow := False;{取词结束}
end;
end;
finally
{调用被截的函数}
result := TDrawTextW(Hook[fDrawTextW].OldFunction)(theDC, lpString, nCount, lpRect, uFormat);
end;
Hook[fDrawTextW].Change;{重新截取API}
end;

{遍历所有菜单项}
procedure IterateThroughItems(WND:HWND;menu:Hmenu;p:TPoint;Level:integer);
var
i:integer;
info:TMenuItemInfo;
rec:TRect;
begin
for i:=0 to GetMenuItemCount(menu)-1 do {遍历所有子菜单项}
begin
fillchar(info,sizeof(info),0);
info.cbSize:=sizeof(info);
info.fMask:=MIIM_TYPE or MIIM_SUBMENU;
info.cch:=256;
getmem(info.dwTypeData,256);
{取菜单的文字}
GetMenuItemInfo(menu,i,true,info);
{取菜单的坐标}
GetMenuItemRect(wnd,menu,i,rec);
{如果鼠标在菜单的矩形区域内}
if (rec.Left<=p.X)and(p.X<=rec.Right)and(rec.Top<=p.Y)and(p.Y<=rec.Bottom)then
if (info.cch<>0) then
begin
{取出菜单文字}
strlcopy(pShMem^.Text,info.dwTypeData,min(info.cch,MaxStringLen));
pShMem^.bCanSpyNow := False;
{发送WM_MOUSEPT成功取词的消息给主程序}
PostMessage(pShMem^.hProcWnd, WM_MOUSEPT, fDrawTextW, 2);
end;
// freemem(info.dwTypeData,256);
// info.dwTypeData:=nil;
if info.hSubMenu<>0 then {如果它有下级子菜单,则归递调用}
begin
IterateThroughItems(wnd,info.hSubMenu,p,Level+1);
end;
end;
end;

{定时器,每10毫秒被调用一次}
procedure fOnTimer(theWnd: HWND; msg, idTimer: Cardinal; dwTime: DWORD); stdcall;
var
InvalidRect: TRECT;
buffer:array[0..256]of char;
menu:Hmenu;
MousePoint:TPoint;
begin
pShMem^.nTimePassed := pShMem^.nTimePassed + 1;
if pShMem^.nTimePassed = 10 then {如果鼠标停留了0.1秒}
begin
MousePoint:=pshmem^.pMouse;
{获取当前鼠标所在的窗口(等效于Delphi的控件)句柄}
pshmem^.hHookWnd := WindowFromPoint(MousePoint);
{屏幕坐标转换为窗口(等效于Delphi的控件)客户区的坐标}
ScreenToClient(pshmem^.hHookWnd, MousePoint);
pShMem^.bCanSpyNow := true;{可以开始取词}
{如果客户区的坐标为负值,则说明鼠标位于菜单或标题的上空}
if(MousePoint.x<0)or(MousePoint.y<0) then
begin
{读取并设置标题,让其重绘}
Getwindowtext(pshmem^.hHookWnd,buffer,sizeof(buffer)-1);
Setwindowtext(pshmem^.hHookWnd,pchar(string(buffer)+’ ‘));
Setwindowtext(pshmem^.hHookWnd,buffer);
{客户区的坐标恢复为屏幕坐标}
ClientToScreen(pshmem^.hHookWnd, MousePoint);
{取出当前的菜单}
menu:=GetMenu(pshmem^.hHookWnd);
if menu<>0 then
{遍历所有菜单,判断是否位于鼠标的下方}
IterateThroughItems(pshmem^.hHookWnd,menu,MousePoint,1);
end
else begin{否则,说明鼠标位于客户区}
InvalidRect.left := MousePoint.x;
InvalidRect.top := MousePoint.y;
InvalidRect.Right := MousePoint.x + 1;
InvalidRect.Bottom := MousePoint.y + 1;
{重绘客户区}
InvalidateRect(pshmem^.hHookWnd, @InvalidRect, false);
end;
end
else if pShMem^.nTimePassed >= 11 then
begin
pShMem^.nTimePassed := 11;
end;
{清空pShmem}
end;

{鼠标钩子}
function MouseHookProc(nCode: integer; wPar: WParam; lPar: LParam): lResult;
stdcall;
var
pMouseInf: TMouseHookStruct;
begin
pShMem^.nTimePassed := 0;
if (nCode >= 0) and ((wPar = WM_MOUSEMOVE)or(wPar = WM_NCMOUSEMOVE)) then
begin
pMouseInf := (PMouseHookStruct(lPar))^;
if (pShMem^.pMouse.x <> pMouseInf.pt.x) or
(pShMem^.pMouse.y <> pMouseInf.pt.y) then
begin
if nCode = HC_NOREMOVE then
pShMem^.fStrMouseQueue := ‘Not removed from the queue’
else
pShMem^.fStrMouseQueue := ‘Removed from the queue’;
{鼠标的坐标}
pShMem^.pMouse := pMouseInf.pt;
{鼠标所在的窗口}
pShMem^.hHookWnd := pMouseInf.hwnd;
{1是自定义的数值,表明这是鼠标消息}
postMessage(pShMem^.hProcWnd, WM_MOUSEPT, 1, 1);
end;
end;
Result := CallNextHookEx(MouseHook, nCode, wPar, lPar);
end;

{开始取词}
procedure StartHook; stdcall;
begin
if MouseHook=0 then
begin
pShMem^.fTimerID := SetTimer(0, 0, 10, @fOnTimer);
{注入其它进程}
MouseHook := SetWindowsHookEx(WH_MOUSE, MouseHookProc, HInstance, 0);
end;
end;

{停止取词}
procedure StopHook; stdcall;
begin
if MouseHook<>0 then
begin
KillTimer(0, pShMem^.fTimerID);
UnhookWindowsHookEx(MouseHook);
MouseHook:=0;
end;
end;

initialization
hMappingFile := OpenFileMapping(FILE_MAP_WRITE,False,MappingFileName);
if hMappingFile=0 then
begin
hMappingFile := CreateFileMapping($FFFFFFFF,nil,PAGE_READWRITE,0,SizeOf(TShareMem),MappingFileName);
FirstProcess:=true; {这是第一个进程,即主程序}
end
else FirstProcess:=false;
if hMappingFile=0 then Exception.Create(‘不能建立共享内存!’);

pShMem := MapViewOfFile(hMappingFile,FILE_MAP_WRITE or FILE_MAP_READ,0,0,0);
if pShMem = nil then
begin
CloseHandle(hMappingFile);
Exception.Create(‘不能映射共享内存!’);
end;
if FirstProcess then
begin
pShMem^.bCanSpyNow:=false;
end;
Hook[fBeginPaint]:=THookClass.Create(Trap,@BeginPaint,@NewBeginPaint);{Trap=True陷阱式}
Hook[fGetWindowDC]:=THookClass.Create(Trap,@GetWindowDC,@NewGetWindowDC);
Hook[fGetDC]:=THookClass.Create(Trap,@GetDC,@NewGetDC);
Hook[fCreateCompatibleDC]:=THookClass.Create(Trap,@CreateCompatibleDC,@NewCreateCompatibleDC);
Hook[fTextOutA]:=THookClass.Create(Trap,@TextOutA,@NewTextOutA);
Hook[fTextOutW]:=THookClass.Create(Trap,@TextOutW,@NewTextOutW);
Hook[fExtTextOutA]:=THookClass.Create(Trap,@ExtTextOutA,@NewExtTextOutA);
Hook[fExtTextOutW]:=THookClass.Create(Trap,@ExtTextOutW,@NewExtTextOutW);
Hook[fDrawTextA]:=THookClass.Create(Trap,@DrawTextA,@NewDrawTextA);
Hook[fDrawTextW]:=THookClass.Create(Trap,@DrawTextW,@NewDrawTextW);
finalization
for i:=Low(hook) to High(hook) do
if Hook[i]<>nil then
Hook[i].Destroy;
UnMapViewOfFile(pShMem); {取消映射视图}
CloseHandle(hMappingFile); {关闭映射文件句柄}
end.



UnitHookDll.pas (2)
//-----------------------------------------------------------------------------------
主窗体单元UnitMain.pas
unit UnitMain;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls,UnitHookType, ExtCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
procedure Button1Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormCreate(Sender: TObject);
private
procedure getMouseInfo(var theMess:TMessage); message WM_MOUSEPT;{处理WM_MOUSEPT}
private
hMapObj : THandle;
pShMem : PShareMem;
fWndClosed:boolean;{是否正在退出主程序}
{ Private declarations }
public
{ Public declarations }
end;
// {未公开的函数,实现隐浮窗口}
// procedure SwitchToThisWindow(wnd:Hwnd;Switch:BOOL);stdcall;external 'user32.dll';
procedure StartHook; stdcall; external 'GetWordDll.DLL';
procedure StopHook; stdcall; external 'GetWordDll.DLL';
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
begin
if button1.caption='取词' then
begin
StartHook;
button1.caption:='停止';
end
else begin
StopHook;
button1.caption:='取词';
end;
end;
const
StrProcNames : array[fTextOutA..fDrawTextW] of String =
('来自TextOutA',
'来自TextOutW',
'来自ExtTextOutA',
'来自ExtTextOutW',
'来自DrawTextA',
'来自菜单(来自DrawTextW)'
);
procedure TForm1.getMouseInfo(var theMess : TMessage);
begin
if fWndClosed then
Exit;
//if theMess.Msg=WM_MOUSEPT then showmessage('fff');
if theMess.LParam = 1 then{显示鼠标位置}
edit1.Text := 'X:' + IntToStr(pShMem^.pMouse.x) + ' ' +
'Y:' + IntToStr(pShMem^.pMouse.y) + ' ' +
'HWND:0x' + IntToHex(pShMem^.hHookWnd, 8) + ' ' +
pShMem^.fStrMouseQueue
else if theMess.LParam = 2 then
begin
edit2.Text := pShMem^.Text;
if (theMess.WParam>=4)and(theMess.WParam<=9) then
edit3.Text :=StrProcNames[theMess.Wparam-4];
end;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
fWndClosed := True;{正在退出主程序}
if button1.caption<>'取词' then
Button1Click(sender);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
SetForegroundWindow(self.Handle);{实现隐浮窗口}
hMapObj := OpenFileMapping(FILE_MAP_WRITE,{获取完全访问映射文件}
False,{不可继承的}
LPCTSTR(MappingFileName));{映射文件名字}
if hMapObj = 0 then
begin
ShowMessage('不能定位内存映射文件块!');
Halt;
end;
pShMem := MapViewOfFile(hMapObj,FILE_MAP_WRITE,0,0,0);
if pShMem = nil then
begin
ShowMessage('映射文件错误'+ IntToStr(GetLastError));
CloseHandle(hMapObj);
Halt;
end;
FillChar(pShMem^, SizeOf(TShareMem), 0);
pShMem^.hProcWnd := Self.Handle;
fWndClosed:=false;
end;
end.

폼에 드래그 앤 드롭 구현

출처 : 김영대님 홈피 (http://www.howto.pe.kr)



unitMain;

interface

uses
Windows, Messages, SysUtils, Classes, ShellApi;

type
TfrmMain=class(TForm)
procedureFormActivate(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
private
procedure WMDropFiles(var Msg: TMessage); message WM_DROPFILES;
end;

var
frmMain: TfrmMain;



implementation

procedure TfrmMain.FormActivate(Sender: TObject);
begin
// Drag&Drop Accept
DragAcceptFiles(Handle, True);
end;

procedure TfrmMain.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
// Drag&Drop Accept 해제
DragAcceptFiles(Handle, False);
// 폼닫기
CanClose:=True;
end;

procedure TfrmMain.WMDropFiles(var Msg: TMessage);
var
i, cntDropItem, DropItemNameLength: Integer;
hDrop: THandle;
DropItemPath: array [0..MAX_PATH] of Char;

begin
try
// Drop Handle
hDrop:=Msg.wParam;

// Drop된 아이템 갯수
cntDropItem:=DragQueryFile(hDrop, $FFFFFFFF, nil,0);
for i:=0tocntDropItem-1 do begin
// Drop된 파일경로 길이
DropItemNameLength:=DragQueryFile(hDrop, i, nil, 0);
// Drop된 파일경로
DragQueryFile(hDrop, i, DropItemPath, DropItemNameLength+1);
// 출력...
OutputDebugString(PWideChar(DropItemPath));
end;
finally
DragFinish(hDrop);
end;

Msg.Result:=0;

inherited;
end;

다른 프로그램의 텍스트 가져오기

WM_GETTEXT 사용하기.
GetWindowText 요런건 다른 프로세스의 것은 잘 안된다.
그래서 만든 함수.


function GetWindowText(aHWND: HWND): String;
var
len: Integer;
begin
len:=SendMessage(aHWND, WM_GETTEXTLENGTH, 0, 0);
SetLength(Result, len+1);
SendMessage(aHWND, WM_GETTEXT, len+1, lParam(PChar(Result)));
end;



예제) 아래처럼 하면 커서 밑에 있는 윈도우의 텍스트를 가져온다.
Form1.Memo1.Lines.Add(GetWindowText(WindowFromPoint(Mouse.CursorPos)));




!!!
그러나 에디트플러스의 에디터 창에 있는 걸 가져오면,
왠만하면 가져와지는데 일정 길이가 넘어가면 이상하게 잘린다.
중간에 #0 을 만나버리는 걸 확인했다.
WM_GETTEXT 를 사용하는 SendMessage 에서 wParam 값을 살살 바꿔가며 실험해보니 이게 또 달라진다.