Сейчас на форуме: asfa, Rio, _MBK_, Adler (+8 невидимых)

 eXeL@B —› Вопросы новичков —› Как научить видеть игру широкоформатные мониторы?
. 1 . 2 . 3 . >>
Посл.ответ Сообщение


Ранг: 111.0 (ветеран), 2thx
Активность: 0.090
Статус: Участник

Создано: 23 декабря 2012 19:07
· Личное сообщение · #1

Здравствуйте. Нашёл CD древней игрушки, но после установки, заметил, что разработчики ограничились только самыми распространёнными разрешениями экрана. Возможно ли сделать каким-либо образом поддержку 1366х768, 1920х1080? Прикладываю файлы кинфигуратора разрешения.

пароль: exelab

4272_23.12.2012_EXELAB.rU.tgz - p3.rar

-----
Ламер - не профессия :))




Ранг: 88.2 (постоянный), 58thx
Активность: 0.110.04
Статус: Участник

Создано: 23 декабря 2012 21:17
· Личное сообщение · #2

Вот один из известных патчеров для игр с маленьким разрешением


6efb_23.12.2012_EXELAB.rU.tgz - Mishar.zip




Ранг: 111.0 (ветеран), 2thx
Активность: 0.090
Статус: Участник

Создано: 23 декабря 2012 21:24
· Личное сообщение · #3

Mishar_Hacker
Игра называется Patrician 3, тут такой нет.

-----
Ламер - не профессия :))




Ранг: 88.2 (постоянный), 58thx
Активность: 0.110.04
Статус: Участник

Создано: 23 декабря 2012 23:24
· Личное сообщение · #4

aspirin
Я тебе пример дал как сделать))




Ранг: 111.0 (ветеран), 2thx
Активность: 0.090
Статус: Участник

Создано: 23 декабря 2012 23:36
· Личное сообщение · #5

Mishar_Hacker
В этом примере для каждой игры есть "sig=", как мне найти для моего .ехе?

-----
Ламер - не профессия :))




Ранг: 88.2 (постоянный), 58thx
Активность: 0.110.04
Статус: Участник

Создано: 23 декабря 2012 23:56
· Личное сообщение · #6

так давай на примере nfs underground 2 (не смейтесь бывает играю)
exe
Вот и ищи примерно
Больше вариантов нет
пока что



Ранг: 481.4 (мудрец), 109thx
Активность: 0.180
Статус: Участник
Тот самый :)

Создано: 24 декабря 2012 15:46
· Личное сообщение · #7

Mishar_Hacker пишет:
так давай на примере nfs underground 2 (не смейтесь бывает играю)

Мне тоже интересен этот вопрос. Потому что это делается зачастую нетривиально, особенно если дело касается игр на DirectX. Просто патчем цифирок отвечающих за разрешение экрана, дело необходится.

-----
Реверсивная инженерия - написание кода идентичного натуральному




Ранг: 10.1 (новичок), 5thx
Активность: 0.010
Статус: Участник

Создано: 24 декабря 2012 15:58 · Поправил: Runner
· Личное сообщение · #8

Встречал вот --> такое вот <-- "универсальное" (т.е. как повезет) решение проблемы с разрешением.

"This DLL attempts to override the screen resolution set
by a Direct3D 9 program."




Ранг: 1131.7 (!!!!), 447thx
Активность: 0.670.2
Статус: Участник

Создано: 24 декабря 2012 17:20 · Поправил: Gideon Vi
· Личное сообщение · #9

aspirin пишет:
Возможно ли сделать каким-либо образом поддержку 1366х768, 1920х1080?


во многих играх будут проблемы со шрифтами.




Ранг: 111.0 (ветеран), 2thx
Активность: 0.090
Статус: Участник

Создано: 24 декабря 2012 18:39 · Поправил: aspirin
· Личное сообщение · #10

Mishar_Hacker пишет:
так давай на примере nfs underground 2 (не смейтесь бывает играю)

Ну а чего там смеяться, кстати, одна из лучших игр серии. Думаете Patrician 3 будет новинкой?
Gideon Vi
предостережения не особо интересны
В каком направлении лучше всего искать решение?

-----
Ламер - не профессия :))




Ранг: 301.4 (мудрец), 194thx
Активность: 0.170.01
Статус: Участник

Создано: 24 декабря 2012 18:59
· Личное сообщение · #11

1) Перевести игру в оконный режим и играть на меньшем разрешении
2) Искать где создается viewport и сместить его в центр экрана, по краям оставляя черные полосы



Ранг: 88.2 (постоянный), 58thx
Активность: 0.110.04
Статус: Участник

Создано: 24 декабря 2012 22:45
· Личное сообщение · #12

aspirin
Может на оф сайте программы есть исходник или манула



Ранг: 65.3 (постоянный), 10thx
Активность: 0.020
Статус: Участник

Создано: 25 декабря 2012 00:48 · Поправил: tomac
· Личное сообщение · #13

aspirin
Выложи всю игрушку, искать именно твою версию неохота.
Выбиралка разрешений падает на тесте моего родного разрешения, хп 32бит сп3.

Я обучал NFS Carbon работать на 1600*900.



Ранг: 88.2 (постоянный), 58thx
Активность: 0.110.04
Статус: Участник

Создано: 25 декабря 2012 00:55
· Личное сообщение · #14

tomac
а у меня windows 8
тоже краш((




Ранг: 111.0 (ветеран), 2thx
Активность: 0.090
Статус: Участник

Создано: 25 декабря 2012 12:04 · Поправил: aspirin
· Личное сообщение · #15

tomac, Mishar_Hacker
P3.rar
exelab

-----
Ламер - не профессия :))




Ранг: 65.3 (постоянный), 10thx
Активность: 0.020
Статус: Участник

Создано: 25 декабря 2012 18:00 · Поправил: tomac
· Личное сообщение · #16

Файл выложен на фтп: --> Link <--
Тот, что на народе, битый.




Ранг: 111.0 (ветеран), 2thx
Активность: 0.090
Статус: Участник

Создано: 25 декабря 2012 20:30 · Поправил: aspirin
· Личное сообщение · #17

tomac
Надо же, у меня у самого тот архив оказался битым, хотя и при упаковке добавил тестировать. В очередной раз доказательства того, что ничему не стоит слепо доверять. Проверяйте, отправил.

-----
Ламер - не профессия :))




Ранг: 65.3 (постоянный), 10thx
Активность: 0.020
Статус: Участник

Создано: 25 декабря 2012 23:05 · Поправил: tomac
· Личное сообщение · #18

Предварительный анализ показывает, что разрешения зашиты в код, в частности, в архивах есть переменные ObenLinks800Anim, ObenLinks1024Anim, ObenLinks1280Anim. Похоже, что на других разрешениях работать будет крайне криво, если вообще будет.

Покопаюсь потом еще.

Кстати, да, конфигуратор разрешения нифига не конфигурирует. Падал из-за недостатка какой-то либы, сейчас, с полным набором файлов, не падает.



Ранг: 105.6 (ветеран), 69thx
Активность: 0.060
Статус: Участник

Создано: 26 декабря 2012 01:00
· Личное сообщение · #19

Проворачивал подобный трюк с игрой Tank Race. Уже не помню что конкретно делал. Вроде как действовал так. Искал функцию для работы с режимами экрана в импорте. Вышел на switch в котором задавались параметры для разрешения экрана и поправил их на нужные. Вполне замечательно все работало вплодь до разрешения 1600x1200. Широкоформатные разрешения тоже делал и тоже все работало замечательно.

Может я конечно путаю что-то. Я все-таки дилетант в этом деле.



Ранг: 74.1 (постоянный), 34thx
Активность: 0.030
Статус: Участник

Создано: 26 декабря 2012 10:36
· Личное сообщение · #20

Делал перехватом ддрав/директикс

Обрабатывал в рантайме кадр (в принципе любой алгоритм можно, у меня масштабирование и сглаживание было), потом рендерил


http://blackninja2000.narod.ru/rus/directx_logger.html

| Сообщение посчитали полезным: Gideon Vi

Ранг: 301.4 (мудрец), 194thx
Активность: 0.170.01
Статус: Участник

Создано: 26 декабря 2012 15:02 · Поправил: Veliant
· Личное сообщение · #21

Стоит смотреть начиная отсюда
Code:
  1. 0046373D      C705 B4CD6E00 MOV DWORD PTR DS:[6ECDB4],258
  2. 00463747      C705 B0CD6E00 MOV DWORD PTR DS:[6ECDB0],320

Это разрешение потом передается почти все функциям ddraw_dll. Но после выставления нужного фон рисуется под старое разрешение, а контролы со смещением. Нужно искать где пересчет идет.
Проще наверное все же сделать запуск игры в окне с меньшим разрешением. Там не directx, там gdi

Add:
Возможно стоит смотреть в сторону функции sgl_SetZoomFactor, которая вызывает функцию 05026050 с расчетами. Сама же sgl_SetZoomFactor вызывается перед каждой отрисовкой.

Add2: с установленным широкоформатным разрешением, но внутренним 1024x768 выглядит как-то так
http://rghost.ru/42525347/image.png



Ранг: 301.4 (мудрец), 194thx
Активность: 0.170.01
Статус: Участник

Создано: 27 декабря 2012 12:54
· Личное сообщение · #22

Навелосипедил пока следующим образом. Так и не разобрал до конца какие адреса еще участвуют в пересчете экранных координат

http://rghost.ru/42546882




Ранг: 111.0 (ветеран), 2thx
Активность: 0.090
Статус: Участник

Создано: 27 декабря 2012 14:54
· Личное сообщение · #23

Veliant пишет:
Навелосипедил пока следующим образом. Так и не разобрал до конца какие адреса еще участвуют в пересчете экранных координат
http://rghost.ru/42546882

Попробовал, кроме рамки игры на чёрном фоне - работает.
dll такой вроде не было в папке с игрой, собственная разработка?
Не могли бы вы хоть в кратце объяснить, для чего нужна dll, и вообще свою технологию апгрейда игры?

-----
Ламер - не профессия :))




Ранг: 301.4 (мудрец), 194thx
Активность: 0.170.01
Статус: Участник

Создано: 27 декабря 2012 18:09
· Личное сообщение · #24

Идея собственно в том чтоб при создании окна и вызова функций sgl_InitScreen и sgl_SetScreenDimension передавать разрешение нативное, после их отработки возвращается старое внутреннее разрешение.
В dll ставится veh обработчик и в нужные места программы ставятся hw бряки на которых и происходит подмена.




Ранг: 324.3 (мудрец), 221thx
Активность: 0.480.37
Статус: Участник

Создано: 29 декабря 2012 09:59 · Поправил: DenCoder
· Личное сообщение · #25

С согласия автора топика, выкладываю обещанный свой вариант.

Первое, что нужно сделать - написать прокладку и вставить в код исполняемого файла игрушки её загрузку. Под прокладкой имеется ввиду dll, которая хучит нужные функции. Опущу подробности как это делать, поскольку об этом много раз писалось. Сосредоточусь на реализации самой прокладки.

Нам требуется изменить видео режим. Поскольку игрушка старая, то вряд ли в ней используется Direct3D, используется DirectDraw версий от 1 до 4, 7-ой скорей всего ещё и не было. Функция в DirectDraw, которая меняет видео режим - IDirectDraw::SetDisplayMode. Её описание можно найти --> здесь <--. Но для того, чтобы её перехватить и перехватить ещё 3 функции двух интерфейсов, нам нужно сначала перехватить вызов DirectDrawCreate, чтобы получить указатель на интерфейс IDirectDraw.

Пишем для этого в DllMain.cpp под case DLL_PROCESS_ATTACH: вызов функции установки хуков:
Code:
  1. SetHooks();


Хочу отметить, что для того, чтобы компилятор смог скомпилировать код dll, требуется найти и скачать ddraw.h, если нет, а также подключить директивой #include и указать линкеру ddraw.lib

В функции SetHooks() пишем тело:
Code:
  1.          HMODULE hDDrawMod = GetModuleHandle("ddraw.dll");
  2.          SetApiHook(hDDrawMod/*dll handle*/, "DirectDrawCreate"/*Имя перехватываемой функции*/, DirectDrawCreateHook/*наша функция, которая будет выполняться вместо перехваченной*/, 3/*кол-во аргументов оригинальной функции*/);


В функции SetApiHook:
Code:
  1. void __stdcall SetApiHook(HMODULE hMod, char* sFunc, void* fPre, int nArgs)
  2. {
  3.          //Получаем адрес перехватываемой функции
  4.          DWORD dwAddress = (DWORD)GetProcAddress(hMod, sFunc);
  5.          //проверям наличие сигнатуры в начале перехватываемой функции
  6.          if(dwAddress && !memcmp((void*)dwAddress, (void*)"\x8b\xff\x55\x8b\xec", 5))
  7.          {
  8.                  DWORD dwBytes = 0, dwPos = 0, dwPrevPos;
  9.  
  10.                  if(fPre != NULL)
  11.                  {
  12.  
  13.                         dwBytes = sizeof(PrologCode) + nArgs * sizeof(PassArgsCode) + sizeof(HookCode) + sizeof(ReturnCode);//считаем, сколько байт потребуется для функции-хука
  14.  
  15.                         BYTE* pCode = new BYTE[dwBytes];//выделяем память под функцию
  16.                         DWORD dwOldProtect;
  17.                         VirtualProtect(pCode, dwBytes, PAGE_EXECUTE_READWRITE, &dwOldProtect);//делаем выделенную область исполняемой
  18.                         
  19.                         //копируем нужные куски кода в выделенную область
  20.                         CopyCode(PrologCode) *(DWORD*)(pCode + dwPos - 5) = dwAddress;
  21.                         if(nArgs > 0)
  22.                         {
  23.                               for(int i = 0; i < nArgs; i++)
  24.                               {
  25.                                    CopyCode(PassArgsCode)
  26.                                    *(pCode + dwPrevPos + 3) += nArgs * 4;
  27.                               }
  28.                         }
  29.                         CopyCode(PreHookCode) SetJmp(((DWORD)pCode + dwPos), (DWORD)fPre)
  30.                         CopyCode(ReturnCode) *(WORD*)(pCode + dwPrevPos + 2) += nArgs * 4;
  31.  
  32.                         VirtualProtect((void*)dwAddress, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);
  33.                         *(BYTE*)dwAddress = 0xe9;
  34.                         SetJmp((dwAddress + 5), (DWORD)pCode)
  35.                         VirtualProtect((void*)dwAddress, 5, dwOldProtect, &dwOldProtect);
  36.                         FlushInstructionCache(GetCurrentProcess(), (void*)dwAddress, 5);
  37.                  }
  38.          }
  39. }


В заголовочном файле определяем 2 макроса:
Code:
  1. #define CopyCode(CodeType) memcpy(pCode + dwPos, CodeType, sizeof(CodeType)); dwPrevPos = dwPos; dwPos += sizeof(CodeType);
  2. #define SetJmp(NextInstr, Address) *(DWORD*)(NextInstr - 4) = Address - NextInstr;


Определяем все нужные куски кода
//push ebp
//mov ebp, esp
//push ebp
//push Address - адрем перехватываемой функции, которую нужно будет вызвать после нужных операций
Code:
  1. BYTE PrologCode[] =
  2. {
  3.          0x55,
  4.          0x8b, 0xec,
  5.          0x68, 0x00, 0x00, 0x00, 0x00,
  6.          0x55
  7. };
  8.  
  9. //push dword ptr[esp + 0xC]
  10. BYTE PassArgsCode[] =
  11. {
  12.          0xff, 0x74, 0xe4, 0x0C
  13. };
  14.  
  15. //call func
  16. BYTE PreHookCode[] =
  17. {
  18.          0xe8, 0x00, 0x00, 0x00, 0x00
  19. };
  20.  
  21. //leave
  22. //retn nArgs
  23. BYTE ReturnCode[] =
  24. {
  25.          0xc9,
  26.          0xc2, 0x00, 0x00
  27. };
  28.  


Таким образом, мы перехватываем функцию и заставляем процессор при вызове функции выполнить код переходника на нашу функцию. Теперь можно приступить к нашей функции
Code:
  1. HRESULT __stdcall DirectDrawCreateHook(GUID* pGuid, LPDIRECTDRAW *ppDD, IUnknown* pUnkOuter, DWORD rEsp, void* fOrigin)
  2. {
  3.          HRESULT hResult;
  4.  
  5.          //Вызываем оригинальную функцию
  6.          hResult = CallHookedStdcallFunc(fOrigin, pGuid, ppDD, pUnkOuter);
  7.          //Поскольку оригинальная функция DirectDrawCreate конвенции __stdcall, а компилятор при вызове функции с переменным числом аргументов вставляет add esp, 0x10, то вернуть указатель стека обратно
  8.          __asm sub esp, 0x10;
  9.  
  10.          //Если всё прошло нормально, устанавливаем хуки на 2 функции полученного в ppDD интерфейса
  11.          if(hResult == DD_OK)
  12.          {
  13.                  SET_INTERFACE_HOOK(IDirectDraw, CreateSurface, ppDD, 3)
  14.                  SET_INTERFACE_HOOK(IDirectDraw, QueryInterface, ppDD, 2)
  15.          }
  16.  
  17.          return hResult;
  18. }


Функция вызова оригинальной функции с переменным числом аргументов
Code:
  1. __declspec(naked) DWORD __stdcall CallHookedStdcallFunc(void* Func, ...)
  2. {
  3.          __asm
  4.          {
  5.                  pop eax; извлекаем адрес возврата
  6.                  xchg eax, [esp]; обмениваем в стеке адрес возврата с адресом оригинальной функции
  7.                  push ebp; в eax адрес оригинальной функции, но по адресу мы поставили jmp
  8.                  mov ebp, esp; поэтому выполняем код пролога и прибавляем к адресу размер команды jmp
  9.                  add eax, 5; чтобы перейти по этому адресу
  10.                  jmp eax; в стеке адрес возврата из нашей функции + аргументы оригинальной функции
  11.          }
  12. }


Макросы для установки хуков на метода интерфейса выглядят так
Code:
  1. #define INTERFACE_POINTER_FUNC(Interface, Func, pRealInterface) \
  2.          (DWORD*)((DWORD)*(DWORD*)*pRealInterface + ((DWORD)&p##Interface.Func - (DWORD)&p##Interface.QueryInterface))
  3.  
  4. #define SET_INTERFACE_HOOK(Interface, Func, pRealInterface, nArgs) \
  5.          SetInterfaceHook(INTERFACE_POINTER_FUNC(Interface, Func, pRealInterface), (void*)##Interface##_##Func##HookPre, nArgs, #Interface"::"#Func);


Адрес метода интерфейса вычисляется значением [адреса таблицы + порядковый номер метода * 4]. Нам требуется не сам адрес метода, а указатель на его место в таблице, чтобы подменить оригинальный адрес на адрес нашей функции интерфейса. В си/си++ нельзя производить действия над укателями на разные методы классов, поэтому пришлось определять целые таблицы функций интерфейсов

-----
IZ.RU


| Сообщение посчитали полезным: Gideon Vi, Abraham


Ранг: 324.3 (мудрец), 221thx
Активность: 0.480.37
Статус: Участник

Создано: 29 декабря 2012 10:00 · Поправил: DenCoder
· Личное сообщение · #26

Code:
  1. struct IDirectDraw_Functions
  2. {
  3.   /*** IUnknown methods ***/
  4.   DWORD QueryInterface; //(THIS_ REFIID riid, LPVOID FAR * ppvObj) PURE;
  5.   DWORD AddRef; //(THIS) PURE;
  6.   DWORD Release; //(THIS) PURE;
  7.   /*** IDirectDraw methods ***/
  8.   DWORD Compact; //(THIS) PURE;
  9.   DWORD CreateClipper; //(THIS_ DWORD, LPDIRECTDRAWCLIPPER FAR*, IUnknown FAR * ) PURE;
  10.   DWORD CreatePalette; //(THIS_ DWORD, LPPALETTEENTRY, LPDIRECTDRAWPALETTE FAR*, IUnknown FAR * ) PURE;
  11.   DWORD CreateSurface; //(THIS_ LPDDSURFACEDESC, LPDIRECTDRAWSURFACE FAR *, IUnknown FAR *) PURE;
  12.   DWORD DuplicateSurface; //( THIS_ LPDIRECTDRAWSURFACE, LPDIRECTDRAWSURFACE FAR * ) PURE;
  13.   DWORD EnumDisplayModes; //( THIS_ DWORD, LPDDSURFACEDESC, LPVOID, LPDDENUMMODESCALLBACK ) PURE;
  14.   DWORD EnumSurfaces; //(THIS_ DWORD, LPDDSURFACEDESC, LPVOID,LPDDENUMSURFACESCALLBACK ) PURE;
  15.   DWORD FlipToGDISurface; //(THIS) PURE;
  16.   DWORD GetCaps; //( THIS_ LPDDCAPS, LPDDCAPS) PURE;
  17.   DWORD GetDisplayMode; //( THIS_ LPDDSURFACEDESC) PURE;
  18.   DWORD GetFourCCCodes; //(THIS_ LPDWORD, LPDWORD ) PURE;
  19.   DWORD GetGDISurface; //(THIS_ LPDIRECTDRAWSURFACE FAR *) PURE;
  20.   DWORD GetMonitorFrequency; //(THIS_ LPDWORD) PURE;
  21.   DWORD GetScanLine; //(THIS_ LPDWORD) PURE;
  22.   DWORD GetVerticalBlankStatus; //(THIS_ LPBOOL ) PURE;
  23.   DWORD Initialize; //(THIS_ GUID FAR *) PURE;
  24.   DWORD RestoreDisplayMode; //(THIS) PURE;
  25.   DWORD SetCooperativeLevel; //(THIS_ HWND, DWORD) PURE;
  26.   DWORD SetDisplayMode; //(THIS_ DWORD, DWORD,DWORD) PURE;
  27.   DWORD WaitForVerticalBlank; //(THIS_ DWORD, HANDLE ) PURE;
  28. };
  29.  
  30. struct IDirectDraw2_Functions
  31. {
  32.   /*** IUnknown methods ***/
  33.   DWORD QueryInterface; //(THIS_ REFIID riid, LPVOID FAR * ppvObj) PURE;
  34.   DWORD AddRef; //(THIS) PURE;
  35.   DWORD Release; //(THIS) PURE;
  36.   /*** IDirectDraw methods ***/
  37.   DWORD Compact; //(THIS) PURE;
  38.   DWORD CreateClipper; //(THIS_ DWORD, LPDIRECTDRAWCLIPPER FAR*, IUnknown FAR * ) PURE;
  39.   DWORD CreatePalette; //(THIS_ DWORD, LPPALETTEENTRY, LPDIRECTDRAWPALETTE FAR*, IUnknown FAR * ) PURE;
  40.   DWORD CreateSurface; //(THIS_ LPDDSURFACEDESC, LPDIRECTDRAWSURFACE FAR *, IUnknown FAR *) PURE;
  41.   DWORD DuplicateSurface; //(THIS_ LPDIRECTDRAWSURFACE, LPDIRECTDRAWSURFACE FAR * ) PURE;
  42.   DWORD EnumDisplayModes; //(THIS_ DWORD, LPDDSURFACEDESC, LPVOID, LPDDENUMMODESCALLBACK ) PURE;
  43.   DWORD EnumSurfaces; //(THIS_ DWORD, LPDDSURFACEDESC, LPVOID,LPDDENUMSURFACESCALLBACK ) PURE;
  44.   DWORD FlipToGDISurface; //(THIS) PURE;
  45.   DWORD GetCaps; //(THIS_ LPDDCAPS, LPDDCAPS) PURE;
  46.   DWORD GetDisplayMode; //(THIS_ LPDDSURFACEDESC) PURE;
  47.   DWORD GetFourCCCodes; //(THIS_ LPDWORD, LPDWORD ) PURE;
  48.   DWORD GetGDISurface; //(THIS_ LPDIRECTDRAWSURFACE FAR *) PURE;
  49.   DWORD GetMonitorFrequency; //(THIS_ LPDWORD) PURE;
  50.   DWORD GetScanLine; //(THIS_ LPDWORD) PURE;
  51.   DWORD GetVerticalBlankStatus; //(THIS_ LPBOOL ) PURE;
  52.   DWORD Initialize; //(THIS_ GUID FAR *) PURE;
  53.   DWORD RestoreDisplayMode; //(THIS) PURE;
  54.   DWORD SetCooperativeLevel; //(THIS_ HWND, DWORD) PURE;
  55.   DWORD SetDisplayMode; //(THIS_ DWORD, DWORD,DWORD, DWORD, DWORD) PURE;
  56.   DWORD WaitForVerticalBlank; //(THIS_ DWORD, HANDLE ) PURE;
  57.   /*** Added in the v2 interface ***/
  58.   DWORD GetAvailableVidMem; //(THIS_ LPDDSCAPS, LPDWORD, LPDWORD) PURE;
  59. };
  60.  
  61. struct IDirectDraw4_Functions
  62. {
  63.     /*** IUnknown methods ***/
  64.     DWORD QueryInterface; //(THIS_ REFIID riid, LPVOID FAR * ppvObj) PURE;
  65.     DWORD AddRef; //(THIS) PURE;
  66.     DWORD Release; //(THIS) PURE;
  67.     /*** IDirectDraw methods ***/
  68.     DWORD Compact; //(THIS) PURE;
  69.     DWORD CreateClipper; //(THIS_ DWORD, LPDIRECTDRAWCLIPPER FAR*, IUnknown FAR * ) PURE;
  70.     DWORD CreatePalette; //(THIS_ DWORD, LPPALETTEENTRY, LPDIRECTDRAWPALETTE FAR*, IUnknown FAR * ) PURE;
  71.     DWORD CreateSurface; //(THIS_ LPDDSURFACEDESC2, LPDIRECTDRAWSURFACE4 FAR *, IUnknown FAR *) PURE;
  72.     DWORD DuplicateSurface; //(THIS_ LPDIRECTDRAWSURFACE4, LPDIRECTDRAWSURFACE4 FAR * ) PURE;
  73.     DWORD EnumDisplayModes; //(THIS_ DWORD, LPDDSURFACEDESC2, LPVOID, LPDDENUMMODESCALLBACK2 ) PURE;
  74.     DWORD EnumSurfaces; //(THIS_ DWORD, LPDDSURFACEDESC2, LPVOID,LPDDENUMSURFACESCALLBACK2 ) PURE;
  75.     DWORD FlipToGDISurface; //(THIS) PURE;
  76.     DWORD GetCaps; //(THIS_ LPDDCAPS, LPDDCAPS) PURE;
  77.     DWORD GetDisplayMode; //(THIS_ LPDDSURFACEDESC2) PURE;
  78.     DWORD GetFourCCCodes; //(THIS_ LPDWORD, LPDWORD ) PURE;
  79.     DWORD GetGDISurface; //(THIS_ LPDIRECTDRAWSURFACE4 FAR *) PURE;
  80.     DWORD GetMonitorFrequency; //(THIS_ LPDWORD) PURE;
  81.     DWORD GetScanLine; //(THIS_ LPDWORD) PURE;
  82.     DWORD GetVerticalBlankStatus; //(THIS_ LPBOOL ) PURE;
  83.     DWORD Initialize; //(THIS_ GUID FAR *) PURE;
  84.     DWORD RestoreDisplayMode; //(THIS) PURE;
  85.     DWORD SetCooperativeLevel; //(THIS_ HWND, DWORD) PURE;
  86.     DWORD SetDisplayMode; //(THIS_ DWORD, DWORD,DWORD, DWORD, DWORD) PURE;
  87.     DWORD WaitForVerticalBlank; //(THIS_ DWORD, HANDLE ) PURE;
  88.     /*** Added in the v2 interface ***/
  89.     DWORD GetAvailableVidMem; //(THIS_ LPDDSCAPS2, LPDWORD, LPDWORD) PURE;
  90.     /*** Added in the V4 Interface ***/
  91.     DWORD GetSurfaceFromDC; //(THIS_ HDC, LPDIRECTDRAWSURFACE4 *) PURE;
  92.     DWORD RestoreAllSurfaces; //(THIS) PURE;
  93.     DWORD TestCooperativeLevel; //(THIS) PURE;
  94.     DWORD GetDeviceIdentifier; //(THIS_ LPDDDEVICEIDENTIFIER, DWORD ) PURE;
  95. };


Два метода, IDirectDraw::QueryInterface и IDirectDraw::CreateSurface, перехватываются для получения контроля над используемым интерфейсом IDirectDraw более новой версии и для получения контроля интерфейса для работы с поверхностями IDirectDrawSurface. Также нам потребуется перехватить метод IDirectDraw::SetDisplayMode, для чего аналогичным образом добавляем установку хука
Code:
  1. SET_INTERFACE_HOOK(IDirectDraw, SetDisplayMode, ppDD, 5)


Установщик хуков на методы интерфейса выглядит следующим образом
Code:
  1. void __stdcall SetInterfaceHook(DWORD* dwpDDFunc, void* HookFunc, int nArgs, char* Name)
  2. {
  3.          DWORD dwOriginalFunc = *dwpDDFunc, dwBytes = 0, dwPos = 0, dwPrevPos;
  4.          if(dwpDDFunc != NULL)
  5.          {
  6.                         dwBytes = sizeof(PrologCode) + (nArgs + 1) * sizeof(PassArgsCode) + sizeof(PreHookCode) + sizeof(ReturnCode);
  7.                         BYTE* pCode = new BYTE[dwBytes];
  8.                         DWORD dwOldProtect;
  9.                         VirtualProtect(pCode, dwBytes, PAGE_EXECUTE_READWRITE, &dwOldProtect);
  10.                         
  11.                         CopyCode(PrologCode) *(DWORD*)(pCode + dwPos - 5) = dwOriginalFunc;
  12.                         if(nArgs >= 0)
  13.                         {
  14.                               for(int i = 0; i <= nArgs; i++)
  15.                               {
  16.                                    CopyCode(PassArgsCode)
  17.                                    *(pCode + dwPrevPos + 3) += (nArgs + 1) * 4;
  18.                               }
  19.                         }
  20.                         CopyCode(PreHookCode) SetJmp(((DWORD)pCode + dwPos), (DWORD)HookFunc)
  21.                         CopyCode(ReturnCode) *(WORD*)(pCode + dwPrevPos + 2) += (nArgs + 1) * 4;
  22.  
  23.                         *dwpDDFunc = (DWORD)pCode;
  24.          }
  25. }


Определим наши функции-хуки для QueryInterface и CreateSurface, а также SetDisplayMode:
Code:
  1. HRESULT __stdcall IDirectDraw_QueryInterfaceHookPre(LPDIRECTDRAW This, REFIID riid, LPVOID FAR * ppvObj, DWORD rEsp, void* fOrigin)
  2. {
  3.          HRESULT hResult = DD_OK;
  4.  
  5.          hResult = CallHookedInterfaceFunc(fOrigin, This, &riid, ppvObj);
  6.          __asm sub esp, 0x10;
  7.  
  8.          if(hResult == DD_OK)
  9.          {
  10.                  if(!memcmp(&riid, &IID_IDirectDraw, sizeof(GUID)))
  11.                  {
  12.                         sprintf(s, "IID_IDirectDraw\r\n");
  13.                         SET_INTERFACE_HOOK(IDirectDraw, CreateSurface, ppvObj, 3)
  14.                         SET_INTERFACE_HOOK(IDirectDraw, QueryInterface, ppvObj, 2)
  15.                  }
  16.                  else if(!memcmp(&riid, &IID_IDirectDraw2, sizeof(GUID)))
  17.                  {
  18.                         sprintf(s, "IID_IDirectDraw2\r\n");
  19.                         SET_INTERFACE_HOOK(IDirectDraw2, CreateSurface, ppvObj, 3)
  20.                         SET_INTERFACE_HOOK(IDirectDraw2, QueryInterface, ppvObj, 2)
  21.                  }
  22.                  else if(!memcmp(&riid, &IID_IDirectDraw4, sizeof(GUID)))
  23.                  {
  24.                         sprintf(s, "IID_IDirectDraw4\r\n");
  25.                         SET_INTERFACE_HOOK(IDirectDraw4, CreateSurface, ppvObj, 3)
  26.                         SET_INTERFACE_HOOK(IDirectDraw4, QueryInterface, ppvObj, 2)
  27.                         lpDD4 = (LPDIRECTDRAW4)*ppvObj;
  28.                  }
  29.          }
  30.  
  31.          return hResult;
  32. }


Code:
  1. HRESULT __stdcall IDirectDraw_CreateSurfaceHookPre(LPDIRECTDRAW This, LPDDSURFACEDESC pSurfDesc, LPDIRECTDRAWSURFACE FAR * ppDDSurf, IUnknown FAR * pUnk, DWORD rEsp, void* fOrigin)
  2. {
  3.          HRESULT hResult = DD_OK;
  4.  
  5.          char s[0x1000];
  6.  
  7.          hResult = CallHookedInterfaceFunc(fOrigin, This, pSurfDesc, ppDDSurf, pUnk);
  8.          __asm sub esp, 0x14;
  9.  
  10.          if(hResult == DD_OK)
  11.          {
  12.                  SET_INTERFACE_HOOK(IDirectDrawSurface, GetAttachedSurface, ppDDSurf, 2)
  13.                  SET_INTERFACE_HOOK(IDirectDrawSurface, Flip, ppDDSurf, 2)
  14.          }
  15.  
  16.          return hResult;
  17. }


Code:
  1. DWORD glOriginalWidth, glOriginalHeight;
  2. HRESULT __stdcall IDirectDraw_CreateSurfaceHookPre(LPDIRECTDRAW This, DWORD dwWidth, DWORD dwHeight, DWORD dwBPP, DWORD dwRefreshRate, DWORD dwFlags, DWORD rEsp, void* fOrigin)
  3. {
  4.          HRESULT hResult = DD_OK;
  5.          //запоминаем выбранные приложением ширину и высоту
  6.          glOriginalWidth = dwWidth, glOriginalHeight = dwHeight;
  7.          //Наши характеристики устанавливаемого режима
  8.          DWORD dwOurWidth =1920, dwOurHeight =1080, dwOurRefreshRate = 75/*если поддерживает видеокарта с монитором*/;
  9.  
  10.          char s[0x1000];
  11.  
  12.          hResult = CallHookedInterfaceFunc(fOrigin, This, dwOurWidth, dwOurHeight, dwBPP, dwRefreshRate, dwFlags);
  13.          __asm sub esp, 0x1C;
  14.  
  15.          if(hResult == DD_OK)
  16.          {
  17.          }
  18.  
  19.          return hResult;
  20. }


Если используется DirectDraw2 или DirectDraw4, следует аналогичным образом установить хуки на нужные методы используемого интерфейса.

Функция вызова оригинального метода
Code:
  1. __declspec(naked) DWORD __stdcall CallHookedInterfaceFunc(void* Func, ...)
  2. {
  3.          __asm
  4.          {
  5.                  pop eax
  6.                  xchg eax, [esp]
  7.                  jmp eax
  8.          }
  9. }


Установить режим - это ещё не всё. В коде исполняемого файла игры и её библиотек во многих местах могут быть прописаны относительные и абсолютные размеры экрана, графических объектов. И в лучшем случае выводиться будет на левую верхнюю часть экрана, а нижняя и правая части останутся нетронутыми. Чтобы изображение растянулось, и потребуются два установленных хука: на IDirectDrawSurface::GetAttachedSurface и IDirectDrawSurface::Flip. Первый метод получает поверхность(или поверхности, которых может быть несколько), присоединённую к экрану, с которой готовый результат копируется на экран вторым методом IDirectDrawSurface::Flip. Такие поверхности называются в DirectX бэкбуферами.

-----
IZ.RU


| Сообщение посчитали полезным: mdscorp


Ранг: 324.3 (мудрец), 221thx
Активность: 0.480.37
Статус: Участник

Создано: 29 декабря 2012 10:01
· Личное сообщение · #27

Идея перехватов IDirectDrawSurface::GetAttachedSurface и IDirectDrawSurface::Flip состоит в том, чтобы при получении приложением бэкбуфера подсунуть созданную нами промежуточную поверхность с теми размерами, которые приложение ставит в вызове метода IDirectDraw::SetDisplayMode, чтобы при переключении приложением бэкбуферов методом IDirectDrawSurface::Flip перед этим скопировать с внедрённой промежуточной на действительный бэкбуфер всю подготовленную приложением графику методом IDirectDrawSurface::Blt, который при передаче NULL в качестве исходного и целевого прямоугольников производит автоматическое растягивание.

Перехваты нужных методов работы с поверхностями будут выглядеть так
Code:
  1. LPDIRECTDRAWSURFACE pBackSurf, pMidSurf;
  2. HRESULT __stdcall IDirectDrawSurface_GetAttachedSurfaceHookPre(LPDIRECTDRAWSURFACE This, DDSCAPS* pDDSCaps, LPDIRECTDRAWSURFACE* ppDDSurf, DWORD rEsp, void* fOrigin)
  3. {
  4.          HRESULT hResult = DD_OK;
  5.  
  6.          hResult = CallHookedInterfaceFunc(fOrigin, This, pDDSCaps, ppDDSurf);
  7.          __asm sub esp, 0x10;
  8.  
  9.          if(hResult == DD_OK)
  10.          {
  11.                  pBackSurf = *ppDDSurf;
  12.  
  13.                  DDSURFACEDESC pMidSurfDesc;
  14.                  ZeroMemory(&pMidSurfDesc, sizeof(DDSURFACEDESC));
  15.                  pMidSurfDesc.dwSize = sizeof(DDSURFACEDESC);
  16.                  pMidSurfDesc.dwFlags = DDSD_HEIGHT | DDSD_WIDTH | DDSD_CAPS;
  17.                  pMidSurfDesc.dwWidth = glOriginalWidth;
  18.                  pMidSurfDesc.dwHeight = glOriginalHeight;
  19.                  pMidSurfDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
  20.  
  21.                  //Приложение теперь будет копировать графику не в бэкбуфер, а в промежуточную поверхность
  22.                  hResult = lpDD->CreateSurface(&pMidSurfDesc, ppDDSurf, NULL);
  23.                  pMidSurf = *ppDDSurf;
  24.          }
  25.  
  26.          return hResult;
  27. }
  28.  


Code:
  1. HRESULT __stdcall IDirectDrawSurface_FlipHookPre(LPDIRECTDRAWSURFACE This, LPDIRECTDRAWSURFACE lpTargetSurf, DWORD dwFlags, DWORD rEsp, void* fOrigin)
  2. {
  3.          HRESULT hResult = 0;
  4.  
  5.          RECT rDest;
  6.          DDBLTFX BltFx;
  7.          ZeroMemory(&BltFx, sizeof(DDBLTFX));
  8.          BltFx.dwSize = sizeof(DDBLTFX);
  9.          hResult = pBackSurf4->Blt(NULL, pMidSurf, NULL, DDBLT_WAIT, &BltFx);
  10.  
  11.          hResult = CallHookedInterfaceFunc(fOrigin, This, lpTargetSurf, dwFlags);
  12.          __asm sub esp, 0x10;
  13.  
  14.          return hResult;
  15. }


Собственно и всё. Может где-то пропустил объявление переменных - в свободное время пройдусь по написанному пару раз, вставлю, поправлю. В случае, если приложение получает не один бэкбуфер, а больше, то следует организовать массивы бэкбуферов и соответствующих им промежуточных поверхностей, а в коде перехвата Flip() смотреть для какой поверхности Flip вызывается, на соответствующий бэкбуфер и будет выполняться копирование графики.

-----
IZ.RU





Ранг: 111.0 (ветеран), 2thx
Активность: 0.090
Статус: Участник

Создано: 31 декабря 2012 17:10 · Поправил: aspirin
· Личное сообщение · #28

DenCoder
Ваше решение выглядит в общем-то серьёзно. Если это всё будет работать, тогда программистам из Акеллы есть, чему поучиться в ответах этого топа. Т.к. когда я обращался в тех. поддержку года 2 назад, мне сказали, что ничего сделать, в принципе, невозможно в данном случае.
Сам я только немного играюсь с кодом в консольных приложениях на сях++, как мне всё это скомпелировать в одно решение?

-----
Ламер - не профессия :))





Ранг: 324.3 (мудрец), 221thx
Активность: 0.480.37
Статус: Участник

Создано: 31 декабря 2012 19:11 · Поправил: DenCoder
· Личное сообщение · #29

aspirin пишет:
Если это всё будет работать

Ну у меня же работало. ) Правда была немного другая задача - сжать окно с графикой немного и добавить 2 окошка - вверху и справа. Метод разработал сам, пройдя вводный курс в DirectX. Одна проблема при таком способе возможна - нелинейность изображения, так как его растянули, квадрат будет прямоугольником, а круг эллипсом. Не сомневаюсь, можно это как-то улучшить. Но для этого надо основательно покопаться в коде игры.

aspirin пишет:
Сам я только немного играюсь с кодом в консольных приложениях на сях++, как мне всё это скомпелировать в одно решение?

dll. Но сначала поиграйтесь с DirectX, оно ещё интересней ) http://netlib.narod.ru/category.htm?1240

aspirin пишет:
программистам из Акеллы есть, чему поучиться в ответах этого топа.

Ну, тут дело не в грамотности программистов, а в желании! Никто не будет бесплатно поддерживать старый проект! Максимум, чего можно ждать от разработчиков - какой-нибудь ремейк.

-----
IZ.RU




Ранг: 74.1 (постоянный), 34thx
Активность: 0.030
Статус: Участник

Создано: 03 января 2013 12:26 · Поправил: Rustem
· Личное сообщение · #30

DenCoder

Чтобы не гадать какой директ используется, можно посмотреть вызовы этой утилитой,
http://blackninja2000.narod.ru/rus/directx_logger.html

Кстати поддерживаются плагины, которые позволяют сразу реагировать на вызов функций, а не возится самому с хуками и интерфейсами
Там есть пример плагина под игру мдк


. 1 . 2 . 3 . >>
 eXeL@B —› Вопросы новичков —› Как научить видеть игру широкоформатные мониторы?
:: Ваш ответ
Жирный  Курсив  Подчеркнутый  Перечеркнутый  {mpf5}  Код  Вставить ссылку 
:s1: :s2: :s3: :s4: :s5: :s6: :s7: :s8: :s9: :s10: :s11: :s12: :s13: :s14: :s15: :s16:


Максимальный размер аттача: 500KB.
Ваш логин: german1505 » Выход » ЛС
   Для печати Для печати