|
Вопрос # 2 762/ вопрос решён / |
|
Здравствуйте!
Как можно сделать так чтобы только одна копия моей проги работала а не 2 в копии?
Чтобы была скрыть в списке задач диспетчера задач!
 |
Вопрос задал: Hideman (статус: Посетитель)
Вопрос отправлен: 11 мая 2009, 07:51
Состояние вопроса: решён, ответов: 2.
|
Ответ #1. Отвечает эксперт: min@y™
Цитата:
Как можно сделать так чтобы только одна копия моей проги работала а не 2 в копии?
Способов полно, чтобы посмотреть их, нажми сюда.
Цитата:
Чтобы была скрыть в списке задач диспетчера задач!
Надо писать программу как сервис.
 |
Ответ отправил: min@y™ (статус: Доктор наук)
Время отправки: 11 мая 2009, 09:34
Оценка за ответ: 5
|
Ответ #2. Отвечает эксперт: 7Ghost
Здравствуйте, Hideman! Вы спрашиваете, как не допустить запуск второй копии программы?На мой взгляд вот самый лучший способ!
Приложение: Переключить в обычный режим-
-
-
-
- unit Only_One;
-
- interface
-
- function Init_Mutex(mid: string): boolean;
-
- implementation
-
- uses Windows;
-
- var
- mut: thandle;
-
- function mut_id(s: string): string;
- var
- f: integer;
- begin
- result := s;
- for f := 1 to length(s) do
- if result[f] = '' then
- result[f] := '_';
- end;
-
- function Init_Mutex(mid: string): boolean;
- begin
- Mut := CreateMutex(nil, false, pchar(mut_id(mid)));
- Result := not ((Mut = 0) or (GetLastError = ERROR_ALREADY_EXISTS));
- end;
-
- initialization
- mut := 0;
- finalization
- if mut <> 0 then
- CloseHandle(mut);
- end.
-
-
-
-
-
- uses
-
- Forms,
-
- MainForm in 'MainForm.pas' {Form1};
-
- {$R *.res}
-
- const
-
-
- begin
- if not init_mutex(UniqueString) then
- begin
-
-
-
- exit;
- end;
- Application.Initialize;
- Application.CreateForm(TForm1, Form1);
- Application.Run;
- end.
-
-
 |
Ответ отправил: 7Ghost (статус: 1-ый класс)
Время отправки: 11 мая 2009, 17:18
Оценка за ответ: 5
|
Мини-форум вопроса
Всего сообщений: 29; последнее сообщение — 12 мая 2009, 13:28; участников в обсуждении: 6.
Страницы: [1] [2] [Следующая »]
|
Hideman (статус: Посетитель), 11 мая 2009, 09:51 [#1]:
На счет чтобы прогу скрыть я использовал ShowWindow(application.handle,SW_HIDE) не виден в списке задач а не списке процессов!
|
|
Hideman (статус: Посетитель), 11 мая 2009, 10:24 [#2]:
Как можно писать прогу как сервис?
|
|
min@y™ (статус: Доктор наук), 11 мая 2009, 10:52 [#3]:
Набери в гугле "написание сервиса delphi"
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
|
Вадим К (статус: Академик), 11 мая 2009, 13:00 [#4]:
А зачем скрывать программу с списка процессов? На самом деле, если программы нет в списке процессов, то она и выполнятся не будет - ей не будет доставаться процессорного времени.
Во вторых - желание скрывать сразу наводит на мысль о вирусах и прочем.
Сервис - это хорошее дело, но там есть куча особенностей. Во первых, по умолчанию сервис работает в своем сеансе и доступа до рабочего стола по умолчанию не имеет...
Галочка "подтверждения прочтения" - вселенское зло.
|
|
Hideman (статус: Посетитель), 11 мая 2009, 13:04 [#5]:
А что насчет запрета запуска 2 копии одной и той же проги?
|
|
Hideman (статус: Посетитель), 11 мая 2009, 13:08 [#6]:
Ест ли более простой способ как VB например(if pp.PrevInstance = True then .......) или для скрытия в списке задач (App.TaskVisible = False)???
|
|
Вадим К (статус: Академик), 11 мая 2009, 13:10 [#7]:
Ну это не сложно. Сотни способов. Программа при запуске просто проверяет, не запущенна ли её копия. Например самый простой способ - проверить, нет ли окна с нужным именем, либо создавать общий именованный мютекс.
Но!
1) надо - все равно обойдут.
2) Можно всегда сделать хуже пользователю - а это самое плохое.
Наверно, для программистов, надо как для докторов, делать клятву "не навреди юзеру своему". а там и качество софта улучшиться...
Галочка "подтверждения прочтения" - вселенское зло.
|
|
Вадим К (статус: Академик), 11 мая 2009, 13:12 [#8]:
по поводу (if pp.PrevInstance = True then .......).
Старые книги читаете очень старые, по 3.11 винде. Да, когда то подобный способ работал. Теперь нет.
Галочка "подтверждения прочтения" - вселенское зло.
|
|
Hideman (статус: Посетитель), 11 мая 2009, 13:26 [#9]:
Этот пример: APP.Previnstance данный момент работает Visual Basic-ке вот о чем идёт реч!
|
|
Вадим К (статус: Академик), 11 мая 2009, 13:34 [#10]:
Странно, вообще то не должно работать, работать корректно. Хотя может быть Майкрософт, что бы не создавать проблем бейсик программистам, сделала костыль-симулятор. А так, начиная с 95 виндовс, этот способ официально не работает во всех языках - соответсвующий вызов апи функции сделан заглушкой.
Галочка "подтверждения прочтения" - вселенское зло.
|
|
Hideman (статус: Посетитель), 11 мая 2009, 13:44 [#11]:
Но несмотря на это я пишу проги используя это на VB всё работает хорошо даже по сей день!!!
|
|
Вадим К (статус: Академик), 11 мая 2009, 14:56 [#12]:
Сложно сравнивать VB и Delphi. В первом все таки виртуальная машина... А в последней версии уже под .NET всё перешло...
Галочка "подтверждения прочтения" - вселенское зло.
|
|
Ученый (статус: 8-ой класс), 11 мая 2009, 15:02 [#13]:
А интересно, какая такая надобность скрыть процесс в диспечере? Обычно скрываются те программы которые призваны нанести вред, а с Вадимом согласен на счет клятвы
А если App.TaskVisible = False и скроет процесс, то это скорее всего только в стандартном диспечере задач, но если посмотреть чем-то посерьезнее, то большая доля вероятности что не удасться скрыть процесс...
|
|
7Ghost (статус: 1-ый класс), 11 мая 2009, 17:17 [#14]:
Здравствуйте, Hideman! Вы спрашиваете, как не допустить запуск второй копии программы?На мой взгляд вот самый лучший способ!
Для того чтобы не допустить запуск второй копии программы сделайте следующие шаги!
1) В корневой папке вашей программы создайте текстовый файл и пропишите в него ниже указанный код и перемените имя вашего файла на "Only_One.pas";
unit Only_One;
interface
function Init_Mutex(mid: string): boolean;
implementation
uses Windows;
var
mut: thandle;
function mut_id(s: string): string;
var
f: integer;
begin
result := s;
for f := 1 to length(s) do
if result[f] = '\' then
result[f] := '_';
end;
function Init_Mutex(mid: string): boolean;
begin
Mut := CreateMutex(nil, false, pchar(mut_id(mid)));
Result := not ((Mut = 0) or (GetLastError = ERROR_ALREADY_EXISTS));
end;
initialization
mut := 0;
finalization
if mut <> 0 then
CloseHandle(mut);
end.
2) Откройте вашу программу в Delphi и выполните команду главного меню "Project->View Source" и добавьте то чего нет в такой же последовательности:
program ЗДЕСЬ НАЗВАНИЕ ВАШЕЙ ПРОГРАММЫ;
uses
Only_one, //этот модуль вы создали в корневом каталоге вашей программ!
Forms,
Dialog, //данный модуль поможет вывести сообщение на экран!
MainForm in 'MainForm.pas' {Form1};
{$R *.res}
const
UniqueString = 'DFG005BNME5007DA'; //идентификатор вашей программы(должны быть ваши символы) по этим символам мы поймем что программа открылась дважды!
begin
if not init_mutex(UniqueString) then
begin
MessageDlg('Приложение уже запущено (возможно оно свернуто
на панели задач): Нажмите кнопку ОК для продолжения работы!
Производственно-диспетчерская служба', mtInformation, [mbOK], 0);
exit;
end;
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
Все удачи!
|
|
Вадим К (статус: Академик), 11 мая 2009, 17:27 [#15]:
вот только для генерации уникальной строки лучше использовать GUID. А то все равно найдется "умный человек", который умудриться не поменять строку... или указать что то простое.
В делфи GUID сгенерировать очень просто - просто нажать Ctrl+Shift+G. Полученная строка считается достаточно уникальной.
Галочка "подтверждения прочтения" - вселенское зло.
|
|
7Ghost (статус: 1-ый класс), 11 мая 2009, 21:40 [#16]:
Вполне согласен с Вадимом К! Это моя ошибка! Но на мой взгляд, если нужно истинно получить случайный набор символов используйте крипто-ключ например полученный из расчета контрольной суммы оригинального файла или перемещения мыши на экране, тогда точно не будет совпадений! А для полной безопасности зашифруйте идентификационный ключ хотя бы простым методом сдвига XOR!!! Удачи!
|
|
7Ghost (статус: 1-ый класс), 11 мая 2009, 21:49 [#17]:
А вот предложение скрыть приложение из Диспетчера задач очень заманчиво!!! Интересно для чего вам это нужно? Хотите написать троян? В принципе для меня это не составит труда в написании для Windows 98, а вот с XP достаточно сложно!!! Может другие эксперты подскажут??!!
|
|
Вадим К (статус: Академик), 11 мая 2009, 21:59 [#18]:
Дело в том, что скрыть не сложно. Но тут проблема в другом - что после этого приложение не будет выполняться. Ведь если приложения нет в списке процессов, то оно не получает процессорного времени и как следствие, не выполняется...
Другое дело, что под словом "скрыть" подразумевают "обмануть" диспетчер задач. Но это уже другая песня... тут сервис пак поменялся и надо другие методы.
Галочка "подтверждения прочтения" - вселенское зло.
|
|
Silaims (статус: Посетитель), 11 мая 2009, 22:22 [#19]:
Можно скрыть процесс программы из диспетчера задач при помощи перехвата модуля, который использует сам диспечер.
Вот мой пример:
Делаем две модульки для одного модуля...
1) "ExtendedAPIFunctions"
unit ExtendedAPIFunctions;
interface
uses Windows;
const
SystemBasicInformation = 0;
SystemProcessorInformation = 1;
SystemPerformanceInformation = 2;
SystemTimeOfDayInformation = 3;
SystemNotImplemented1 = 4;
SystemProcessesAndThreadsInformation = 5;
SystemCallCounts = 6;
SystemConfigurationInformation = 7;
SystemProcessorTimes = 8;
SystemGlobalFlag = 9;
SystemNotImplemented2 = 10;
SystemModuleInformation = 11;
SystemLockInformation = 12;
SystemNotImplemented3 = 13;
SystemNotImplemented4 = 14;
SystemNotImplemented5 = 15;
SystemHandleInformation = 16;
SystemObjectInformation = 17;
SystemPagefileInformation = 18;
SystemInstructionEmulationCounts = 19;
SystemInvalidInfoClass = 20;
SystemCacheInformation = 21;
SystemPoolTagInformation = 22;
SystemProcessorStatistics = 23;
SystemDpcInformation = 24;
SystemNotImplemented6 = 25;
SystemLoadImage = 26;
SystemUnloadImage = 27;
SystemTimeAdjustment = 28;
SystemNotImplemented7 = 29;
SystemNotImplemented8 = 30;
SystemNotImplemented9 = 31;
SystemCrashDumpInformation = 32;
SystemExceptionInformation = 33;
SystemCrashDumpStateInformation = 34;
SystemKernelDebuggerInformation = 35;
SystemContextSwitchInformation = 36;
SystemRegistryQuotaInformation = 37;
SystemLoadAndCallImage = 38;
SystemPrioritySeparation = 39;
SystemNotImplemented10 = 40;
SystemNotImplemented11 = 41;
SystemInvalidInfoClass2 = 42;
SystemInvalidInfoClass3 = 43;
SystemTimeZoneInformation = 44;
SystemLookasideInformation = 45;
SystemSetTimeSlipEvent = 46;
SystemCreateSession = 47;
SystemDeleteSession = 48;
SystemInvalidInfoClass4 = 49;
SystemRangeStartInformation = 50;
SystemVerifierInformation = 51;
SystemAddVerifier = 52;
SystemSessionProcessesInformation = 53;
STATUS_SUCCESS = $00000000;
STATUS_ACCESS_DENIED = $C0000022;
STATUS_INFO_LENGTH_MISMATCH = $C0000004;
SEVERITY_ERROR = $C0000000;
type
NTStatus = Cardinal;
PUNICODE_STRING = ^UNICODE_STRING;
UNICODE_STRING = packed record
Length: Word;
MaximumLength: Word;
Buffer: PWideChar;
end;
PVM_COUNTERS = ^VM_COUNTERS;
VM_COUNTERS = packed record
PeakVirtualSize,
VirtualSize,
PageFaultCount,
PeakWorkingSetSize,
WorkingSetSize,
QuotaPeakPagedPoolUsage,
QuotaPagedPoolUsage,
QuotaPeakNonPagedPoolUsage,
QuotaNonPagedPoolUsage,
PagefileUsage,
PeakPagefileUsage: DWORD;
end;
PIO_COUNTERS = ^IO_COUNTERS;
IO_COUNTERS = packed record
ReadOperationCount,
WriteOperationCount,
OtherOperationCount,
ReadTransferCount,
WriteTransferCount,
OtherTransferCount: LARGE_INTEGER;
end;
PClientID = ^TClientID;
TClientID = packed record
UniqueProcess WORD;
UniqueThread WORD;
end;
PSYSTEM_THREADS = ^SYSTEM_THREADS;
SYSTEM_THREADS = packed record
KernelTime: LARGE_INTEGER;
UserTime: LARGE_INTEGER;
CreateTime: LARGE_INTEGER;
WaitTime: DWORD;
StartAddress: Pointer;
ClientId: TClientID;
Priority: DWORD;
BasePriority: DWORD;
ContextSwitchCount: DWORD;
State: dword;
WaitReason: dword;
end;
PSYSTEM_PROCESSES = ^_SYSTEM_PROCESSES;
_SYSTEM_PROCESSES = packed record
NextEntryDelta,
ThreadCount: DWORD;
Reserved1:array [0..5] of DWORD;
CreateTime:LARGE_INTEGER;
UserTime:LARGE_INTEGER;
KernelTime:LARGE_INTEGER;
ProcessName:UNICODE_STRING;
BasePriority WORD;
ProcessID WORD;
InheritedFromProcessID WORD;
HandleCount: DWORD;
Reserved2: array [0..1] of DWORD;
VmCounters: VM_COUNTERS;
IoCounters: IO_COUNTERS; // Windows 2000 only
Threads: array [0..0] of SYSTEM_THREADS;
end;
Function ZwQuerySystemInformation(ASystemInformationClass: DWORD; ASystemInformation: Pointer;
ASystemInformationLength: DWORD; AReturnLength Cardinal): NTStatus; stdcall;external 'ntdll.dll';
Function GetSystemInfo(InfoClass WORD) ointer;
implementation
//получение буфера с системной информацией
Function GetSystemInfo(InfoClass WORD) ointer;
var
mSize: DWORD;
pInfoDATA: Pointer;
NTRes: NTStatus;
begin
Result := 0;
mSize := $2000;
repeat
pInfoDATA := VirtualAlloc(0, mSize, MEM_COMMIT or MEM_RESERVE, PAGE_READWRITE);
if pInfoDATA = nil then Exit;
NTRes := ZwQuerySystemInformation(InfoClass, pInfoDATA, mSize, 0);
if NTRes = STATUS_INFO_LENGTH_MISMATCH then
begin
VirtualFree(pInfoDATA, 0, MEM_RELEASE);
mSize := mSize + $1000;
end;
until NTRes <> STATUS_INFO_LENGTH_MISMATCH;
if NTRes = STATUS_SUCCESS then Result := pInfoDATA
else VirtualFree(pInfoDATA, 0, MEM_RELEASE);
end;
end.
|
|
Silaims (статус: Посетитель), 11 мая 2009, 22:22 [#20]:
2) "ApiHookTools"
unit ApiHookTools;
interface
uses Windows,TlHelp32;
const
THREAD_ALL_ACCESS = $001F03FF;
THREAD_SUSPEND_RESUME = $00000002;
type
PFunctionRestoreData = ^ TFunctionRestoreData;
TFunctionRestoreData = packed record
Address ointer;
val1:Byte;
val2 WORD;
end;
function EnableDebugPrivilege:Boolean;
Function GetProcessName(ProcessID WORD):string;
function GetProcessID(ProcessName:string) WORD;
Function StopProcess(ProcessID: DWORD): boolean;
Function ResumeProcess(ProcessID: DWORD): Boolean;
function LoadLibrary_Ex(ProcessID WORD;LibName Char):boolean;
function SetCodeHook(ProcAddress,NewProcAddress:pointer;RestoreDATA FunctionRestoreData):boolean;
function UnHookCodeHook(RestoreDATA FunctionRestoreData):Boolean;
function SetProcedureHook(ModuleHandle:HMODULE;ProcedureName Char;NewProcedureAddress ointer;
RestoreDATA FunctionRestoreData):Boolean;
Function OpenThread(dwDesiredAccess: DWORD;bInheritHandle: BOOL;
dwThreadID: DWORD): THandle; stdcall; external 'kernel32.dll';
implementation
{-----------------------------------------------------------------------------
Установка перхвата функции по её имени
Procedure: SetProcedureHook
ModuleHandle:HMODULE; Хендл модуля в котором находится целевая функция
ProcedureName Char; Имя процедуры
NewProcedureAddress ointer; Указатель на процедуру перехватчик
RestoreDATA FunctionRestoreData Указатель на мост к старой функции
Result: Boolean Успешность установки перехвата
-----------------------------------------------------------------------------}
function SetProcedureHook(ModuleHandle:HMODULE;ProcedureName Char;NewProcedureAddress ointer;
RestoreDATA FunctionRestoreData):Boolean;
var
ProcAddress ointer;
begin
ProcAddress:=GetProcAddress(ModuleHandle,ProcedureName);
Result:=SetCodeHook(ProcAddress,NewProcedureAddress,RestoreDATA);
end;
{-----------------------------------------------------------------------------
Снятие перехвата функции
Procedure: UnHookCodeHook
RestoreDATA FunctionRestoreData адрес моста к старой функции
Result: Boolean
-----------------------------------------------------------------------------}
function UnHookCodeHook(RestoreDATA FunctionRestoreData):Boolean;
var
ProcAddress ointer;
OldProtect,JMPValue WORD;
begin
Result:=False;
ProcAddress:=RestoreDATA^.Address;
if not VirtualProtect(ProcAddress,5,PAGE_EXECUTE_READWRITE,OldProtect) then exit;
Byte(ProcAddress^):=RestoreDATA^.val1;
DWORD(Pointer(DWORD(ProcAddress)+1)^):=RestoreDATA^.val2;
Result:=VirtualProtect(ProcAddress,5,OldProtect,OldProtect);
end;
{-----------------------------------------------------------------------------
Установка перехвата функции по её указаелю
Procedure: SetCodeHook
ProcAddress, указатель на целевую функцию
NewProcAddress:pointer; указатель на функцию перехватчик
RestoreDATA FunctionRestoreData Указатель на мост к старой функции
Result: boolean успешность
-----------------------------------------------------------------------------}
function SetCodeHook(ProcAddress, NewProcAddress: pointer; RestoreDATA FunctionRestoreData):boolean;
var
OldProtect, JMPValue WORD;
begin
Result:=False;
if not VirtualProtect(ProcAddress,5,PAGE_EXECUTE_READWRITE,OldProtect) then exit;
JMPValue := DWORD(NewProcAddress) - DWORD(ProcAddress) - 5;
RestoreDATA^.val1:= Byte(ProcAddress^);
RestoreDATA^.val2:= DWORD(Pointer(DWORD(ProcAddress)+1)^);
RestoreDATA^.Address:=ProcAddress;
byte(ProcAddress^):=$E9;
DWORD(Pointer(DWORD(ProcAddress)+1)^):=JMPValue;
Result:=VirtualProtect(ProcAddress,5,OldProtect,OldProtect);
end;
{-----------------------------------------------------------------------------
Загрузка DLL в чужой проццесс
Procedure: LoadLibrary_Ex
ProcessID WORD;
LibName Char
Result: boolean
-----------------------------------------------------------------------------}
function LoadLibrary_Ex(ProcessID WORD;LibName Char):boolean;
var
pLL,pDLLPath ointer;
hProcess,hThr:THandle;
LibPathLen,_WR,ThrID WORD;
begin
Result:=False;
LibPathLen:=Length(string(LibName));
hProcess:=OpenProcess(PROCESS_ALL_ACCESS,false,ProcessID);
if hProcess=0 then exit;
pDLLPath:=VirtualAllocEx(hProcess,0,LibPathLen+1,MEM_COMMIT,PAGE_READWRITE);
if DWORD(pDLLPath)=0 then exit;
pLL:=GetProcAddress(GetModuleHandle(kernel32),'LoadLibraryA');
WriteProcessMemory(hProcess,pDLLPath,LibName,LibPathLen+1,_WR);
hThr:=CreateRemoteThread(hProcess,0,0,pLL,pDLLPath,0,ThrID);
if hThr=0 then exit;
Result:=CloseHandle(hProcess);
end;
function GetProcessID;
var
Snap: dword;
Process: TPROCESSENTRY32;
begin
Result := 0;
Snap := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if Snap <> INVALID_HANDLE_VALUE then
begin
Process.dwSize := SizeOf(TPROCESSENTRY32);
if Process32First(Snap, Process) then
repeat
if lstrcmpi(Process.szExeFile, pchar(ProcessName)) = 0 then
begin
Result := Process.th32ProcessID;
CloseHandle(Snap);
Exit;
end;
until not Process32Next(Snap, Process);
Result := 0;
CloseHandle(Snap);
end;
end;
Function GetProcessName;
var Snapshot:THandle;
Process: TPROCESSENTRY32;
begin
Result:='';
Snapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if Snapshot = INVALID_HANDLE_VALUE then exit;
Process.dwSize := SizeOf(TPROCESSENTRY32);
if Process32First(SnapShot, Process) then
repeat
if ProcessID=Process.th32ProcessID then
begin
Result := Process.szExeFile;
CloseHandle(Snapshot);
Exit;
end;
until not Process32Next(Snapshot, Process);
CloseHandle(Snapshot);
end;
function EnableDebugPrivilege:Boolean;
var
hToken: dword;
SeDebugNameValue: Int64;
tkp: TOKEN_PRIVILEGES;
ReturnLength: dword;
begin
Result:=false;
//Получаем токен нашего процесса
OpenProcessToken(INVALID_HANDLE_VALUE, TOKEN_ADJUST_PRIVILEGES
or TOKEN_QUERY, hToken);
//Получаем LUID привилегии
if not LookupPrivilegeValue(nil, 'SeDebugPrivilege', SeDebugNameValue) then
begin
CloseHandle(hToken);
exit;
end;
tkp.PrivilegeCount := 1;
tkp.Privileges[0].Luid := SeDebugNameValue;
tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
//Добавляем привилегию к процессу
AdjustTokenPrivileges(hToken, false, tkp, SizeOf(TOKEN_PRIVILEGES),
tkp, ReturnLength);
Result:= GetLastError = ERROR_SUCCESS;
end;
Function StopProcess(ProcessID: DWORD): boolean;
var
Snapshot,cThr: dword;
ThrHandle: THandle;
Thread:TThreadEntry32;
begin
Result := False;
cThr := GetCurrentThreadId;
Snapshot := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if Snapshot <> INVALID_HANDLE_VALUE then
begin
Thread.dwSize := SizeOf(TThreadEntry32);
if Thread32First(Snapshot, Thread) then
repeat
if (Thread.th32ThreadID <> cThr) and (Thread.th32OwnerProcessID = ProcessID) then
begin
ThrHandle := OpenThread(THREAD_ALL_ACCESS, false, Thread.th32ThreadID);
if ThrHandle = 0 then Exit;
SuspendThread(ThrHandle);
CloseHandle(ThrHandle);
end;
until not Thread32Next(Snapshot, Thread);
Result:=CloseHandle(Snapshot);
end;
end;
Function ResumeProcess(ProcessID: DWORD): Boolean;
var
Snapshot,cThr: DWORD;
ThrHandle: THandle;
Thread:TThreadEntry32;
begin
Result := False;
cThr := GetCurrentThreadId;
Snapshot := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if Snapshot <> INVALID_HANDLE_VALUE then
begin
Thread.dwSize := SizeOf(TThreadEntry32);
if Thread32First(Snapshot, Thread) then
repeat
if (Thread.th32ThreadID <> cThr) and (Thread.th32OwnerProcessID = ProcessID) then
begin
ThrHandle := OpenThread(THREAD_ALL_ACCESS, false, Thread.th32ThreadID);
if ThrHandle = 0 then Exit;
ResumeThread(ThrHandle);
CloseHandle(ThrHandle);
end;
until not Thread32Next(Snapshot, Thread);
Result := CloseHandle(Snapshot);
end;
end;
end.
|
Страницы: [1] [2] [Следующая »]
Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.
|