C/C++ *Example* | "Продвинутое" отключение XP

Ответить
Аватара пользователя
hasherfrog

C/C++ *Example* | "Продвинутое" отключение XP

Сообщение hasherfrog »

Несколько вопросов обсуждались в разное время на форуме.

1. Как заставить ХР предупредить о подключенных соединениях при выключении машины;

2. Как прервать отключение машины, если что-то забыл сделать.



Поскольку я сейчас чем-то подобным занимаюсь, набросал небольшую программку, предназначенную для отключения XP машин. Её можно использовать вместо стандарного Shutdown в меню Пуск.





Код:

Код: Выделить всё

#ifndef UNICODE 
#define UNICODE 
#endif 
#include  
#include  
#include  
#include  
#include  
#include  
// собранная информация о сессиях 
static wchar_t * pszSessions = NULL; 
// добавление очередной записи к хранилищу 
void save_session(const wchar_t * fmt, ...) 
{     
    // размер очередной строки, ориентировочно ~100 байт 
    int size = 100; 
    // память под очередную строку 
    wchar_t *p = (wchar_t *) malloc(size * sizeof(wchar_t)); 
    // безопасность 
    if (!p) return; p[0] = '\0'; 
    // формируем строку 
    va_list ap; 
    while (1) 
    { 
	// попытаемся вместиться в уже выделенную память 
	va_start(ap, fmt); 
	// реальная длина новой строки 
	int n = _vsnwprintf(p, size, fmt, ap); 
	va_end(ap); 
	// если влезли, ок 
	if (n > -1 && n < size) break; 
	// иначе - увеличиваем буфер под строку 
	size *= 2; 
	if ((p = (wchar_t *) realloc(p, size * sizeof(wchar_t))) == NULL) return; //oops 
    } 
    // строку сформирована, надо её добавить к имеющимся 
    size = lstrlen(p); 
    if (pszSessions) size += lstrlen(pszSessions); 
    wchar_t *pn = (wchar_t *)malloc((size + 1)*sizeof(wchar_t)); //eos 
    if (!pn) return; pn[0] = '\0'; 
    //складываем строки 
    if (pszSessions) lstrcpy(pn, pszSessions); 
    lstrcat(pn, p); 
    free(p); 
    free(pszSessions); 
    pszSessions = pn; 
    return; 
} 
//int main(int argc, wchar_t *argv[]) 
int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrev,LPSTR lpszCmd,int nCmd) 
{ 
    DWORD dwTotalCount = 0; 
    NET_API_STATUS nStatus; 
     
    // начальная фраза сообщения 
    save_session(L"%s", L"Warning! Some sessions are not closed:\n\n"); 
   
    // для всех имеющихся соединений 
    do 
    { 
	LPSESSION_INFO_10 pBuf = NULL; 
	DWORD dwEntriesRead = 0; 
	DWORD dwTotalEntries = 0; 
	DWORD dwResumeHandle = 0; 
	// вызываем очередной NetSessionEnum 
	nStatus = NetSessionEnum(NULL,	//всё локально 
				NULL,	//для всех сессий 
				NULL, 	//для всех пользователей 
				10,	//тип запроса хост-юзер-время-простой 
				(LPBYTE*)&pBuf,	//данные на выходе 
				MAX_PREFERRED_LENGTH, //длина записи 
				&dwEntriesRead,	//сколько считано 
				&dwTotalEntries,		//сколько всего 
				&dwResumeHandle);	//номер запроса 
	// проверяем результат 
	if ((nStatus == NERR_Success) || (nStatus == ERROR_MORE_DATA)) 
	{ 
	    // запоминаем сессии клиентов 
	    if (LPSESSION_INFO_10 pTmpBuf = pBuf) 
		for (int i = 0; i < dwEntriesRead; i++) 
		    if (pTmpBuf) 
		    { 
			save_session(L"Client: %s\tUser: %s\tActive: %d\tIdle: %d\n", 
				     pTmpBuf->sesi10_cname, pTmpBuf->sesi10_username, 
				     pTmpBuf->sesi10_time, pTmpBuf->sesi10_idle_time); 
			pTmpBuf++; 
			dwTotalCount++; 
		    } 
	} 
	// идём на следующий запрос 
	if (pBuf) 
	{ 
	    NetApiBufferFree(pBuf); 
	    pBuf = NULL; 
	} 
    } while (nStatus == ERROR_MORE_DATA); 
     
    // если есть сессии, сообщаем об этом выключателю 
    if (dwTotalCount) 
    { 
	// финальная часть сообщения 
	save_session(L"%s", L"\nDo you wish to cancel shutdown?\n"); 
	// вывод сообщения 
	if (IDYES == MessageBox(NULL, pszSessions, L"Warning!", MB_YESNO)) return 0; 
    } 
    //чистим память от сообщения - оно нам больше не нужно 
    free(pszSessions); 
     
    HANDLE hToken;              // handle to process token 
    TOKEN_PRIVILEGES tkp;       // pointer to token structure 
    // Get the current process token handle so we can get shutdown privilege. 
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, 
			  &hToken)) return 1; 
     
    // Get the LUID for shutdown privilege. 
    LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid); 
    tkp.PrivilegeCount = 1;  // one privilege to set 
    tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 
     
    // Get shutdown privilege for this process. 
    AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0); 
    if (GetLastError() != ERROR_SUCCESS) return 1; 
     
    // Вывести окошечко обратного отсчёта 
    if (!InitiateSystemShutdown( 
	    NULL,    // shut down local computer 
	    L"We starts system shutdown.\nIf You have forget to do something, press " 
	    L"Ok in message box for stop shutdown.",   // message for user 
	    20,      // time-out period 
	    FALSE,   // ask user to close apps 
	    FALSE)) //shutdown, no reboot 
	return 1; 
     
    // Disable shutdown privilege. 
    tkp.Privileges[0].Attributes = 0; 
    AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0); 
     
    MessageBox(NULL, L"Press OK to stop shutdown", L"Haves forget somehing?", 
	       MB_OK | MB_SYSTEMMODAL); 
    // если мы сюда попали, надо отключать шатдаун 
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, 
			  &hToken)) return 1; 
    LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid); 
    tkp.PrivilegeCount = 1; 
    tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 
    AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0); 
    if (GetLastError() != ERROR_SUCCESS) return 1; 
     
    // Prevent the system from shutting down. 
    if ( !AbortSystemShutdown(NULL) ) return 1; 
    // Disable shutdown privilege. 
    tkp.Privileges[0].Attributes = 0; 
    AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0); 
     
    return 0; 
}

FAQ



Q. И как использовать?

A. Компилите. Кладёте ярлык на рабочий стол. При необходимости выключить машину жмёте не Пуск->Выключить, а щёлкаете по этому ярлыку. Он Вас спросит про активные подключения (если они есть). Потом даст 20 секунд на раздумья. Потом выключится.



Q. Почему C++, а не, скажем, VBS?

A. Потому что C++ мне ближе.



Q. Как компилить?

A. Я использую Visual C++ Toolkit. Компиляция:

cl enum_shares.cpp /GA /O1 /link /defaultlib:netapi32.lib /defaultlib:advapi32.lib /defaultlib:user32.lib[/i]



Q. А в 9х будет работать?

A. Нет. В 9х сообщение об активных подключениях и так выдается.



Q. Почему UNICODE?

A.Потому что NetSessionEnum



Q. Что так странно (в смысле стиля написания) сформирован текст и комментарии?

A. Потому что при написании использовались фрагменты из PSDK.



Q. А есть ли бинарник?

A. Есть.
Тут
пока лежит.



Q. Можно использовать в моих программах куски текста?

A. Да, сделано специально для посетителей
www.oszone.net




Q. У меня ещё вопросы...

A. Задавайте здесь, я отвечу.
Аватара пользователя
hasherfrog

Re: C/C++ *Example* | "Продвинутое" отключение XP

Сообщение hasherfrog »

Есть маленькая "учечка памяти". Чтобы убрать:

Код: Выделить всё

...
    // если есть сессии, сообщаем об этом выключателю 
    if (dwTotalCount) 
    { 
	// финальная часть сообщения 
	save_session(L"%s", L"\nDo you wish to cancel shutdown?\n"); 
	// вывод сообщения 
	if (IDYES == MessageBox(NULL, pszSessions, L"Warning!", MB_YESNO)) 
        { 
            return 0; 
            free(pszSessions); // <--------- добавить. 
         } 
    } 
    //чистим память от сообщения - оно нам больше не нужно 
    free(pszSessions); 
    ...
Аватара пользователя
DAnG

Re: C/C++ *Example* | "Продвинутое" отключение XP

Сообщение DAnG »

hasherfrog

Хорошая программа.



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

Если вызывать эти функции по таймеру - есть вероятность, что какое-то подключение или открытие файла успеет открыться и закрыться.

Возможно, нужно использовать механизм hook-ов, *можно ли сделать это без существенного снижения производительности системы?
Аватара пользователя
hasherfrog

Re: C/C++ *Example* | "Продвинутое" отключение XP

Сообщение hasherfrog »

DAnG

Таймер однозначно "не катит". Хуки - это да Изображение. Снижение производительности будет очень незначительным. У Руссиновича на
www.sysinternals.com
есть исходник, правда, для линукса. Там же есть бинарники FileMon. Если залезть туда (через HIEW, или ещё как) и посмотреть таблицу используемых системных функций, то хуки наверняка найдутся. Впрочем, я не проверял, так что это только предположение!
Аватара пользователя
hasherfrog

Re: C/C++ *Example* | "Продвинутое" отключение XP

Сообщение hasherfrog »

Некоторые замечания сделаны
здесь
.
Аватара пользователя
DAnG

Re: C/C++ *Example* | "Продвинутое" отключение XP

Сообщение DAnG »

hasherfrog

Кучу времени пользуюсь и tcpview и regmon и filemon, а на сайт авторов так и не заглянул. Позор.

Очень много полезных вещей и с исходниками по windows, что редкость. Спасибо, огромное!.
Аватара пользователя
DAnG

Re: C/C++ *Example* | "Продвинутое" отключение XP

Сообщение DAnG »

Для написания таких программ лучше использовать Visual Basic.



Добавлено:



Кстати, кому надо, могу выложить исходник. Написал программку на VB, она умеет выключать/перезагружать комп, да ещё с такими наворотами (в смысле оформления)...



Добавлено:



И ещё, она может выключать/перезагружать комп в заданное время.
Аватара пользователя
[mzd]

Re: C/C++ *Example* | "Продвинутое" отключение XP

Сообщение [mzd] »

Guest

Для системного программирования, IMHO, лучше С++ ничего нет.

VB для этого не разрабатывался



[s]Исправлено: [mzd], 19:20 15-08-2004[/s]
Аватара пользователя
StasIs

Re: C/C++ *Example* | "Продвинутое" отключение XP

Сообщение StasIs »

Тема все еще акуальна а ссылки на скомпилиную прогу от hasherfrog уже мертвые Изображение

можно ли перезалить или на мыло stasisСОБАКАpisem.net сбросить? или кто перекомпилит поновой?
Ответить

Вернуться в «Программирование и базы данных»