Пятница, 18.07.2025, 11:17 Приветствую Вас Гость

On-line: Книги, учебники, статьи

Главная | Регистрация | Вход | RSS

Глава 5. Разрешение некоторых проблем программирования в Windows(4)

Рис. 3.5.3. Пример взаимодействия с консольным процессом через PIPE.





Трансляция программы на Рис. 3.5.3.
MASM32:

Трансляция программы на Рис. 3.5.3.
MASM32:

 ml /c /coff /DMASM pipe.asm
 rc pipe.rc
 link /subsystem:windows pipe.obj pipe.res
TASM32:
 tasm32 /ml pipe.asm
 brcc32 pipe.rc
 tlink32 -aa pipe.obj,,,,,pipe.res

Комментарий к программе на Рис. 3.5.3.

Вообще, запуск консольного приложения - дело довольно запутанное. Мы не будем вдаваться в детали. В нашей программе этот запуск почти не отличается от запуска программы Word.exe в главе 3.2. Отмечу новое для Вас в этой программе. Обратите внимание, что управляющий элемент EditBox выступает в несколько новой ипостаси. По сути, этот элемент играет роль консоли вывода. Для этого мы указали свойство ES_MULTILINE, что дает возможность помещать в окно целый текст, который отправляется в окно при помощи сообщения EM_REPLACESEL. Для чтения информации мы используем довольно большой буфер. В принципе, как и в случае с файлами, можно читать несколькими порциями, проверяя количество считанных байт.


46 Так называемые именованные каналы реализованы в Windows NT.


V

В. Можно ли не допустить многократный запуск одного и того же приложения?

Да. Наиболее часто употребляемым для этого средством является создание объекта Mutex. Этот объект как раз и предназначен для того, чтобы координировать разные процессы. Создается данный объект при помощи функции CreateMutex. Рассмотрим параметры этой функции.

  1. 1-й параметр. Указатель на структуру, определяющую атрибут доступа. Обычно NULL (0).
  2. 2-й параметр. Флаг. В случае ненулевого значения процесс требует немедленного владения объектом (!).
  3. 3-й параметр. Указатель на имя объекта.

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

К тому же результату можно прийти, используя семафор или файл, отображаемый в память. В данном случае все достаточно тривиально.

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

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

VI

В. Имеет ли операционная система Windows средства, упрощающие операции над группами файлов и каталогами?

Да, имеется функция SHFileOperation, которая умеет выполнять копирование, перенос, переименование или удаление файловых объектов (т.е. файлов и каталогов, в том числе и вложенных). Данная функция имеет всего один параметр - указатель на структуру, которая и определяет, какую операцию следует произвести, над чем и как. Вот эта структура.

SH STRUCT
 hwnd DWORD ?
 wFunc DWORD ?
 pFrom DWORD ?
 pTo DWORD ?
 fFlags DWORD ?
 fAnyOperationsAborted DWORD ?
 hNameMappings DWORD ?
 lpszProgressTitle DWORD ?
SH ENDS

Рассмотрим значение этих полей.

  • hwnd - дескриптор окна, куда будет выводиться статус операции.
  • wFunc - код операции. Может принимать следующие значения: FO_COPY, FO_DELETE, FO_MOVE, FO_RENAME. Смысл этих значений, я думаю, Вам понятен.
  • pFrom - название файла, каталога или группы файлов или каталогов, над которыми будет производиться операция. Если несколько объектов, то имена отделяются символами с кодом 0. Можно выделять списки, которые отделяются друг от друга двумя нулевыми символами.
  • pTo - имя или группа имен - результат операции, например копирование.
  • fFlags - флаг, определяет характер операции. Может являться комбинацией следующих констант:
    • FOF_ALLOWUNDO - сохранить, если возможно, информацию для возвращения в исходное состояние.
    • FOF_CONFIRMMOUSE - данное значение не реализовано.
    • FOF_FILESONLY - выполнять только над файлами, если определен шаблон.
    • FOF_MULTIDESTFILES - указывает, что pTo содержит несколько результирующих файлов или каталогов. Например, можно копировать сразу в несколько каталогов. Если pFrom состоит из нескольких файлов, то каждый файл будет копироваться в свой каталог.
    • FOF_NOCONFIRMATION - отвечать утвердительно на все запросы.
    • FOF_NOCONFIRMMKDIR- не подтверждать создание каталога, если это требуется.
    • FOF_RENAMEONCOLLISION - давать файлам новые имена, если файлы с такими именами уже существуют.
    • FOF_SILENT - не показывать окно-статус.
    • FOF_SIMPLEPROGRESS - показывать окно-статус, но не показывать имена файлов.
    • FOF_WANTMAPPINGHANDLE - заполнять отображаемый файл (см. ниже).
  • fAnyOperationsAborted - переменная, по которой после операции можно определить, была ли прервана операция (<>0) или нет (0).
  • hNameMappings - дескриптор отображаемого в памяти файла, содержащего массив, состоящий из новых и старых имен файлов, участвующих в операции.
  • lpszProgressTitle - указывает на строку-заголовок для диалогового окна-статуса.

Кроме описанной функции, есть еще целая группа функций, начинающихся на SH. Среди них особенно полезна функция SHGetDesktopFolder, осуществляющая вывод диалогового окна для выбора нужной папки каталога.

VII

В. Как отправить данные на печатающее устройство?

Вопрос весьма обширен, и за подробностями отсылаю читателей к книге [12]. Здесь же приведу общий алгоритм, который используется при печати в Windows. Вот основные положения, которые позволят Вам быстро разобраться в сути проблемы.

  1. Печать очень схожа с выводом на экран. При этом используются те же функции вывода, например TextOut или Ellipse. Как и в случае с экраном, для этого необходимо знать контекст принтера.
  2. Контекст принтера создается, а не получается, как в случае с экраном. Для этого используется функция CreateDC, у которой второй параметр - это указатель на строку, содержащую имя принтера. Все остальные три параметра, как правило, равны NULL.
  3. Функция PrintDlg позволяет выбрать название принтера в диалоге. При этом она возвращает тот контекст принтера.
  4. Если Вы все же решили использовать функцию CreateDC, Вам крайне необходимо узнать имена принтеров, которые есть в системе. Для этого Вам как раз подойдет функция EnumPrinters. Это весьма мощное средство может определить не только локальные, но и сетевые принтеры.
  5. Начало печати документа осуществляется функцией StartDoc. Конец печати - EndDoc. Эти две функции обрамляют блок, осуществляющий печать. В пределах этого блока можно выделять также страницы при помощи функций StartPage и EndPage.
  6. По окончании печати следует удалить контекст при помощи функции DeleteDC.

VIII

В. Может ли приложение узнать, какие программы в настоящее время запущены?

Да. В основу метода положено использование функции EnumWindows (т.е. пересчитать окна). Вот параметры этой функции.

  • 1-й параметр. Адрес процедуры, которая будет вызываться автоматически, если будет найдено окно.
  • 2-й параметр. Произвольное значение, которое будет передаваться в процедуру.

Сама вызываемая процедура получает два параметра: дескриптор найденного окна и определенный выше параметр. По известному дескриптору с помощью функции GetWindowThreadProcessId можно определить уникальный идентификатор процесса или потока, который владеет данным окном. Имея же идентификатор, мы можем, в частности, удалить данный процесс из памяти с помощью функции TerminateProcess (впрочем, будьте осторожнее).

Ниже на Рис. 3.5.4 представлен пример программы, выдающей список работающих процессов. Обратите внимание на использование функции GetWindowText, которая определяет текст заголовка окна. Не пугайтесь, что в списке будут представлены и те процессы, окна которых мы не видим. Окна, как известно, могут быть скрытыми. Заметьте, что в список попадают и консольные приложения. Программа определяет также уникальные идентификаторы процессов.

// файл proc.rc
// определение констант

#define WS_SYSMENU 0x00080000L
#define WS_MINIMIZEBOX 0x00020000L
#define WS_VISIBLE 0x10000000L
#define WS_TABSTOP 0x00010000L
#define WS_VSCROLL 0x00200000L
#define WS_HSCROLL 0x00100000L
#define DS_3DLOOK 0x0004L
#define LBS_NOTIFY 0x000lL
#define LBS_SORT 0x0002L

// идентификаторы
#define LIST1 101

// определение диалогового окна
DIAL1 DIALOG 0, 0, 220, 110
STYLE WS_SYSMENU | WS_MINIMIZEBOX | DS_3DLOOK
CAPTION "Поиск процессов"
FONT 8, "Arial"
{
 CONTROL "ListBox1", LIST1, "listbox", WS_VISIBLE |
 WS_TABSTOP | WS_VSCROLL | WS_HSCROLL | LBS_NOTIFY,
 16, 16, 190, 75
}

; файл proc.inc
; константы
; значения, возвращаемые функцией GetDriveType
; значения 0 и 1 можно считать признаком отсутствия устройства

DRIVE_REMOVABLE equ 2 ; накопитель на гибком диске
DRIVE_FIXED equ 3 ; устройство жесткого диска
DRIVE_REMOTE equ 4 ; сетевой диск
DRIVE_CDROM equ 5 ; накопитель на лазерном диске
DRIVE_RAMDISK equ 6 ; электронный диск

; сообщение приходит при закрытии окна
WM_CLOSE equ 10h
WM_INITDIALOG equ 110h
WM_COMMAND equ 111h
LB_ADDSTRING equ 180h
LB_RESETCONTENT equ 184h
WM_LBUTTONDOWN equ 201h

; прототипы внешних процедур
IFDEF MASM
 EXTERN wsprintfA:NEAR
 EXTERN GetWindowThreadProcessId@8:NEAR
 EXTERN GetWindowTextA@12:NEAR
 EXTERN EnumWindows@8:NEAR
 EXTERN lstrcat@8:NEAR
 EXTERN ExitProcess@4:NEAR
 EXTERN GetModuleHandleA@4:NEAR
 EXTERN DialogBoxParamA@20:NEAR
 EXTERN EndDialog@8:NEAR
 EXTERN SendDlgItemMessageA@20:NEAR
ELSE
 EXTERN _wsprintfA:NEAR
 EXTERN GetWindowThreadProcessId:NEAR
 EXTERN GetWindowTextA@12:NEAR
 EXTERN EnumWindows:NEAR
 EXTERN lstrcat:NEAR
 EXTERN ExitProcess:NEAR
 EXTERN GetModuleHandleA:NEAR
 EXTERN DialogBoxParamA:NEAR
 EXTERN EndDialog:NEAR
 EXTERN SendDlgItemMessageA:NEAR
 
 wsprintfA = _wsprintfA
 GetWindowThreadProcessId@8 = GetWindowThreadProcessId
 GetWindowTextA@12 = GetWindowTextA
 EnumWindows@8 = EnumWindows
 lstrcat@8 = lstrcat
 ExitProcess@4 = ExitProcess
 GetModuleHandleA@4 = GetModuleHandleA
 DialogBoxParamA@20 = DialogBoxParamA
 EndDialog@8 = EndDialog
 SendDlgItemMessageA@20 = SendDlgItemMessageA
ENDIF

; структуры
; структура сообщения
MSGSTRUCT STRUC
 MSHWND DD ?
 MSMESSAGE DD ?
 MSWPARAM DD ?
 MSLPARAM DD ?
 MSTIME DD ?
 MSPT DD ?
MSGSTRUCT ENDS


; файл proc.asm
.386P
; плоская модель
.MODEL FLAT, stdcall
include proc.inc
; директивы компоновщику для подключения библиотек
IFDEF MASM
 includelib c:\masm32\lib\user32.lib
 includelib c:\masm32\lib\kernel32.lib
ELSE
 includelib c:\tasm32\lib\import32.lib
ENDIF
;-------------------------------------------------
; сегмент данных
_DATA SEGMENT DWORD PUBLIC USE32 'DATA'
 MSG MSGSTRUCT <?>
 HINST DD 0 ; дескриптор приложения
 PA DB "DIAL1",0
 BUFER DB 200 DUP (0)
 BUF DB 20 DUP (0)
 FORM DB ";%lu",0
 IDP DD ?
 HWN DD ?
_DATA ENDS

; сегмент кода
_TEXT SEGMENT DWORD PUBLIC USE32 'CODE'
START:
; получить дескриптор приложения
 PUSH 0
 CALL GetModuleHandleA@4
 MOV [HINST], EAX
;---------------------------------------
 PUSH 0
 PUSH OFFSET WNDPROC
 PUSH 0
 PUSH OFFSET PA
 PUSH [HINST]
 CALL DialogBoxParamA@20
 CMP EAX,-1
 JNE KOL
; сообщение об ошибке
KOL:
;---------------------------------------
 PUSH 0
 CALL ExitProcess@4
;---------------------------------------

; процедура окна
; расположение параметров в стеке
; [EBP+014Н] ;LPARAM
; [EBP+10Н] ;WAPARAM
; [EBP+0CH] ;MES
; [EBP+8] ;HWND
WNDPROC PROC
 PUSH EBP
 MOV EBP,ESP
 PUSH EBX
 PUSH ESI
 PUSH EDI
;-------------------------
 CMP DWORD PTR [EBP+0CH],WM_CLOSE
 JNE L1
 PUSH 0
 PUSH DWORD PTR [EBP+08H]
 CALL EndDialog@8
 JMP FINISH
L1:
 CMP DWORD PTR [EBP+0CH],WM_INITDIALOG
 JNE FINISH
; запомним дескриптор окна
 MOV EAX,DWORD PTR [EBP+08H] 
 MOV HWN,EAX
; вызвать функцию EnumWindows
 PUSH 1 ; неиспользуемый параметр
 PUSH OFFSET PENUM
 CALL EnumWindows@8
FINISH:
 MOV EAX,0
 POP EDI
 POP ESI
 POP EBX
 POP EBP
 RET 16
WNDPROC ENDP

; процедура обратного вызова, вызываемая при поиске окон
; [EBP+0CH] ; параметр
; [EBP+8] ; дескриптор окна
PENUM PROC
 PUSH EBP
 MOV EBP,ESP
; получить заголовок окна
 PUSH 200
 PUSH OFFSET BUFER
 PUSH DWORD PTR [EBP+8]
 CALL GetWindowTextA@12
; получить идентификатор процесса или потока,
; владеющего окном
 PUSH OFFSET IDP
 PUSH DWORD PTR [EBP+8]
 CALL GetWindowThreadProcessId@8
; сформировать строку для списка
 PUSH OFFSET IDP
 PUSH OFFSET FORM
 PUSH OFFSET BUF
 CALL wsprintfA
 ADD ESP,12
 PUSH OFFSET BUF
 PUSH OFFSET BUFER
 CALL lstrcat@8
; добавить в список
 PUSH OFFSET BUFER
 PUSH 0
 PUSH LB_ADDSTRING
 PUSH 101
 PUSH [HWN]
 CALL SendDlgItemMessageA@20
 POP EBP
 MOV EAX,1
 RET 8
PENUM ENDP
_TEXT ENDS
END START

Рис. 3.5.4. Программа поиска процессов.

Трансляция программы на Рис. 3.5.4.
MASM32:

 ml /c /coff /DMASM PROC.asm
 rc proc.rc
 link /subsystem:windows PROC.obj proc.res
TASM32:
 tasm32 /ml proc.asm
 brcc32 proc.rc
 tlink32 -aa proc.obj,,,,,proc.res

Рис. 3.5.5. Пример работы программы на Рис. 3.5.4.




Вход на сайт
Поиск
Календарь
«  Июль 2025  »
ПнВтСрЧтПтСбВс
 123456
78910111213
14151617181920
21222324252627
28293031
Архив записей
Наш опрос
Как Вам удобнее??
Всего ответов: 341
Мини-чат
Друзья сайта
  • Официальный блог
  • Сообщество uCoz
  • FAQ по системе
  • Инструкции для uCoz
  • Статистика

    Онлайн всего: 1
    Гостей: 1
    Пользователей: 0