Модераторы: Snowy, bartram, MetalFan, bems, Poseidon, Riply
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Windows XP SP2. Завершение работы, Исследование msgina.dll 
:(
    Опции темы
Rrader
  Дата 25.3.2009, 18:22 (ссылка) |    (голосов:3) Загрузка ... Загрузка ... Быстрая цитата Цитата


Inspired =)
***


Профиль
Группа: Экс. модератор
Сообщений: 1535
Регистрация: 7.5.2005

Репутация: 29
Всего: 191



Windows XP SP2. Завершение работы.

Навеяно недавней темой... Решил написать свои мысли и наработки по этому вопросу.

При появлении окошка завершения работы определяем, что на экране на самом деле отображаются два главных окна - одно класса #32770 - непосредственно диалог завершения работы, и весьма интересное окошко с именем класса "DimmedWindowClass", которое при вызове команды "Завершение работы" постепенно обесцвечивается. Dim по-английски означает "тусклый" smile

Задаюсь вопросом, а что это за окно такое, и как создается? Чтобы получить наибольшее количество информации об окне в чужом приложении, нужно сделать две вещи:

1) Определить адрес оконной процедуры через инжект (специфика SetWindowLong не позволяет сделать это "мирно" из "чужого" АП);
2) Определить время создания окна - то есть перехватить функцию CreateWindowExA(W). Перехват даст параметры и адрес возврата, куда можно отправиться дизассемблером. explorer.exe написан с использованием Unicode-версий API-функций, поэтому смело можно ставить перехват на CreateWindowExW. Для уверенности можно вызвать IsWindowUnicode для любого окна, созданного процессом, и получить True smile

После контролируемого запуска explorer.exe, отфильтровав логи, обнаруживаем следующую строку:
Код

MSGINA.dll 759678D5 08F0 CreateWindowExW(00000008, 759548E0: "DimmedWindowClass", 00000000, 80000000, 
  00000000, 00000000, 00000780, 000004B0, 00000000, 00000000, 75940000, 0038BD38) returns: 00170254


Более подобных окон explorer не создает. Тут же убеждаемся, что создание идет не напрямую в EXE, а через специальную библиотеку расширения GINA (Graphical Identification and Authentication DLL). Теперь пропускаем все параметры через декодеры стилей и в конечном итоге получаем (Pascal):
Код

...

var
  DimmedWnd: HWND;
begin
  ...
  { Вызов идет в msgina.dll ; мой экран имеет разрешение 1920х1200 }
  DimmedWnd := CreateWindowExW(WS_EX_TOPMOST, 'DimmedWindowClass', nil, WS_POPUP, 0, 0, 
    1920, 1200, 0, 0, $75940000, $0038BD38);
  ...
end;

Окно имеет нулевого родителя. При создании невидимо. Ширина и высота, Left, Top определяются до этого вызова предварительно через вызовы GetSystemMetrics(SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN, SM_XVIRTUALSCREEN, SM_YVIRTUALSCREEN), но об этом далее. Возвращённый дескриптор $00170254 есть само окно - при каждом показе оно пересоздается, поэтому этот дескриптор нужно получать каждый раз заново для сбора информации. Его можно получить, если создать StayOnTop-форму во время показа окна завершения работы, и вывести информацию об окне "DimmedWindowClass" под курсором мыши.

$75940000 - соответственно базовый адрес загрузки (который PEB.ImageBaseAddress) msgina.dll в данном случае.

Декодируем стили (нулевые стили опущены) уже в runtime и получаем:

Обычные стили: WS_CLIPSIBLINGS or WS_VISIBLE or WS_POPUP or WS_DISABLED;
Расширенные стили: WS_EX_TOPMOST;
Стили класса: 0;

Делаю вывод - стили дополнительно изменяются при показе окна. Настало время получить адрес оконной процедуры окна. Инжект необходимо делать через W-функции, иначе будут возвращаться некорректные значения.

Инжект осуществляю следующим образом:
Код

type
  TGetWindowLong = function (hWnd: HWND;
   nIndex: Integer): Longint; stdcall;
  TSetWindowLong = function (hWnd: HWND; nIndex: Integer;
    dwNewLong: Longint): Longint; stdcall;
  PInjectData = ^TInjectData;
  TInjectData = packed record
    FWnd: HWND;
    FGetWindowLong: TGetWindowLong;
    FSetWindowLong: TSetWindowLong;
  end;
  
...

procedure DataGrabber(Data: PInjectData); stdcall;
asm
        push    ebx
        mov     ebx, [Data]
        push    GWL_WNDPROC
        push    (TInjectData)[ebx].FWnd
        call    (TInjectData)[ebx].FGetWindowLong
        push    eax
        { Неиспользуемый индекс }
        push    GWL_ID
        push    (TInjectData)[ebx].FWnd
        call    (TInjectData)[ebx].FSetWindowLong
        pop     ebx
end;

function GetUnicodeWindowWndProcAddr(AWnd: HWND): Integer;
const
  FSize = 4096;
  InjectSize = SizeOf(TInjectData);
var
  FPID: DWORD;
  hUser32, hProcess, hThread: THandle;
  Size: Integer;
  LocalData: TInjectData;
  RemoteData, RemoteDataGrabber: Pointer;
begin
  Result := 0;
  hUser32 := GetModuleHandle('user32.dll');
  if hUser32 <> 0 then
  begin
    GetWindowThreadProcessId(AWnd, @FPID);
    if FPID = 0 then Exit;
    hProcess := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_QUERY_INFORMATION
      or PROCESS_VM_OPERATION or PROCESS_VM_WRITE or PROCESS_VM_READ,
      False, FPID);
    if hProcess <> 0 then
    try
      Size := SizeOf(TInjectData) + FSize;
      RemoteData := VirtualAllocEx(hProcess, nil, Size,
        MEM_COMMIT, PAGE_EXECUTE_READWRITE);
      if Assigned(RemoteData) then
      try
        RemoteDataGrabber := RemoteData;
        Inc(PByte(RemoteDataGrabber), InjectSize);
        if WriteProcessMemory(hProcess, RemoteDataGrabber,
          @DataGrabber, FSize, PDWORD(nil)^) then
        begin
          with LocalData do
          begin
            FWnd := AWnd;
            @FGetWindowLong := GetProcAddress(hUser32, 'GetWindowLongW');
            @FSetWindowLong := GetProcAddress(hUser32, 'SetWindowLongW');
          end;
          if WriteProcessMemory(hProcess, RemoteData, @LocalData,
            SizeOf(TInjectData), PDWORD(nil)^) then
          begin
            hThread := CreateRemoteThread(hProcess, nil, 0, RemoteDataGrabber,
              RemoteData, 0, PDWORD(nil)^);
            if hThread <> 0 then
            try
              WaitForSingleObject(hThread, INFINITE);
            finally
              CloseHandle(hThread);
            end;
            Result := Integer(GetWindowLongW(AWnd, GWL_ID));
          end;
        end;
      finally
        VirtualFreeEx(hProcess, RemoteData, 0, MEM_RELEASE);
      end;
    finally
      CloseHandle(hProcess);
    end;
  end;
end;

Адрес оконной процедуры: 
@WndProc = $75967A78;
Вернемся к нему позже. У нас есть адрес возврата CreateWindowExW:
@Func = $759678D5;

Отправляемся по данному адресу в дизассемблере. На предварительном этапе исследования нас не интересует весь листинг функции.
Код

;DimmedWindow - так будем называть окно, подробнее см. ниже
... 
        xor     edi, edi                   ; edi := 0
...
        call    CreateWindowExW            ; Вызываем функцию, возвращает дескриптор DimmedWindow
        cmp     eax, edi                   ; Сравниваем дескриптор созданного окна с 0
        mov     [esi+10h], eax             ; Запоминаем дескриптор
        je      @@Quit                     ; Прыгаем, если окно не создалось
        push    SH_SHOW
        push    eax                        ; Дескриптор
        call    ShowWindow                 ; ShowWindow(DimmedWindow, SW_SHOW)
        push    dword ptr [esi+10h]        ; Дескриптор
        call    SetForegroundWindow        ; SetForegroundWindow(DimmedWindow)
        push    edi                        ; edi = False
        push    dword ptr [esi+10h]        ; Дескриптор
        call    EnableWindow               ; EnableWindow(DimmedWindow, False)
        
        ; Теперь у нас появились стили WS_DISABLED + WS_VISIBLE + WS_CLIPSIBLINGS
        
@@Quit: 
        mov     eax, [esi+10h]             ; Result := [esi+10h] - то, что ранее вернула CreateWindowExW
        pop     edi
        pop     esi
        pop     ebx
        leave  
        retn                               ; Функция без аргументов

А что это за функция такая в этой библиотеке? Называется она CDimmedWindow::Create Данная функция является внутренней библиотечной функцией класса CDimmedWindow и не экспортируется. Это не конструктор класса. Остаётся лишь подсмотреть, что происходит с окном после создания, а для этого необходимо изучить, как работает оконная процедура.
Код

<LRESULT CALLBACK DimmedWindowWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)>
; Assembly code listing
        mov     edi, edi            ; Alignment
        push    ebp                 ; Код входа
        mov     ebp, esp            ; Код входа
        sub     esp, 44h            ; Код входа, резервирование памяти для локальных переменных

; У функции две локальных переменных - одна хранит __security_cookie (это просто число DWORD), другая - структуру TPaintStruct.
; SizeOf(TPaintStruct) = $40 байт, SizeOf(DWORD) = 4 байта, итого $44 байт.
        
        mov     eax, __security_cookie
        push    ebx
        push    esi
        mov     esi, lParam
        push    edi
        mov     edi, hWnd
        push    GWL_USERDATA
        push    edi                 ; edi = hWnd
        mov     [ebp-4], eax        ; __security_cookie    
        xor     ebx, ebx            ; ebx := 0
        call    GetWindowLongW      ; GetWindowLongW(hWnd, GWL_USERDATA)
        mov     edx, uMsg           ; Пришедшее сообщение
        
; Далее идет сассемблированный оператор switch языка C. msgina.dll скомпилирована на MSVC++,
; мы должны знать специфику ассемблирования данного оператора, чтобы правильно  
; трактовать дальнейший код. Скажу, что в Delphi оператор case ассемблируется схожим образом.
;
; Может быть либо эффективный case (через адресную таблицу и один прыжок), либо обыкновенный (аналог if-then-else).

; Посмотрев на нижеследующий код, видим обработку трёх сообщений: WM_CREATE (1), WM_TIMER ($113), WM_PAINT ($F).
; Их идентификаторы указаны в скобках. Итого диапазон case равен [$1..$113]. В данном случае разброс значителен,
; и эффективный case не применяется (создание таблицы невозможно). Анализ идет по схеме if-then-else.

; Оптимизатор все равно сделал довольно неплохо :)
    
        mov     edx, uMsg           ; Пришедшее сообщение
        dec     edx                 ; Для быстрого сравнения с 0
        je      @@WM_Create         ; Пришло WM_CREATE
        sub     edx, 0Eh            ; edx := edx - $F - 1
        je      @@WM_Paint          ; Пришло WM_PAINT
        sub     edx, 104h           ; edx := edx - $113 - $F
        je      @@WM_Timer          ; Пришло WM_TIMER
        
; Пришло любое другое сообщение

        push    esi                 ; esi = lParam
        push    wParam
        push    uMsg        
        push    edi                 ; edi = hWnd
        call    DefWindowProcW      ; DefWindowProcW(hWnd, uMsg, wParam, lParam)
        mov     ebx, eax            ; Результат DefWindowProcW в ebx
        jmp     @@Quit

@@WM_Timer:
        mov     ecx, wParam         ; Timer identifier
        
; Видим валидацию с некоторым идентификатором таймера.    
; В этом месте eax = GetWindowLongW(hWnd, GWL_USERDATA) = lpCreateParams
; В чем суть, станет понятно далее :)

        cmp     ecx, [eax+3Ch]
        jnz     @@Quit
        mov     ecx, eax            ; Параметр в следующий вызов - lpCreateParams
        call    CDimmedWindow::StepDim
        jmp     @@Quit
        
@@WM_Paint:
;Paint: TPaintStruct;

        lea     eax, Paint          ; Получаем адрес Paint
        push    eax                 ; @PaintStruct
        push    edi                 ; edi = hWnd
        call    BeginPaint          ; BeginPaint(hWnd, Paint) 
        lea     eax, Paint          ; Снова получаем адрес Paint
        push    eax
        push    edi
        call    EndPaint            ; EndPaint(hWnd, Paint)
        jmp     @@Quit
        
@@WM_Create:
        push    dword ptr [esi]     ; esi = lParam (см. начало функции), содержит указатель на CreateStruct
        push    GWL_USERDATA 
        push    edi                 ; edi = hWnd
        call    SetWindowLongW      ; SetWindowLong(hWnd, GWL_USERDATA, (PCreateStruct(lParam)^.lpCreateParams)
        mov     ecx, [esi]          ; ecx будет использоваться в нижеследующем вызове  
        push    edi                 ; Параметр в следующий вызов
        call    CDimmedWindow::SetupDim
        
@@Quit:
        mov     ecx, [ebp-4]        ; __security_cookie
        pop     edi
        pop     esi
        mov     eax, ebx            ; Result := ebx
        pop     ebx
        call    __security_check_cookie
        leave
        retn    10h                 ; 4 аргумента
    
Здесь есть две новые функции - CDimmedWindow::SetupDim и CDimmedWindow::StepDim. Из названия примерно понятно, для чего они служат, но нужно детально разобраться, как ребята из MS все сделали!
Код

<void __thiscall StepDim(void)>
; Assembly code listing
; На входе через ecx принимает член lpCreateParams, который принадлежит структуре TCreateStructW
; Этот член указывает на недокументированную структуру, в ней лежит довольно много параметров
        mov     edi, edi            ; Alignment
        push    ebx
        push    esi
        push    edi
        mov     esi, ecx            ; esi := CreateParams
        push    dword ptr [esi+10h] ; hWnd
        call    GetDC               ; GetDC(hWnd) 
        mov     ebx, eax
        mov     eax, [esi+34h]
        xor     edi, edi            ; edi := 0
        cmp     eax, edi            ; if eax < 0 then goto @@L1
        jl      @@L1
        push    SRCCOPY             ; ROP
        
        ; Команда lea может быть использована для быстрого умножения
        ; eax := eax + eax*4
        lea     eax, [eax+eax*4]    
        shl     eax, 2              ; eax := eax * 4
        push    eax                 ; YSrc
        push    edi                 ; XSrc = 0
        push    ebx                 ; hSrcDc - результат прошлой GetDC
        push    14h                 ; Height
        push    dword ptr [esi+1Ch] ; Width  
        push    eax                 ; YDest
        push    edi                 ; XDest = 0
        push    dword ptr [esi+24h] ; hDestDC 
        call    BitBlt
        dec     dword ptr [esi+34h]
        jns     @@Quit              ; Прыгаем, если член структуры [esi+34h] >=0
        
; Это (edi) процедура обработки таймера. Поскольку обработка ведётся через WM_TIMER, она не используется

        push    edi                 ; @Timerproc = nil
        push    0FAh                ; Интервал таймера 250 миллисекунд
        push    dword ptr [esi+3Ch] ; Тот самый валидационный идентификатор таймера
        push    dword ptr [esi+10h] ; hWnd
        call    SetTimer
        mov     [esi+38h], 10h
        jmp     @@Quit
        
@@L1:        
        mov     eax, [esi+20h]
        imul    eax, [esi+1Ch]
        push    0D5h
        push    eax
        push    dword ptr [esi+30h]
        call    DimPixels           ; Эта функция выполняет графическое преобразование
        push    SRCCOPY             ; ROP
        push    edi                 ; YSrc
        push    edi                 ; XSrc
        push    dword ptr [esi+24h] ; hSrcDC
        push    dword ptr [esi+20h] ; Height
        push    dword ptr [esi+1C]  ; Width
        push    edi                 ; YDest
        push    edi                 ; XDest
        push    ebx                 ; hDestDC - ebx - результат прошлой GetDC
        call    BitBlt
        dec     dword ptr [esi+38h]
        jnz     @@Quit              ; if [esi+38h] <> 0 then goto @@Quit
        push    dword ptr [esi+3Ch]
        push    dword ptr [esi+10h]
        call    KillTimer           ; KillTimer(hWnd, TimerID)
        mov     [esi+3Ch], edi
        
@@Quit:
        pop     edi
        pop     esi
        pop     ebx
        retn

Как видно, здесь идёт идет работа со структурой данных через [esi+0xxh], параметры которой недокументированы. Придется самостоятельно их описать. Займемся этим после изучения работы функции CDimmedWindow::SetupDim. Функция DimPixels, встретившаяся выше, выполняет математические преобразования цветов. Её ассемблерный вариант с адаптацией для Delphi:
Код

procedure DimPixels(Bits: Pointer; Area, DimLevel: Integer); stdcall;
asm
        mov     eax, Area
        dec     eax
        push    esi
        mov     esi, Bits
        js      @@Quit
        mov     ecx, 0FFh
        sub     ecx, DimLevel
        inc     eax
        push    ebx
        mov     Area, ecx
        mov     Bits, eax
        push    edi
@@Cycle:
        mov     edi, [esi]
        movzx   ecx, byte ptr [esi+1]
        movzx   ebx, byte ptr [esi]
        imul    ebx, ebx, 36h
        mov     eax, edi
        shr     eax, 10h
        movzx   edx, al
        mov     eax, ecx
        imul    ecx, DimLevel
        imul    eax, eax, 0B7h
        add     eax, ebx
        mov     ebx, edx
        imul    edx, DimLevel
        imul    ebx, ebx, 13h
        add     eax, ebx
        shr     eax, 8
        imul    eax, Area
        xor     ebx, ebx
        add     edx, eax
        shr     edx, 8
        mov     bh, dl
        add     ecx, eax
        and     edi, 0FF000000h
        mov     bl, ch
        movzx   ecx, byte ptr [esi]
        imul    ecx, DimLevel
        add     ecx, eax
        shr     ecx, 8
        shl     ebx, 8
        movzx   eax, cl
        or      ebx, eax
        or      ebx, edi
        mov     [esi], ebx
        add     esi, 4
        dec     Bits
        jnz     @@Cycle
        pop     edi
        pop     ebx
@@Quit:
        pop     esi
end;



--------------------
Let's do this quickly!
Rest in peace, Vit!
PM MAIL Skype   Вверх
Rrader
Дата 25.3.2009, 18:34 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Inspired =)
***


Профиль
Группа: Экс. модератор
Сообщений: 1535
Регистрация: 7.5.2005

Репутация: 29
Всего: 191



Мой вольный перевод этой функции на "чистый" Delphi есть в конце этого материала (но и в таком виде она рабочая). Более того, в ассемблерном виде она быстрее работает. Итак, CDimmedWindow::SetupDim:
Код

<int __stdcall SetupDim(HWND hWnd)>
; Assembly code listing
; Судя по названию, производит приготовление окна к работе
; Точно также на входе через ecx принимает lpCreateParams
; У функции две локальных переменных - одна хранит контекст устройства типа HDC, другая - структуру TBitmapInfo.
; SizeOf(TBitmapInfo) = $2C байт, SizeOf(HDC) = 4 байта, итого $30 байт.
; DC: HDC;
; BitmapInfo: TBitmapInfo;
        mov     edi, edi
        push    ebp                 
        mov     ebp, esp
        sub     esp, 30h
        push    ebx
        push    esi
        push    hWnd                ; Аргумент функции - окно DimmedWindow
        mov     esi, ecx            ; Основная структура 
        call    GetDC               ; eax := GetDC(hWnd)
        xor     ebx, ebx            ; ebx := 0
        cmp     eax, ebx 
        mov     DC, eax             ; Запомнили контекст в локальную переменную
        jz      @@Quit              ; Прыгаем, если GetDC вернула 0
        push    eax                 ; hdc
        call    CreateCompatibleDC  ; CreateCompatibleDC(hdc) - создание совместимого контекста
        mov     edx, eax
        cmp     edx, ebx            ; Сравнение с 0
        mov     [esi+24h], edx      ; Запомнили контекст
        jz      @@NullDC
        push    edi
        push    0Bh
        pop     ecx                 ; ecx := 0Bh = 11
        xor     eax, eax            ; eax := 0
        lea     edi, BitmapInfo      
        
        ; Инициализация нулями первых 11 байт переменной BitmapInfo
        rep stosd
        mov     eax, [esi+1Ch]      ; Ширина 
        mov     BitmapInfo.bmiHeader.biWidth, eax      
        mov     eax, [esi+20h]      ; Высота
        push    ebx                 ; Параметр dwOffset = 0 
        push    ebx                 ; Параметр hSection = 0

        ; Высота
        mov     BitmapInfo.bmiHeader.biHeight, eax
        lea     eax, [esi+30h]      ; Массив битовых значений
        push    eax                 ; Параметр ppvBits  
        push    ebx                 ; Параметр iUsage = 0 = DIB_RGB_COLORS 
        lea     eax, BitmapInfo
        push    eax                 ; Параметр pbmi
        push    edx                 ; Параметр hdc

        ; Подготовка структуры, о параметрах рассказано в MSDN 
        mov     BitmapInfo.bmiHeader.biSize, 2Ch
        mov     BitmapInfo.bmiHeader.biPlanes, 1

        ; 32 бита  
        mov     BitmapInfo.bmiHeader.biBitCount, 20h
        mov     BitmapInfo.bmiHeader.biCompression, ebx
        mov     BitmapInfo.bmiHeader.biSizeImage, ebx
        call    CreateDIBSection
        cmp     eax, ebx
        mov     [esi+2Ch], eax      ; Запоминаем результат
        pop     edi
        jz      @@NullDIBSection
        push    eax 
        push    dword ptr [esi+24h]
        call    SelectObject        ; Выбираем DIB-секцию (HBITMAP) в контекст
        mov     [esi+28h], eax      ; Запоминаем старый объект

        mov     eax, [esi+20h]      ; Это высота виртуального экрана
        push    14h
        pop     ecx                 ; ecx := 14h = 20 
        cdq                         ; Расширяем eax до edx 
 
        ; Обычно edx будет равен 0 здесь, т.е. мы просто целочисленно делим eax на 20 :)  
        idiv    ecx                 ; Делитель равен 20

        ; Подготовка таймера
        push    ebx                 ; @lpTimerFunc = nil
        push    1Eh                 ; Интервал 30 миллисекунд
        push    1                   ; Идентификатор таймера
        push    hWnd 
        mov     [esi+34h], eax      ; Высота виртуального экрана div 20
        call    SetTimer  
        mov     [esi+3Ch], eax
        jmp     @@NullDC 


@@NullDIBSection:
        push    dword ptr [esi+24h]
        call    DeleteDC            ; DeleteDC([esi+24h]) 
        mov     [esi+24h], ebx         

@@NullDC:
        push    DC                  ; Локальная переменная
        push    hWnd                ; Аргумент функции
        call    ReleaseDC           ; ReleaseDC(hWnd, DC)

@@Quit:
        pop     esi
        pop     ebx
        leave
        retn    4


Вернемся к недокументированной структуре данных, которую адресует регистр esi (указатель на которую передают в CreateWindowExW через последний параметр). Требуется её воссоздать - все безликие смещения заменить на поля. Но назначение полей, названия, их размер и число неизвестны. Придется думать. Поговорим о каждом параметре по порядку. Все выкладки относятся к полностью недокументированной структуре, которой нет даже в отладочных символах.

Определение назначения полей структуры при документировании

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

Определение названий полей структуры при документировании

Название поля выбирается с учетом выбранной нотации: можно использовать, например, венгерскую нотацию, а можно и не использовать smile Я не использовал. В названии должна быть отражена мнемоника, все должно быть на английском, не на транслите smile Название должно отражать суть!

Определение размера и числа полей структуры при документировании

Предварительно считаем, что размер всех полей = SizeOf(Pointer). Плюс допускаем, что все структуры упакованы (packed - нет выравнивания). Это работает в большинстве случаев для Windows-структур. Но не всегда, это следует помнить! Поля могут быть и типа Byte, и сложных типов (например, структур или динамических массивов). Может быть и выравнивание, а также неполное использование полей. После таких допущений идет анализ исходных текстов (можно анализировать и память) - ищем обращения к различным полям (т.е. разные смещения), все смещения заносим в таблицу. После этого смотрим на соотношения между смещениями, корректируем результаты (если отличия везде на SizeOf(Pointer), то просто замечательно). Число полей = числу записей в табличке.

Вернемся к исследованию. Для полноты картины осталось рассмотреть еще кое-что - конструктор и деструктор класса CDimmedWindow, а также полностью разобрать работу CDimmedWindow::Create. Конструктор:
Код

<__thiscall CDimmedWindow::CDimmedWindow(HINSTANCE__ * Instance)>
; Assembly code listing
; В параметре передается переменная _hDllInstance - ImageBase библиотеки
; WndClass: TWndClassEx;
; CDimmedWindow = указатель на таблицу vftable (virtual function table)
; Эта таблица служит для вызова виртуальных методов

        mov     edi, edi 
        push    ebp
        mov     ebp, esp

; У конструктора одна локальная переменная - структура TWndClassExW
; SizeOf(TWndClassExW) = $30 байт 

        sub     esp, 30h            ; Резервируем место под WndClass
        push    ebx
        mov     ebx, Instance
        push    esi
        mov     esi, ecx
        push    edi
        xor     edx, edx            ; edx = 0 
        push    0Ch
        pop     ecx                 ; ecx = 0Ch = 12
        xor     eax, eax            ; eax = 0
        push    IDC_ARROW           ; Параметр lpCursorName
        lea     edi, WndClass 

        ; Инициализация нулями 

        rep stosd                   ; ZeroMemory(@WndClass, 12)
        push    edx                 ; Параметр hInstance = 0     
        mov     dword ptr [esi], offset CDimmedWindow

        ; Счётчик ссылок - уменьшается при вызове Release через InterlockedDecrement 
        ; При создании объекта, соответственно, равен 1 

        mov     dword ptr [esi+4], 1
        mov     [esi+8], ebx        ; Instance

        ; Инициализация нулями
       
        mov     [esi+0Ch], dx
        mov     [esi+10h], edx
        mov     [esi+24h], edx
        mov     [esi+28h], edx
        mov     [esi+2Ch], edx
        mov     [esi+30h], edx
        mov     [esi+34h], edx
        mov     [esi+38h], edx
        mov     [esi+3Ch], edx
        
        ; Заполнение структуры оконного класса
     
        mov     WndClass.cbSize, 30h
        mov     WndClass.lpfnWndProc, offset DimmedWindowWndProc
        mov     WndClass.hInstance, ebx

       ; Константа s_szWindowClassName = 'DimmedWindowClass'

        mov     WndClass.lpszClassName, offset s_szWindowClassName
        call    LoadCursor          ; eax := LoadCursor(0, IDC_ARROW)
        mov     WndClass.hCursor, eax
        lea     eax, WndClass
        push    eax
        call    RegisterClassExW    ; ax := RegisterClassExW(WndClass)
        mov     [esi+0Ch], ax       ; Атом класса 
        pop     edi
        mov     eax, esi            ; Далее это пойдет в CDimmedWindow::Create
        pop     esi
        pop     ebx
        leave
        retn   4

Деструктор:
Код

<virtual __thiscall CDimmedWindow::~CDimmedWindow(void)>
; Assembly code listing
; Виртуальный деструктор класса CDimmedWindow
; Константа CDimmedWindow = указатель на таблицу vftable (virtual function table)

        mov     edi, edi 
        push    esi
        mov     esi, ecx            ; Все та же структура в lpCreateParams
        mov     eax, [esi+24h]
        test    eax, eax

        ; [esi] = [esi+0] = первое поле структуры, этот указатель лежит в GWL_USERDATA

        mov     [esi], CDimmedWindow 
        jz      @@NullDC            ; Прыгаем, если [esi+24h] = 0
        push    dword ptr [esi+28h] ; Параметр hgdiobj
        push    eax                 ; Параметр hdc

        ; Выбираем оригинальную DIB-секцию в контекст 

        call    SelectObject        ; SelectObject(hdc, hgdiobj)
        push    dword ptr [esi+24h] ; Снова здесь DC
        call    DeleteDC            ; DeleteDC([esi+24h]) 

@@NullDC:
        mov    eax, [esi+2Ch]        
        test   eax, eax
        jz     @@NullObj            ; Прыгаем, если [esi+2Ch] = 0
        push   eax                  ; Параметр hgdiobj
        call   DeleteObject         ; DeleteObject([esi+2Ch])

@@NullObj:      
        mov    eax, [esi+10h]         
        test   eax, eax         
        jz     @@NullWnd            ; Прыгаем, если [esi+10h] = 0
        push   eax                  ; hWnd
        call   DestroyWindow        ; DestroyWindow([esi+10h]) 

@@NullWnd:         
        mov    ax, [esi+0Ch]
        test   ax, ax
        jz     @@NullClassAtom      ; Прыгаем, если [esi+0Ch] = 0
        push   dword ptr [esi+8]    ; Параметр hInstance
        movzx  eax, ax              ; Преобразуем в операнд большей размерности, слово -> двойное слово
        push   eax                  ; Параметр lpClassName - атом класса
        call   UnregisterClassW     ; UnregisterClassW([esi+8], eax)

@@NullClassAtom:
        pop    esi
        retn 

CDimmedWindow::Create:
Код

<HWND * __thiscall CDimmedWindow::Create(void)>
; Assembly code listing
; Функция использует две локальных перменных. Обе занимают 8 байт.
; Но одна переменная используется не полностью, а только один байт!

; pvParam: DWORD;
; RemoteSession: DWORD;

        mov     edi, edi
        push    ebp
        mov     ebp, esp

        ; Эти две команды уменьшают указатель вершины стека на 8
        ; Таким образом создается окно для локальных переменных без классического пролога
        push    ecx
        push    ecx

        ; Сохранение регистров по соглашению
        push    ebx
        push    esi
        push    edi
        mov     esi, ecx
        call    IsDebuggerPresent   ; Эта функция не требует аргументов

        ; В регистр edi заносим адрес GetSystemMetrics
        mov     edi, GetSystemMetrics
        mov     ebx, eax            ; Результат IsDebuggerPresent в ebx

; Далее видим не совсем понятный для нас код: )
; Команда neg изменяет знак, при этом модифицирует флаг переноса CF:
; Если операнд равен нулю, то CF = 0, иначе CF = 1
; Команда sbb производит вычитаение с заёмом, т.е. учитывая флаг CF:
; sbb bl, bl означает bl := bl - (bl + CF)


        neg     ebx                 ; Изменяем знак
        sbb     bl, bl
        push    SM_REMOTESESSION    ; Параметр в GetSystemMetrics

; После следующей команды bl будет содержать либо 1 (нас не отлаживали), 
; либо 0 (нас отлаживали)
 
        inc     bl  

; Выдержка из MSDN (SM_REMOTESESSION):

;This system metric is used in a Terminal Services environment. If the calling process is associated with a Terminal Services 
;client session, the return value is nonzero. If the calling process is associated with the Terminal Server console session,
;the return value is 0. The console session is not necessarily the physical console. For more information, see 
;WTSGetActiveConsoleSessionId. 

        call    edi                 ; eax := GetSystemMetrics(SM_REMOTESESSION)
        neg     eax
        sbb     al, al

; После следующей команды al будет содержать либо 1 (запущены локально), 
; либо 0 (запущены удалённо)

        inc     al
        push    0                   ; Параметр fWinIni
        mov     RemoteSession, al
        lea     eax, pvParam
        push    eax                 ; Примет в себя результат SystemParametersInfoW
        push    0                   ; Параметр uiParam
        push    SPI_GETSCREENREADER ; Параметр uiAction

        ; SystemParametersInfoW(SPI_GETSCREENREADER, 0, @pvParam, 0); 
        call    SystemParametersInfoW
        test    eax, eax            ; Проверяем успешность предыдущего вызова 
        jz      @@SPI               ; Прыгаем, если вызов был неуспешен

; Выдержка из MSDN (SPI_GETSCREENREADER):

;Determines whether a screen reviewer utility is running. A screen reviewer utility directs textual information to an output device, 
;such as a speech synthesizer or Braille display. When this flag is set, an application should provide textual information in 
;situations where it would otherwise present the information graphically. The pvParam parameter is a pointer to a BOOL variable
;that receives TRUE if a screen reviewer utility is running, or FALSE otherwise.

; Делаем вывод - если от нас не требуется графическая информация, то создавать окно нет смысла

        cmp     pvParam, 0  
        jz      @@SPI              ; Прыгаем, если pvParam = False
        xor     al, al             ; al := 0
        jmp     @@L2               ; Чуть далее будет выход 

@@SPI:
        mov     al, 1              ; Чтобы последующие проверки прошли как нам надо

@@L2:
        test    bl, bl             
        jz      @@Quit             ; Если нас отлаживают, то выходим
        cmp     RemoteSession, 0   
        jz      @@Quit             ; Если запущены удалённо, то выходим 
        test    al, al             ; Если требуется только графическая информация, то выходим
        jz      @@Quit          

        ; Далее идет заполнение нескольких полей структуры и подготовка к показу окна 
        ; Координата X левого вернего угла
        push    SM_XVIRTUALSCREEN
        call    edi                ; eax := GetSystemMetrics(SM_XVIRTUALSCREEN) 
        ; Координата Y левого вернего угла
        push    SM_YVIRTUALSCREEN  
        mov     [esi+14h], eax     ; Запомнили Left
        call    edi                ; eax := GetSystemMetrics(SM_YVIRTUALSCREEN)
        ; Ширина виртуального экрана
        push    SM_CXVIRTUALSCREEN
        mov     [esi+18h], eax     ; Запомнили Top
        call    edi                ; eax := GetSystemMetrics(SM_CXVIRTUALSCREEN)
        ; Высота виртуального экрана   
        push    SM_CYVIRTUALSCREEN
        mov     [esi+1Ch], eax     ; Запомнили Width
        call    edi                ; eax := GetSystemMetrics(SM_CYVIRTUALSCREEN)

        ; Готовимся к вызову CreateWindowExW, в eax находится высота виртуального экрана Height 
        push    esi                ; lpParam
        push    dword ptr [esi+8]  ; hInstance
        xor     edi, edi           ; edi := 0
        push    edi                ; hMenu = 0
        push    edi                ; hWndParent = 0
        push    eax                ; Высота nHeight
        ; Ширина nWidth
        push    dword ptr [esi+1Ch]         
        mov     [esi+20h], eax     ; Запомним высоту
        ; Координата Y левого вернего угла
        push    dword ptr [esi+18h]
        ; Координата X левого вернего угла
        push    dword ptr [esi+14h]
        push    WS_POPUP           ; Стиль окна dwStyle
        push    edi                ; Текст окна lpWindowName = nil

        ; Константа s_szWindowClassName = 'DimmedWindowClass'
        push    offset s_szWindowClassName
        push    WS_EX_TOPMOST      ; Расширенные стили окна 
        call    CreateWindowExW    ; Вызываем функцию, возвращает дескриптор DimmedWindow
        cmp     eax, edi           ; Сравниваем дескриптор созданного окна с 0
        mov     [esi+10h], eax     ; Запоминаем дескриптор
        jz      @@Quit             ; Прыгаем, если окно не создалось
        push    SH_SHOW
        push    eax                       
        call    ShowWindow         ; ShowWindow(DimmedWindow, SW_SHOW)
        push    dword ptr [esi+10h] 
        ; SetForegroundWindow(DimmedWindow)       
        call    SetForegroundWindow 
        push    edi                ; edi = False
        push    dword ptr [esi+10h]       
        call    EnableWindow       ; EnableWindow(DimmedWindow, False)        
@@Quit: 
        mov     eax, [esi+10h]     ; Result := [esi+10h] - то, что ранее вернула CreateWindowExW
        pop     edi
        pop     esi
        pop     ebx
        leave  
        retn



--------------------
Let's do this quickly!
Rest in peace, Vit!
PM MAIL Skype   Вверх
Rrader
  Дата 25.3.2009, 18:37 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Inspired =)
***


Профиль
Группа: Экс. модератор
Сообщений: 1535
Регистрация: 7.5.2005

Репутация: 29
Всего: 191



Подводя небольшой итог, можно сказать, что работа всего класса базируется на интересующей нас структуре, адресуемой регистром esi. В этот регистр изначально структура попадает через регистр ecx (еще до передачи в CreateWindowExW). Это означает, что нам нужно произвести дополнительное исследование той функции, которая вызывает функцию CDimmedWindow::Create, на предмет содержимого регистра ecx.

Но до вызова любой функции класса при его объявлении вызывается конструктор класса. Конструирование класса CDimmedWindow осуществляется в двух местах библиотеки одинаковым кодом (не буду слишком углубляться):
Код

        push    40h                        ; Размер
        call    <operator new(uint size)>
...
        ; В ecx содержится указатель на данные размером 40h байт
        ; Такой способ передачи данных называется соглашением о вызове thiscall
        mov     ecx, eax

        ; Здесь данные пройдут инициализацию
  
        call    CDimmedWindow::CDimmedWindow 

Немного погодя идет вызов CDimmedWindow::Create:
Код

        push    40h
        call    <operator new(uint size)>
...
        mov     ecx, eax
        call    CDimmedWindow::CDimmedWindow 
        mov     ed(s)i, eax
...
        mov     ecx, ed(s)i
        call    CDimmedWindow::Create     ; Непосредственно показ       
...

Число 40h - количество памяти, которая должна быть выделена. 

В конструкторе многое прекрасно видно (имею в виду размеры) smile Но часть полей там не затронута. Возьмем их из других функций. Составляю таблицу полей с указанием их размеров. Также после анализа кода можно дать им символьные имена.
Код

[esi] - 4b
; Это поле содержит указатель на таблицу vftable и нас совершенно не интересует

[esi+4] - 4b 
; Изначально равен 1 - это счётчик ссылок RefCount (относится к механизму управления жизнью интерфейсов)
; Это поле нас также не интересует, мы не будем использовать интерфейсы.

[esi+8] - 4b 
; Параметр hInstance, назовем ModuleHandle

[esi+0Ch] - 4b
; Указатель на атом класса, назовем ClassAtom (используются 2 младших разряда, старшие обнуляются)
; Почему только 2 байта? Потому что RegisterClassExW возвращает двухбайтовый атом класса.

[esi+10h] - 4b 
; Это дескриптор окна DimmedWindow

[esi+14h] - 4b
; Сюда заносилось значение SM_XVIRTUALSCREEN - назовём X

[esi+18h] - 4b
; Сюда заносилось значение SM_YVIRTUALSCREEN - назовём Y

[esi+1Ch] - 4b
; Сюда заносилось значение SM_CXVIRTUALSCREEN - назовём Width

[esi+20h] - 4b
; Сюда заносилось значение SM_CYVIRTUALSCREEN - назовём Height

[esi+24h] - 4b
; Это контекст устройства окна DimmedWindow - назовём WndDC

[esi+28h] - 4b
; Это дескриптор, возвращаемый после вызова SelectObject(DC, Bitmap)
; Запоминание оригинального объекта - общепринятый прием при работе с GDI:
; объект GDI можно удалить лишь в том случае, когда он не выбран в контекст.
; Ну еще объект должен быть валиден :) Назовём OldBitmap

[esi+2Ch] - 4b
; Это дескриптор DIB-секции - назовём Bitmap

[esi+30h] - 4b
; Это массив битовых значений DIB-секции - назовём Bits

[esi+34h] - 4b
; Высота виртуального экрана div 20 - назовём DHeight

[esi+38h] - 4b
; Изначально равен 16 и является счётчиком - назовём Counter

[esi+3Ch] - 4b
; Это идентификатор таймера, назовём TimerID


Просуммировав все размеры, можно получить 40h. Назовем структуру TDimmedParams.

Теперь можно перевести все коды на Delphi, при этом часть действий можно опустить. Делается это последовательно, мы теперь знаем, что и где лежит в структуре, переписываем листинги по аналогии smile
Код

unit UDimmedWnd;

{ Моя версия отличается от оригинала: настоящий фрукт имеет название
  CDimmedWindow, реализует интерфейс, использует проверки безопасности,
  использует привилегии Winlogon'а, немного другая логика работы...

  Но мой фрукт выполняет свои обязательства на 100% }

interface

uses Windows, Messages;

type
  PDimmedParams = ^TDimmedParams;
  TDimmedParams = record
    ModuleHandle: THandle;
    ClassAtom: TAtom;
    DimmedWindow: HWND;
    X, Y: DWORD;
    Width, Height: Integer;
    WndDC: HDC;
    OldBitmap: HBITMAP;
    Bitmap: HBITMAP;
    Bits: Pointer;
    DHeight: Integer;
    Counter: Integer;
    TimerID: Integer;
  end;

procedure CreateDimmedWindow;
procedure DestroyDimmedWindow;

implementation

function IsDebuggerPresent: BOOL; stdcall external 'kernel32.dll';

const
  s_szWindowClassName = 'DimmedWindowClass';

var
  Params: TDimmedParams;

{ Мой вольный перевод }
procedure DimPixels(Bits: Pointer; Area, DimLevel: DWORD);
var
  I: Integer;
  Element, Next, Aux, L, A, B: DWORD;
begin
  if Area = 0 then
    Exit;
  { Сам чёрт ногу сломит }
  for I := Area downto 1 do
  begin
    Next := PByte(DWORD(Bits) + SizeOf(Byte))^;
    Aux := Next;
    L := Lo(PDWORD(Bits)^ shr 16);
    Aux := Aux * $B7;
    Inc(Aux, PByte(Bits)^ * $36);
    Inc(Aux, L * $13);
    Aux := (Aux shr 8) * ($FF - DimLevel);
    A := Hi(Next * DimLevel + Aux);
    B := Lo((L * DimLevel + Aux) shr 8);
    Element := MakeWord(A, B) shl 8;
    Element := Element or Lo((PByte(Bits)^ * DimLevel + Aux) shr 8);
    Element := Element or (PDWORD(Bits)^ and $FF000000);
    PDWORD(Bits)^ := Element;
    Inc(PInteger(Bits));
  end;
end;

procedure StepDim;
var
  DC: HDC;
  AY: Integer;
begin
  with Params do
  begin
    DC := GetDC(DimmedWindow);
    if DHeight >= 0 then
    begin
      AY := (DHeight + DHeight shl 2) shl 2;
      BitBlt(WndDC, 0, AY, Width, 20, DC, 0, AY, SRCCOPY);
      Dec(DHeight);
      if DHeight >= 0 then
        Exit;
      SetTimer(DimmedWindow, TimerID, 250, nil);
      Counter := 16;     
    end
    else
    begin
      DimPixels(Bits, Height * Width, $D5);
      BitBlt(DC, 0, 0, Width, Height, WndDC, 0, 0, SRCCOPY);
      Dec(Counter);
      if Counter = 0 then
      begin
        KillTimer(TimerID, DimmedWindow);
        TimerID := 0
      end;
    end;
  end;
end;

procedure SetupDim(Wnd: HWND);
var
  DC: HDC;
  BitmapInfo: TBitmapInfo;
begin
  DC := GetDC(Wnd);
  if DC <> 0 then
  try
    with Params do
    begin
      WndDC := CreateCompatibleDC(DC);
      if WndDC <> 0 then
      begin
        FillChar(BitmapInfo, SizeOf(BitmapInfo), 0);
        BitmapInfo.bmiHeader.biWidth := Width;
        BitmapInfo.bmiHeader.biHeight := Height;
        BitmapInfo.bmiHeader.biSize := SizeOf(BitmapInfo);
        BitmapInfo.bmiHeader.biPlanes := 1;
        BitmapInfo.bmiHeader.biBitCount := 32;
        Bitmap := CreateDIBSection(WndDC, BitmapInfo,
          DIB_RGB_COLORS, Bits, 0, 0);
        if Bitmap <> 0 then
        begin
          OldBitmap := SelectObject(WndDC, Bitmap);
          DHeight := Height div 20;
          TimerID := SetTimer(Wnd, 1, 30, nil);
        end
        else
          DeleteDC(WndDC);
      end;
    end;
  finally
    ReleaseDC(Wnd, DC);
  end;
end;

function DimmedWindowWndProc(hWnd: HWND; uMsg: UINT;
  wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
var
  Paint: TPaintStruct;
begin
  Result := 0;
  case uMsg of
    WM_CREATE:
      begin
        SetWindowLongW(hWnd, GWL_USERDATA,
          Integer(PCreateStruct(lParam)^.lpCreateParams));
        SetupDim(hWnd);
        Exit;
      end;
    WM_PAINT:
      begin
        BeginPaint(hWnd, Paint);
        try
        finally
          EndPaint(hWnd, Paint);
        end;
        Exit;
      end;
    WM_TIMER:
      begin
        if PDimmedParams(GetWindowLongW(hWnd,
          GWL_USERDATA))^.TimerID = wParam then
          StepDim;
        Exit;
      end;
  end;
  Result := DefWindowProcW(hWnd, uMsg, wParam, lParam);
end;

procedure CreateDimmedWindow;
const
  { В старых версиях Delphi не было }
  SM_REMOTESESSION = $1000;
var
  WndClass: TWndClassExW;
  pvParam, Res: BOOL;
begin
  FillChar(Params, SizeOf(Params), 0);
  FillChar(WndClass, SizeOf(WndClass), 0);
  Params.ModuleHandle := HInstance;
  with WndClass do
  begin
    cbSize := SizeOf(WndClass);
    lpfnWndProc := @DimmedWindowWndProc;
    hInstance := Params.ModuleHandle;
    lpszClassName := s_szWindowClassName;
    hCursor := LoadCursor(0, IDC_ARROW);
    Params.ClassAtom := RegisterClassExW(WndClass);
  end;
  { Чтобы можно было запускать из IDE }
  if {(not IsDebuggerPresent) and} (GetSystemMetrics(SM_REMOTESESSION) = 0) then
  begin
    Res := SystemParametersInfoW(SPI_GETSCREENREADER, 0, @pvParam, 0);
    if (not Res) or (Res and not pvParam) then
    with Params do
    begin
      X := GetSystemMetrics(SM_XVIRTUALSCREEN);
      Y := GetSystemMetrics(SM_YVIRTUALSCREEN);
      Width := GetSystemMetrics(SM_CXVIRTUALSCREEN);
      Height := GetSystemMetrics(SM_CYVIRTUALSCREEN);
      DimmedWindow := CreateWindowExW(WS_EX_TOPMOST, s_szWindowClassName,
        nil, WS_POPUP, X, Y, Width, Height, 0, 0, ModuleHandle, @Params);
      if DimmedWindow <> 0 then
      begin
        ShowWindow(DimmedWindow, SW_SHOW);
        SetForegroundWindow(DimmedWindow);
        EnableWindow(DimmedWindow, False);
      end;
    end;
  end;
end;

procedure DestroyDimmedWindow;
begin
  with Params do
  begin
    if WndDC <> 0 then
    begin
      SelectObject(WndDC, OldBitmap);
      DeleteDC(WndDC);
    end;
    if Bitmap <> 0 then
      DeleteObject(Bitmap);
    if DimmedWindow <> 0 then
      DestroyWindow(DimmedWindow);
    if ClassAtom <> 0 then
      UnregisterClassW(PWideChar(ClassAtom), ModuleHandle);
  end;
end;

end.

Пример использования:
Код

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, XPMan, UDimmedWnd;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  CreateDimmedWindow;
  BorderStyle := bsNone;
  FormStyle := fsStayOnTop;
  Color := clBlue;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  DestroyDimmedWindow;
  BorderStyle := bsSingle;
  FormStyle := fsNormal;
end;

end.

Это все. Буду рад услышать любые замечания и критику. Рабочий проект находится в прикреплённом файле.

Всем привет smile

Присоединённый файл ( Кол-во скачиваний: 35 )
Присоединённый файл  Attach.rar 11,53 Kb


--------------------
Let's do this quickly!
Rest in peace, Vit!
PM MAIL Skype   Вверх
Romikgy
Дата 29.3.2009, 15:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Любитель-программер
****


Профиль
Группа: Участник Клуба
Сообщений: 7326
Регистрация: 11.5.2005
Где: Porto Franco Odes sa

Репутация: 13
Всего: 146



интересная статейка 
респект афтору ))

вопрос , вся эта движуха дабы реализовать потускнение формы? аль чет другое?


--------------------
Владение русской орфографией это как владение кунг-фу — истинные мастера не применяют его без надобности. 
smile

PM   Вверх
Rrader
  Дата 29.3.2009, 15:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Inspired =)
***


Профиль
Группа: Экс. модератор
Сообщений: 1535
Регистрация: 7.5.2005

Репутация: 29
Всего: 191



Цитата(Romikgy @  29.3.2009,  21:35 Найти цитируемый пост)
вопрос , вся эта движуха дабы реализовать потускнение формы? аль чет другое?

Имеется в виду msgina? Если да, то это лишь маленький кусочек её содержания.


--------------------
Let's do this quickly!
Rest in peace, Vit!
PM MAIL Skype   Вверх
Romikgy
Дата 31.3.2009, 10:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Любитель-программер
****


Профиль
Группа: Участник Клуба
Сообщений: 7326
Регистрация: 11.5.2005
Где: Porto Franco Odes sa

Репутация: 13
Всего: 146



а что еще вкусного есть в нем ?


--------------------
Владение русской орфографией это как владение кунг-фу — истинные мастера не применяют его без надобности. 
smile

PM   Вверх
Rrader
  Дата 31.3.2009, 12:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Inspired =)
***


Профиль
Группа: Экс. модератор
Сообщений: 1535
Регистрация: 7.5.2005

Репутация: 29
Всего: 191



Цитата(Romikgy @  31.3.2009,  16:29 Найти цитируемый пост)
а что еще вкусного есть в нем ?

Расширение довольно многофункционально. Здесь лежит старая, но очень известная статья про GINA. Остальная инфа в MSDN. Что важно сейчас:
Цитата(MSDN)

Note GINA DLLs are ignored in Windows Vista.

В Windows 7 так же. Внутренний функционал распределили по другим модулям. А вот список классов msgina.dll из XP SP2:
  • CAccessControlList
  • CCompatibility
  • CCountedObject
  • CCredentialClient
  • CCredentialServer
  • CCredentials
  • CCriticalSection
  • CDesktop
  • CDimmedWindow
  • CDynamicArray
  • CDynamicObject
  • CDynamicPointerArray
  • CEvent
  • CExternalProcess
  • CImpersonation
  • CJob
  • CJobCompletionWatcher
  • CLogonDialog
  • CLogonMutex
  • CLogonStatus
  • CLogonWait
  • CMutex
  • CPowerButton
  • CPrivilegeEnable
  • CRegKey
  • CReturnToWelcome
  • CSecuredObject
  • CSecurityDescriptor
  • CSingleThreadedExecution
  • CSpecialAccounts
  • CStatusCode
  • CStringConvert
  • CSystemSettings
  • CThread
  • CThreadToken
  • CTokenGroups
  • CTokenInformation
  • CTooltip
  • CTurnOffDialog
  • CUIHost
  • CUserList
  • CUserSettings
  • CWaitInteractiveReady



--------------------
Let's do this quickly!
Rest in peace, Vit!
PM MAIL Skype   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: WinAPI и системное программирование"
Snowybartram
MetalFanbems
PoseidonRrader
Riply

Запрещено:

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Delphi обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи
  • 99% ответов по WinAPI можно найти в MSDN Library, оставшиеся 1% здесь

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, bartram, MetalFan, bems, Poseidon, Rrader, Riply.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: WinAPI и системное программирование | Следующая тема »


 




[ Время генерации скрипта: 0.0680 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.