Russian Qt Forum

Qt => Вопросы новичков => Тема начата: virtual_root от Июль 05, 2012, 16:11



Название: Блокировка экрана
Отправлено: virtual_root от Июль 05, 2012, 16:11
Добрый день ребята снова) Подскажите, пожалуйста есть ли в Qt какая-нибудь функция для проверки заблокирован ли экран системы? В winAPI есть фун-я LockWorkStation она блокирует экран, а в Qt есть аналоги платформонезависимые и чтоб проверить можно было, заблокирован ли экран.


Название: Re: Блокировка экрана
Отправлено: Пантер от Июль 05, 2012, 16:47
Нет.


Название: Re: Блокировка экрана
Отправлено: virtual_root от Июль 05, 2012, 17:01
Пантер, а вы не подскажите как с помощью winAPI проверить заблокирован ли экран?


Название: Re: Блокировка экрана
Отправлено: DmitryM от Июль 05, 2012, 17:11
Пантер, а вы не подскажите как с помощью winAPI проверить заблокирован ли экран?
How to Lock the Workstation (http://msdn.microsoft.com/en-us/library/windows/desktop/aa376869(v=vs.85).aspx)


Название: Re: Блокировка экрана
Отправлено: virtual_root от Июль 05, 2012, 17:26
почему-то я не могу воспользоваться этой фун-ей LockWorkStation()... какой заголовочный файл ей нужен?


Название: Re: Блокировка экрана
Отправлено: DmitryM от Июль 05, 2012, 17:43
почему-то я не могу воспользоваться этой фун-ей LockWorkStation()... какой заголовочный файл ей нужен?
Гугл забанил?
Код
C++ (Qt)
#define _WIN32_WINNT 0x0500
#define WINVER 0x0500
 
#include <windows.h>
 
#include <cstdio>
 
#pragma comment( lib, "user32.lib" )
 
int main()
{
   // Lock the workstation.
 
   if( !LockWorkStation() )
       printf ("LockWorkStation failed with %d\n", GetLastError());
   return 0;
}
 


Название: Re: Блокировка экрана
Отправлено: virtual_root от Июль 05, 2012, 17:44
да-да уже разобралась, спасибо. Но дело в том что эта фун-я не возвращает никакого значения как вы ей так воспользовались?


Название: Re: Блокировка экрана
Отправлено: virtual_root от Июль 05, 2012, 17:56
нашла фун-ю с помощью которой можно отслеживать, инф-ю о том что пользователь заблокировал экран, разлогинился. Эта фун-я WTSRegisterSessionNotification. Но у меня никак не получается её использовать.. Вот код:
Код:
QLibrary myLib("./user32");

        myLib.load();
        myLib.loadHints();

        if (!myLib.isLoaded())
            exit(0);

        typedef void (*MyPrototype)();
        MyPrototype myFunction = (MyPrototype) myLib.resolve("LockWorkStation"); // фун-я блокировки экрана

        typedef bool (*MyPrototype2)(HWND,DWORD);
        MyPrototype2 WTSRegisterSessionNotification = (MyPrototype2) myLib.resolve("WTSRegisterSessionNotification");

        if (!WTSRegisterSessionNotification(GetDesktopWindow(),NOTIFY_FOR_THIS_SESSION)) qDebug()<<"no";
        else qDebug()<<"yes";
Подскажите кто работал с этой фун-ей, пожалуйста! Как мне с её помощью отлавливать состояние сессии? Может на неё можно хук поставить, стобы получать событие о том что пользователь заблокировал экран?


Название: Re: Блокировка экрана
Отправлено: Alex Custov от Июль 05, 2012, 18:00
вы можете по порядку, строчку за строчкой, объяснить этот код, и почему он написан именно так?


Название: Re: Блокировка экрана
Отправлено: virtual_root от Июль 05, 2012, 18:13
в этом коде я импортируюю dll теперь переделала на wtsapi32 - эту dll подключаю. Оборачиваю фун-ю из неё в прототип потом вызываю её. Изменила на WTSRegisterSessionNotification(GetDesktopWindow(),0)) и всё заработало. GetDesktopWindow() - api фун-я возвращает дескриптор рабочего стола. Но что-то блокировку экрана так и не ловит.. я в таймере эту фун-ю WTSRegisterSessionNotification(GetDesktopWindow(),0)) вызываю. Может у кого есть идеи как отловить блокировку экрана?


Название: Re: Блокировка экрана
Отправлено: kambala от Июль 05, 2012, 18:23
танцы с resolve() нужны только если не знаешь поддерживает ли целевая система эти функции. а если уж пользоваться resolve(), то по-хорошему надо проверять полученный указатель на 0.

а как ловить событие – ну надо документацию читать:
Цитировать
Session change notifications are sent in the form of a WM_WTSSESSION_CHANGE message. These notifications are sent only to the windows that have registered for them using this function.

When a window no longer requires these notifications, it must call WTSUnRegisterSessionNotification before being destroyed. For every call to this function, there must be a corresponding call to WTSUnRegisterSessionNotification.


Название: Re: Блокировка экрана
Отправлено: Alex Custov от Июль 05, 2012, 18:25
В документации написано, что WTSRegisterSessionNotification регистрирует нотификацию, а не возвращает сразу статус блокировки. Возвращает она статус операции по установке нотификатора. Нотификация отправляется в указанное в WTSRegisterSessionNotification окно, зачем вы передаёте туда desktop?


Название: Re: Блокировка экрана
Отправлено: Serr500 от Июль 05, 2012, 20:27
virtual_root, Вы невнимательно читали документацию. Функция WTSRegisterSessionNotification регистрирует окно, которое будет получать сообщение WM_WTSSESSION_CHANGE. Передаёте в неё дескриптор окна и в его оконной процедуре ловите WM_WTSSESSION_CHANGE. В словленном сообщении смотрите на wParam. Если он WTS_SESSION_LOCK, то юзер заблокировал сессию, если WTS_SESSION_UNLOCK - разблокировал. Так же можно ловить logon и logout. http://msdn.microsoft.com/en-us/library/windows/desktop/aa383828%28v=vs.85%29.aspx (http://msdn.microsoft.com/en-us/library/windows/desktop/aa383828%28v=vs.85%29.aspx)


Название: Re: Блокировка экрана
Отправлено: virtual_root от Июль 06, 2012, 09:56
Ребята спасибо, я поняла. Только никак не могу понять как мне тогда ловить сообщения от фун-и WTSRegisterSessionNotification ? Надо же как-то подписаться на них что ли? Я так понимаю, что мне в неё нужно передать дескриптор своего приложения и мне потом будут приходить сообщения, а каким образом мне на них обработчик поставить, ну что-то вроде связать приход сообщения с функ-ей
Код:
LRESULT CALLBACK WindowProc(
  HWND hWnd,       // handle to window
  UINT Msg,        // WM_WTSSESSION_CHANGE
  WPARAM wParam,   // session state change event
  LPARAM lParam    // session ID
);

Я же должна где - то указать что именно ей отправлять сообщение на обработку? И как можно получить дескриптор моего окна, если я планирую приложение сделать без интерфейсным, как службу. Как мне сказать что имено в неё должны приходить сообщения от фун-и WTSRegisterSessionNotification ?
Только не сердитесь, пожалуйста, подскажите мне, чтоб до ума довести))


Название: Re: Блокировка экрана
Отправлено: Serr500 от Июль 06, 2012, 10:39
Ещё раз. WTSRegisterSessionNotification не выдаёт никаких сообщений. Дескриптор нужен не приложения, а окна. Я рекомендую создать функциями WinAPI невидимое окно, подписать его на WM_WTSSESSION_CHANGE и подменить его оконную процедуру. Если это сложно, то можно подписать на сообщение существующее окно. Дескриптор окна можно получить методом QWidget::winId, его и передаём в WTSRegisterSessionNotification. Затем перехватываем оконные сообщения, переопределив у виджета виртуальный метод QWidget::winEvent. В его первом параметре MSG *message проверяем Msg и wParam. Если они те, что нам нужны, генерируем сигнал или делаем что-то другое. Не забудьте в конце вызвать winEvent родителя.


Название: Re: Блокировка экрана
Отправлено: virtual_root от Июль 06, 2012, 11:26
Спасибо! Я попробовала ловить сообщения, вроде что-то приходит. ну я не знаю как этот ответ разобрать и достать от туда wParam... И ещё моё приложение зависает после прихода сообщения...  функцию родителя winevent(MSG,long) вроде вызвала, ну приложение висит... Подскажите, пожалуйста, что я не так сделала????
Вот код:
Код:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <Windows.h>
#include <wtsapi32.h>
#include <winbase.h>
#include <winuser.h>
#include <ws2spi.h>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT
    
public:
    static MainWindow* instance();
    ~MainWindow();
protected:
    bool winEvent(MSG *message, long *result);
    
private:
    explicit MainWindow(QWidget *parent = 0);
    Ui::MainWindow *ui;
    typedef bool (*MyPrototype2)(HWND,DWORD);
    MyPrototype2 WTSRegisterSessionNotification;
protected slots:
  
};

#endif // MAINWINDOW_H


файл .cpp
Код:
#include "mainwindow.h"
#include "ui_mainwindow.h"


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    QLibrary myLib("wtsapi32");

        myLib.load();
        myLib.loadHints();

        if (!myLib.isLoaded())
            exit(0);

        QLibrary myLib2("user32");

            myLib2.load();
            myLib2.loadHints();

            if (!myLib2.isLoaded())
                exit(0);

         WTSRegisterSessionNotification = (MyPrototype2) myLib.resolve("WTSRegisterSessionNotification");
         if (!WTSRegisterSessionNotification)
                 exit(0);
         else WTSRegisterSessionNotification(MainWindow::winId(),0);  // регестрируем наше окно на получение сообщения. Здесь всё правильно?

         typedef BOOL (*MyPrototype)();
         MyPrototype myFunction = (MyPrototype) myLib2.resolve("LockWorkStation"); // фун-я блокировки экрана
         if (!myFunction()) qDebug()<<"!!!!";  // вызываю блокировку экрана

  
 }

MainWindow::~MainWindow()
{
    delete ui;
}


MainWindow* MainWindow::instance(){
    static MainWindow* MainWindowPTR = new MainWindow();
    return MainWindowPTR;
}

bool MainWindow::winEvent(MSG *message, long *result){
    qDebug()<<message<<"\n"<<result;    // как мне вытащить здесь wParam ???
    this->winEvent(message,result);
}

Может я неправильно вызываю функцию родителя?


Название: Re: Блокировка экрана
Отправлено: virtual_root от Июль 06, 2012, 11:38
Мне кажется что эта фун-я WTSRegisterSessionNotification  мне бесконечно много шлёт сообщений и поэтому моя программа зависает, а при вызове родительской фун-и WinEvent вообще падает. Я точно что-то не так сделала... Мне нужно получать сообщения о блокировки,разблокировки экрана всё время пока моя программа работает. Подскажите, пожалуйста, что я не так пишу в коде? Может где-то надо добавить фун-ю
Код:

LRESULT CALLBACK WindowProc(
  HWND hWnd,       // handle to window
  UINT Msg,        // WM_WTSSESSION_CHANGE
  WPARAM wParam,   // session state change event
  LPARAM lParam    // session ID
);
И где-то её связать с сообщениями?


Название: Re: Блокировка экрана
Отправлено: Bepec от Июль 06, 2012, 11:56
Вы действительно не понимаете что делаете?

Помоему вам лучше почитать про winApi, С++ и программирование. Многое почерпнёте.

Код:
bool MainWindow::winEvent(MSG *message, long *result){
    qDebug()<<message<<"\n"<<result;    // как мне вытащить здесь wParam ???
    this->winEvent(message,result);
}

На пальцах - по другому вы не поймете, помоему (как низко я вас оценил однако Оо):

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

Этот метод winEvent. Он ПОКАЗЫВАЕТ вам сообщения, пришедшие вашему окну. И посмотрите на тип функции - bool. Вот что она должна возвращать, а не вызывать себя 100500 раз до посинения.


Название: Re: Блокировка экрана
Отправлено: Serr500 от Июль 06, 2012, 12:11
1) Не this->winEvent, а QMainWindow::winEvent.
2) wParam получается так: message->wParam

И поймите, наконец, что WTSRegisterSessionNotification НИКОМУ НИЧЕГО НЕ ШЛЁТ! Она ПОДПИСЫВАЕТ окно на сообщения.


Название: Re: Блокировка экрана
Отправлено: Serr500 от Июль 06, 2012, 12:25
Вот Вам минимальный проект, который показывает, как работать с этими сообщениями. Сделал "на коленке" за 5 минут.


Название: Re: Блокировка экрана
Отправлено: virtual_root от Июль 06, 2012, 12:37
Спасибо вам большое ребята! У вас большой опыт, я уже второй день с этим вожусь...
Я извиняюсь, что задаю глупые вопросы, порой я действительно не понимаю как делать.. Я только пол года программирую, опыта нет, а обратиться больше не к кому, как не к googly и на форумы.


Название: Re: Блокировка экрана
Отправлено: Alex Custov от Июль 06, 2012, 12:48
Спасибо вам большое ребята! У вас большой опыт, я уже второй день с этим вожусь...
Я извиняюсь, что задаю глупые вопросы, порой я действительно не понимаю как делать.. Я только пол года программирую, опыта нет, а обратиться больше не к кому, как не к googly и на форумы.

Вы ничему не научитесь, если не будут писать много кода и внимательно читать документацию от корки до корки. В данной теме вы ТРИЖДЫ писали код, который полностью противоречит документации.


Название: Re: Блокировка экрана
Отправлено: virtual_root от Июль 06, 2012, 12:50
Да-да, пишу пишу каждый день упражняюсь и документацию читаю, только она на английском и походу я не всегда её правильно понимаю) У меня всё получилось!!! Спасибо всем!!!! :)


Название: Re: Блокировка экрана
Отправлено: virtual_root от Июль 06, 2012, 12:58
У меня тут ещё один вопросик... а можно ли этот код вынести в отдельный поток?  Меня затрудняет получение дескриптора окна и обработка сообщений, ведь класс будет наследоваться от QThread. Или это в принципе нельзя засунуть в поток?
И ещё один вопросик. а если я этот проект как службу буду делать, то тогда придется создавать прозрачную форму, чтоб осталась возможность получать сообщения, так ?


Название: Re: Блокировка экрана
Отправлено: Bepec от Июль 06, 2012, 13:04
Если такими темпами будете делать службу, то думаю мы присутствуем при создании Microsoft 8 Skynet Edition made virtual_root.

Как бы все службы имеют hwid. Просто ты их не видишь и не ощущаешь.


Название: Re: Блокировка экрана
Отправлено: Serr500 от Июль 06, 2012, 13:15
У меня тут ещё один вопросик... а можно ли этот код вынести в отдельный поток?  Меня затрудняет получение дескриптора окна и обработка сообщений, ведь класс будет наследоваться от QThread. Или это в принципе нельзя засунуть в поток?
И ещё один вопросик. а если я этот проект как службу буду делать, то тогда придется создавать прозрачную форму, чтоб осталась возможность получать сообщения, так ?
Можно. 1-й вариант - запихнуть в QThread, в котором есть Event Loop, пустой виджет и ловить на нём сообщения. Вероятно, это Вам будет проще всего. Не забудьте потом сделать виджету moveToThread, иначе обработчик будет "крутиться" не в том потоке. 2-й вариант, с моей точки зрения более правильный, создание собственного окна, которое будет только ловить сообщения и не отображаться. Аналогично можно поступать и в случае создания собственной службы.


Название: Re: Блокировка экрана
Отправлено: virtual_root от Июль 06, 2012, 13:28
а что вы подразумеваете под создание собственного окна? Окно наследованное от стандартных виджетов(QWidget, QMainWindow) или как его создать?


Название: Re: Блокировка экрана
Отправлено: Serr500 от Июль 06, 2012, 13:43
Собственное окно создаётся функциями WinAPI, никакого наследования от стандартных виджетов не будет. Создаётся оно с помощью двух функций RegisterClass и CreateWindow(Ex). Пример создания собственного окна можно найти здесь: http://www.codenet.ru/progr/visualc/windows.php (http://www.codenet.ru/progr/visualc/windows.php).


Название: Re: Блокировка экрана
Отправлено: virtual_root от Июль 06, 2012, 16:11
спасибо поняла. Попробую)
У меня возникла маленькая проблемка: пытаюсь получить список активных процессов с помощью этой фун-и WTSEnumerateProcesses. В документации написано что для работы с ней нужен всё тот же файл Wtsapi32.h и его dll. Всё это у меня уже было подключено, но почему-то компилятор ругается: 'WTSEnumerateProcesses' was not declared in this scope'  Что ему ещё не хватает??? и он не видит структуру WTS_PROCESS_INFO которая тоже относится всё к тому же файлу Wtsapi32.h
Я по ссылке прошла в этот файл, и честно говоря не нашла там ни этой фун-и ни этой структуры, походу поэтому и он не видит... Кто нибудь знает что нужно подключить дополнительно для работы с этой фун-ей и структурой?


Название: Re: Блокировка экрана
Отправлено: Alex Custov от Июль 06, 2012, 16:15
WTSEnumerateProcesses: http://msdn.microsoft.com/en-us/library/windows/desktop/aa383831%28v=vs.85%29.aspx

Minimum supported client Windows 2000 Professional

Modifying WINVER and _WIN32_WINNT: http://msdn.microsoft.com/en-us/library/6sehtctf.aspx


Название: Re: Блокировка экрана
Отправлено: virtual_root от Июль 06, 2012, 16:25
у меня windows 7. Добавила эти строчки #define WINVER 0x0500
#define _WIN32_WINNT 0x0500
Но увы они не помогли...


Название: Re: Блокировка экрана
Отправлено: Alex Custov от Июль 06, 2012, 16:42
похоже что это вообще для Terminal Server. В обычном Win32 API есть функция EnumProcesses:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms682623%28v=vs.85%29.aspx


Название: Re: Блокировка экрана
Отправлено: Serr500 от Июль 06, 2012, 19:18
у меня windows 7. Добавила эти строчки #define WINVER 0x0500
#define _WIN32_WINNT 0x0500
Но увы они не помогли...
Компилятор какой? Если MinGW, то этой функции в хедерах нет. Определяйте самостоятельно. Вот вырезка из WtsApi32.h, котрый лежит в Win SDK 7.1:
Код:
/*=====================================================================
==   WTS_PROCESS_INFO - returned by WTSEnumerateProcesses (version 1)
=====================================================================*/

/*
 *  WTSEnumerateProcesses() also returns data similar to
 *  WTSEnumerateServers().  It returns two variables: pProcessInfo and
 *  Count.  The latter is the number of WTS_PROCESS_INFO structures
 *  contained in the former.  Iteration is similar, except that there
 *  are four parts to each entry, so it would look like this:
 *
 *  for ( i=0; i < Count; i++ ) {
 *      GetUserNameFromSid( pProcessInfo[i].pUserSid, UserName,
 *                          sizeof(UserName) );
 *      _tprintf( TEXT("%-5u  %-20s  %-5u  %s\n"),
 *              pProcessInfo[i].SessionId,
 *              UserName,
 *              pProcessInfo[i].ProcessId,
 *              pProcessInfo[i].pProcessName );
 *  }
 *
 *  The memory returned is also segmented as the above, with all the
 *  structures allocated at the start and the string data at the end.
 *  We'll use S for the SessionId, R for the ProcessId, P for the
 *  pProcessName pointer and D for the string data, and U for pUserSid:
 *
 *  S1 R1 P1 U1 S2 R2 P2 U2 S3 R3 P3 U3 ... Sn Rn Pn Un D1 D2 D3 ... Dn
 *
 *  As above, this makes it easier to iterate the processes.
 */

typedef struct _WTS_PROCESS_INFOW {
    DWORD SessionId;     // session id
    DWORD ProcessId;     // process id
    LPWSTR pProcessName; // name of process
    PSID pUserSid;       // user's SID
} WTS_PROCESS_INFOW, * PWTS_PROCESS_INFOW;

typedef struct _WTS_PROCESS_INFOA {
    DWORD SessionId;     // session id
    DWORD ProcessId;     // process id
    LPSTR pProcessName;  // name of process
    PSID pUserSid;       // user's SID
} WTS_PROCESS_INFOA, * PWTS_PROCESS_INFOA;

#ifdef UNICODE
#define WTS_PROCESS_INFO  WTS_PROCESS_INFOW
#define PWTS_PROCESS_INFO PWTS_PROCESS_INFOW
#else
#define WTS_PROCESS_INFO  WTS_PROCESS_INFOA
#define PWTS_PROCESS_INFO PWTS_PROCESS_INFOA
#endif

/*------------------------------------------------*/

BOOL
WINAPI
WTSEnumerateProcessesW(
    IN HANDLE hServer,
    IN DWORD Reserved,
    IN DWORD Version,
    OUT PWTS_PROCESS_INFOW * ppProcessInfo,
    OUT DWORD * pCount
    );

BOOL
WINAPI
WTSEnumerateProcessesA(
    IN HANDLE hServer,
    IN DWORD Reserved,
    IN DWORD Version,
    OUT PWTS_PROCESS_INFOA * ppProcessInfo,
    OUT DWORD * pCount
    );

#ifdef UNICODE
#define WTSEnumerateProcesses WTSEnumerateProcessesW
#else
#define WTSEnumerateProcesses WTSEnumerateProcessesA
#endif