Click here to Skip to main content
15,879,068 members
Articles / Programming Languages / C++

QServiceTool - A Beginner's Guide to Qt and NT Services

Rate me:
Please Sign up or sign in to vote.
4.91/5 (13 votes)
18 May 2003CPOL6 min read 120.5K   1.1K   27   27
A Qt based tool designed to control Windows NT services (start, stop, pause, continue) and to show information about them.

ATTENTION: This program only works on Windows NT, 2000, XP and up, and only if you have Administrator rights at your machine.

Image 1

Introduction

This entire site is mainly focused on Microsoft related code and tools, that's why I thought of writing an article about an alternative GUI-Toolkit named Qt. Qt is currently being developed by Trolltech [^], Norway.

In this article, I want to show step-by-step how to write a Qt-based program. The sample program to be written is going to control Windows NT services. It will be able to enumerate and list the available services, start, stop, pause and continue certain ones, and to show general information about the selected service.

About Qt (from Qt documentation)

Qt is a cross-platform C++ GUI application framework. It provides application developers with all the functionality needed to build state-of-the-art graphical user interfaces. Qt is fully object-oriented, easily extensible, and allows true component programming. Since its commercial introduction in early 1996, Qt has formed the basis of many thousands of successful applications worldwide. Qt is also the basis of the popular KDE[^] Linux desktop environment, a standard component of all major Linux distributions.

Qt is supported on the following platforms:

  • MS/Windows - 95, 98, NT and 2000 (and up).
  • Unix/X11 - Linux, Sun Solaris, HP-UX, Digital Unix, IBM AIX, SGI IRIX and a wide range of others.
  • Embedded - Linux platforms with frame buffer support.

Qt is released in different editions with different licenses:

  • Qt Enterprise Edition and Qt Professional Edition - permits traditional commercial software distribution, includes free upgrades and technical support.
  • Qt Non-Commercial Edition - available for evaluation purposes and non-commercial development of free software.
  • Qt Free Edition - available for development of Free and Open Source software only (GPL).

Step 1: Deriving a Class

Though Qt is heavily object-orientated, it is necessary to derive a new class QServiceTool from QWidget, which is the base class of all user interface objects and itself derived from QObject (derived from Qt) and QPaintDevice. But that is not the only point to consider. Qt supports so-called signals and slots, which are used for communication between objects. The signal/slot mechanism (we'll get back to this later) is a central feature of Qt and probably the part that differs most from other toolkits. To enable this feature, the keyword Q_OBJECT must be written immediately after the opening brace, and the slots that receive certain signals have their own section:

#include <qwidget.h>


class QServiceTool : public QWidget
 {
  Q_OBJECT

  public:
    QServiceTool(QWidget* parent, const char* name);
    ~QServiceTool();

  public slots: // ... to be added ...
  protected:    // ... to be added ...
  private:      // ... to be added ...
 };

Step 2: User Interface Elements

In this step, the actual user interface is designed. Therefore, it is important to decide what the UI should contain to suit the purpose. First of all, a QListBox is needed to list all the services the program can control. The next are some QPushButtons the user can click on:

  • Start - Start the selected service
  • Stop - Stop the selected service
  • Pause - Pause the selected service
  • Continue - Continue the selected service
  • Update Info - Updates information about the selected service

And to be able to abort an action after a user defined timeout, the timeout can be adjusted by a QSpinBox. Finally, the output is written to a QMultiLineEdit. The class now looks like this:

class QServiceTool : public QWidget
 {
  Q_OBJECT

  public:
    QServiceTool(QWidget* parent, const char* name);
    ~QServiceTool();

  public slots: // ... to be added ...

  protected:
    QListBox*       m_lbServices;
    QSpinBox*       m_sbTimeout;
    QPushButton*    m_btnStart;
    QPushButton*    m_btnStop;
    QPushButton*    m_btnInfo;
    QPushButton*    m_btnPause;
    QPushButton*    m_btnContinue;
    QMultiLineEdit* m_mleOutput;

  private:      // ... to be added ...
 };

This image shows where these GUI items are located:

Image 2

Step 3: Create Slots

To connect a certain action, i.e. function, to a user input, Qt uses slots. These are special functions of a class that can be easily called after user input. Qt therefore uses some macro trickery, and that is why the header file containing the slot definitions must be parsed by moc, the Meta Object Compiler. This program produces a new source file containing some meta object things allowing Qt to easily use these slots. The moc can be used by moc -o moc_QServiceTool.cpp QServiceTool.h if you have installed Qt on your machine. The needed slots are:

C++
...
    public slots:
      void startService(void);
      void stopService(void);
      void pauseService(void);
      void continueService(void);

      void infoService(int doesntmatter);
      void infoService(void);

      void appendText(QString qText);
...

Step 4: Construction of QServiceTool

This is a very important step, because all GUI items are created, configured, and finally shown. This is usually done by:

  // create new item
m_lbServices = new QListBox(this);

  // Configure, e.g.
m_lbServices->setGeometry( x, y, width, height );
...

  // and finally show
m_lbServices->show();

After creating all GUI items, the signals they are emitting are ready for being connected to the slots. This is done by:

C++
bool QObject::connect(const QObject* sender,
const char* signal, const QObject* receiver, const char* member);

... whereas signal is a construction like SIGNAL(clicked()), and member is like SLOT(startService()). Some examples:

QObject::connect(m_btnStart, SIGNAL(clicked()),
                           this, SLOT(startService()));
QObject::connect(m_btnStop, SIGNAL(clicked()),
                            this, SLOT(stopService()));
QObject::connect(m_lbServices, SIGNAL(highlighted(int)),
                         this, SLOT(infoService(int)));

At this point, the program can already be used, but without any functionality, i.e., only the GUI works.

Step 5: Functionality (About Services)

But the GUI functionality is not enough, so let's proceed to the actual functionality. The four main functions (Start, Stop, Pause, Continue) are realized as separate threads that do what they are supposed to do by using some Windows NT API functions. I have to apologize that only Administrators are able to use this program because it needs appropriate rights in order to connect to the service control manager. I think it is possible to modify the program in order to allow also restricted users to control services.

Starting a service is done by the thread named ThreadStartService. The following solution is partly based on the documentation of the Platform SDK (DLLs, Processes, and Threads - Starting a Service). A common WinAPI-thread has the following calling convention:

DWORD WINAPI ThreadStartService(void* pParam);

The parameter pParam contains the name (just char*) of the service to be started, cast to void*. The thread converts the parameter to a usable string by char* name = (char*)pParam;.

Next thing to do is to connect to the service control manager and open the service by:

SC_HANDLE hSCManager = OpenSCManager(NULL, // target computer
                                     NULL, // service control manager database
                                     SC_MANAGER_ALL_ACCESS); // admin access

SC_HANDLE schService = OpenService(hSCManager, // SCM database
                                   name,       // service name
                                   SERVICE_ALL_ACCESS);

To start the opened service, use StartService(...):

if(!StartService(schService, 0, NULL))
 {
  // error handling ...
 }

Now, the service knows that it should start and is in a state called SERVICE_START_PENDING. Simply spoken, the thread then waits until the service leaves this state and checks afterwards whether the service is in state SERVICE_RUNNING, i.e., whether it started successfully. The thread uses QueryServiceStatus(...) to check the state (note: this source has been adapted):

SERVICE_STATUS ssStatus;
if(!QueryServiceStatus(schService, &ssStatus))
 {
  // error handling ...
 }

while(ssStatus.dwCurrentState == SERVICE_START_PENDING)
 {
  Sleep(100);

    // Check the status again.
  if(!QueryServiceStatus(schService, &ssStatus)) { break; }
 }

if(ssStatus.dwCurrentState == SERVICE_RUNNING)
 {
  return 0; // service successfully started
 }

return E_NOT_STARTED; // error during startup

Points of Interest

In my first version, I used the program net supplied with Windows NT to start and stop a service by:

net start service_name
net stop service_name

But this approach was somehow inconvenient, because it opened a command line and waited always some seconds after the actual action. Then I looked into the Platform SDK and found these functions.

Usually, the SERVICE_STATUS::dwWaitHint variable contains a value the service thinks is appropriate to finish its current action, but in some cases like the MySQL service, the stop-hint is extremely high, for example, 86400000. So: don't trust services! Some want you to wait a day to return ...

How to Compile?

Because Qt uses some extensions, it is necessary to use moc as subscribed above. And these lines are also important to avoid linking errors with Visual Studio:

QStringData* QString::shared_null = 0;
extern QApplication* qApp = 0;

The next thing needed is of course Qt including all header files and the import library qt-mt230nc.lib.

To execute a Qt-based program, the Dynamic Link Library qt-mt230nc.dll is needed.

History

  • Mai 19, 2003 - First release 1.0.0.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Question? Service Timeouts Pin
Synetech15-Aug-06 15:21
Synetech15-Aug-06 15:21 
GeneralCool... now for the next article ;) Pin
Peter Mares20-May-03 5:53
Peter Mares20-May-03 5:53 
GeneralRe: Cool... now for the next article ;) Pin
whizer20-May-03 8:13
whizer20-May-03 8:13 
GeneralRe: Cool... now for the next article ;) Pin
Peter Mares20-May-03 19:43
Peter Mares20-May-03 19:43 
GeneralRe: Cool... now for the next article ;) Pin
Anonymous9-Oct-03 4:50
Anonymous9-Oct-03 4:50 
QuestionThread parameter pitfall? Pin
Sardaukar19-May-03 19:51
Sardaukar19-May-03 19:51 
AnswerRe: Thread parameter pitfall? Pin
whizer20-May-03 1:25
whizer20-May-03 1:25 
GeneralRe: Thread parameter pitfall? Pin
Sardaukar20-May-03 1:40
Sardaukar20-May-03 1:40 
GeneralRe: Thread parameter pitfall? Pin
whizer20-May-03 4:27
whizer20-May-03 4:27 
GeneralQT: Cross platform ugly Pin
Anonymous19-May-03 13:21
Anonymous19-May-03 13:21 
GeneralRe: QT: Cross platform ugly Pin
Jörgen Sigvardsson19-May-03 13:23
Jörgen Sigvardsson19-May-03 13:23 
GeneralRe: QT: Cross platform ugly Pin
Uwe Keim19-May-03 19:21
sitebuilderUwe Keim19-May-03 19:21 
GeneralRe: QT: Cross platform ugly Pin
Jörgen Sigvardsson19-May-03 21:25
Jörgen Sigvardsson19-May-03 21:25 
GeneralRe: QT: Cross platform ugly Pin
whizer20-May-03 1:18
whizer20-May-03 1:18 
GeneralRe: QT: Cross platform ugly Pin
Peter Mares20-May-03 5:49
Peter Mares20-May-03 5:49 
GeneralRe: QT: Cross platform ugly Pin
whizer20-May-03 8:15
whizer20-May-03 8:15 
GeneralRe: QT: Cross platform ugly Pin
whizer15-Jun-03 21:28
whizer15-Jun-03 21:28 
GeneralRe: QT: Cross platform ugly Pin
CodeCobbler4-Jun-03 17:22
CodeCobbler4-Jun-03 17:22 
GeneralRe: QT: Cross platform ugly Pin
Jörgen Sigvardsson4-Jun-03 22:25
Jörgen Sigvardsson4-Jun-03 22:25 
GeneralRe: QT: Cross platform ugly Pin
whizer15-Jun-03 21:09
whizer15-Jun-03 21:09 
GeneralRe: QT: Cross platform ugly Pin
whizer20-May-03 1:13
whizer20-May-03 1:13 
I have to admit that Qt looks different to MFC apps, but Qt can also look great. Look for example at KDE 3.1 screenshots[^].

Another advantage is that the GUI looks equal on all supported platforms, i.e. even on Unix the Windows is no different from that windows one ...


Best Regards,
Christian Richardt

Those who know don't talk.
Those who talk don't know.

GeneralRe: QT: Cross platform ugly Pin
CodeCobbler4-Jun-03 17:24
CodeCobbler4-Jun-03 17:24 
GeneralRe: QT: Cross platform ugly Pin
pjsluis14-Feb-05 6:26
pjsluis14-Feb-05 6:26 
GeneralRe: QT: Cross platform ugly Pin
Amit Ziv6-Feb-07 17:46
Amit Ziv6-Feb-07 17:46 
Generaldestructors Pin
dog_spawn19-May-03 10:41
dog_spawn19-May-03 10:41 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.