Click here to Skip to main content
Click here to Skip to main content
Go to top

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

, 18 May 2003
Rate this:
Please Sign up or sign in to vote.
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.

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:

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:

...
    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:

  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)

Share

About the Author

whizer
Web Developer
United Kingdom United Kingdom
No Biography provided

Comments and Discussions

 
Question? Service Timeouts PinmemberSynetech15-Aug-06 15:21 
GeneralCool... now for the next article ;) PinmemberPeter Mares20-May-03 5:53 
GeneralRe: Cool... now for the next article ;) Pinmemberwhizer20-May-03 8:13 
GeneralRe: Cool... now for the next article ;) PinmemberPeter Mares20-May-03 19:43 
GeneralRe: Cool... now for the next article ;) PinsussAnonymous9-Oct-03 4:50 
QuestionThread parameter pitfall? PinmemberSardaukar19-May-03 19:51 
AnswerRe: Thread parameter pitfall? Pinmemberwhizer20-May-03 1:25 
GeneralRe: Thread parameter pitfall? PinmemberSardaukar20-May-03 1:40 
GeneralRe: Thread parameter pitfall? Pinmemberwhizer20-May-03 4:27 
GeneralQT: Cross platform ugly Pinsussanonymous19-May-03 13:21 
GeneralRe: QT: Cross platform ugly PinmemberJörgen Sigvardsson19-May-03 13:23 
GeneralRe: QT: Cross platform ugly PinsitebuilderUwe Keim19-May-03 19:21 
GeneralRe: QT: Cross platform ugly PinmemberJörgen Sigvardsson19-May-03 21:25 
GeneralRe: QT: Cross platform ugly Pinmemberwhizer20-May-03 1:18 
GeneralRe: QT: Cross platform ugly PinmemberPeter Mares20-May-03 5:49 
GeneralRe: QT: Cross platform ugly Pinmemberwhizer20-May-03 8:15 
GeneralRe: QT: Cross platform ugly Pinmemberwhizer15-Jun-03 21:28 
Peter Mares wrote:
Actually it is. You just need to include a manifest resource or file with the VC6 compiled app
No it doesn't work since Qt draws its own GUI elements. But new versions of Qt (3.0.1 or higher) support native Windows GUI elements including WinXP themes.
 
Best Regards,
Christian Richardt
 
Those who know don't talk.
Those who talk don't know.

GeneralRe: QT: Cross platform ugly PinmemberCodeCobbler4-Jun-03 17:22 
GeneralRe: QT: Cross platform ugly PinmemberJörgen Sigvardsson4-Jun-03 22:25 
GeneralRe: QT: Cross platform ugly Pinmemberwhizer15-Jun-03 21:09 
GeneralRe: QT: Cross platform ugly Pinmemberwhizer20-May-03 1:13 
GeneralRe: QT: Cross platform ugly PinmemberCodeCobbler4-Jun-03 17:24 
GeneralRe: QT: Cross platform ugly Pinmemberpjsluis14-Feb-05 6:26 
GeneralRe: QT: Cross platform ugly PinmemberAmitZiv6-Feb-07 17:46 
Generaldestructors Pinmemberdog_spawn19-May-03 10:41 
GeneralRe: destructors PinsitebuilderUwe Keim19-May-03 19:20 
GeneralRe: destructors Pinmemberdog_spawn20-May-03 10:55 

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

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

| Advertise | Privacy | Mobile
Web01 | 2.8.140926.1 | Last Updated 19 May 2003
Article Copyright 2003 by whizer
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid