Chciałem pomóc pytającemu, ale nie trawie rpgów żadnych in real i komputerowych z wyjątkiem może klasyka i świetnej gry jaką był Moonstone na Amidze. Pobrałem ten "lol-crap", ale po założeniu konta nie wpuszcza mnie na serwer twierdząć, że źle podałem login i hasło. Raz mi przyjął, ale napisał że server busy. Szkoda marnować czas na tibiopodobne bzdety. Poza tym gra do momentu rozgrywki jest w oknie. Jedyne co mogę doradzić pytającemu to spróbowac zrobić dialog w WinAPI, a następnie wstrzykiwac dllkę z tym dialogiem przez moduł afxcodehook.pas
. Dla niektórych gier na przykład starej przygodówki "Wacki - Kosmiczna rozgrywka", które są pod DitectX, a nie SDL taki kod zadziałał i okno jakie stworzyłem było na wierzchu i okno głowne gry nie traciło focusa.
//..
const
IDI_MAINICON = 100;
IDC_MAINFORM = 1001;
//...
var
vvv : boolean;
//...
GamePid : DWORD;
GameWindowHandle : HWND;
//...
var // Te trzy zmienne koniecznie muszą być globalnie i użyte w funkcji PidToHwnd:
PidNumTmp : DWORD;
TempHandle : HWND;
TmpClassName : string;
// Koniec zmiennych koniecznie globalnych ;)
POrigProcessWinFunc, POwnProcessWinFunc : Pointer;
//...
function PidToHWnd(DestPid : DWORD; AClassName : string) : HWND;
function EnumProcess(AHWnd : HWND; lParam : integer) : boolean; stdcall;
var
PPid : DWORD;
begin
Result := (AHWnd <> 0);
if Result = True then
begin
GetWindowThreadProcessId(AHWnd, PPid);
if PPid = PidNumTmp then
begin
if (GetWindowLong(AHWnd, GWL_HWNDPARENT) = 0)
and (IsWindowVisible(AHWnd) or IsIconic(AHWnd)) then
begin
if (GetControlClassName(AHWnd) = TmpClassName) then
begin
TempHandle := AHWnd;
end;
end;
end;
end;
Result := True;
end;
begin
PidNumTmp := DestPid;
TmpClassName := AClassName;
EnumWindows(@EnumProcess, 0);
Result := TempHandle;
end;
function MainDlgProc(AHWnd : HWND; Msg : UINT; wParam : wParam; lParam : lParam) : BOOL; stdcall;
// obsługa komunikatów okna
end;
function ProcessCapturedWinFunc(AHWnd : HWND; UMsg : UINT; AWParam : WParam; ALParam : LParam) : integer; stdcall;
var
Msg : TMsg;
DlgH : HWND;
begin
if not vvv then
begin
vvv := True;
DlgH := CreateDialog(hInstance, MAKEINTRESOURCE(IDC_MAINFORM), AHwnd, @MainDlgProc);
ShowWindow(DlgH, SW_SHOW);
end;
Result := CallWindowProc(POrigProcessWinFunc, AHWnd, uMsg, AWParam, ALParam);
end;
//...
GamePid := GetCurrentProcessid;
GameWindowHandle := PidToHWnd(GamePid, 'Wacki');
Sleep(3000);
vvv := False;
POwnProcessWinFunc := @ProcessCapturedWinFunc;
POrigProcessWinFunc := Pointer(SetWindowLong(GameWindowHandle, GWL_WNDPROC, Integer(POwnProcessWinFunc)));
//...
Nie wrzucam kodu całego projektu, bo robiłem to na bazie trainera do Horde, ale na przykład z DosBoxem tak się nie da, bo pojawienie się takiego okna powoduje utrate focusa przez okno DosBoxa. Przykładowy injector wstrzykujący dllkę będącą w zasobach:
program injector;
{$R *.res}
{$APPTYPE GUI)}
{$R 'a_trainer.res' 'a_trainer.rc'}
uses
Windows, Messages, TlHelp32,
afxcodehook in 'afxcodehook.pas';
const
GameProcessName = 'wacki.exe';
Resource_Name = 'dll_to_inject';
Msg_Name = 'Restore_DOSBox_Horde_Trainer_v2_App';
App_Class = 'DOSBox_Horde_Trainer_v2_loader_by_olesio';
App_Title = 'Horde - trainer version 2 - loader by olesio';
var
GamePid : DWORD;
App_Handle : HWND;
function AnsiUpperCase(const S : string) : string;
var
Len : Integer;
begin
Len := Length(S);
SetString(Result, PChar(S), Len);
if Len > 0 then
begin
CharUpperBuff(Pointer(Result), Len);
end;
end;
function ExtractFileName(FileName : string) : string;
var
I : integer;
begin
ExtractFileName := FileName;
for I := Length(FileName) downto 1 do
begin
if (FileName[I] = '\') then
begin
ExtractFileName := Copy(FileName, I + 1, MaxInt);
Break;
end;
end;
end;
function ProcessExists(ExeFileName : string; var PIDResult : Cardinal) : boolean;
var
ContinueLoop : BOOL;
FSnapshotHandle : THandle;
FProcessEntry32 : TProcessEntry32;
begin
FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
FProcessEntry32.dwSize := SizeOf(FProcessEntry32);
ContinueLoop := Process32First(FSnapshotHandle, FProcessEntry32);
Result := False;
while Integer(ContinueLoop) <> 0 do
begin
if ((AnsiUpperCase(ExtractFileName(FProcessEntry32.szExeFile)) =
AnsiUpperCase(ExeFileName)) or (AnsiUpperCase(FProcessEntry32.szExeFile) =
AnsiUpperCase(ExeFileName))) then
begin
Result := True;
PIDResult := FProcessEntry32.th32ProcessID;
end;
ContinueLoop := Process32Next(FSnapshotHandle, FProcessEntry32);
end;
CloseHandle(FSnapshotHandle);
end;
function CheckGameProcessRuning : boolean;
begin
Result := ProcessExists(GameProcessName, GamePid);
if not Result then
begin
MessageBox(App_Handle, 'Cannot find process "' + GameProcessName +
'"! Please run "Horde" under DOSBox and start new game or load saved game.',
App_Title, MB_ICONERROR + MB_OK);
end;
end;
procedure LoadDllFromResourcesAndInjectIt;
var
ResPtr : Pointer;
HGlobal, HResInfo : THandle;
begin
HResInfo := FindResource(HInstance, Resource_Name, RT_RCDATA);
if HResInfo = 0 then
begin
MessageBox(App_Handle, PChar('Cannot find resource named "' + Resource_Name +
'"! with dll library to inject!' + #13#10 + 'Please check trainer''s ' +
'source code and recompile it.'), App_Title, MB_ICONWARNING + MB_OK);
end
else
begin
HGlobal := LoadResource(HInstance, HResInfo);
ResPtr := PChar(LockResource(HGlobal));
InjectLibrary(OpenProcess(PROCESS_ALL_ACCESS, False, GamePid), ResPtr);
end;
end;
function WndProc(Wnd : HWND; uMsg : UINT; wPar : WPARAM; lPar : LPARAM) : LRESULT; stdcall;
begin
Result := 0;
App_Handle := Wnd;
case UMsg of
WM_CREATE :
begin
SetWindowLong(Wnd, GWL_EXSTYLE, WS_EX_TOOLWINDOW and not WS_EX_APPWINDOW);
if CheckGameProcessRuning then
begin
LoadDllFromResourcesAndInjectIt;
end;
SendMessage(App_Handle, WM_DESTROY, 0, 0);
end;
WM_DESTROY :
begin
PostQuitMessage(0);
end;
else
begin
Result := DefWindowProc(Wnd, uMsg, wPar, lPar);
end;
end;
end;
var
Msg : TMsg;
Wnd : TWndClass;
WindowHandle : HWND;
begin
with Wnd do
begin
lpfnWndProc := @WndProc;
hInstance := hInstance;
lpszClassName := App_Class;
hbrBackground := COLOR_WINDOW;
end;
RegisterClass(Wnd);
WindowHandle := CreateWindow(App_Class, App_Title, WS_POPUP, 100, 100,
0, 0, 0, 0, hInstance, nil);
ShowWindow(WindowHandle, SW_SHOW);
while GetMessage(Msg, 0, 0, 0) do
begin
DispatchMessage(Msg);
end;
end.
Nazwę klasy okna gry ustalisz dołączonym programikiem w archiwum wininfo_by_olesio.rar
. Takie kombinacje z oknem klasy były konieczne dla DosBoxa oraz innych procesów, które mają tworzone więcej niż jedno głowne okno gry. Mam nadzieję, że na coś się to Tobie przyda. Kombinuj, ale tak jak pisali poprzednicy wiele się wykombinować nie da. Można w razie czego przecież napisać program działający w tle i korzystający z Hooka na klawiaturę i za pomoca jakiś tam klawiszy dokonujący zmian w procesie gry, jeżeli chodzi Tobie o napisanie na przykład trainera czy jakiegoś cheatu. Ale do takich rzeczy jak cheaty też wykorzystuje się injekcje dllki, ponieważ wtedy wstrzyknięta dllka ma dostep do okna programu, ponieważ jest ona traktowana jak część procesu i można podmienić procedurę obsługi komunikatów, tak jak to widzisz powyżej. Więcej znajdziesz w google. Powodzenia.