Tag: winapi

Entries for tag "winapi", ordered from most recent. Entry count: 21.

Uwaga! Informacje na tej stronie mają ponad 6 lat. Nadal je udostępniam, ale prawdopodobnie nie odzwierciedlają one mojej aktualnej wiedzy ani przekonań.

Pages: > 1 2 3 >

# Generating LIB File for DLL Library

Tue
04
Jan 2011

I've been recently trying to use libVLC - functionality of great, codec-less VLC media player enclosed in form of DLL library. By the way I've came across a great article: GenerateLibFromDll and now I know how to generate LIB file for any DLL library! Here is detailed description of the problem:

When you have a DLL library you want to use in your C++ code, you may do it dynamically by using LoadLibrary and GetProcAddress functions from WinAPI, but it's more convenient to do it statically. But it's not enough to just #include signatures of library functions and use them in your project. You also need to link with some LIB file, even if the file is not a real static library with compiled code, but only a few-kilobyte-long list of imported functions. I believe that's just another flaw of C++ language, because other languages like for example C# don't need this even when importing functions from native DLL libraries.

If you have some SDK prepared for Visual C++ or compile the library by yourself, you also get the LIB file next to DLL. But if you have only the library, that article shows following steps to generate matching LIB:

1. From Start menu run "Visual Studio Command Prompt".

2. Execute command:

dumpbin /exports DLL_FILE.dll > DEF_FILE.def

This command prints some information about given DLL library in textual form to its standard output. We redirect it to a text file with DEF extension. But to make it real DEF file, we need to edit it.

3. Open DEF_FILE.def in some text editor and edit it to contain only the names of exported functions in form of:

EXPORTS
function_1_name
function_2_name
function_3_name
...

4. From the Visual Studio Command Prompt, execute another command:

lib /def:DEF_FILE.def /out:LIB_FILE.lib /machine:x86

And there you have it! The so much required LIB file generated from DLL library. You only need signatures of these functions with proper parameters and return values declared in some H header file and you can successfully use your DLL by linking with LIB file created by yourself :)

Comments | #visual studio #c++ #windows #winapi Share

# Coding Windows Services in C++

Fri
01
Oct 2010

Services in Windows are like daemons in Linux - resident programs that work in background. I've recently learned how to code them in C++ using WinAPI. Here is a quick tutorial about this:

All the documentation you need to develop services can be found in MSDN Library. If you have it offline, go to: Win32 and COM Development / System Services / DLLs, Processes and Threads / SDK Documentation / DLLs, Processed, and Threads / Services. You can also read it online HERE. I talk only about native C and C++ code here, but services can also be written in .NET.

What are pros and cons of services, comparing to normal applications? Service can be automatically started with the system and work all the time, no matter if any user logs on and off. It can have extensive priviledges to access files on hard disk and the like, no matter what limitations do the logged-in user have. But service cannot interact directly with the user - it cannot show console or any window. So the only way for a service to do any input/output is to read some configuration files, write some log files or to communicate with some other client process ran by the user, e.g. via TCP socket connected to "localhost".

Service is written as a console application that uses special WinAPI functions to communicate with so called SCM - Service Control Manager. Example entry point routine looks like this:

// Standard console application entry point.
int main(int argc, char **argv)
{
    SERVICE_TABLE_ENTRY serviceTable[] = {
        { _T(""), &ServiceMain },
        { NULL, NULL }
    };
       
    if (StartServiceCtrlDispatcher(serviceTable))
        return 0;
    else if (GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
        return -1; // Program not started as a service.
    else
        return -2; // Other error.
}

StartServiceCtrlDispatcher is the first service-related function used here. It needs an array because a process can implement multiple different services, but I show only single-service process here. The function blocks for the entire execution time of working service and fails if program was run as normal application, not as a service. While service is working, a callback function is being executed, which I called ServiceMain here. It should initialize service and then execute all the code in loop until system wants to stop the service. You can also exit the function and thus stop the service at any time if you want (e.g. if some critical error occured).

// Main function to be executed as entire service code.
void WINAPI ServiceMain(DWORD argc, LPTSTR *argv)
{
    // Must be called at start.
    g_ServiceStatusHandle = RegisterServiceCtrlHandlerEx(_T("SERVICE NAME"), &HandlerEx, NULL);
   
    // Startup code.
    ReportStatus(SERVICE_START_PENDING);
    g_StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    /* Here initialize service...
    Load configuration, acquire resources etc. */
    ReportStatus(SERVICE_RUNNING);

    /* Main service code
    Loop, do some work, block if nothing to do,
    wait or poll for g_StopEvent... */
    while (WaitForSingleObject(g_StopEvent, 3000) != WAIT_OBJECT_0)
    {
        // This sample service does "BEEP!" every 3 seconds.
        Beep(1000, 100);
    }

    ReportStatus(SERVICE_STOP_PENDING);
    /* Here finalize service...
    Save all unsaved data etc., but do it quickly.
    If g_SystemShutdown, you can skip freeing memory etc. */
    CloseHandle(g_StopEvent);
    ReportStatus(SERVICE_STOPPED);
}

RegisterServiceCtrlHandlerEx is a function that must be called first to register your application as a service, pass its name and a pointer to your control event handler function. Then you do some initialization, execute main service code in a loop and after it's time to stop it, do the cleanup and exit.

Service should report its state to the SCM with SetServiceStatus function. It can be called at any time and from any thread and informs the system about if your service is stopped, running, starting, stopping, paused etc. This function takes quite sophisticated SERVICE_STATUS structure, but I believe it can be simplified to three main cases which I enclosed in the following functions: ReportStatus reports basic status like SERVICE_STOPPED, SERVICE_RUNNING, SERVICE_START_PENDING or SERVICE_STOP_PENDING.

SERVICE_STATUS_HANDLE g_ServiceStatusHandle; 
HANDLE g_StopEvent;
DWORD g_CurrentState = 0;
bool g_SystemShutdown = false;

void ReportStatus(DWORD state)
{
    g_CurrentState = state;
    SERVICE_STATUS serviceStatus = {
        SERVICE_WIN32_OWN_PROCESS,
        g_CurrentState,
        state == SERVICE_START_PENDING ? 0 : SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN,
        NO_ERROR,
        0,
        0,
        0,
    };
    SetServiceStatus(g_ServiceStatusHandle, &serviceStatus);
}

Third member of the SERVICE_STATUS structure - dwControlsAccepted - indicates which events will be accepted by the service after this call. I want to accept events informing about system shutdown and allow user to stop the service. I could also pass SERVICE_ACCEPT_PAUSE_CONTINUE here, which means I supported pausing and resuming the service.

ReportProgressStatus function reports service status during initialization and finalization - SERVICE_START_PENDING, SERVICE_STOP_PENDING, SERVICE_CONTINUE_PENDING, SERVICE_PAUSE_PENDING. I don't actually use it, but if the startup or shutdown of your service takes a lot of time, you should periodically report progress with this function. CheckPoint is simply a counter that should be incremented with each call, telling that service is making some progress. WaitHint is an estimated time it will take to finish initialization, finalization or to perform its next step. By default, system waits about 30 seconds for your service to start or stop and you should not exceed that without a good reason.

void ReportProgressStatus(DWORD state, DWORD checkPoint, DWORD waitHint)
{
    g_CurrentState = state;
    SERVICE_STATUS serviceStatus = {
        SERVICE_WIN32_OWN_PROCESS,
        g_CurrentState,
        state == SERVICE_START_PENDING ? 0 : SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN,
        NO_ERROR,
        0,
        checkPoint,
        waitHint,
    };
    SetServiceStatus(g_ServiceStatusHandle, &serviceStatus);
}

Finally, there is a way for a service to shutdown and inform the system that some critical error occured. To do this, report SERVICE_STOPPED and pass error code. The code will be saved along with information about service failture to the system event log.

void ReportErrorStatus(DWORD errorCode)
{
    g_CurrentState = SERVICE_STOPPED;
    SERVICE_STATUS serviceStatus = {
        SERVICE_WIN32_OWN_PROCESS,
        g_CurrentState,
        0,
        ERROR_SERVICE_SPECIFIC_ERROR,
        errorCode,
        0,
        0,
    };
    SetServiceStatus(g_ServiceStatusHandle, &serviceStatus);
}

HandlerEx is a function to handle events sent by the system to control your service - stop it, pause, inform about the system shutdown or simply query for current status. You must always call SetServiceStatus in this function. It can be executed in different thread, so you must synchronize it with the code in ServiceMain. I do this with g_StopEvent - an event that will be set when the service should exit.

// Handler for service control events.
DWORD WINAPI HandlerEx(DWORD control, DWORD eventType, void *eventData, void *context)
{
    switch (control)
    {
    // Entrie system is shutting down.
    case SERVICE_CONTROL_SHUTDOWN:
        g_SystemShutdown = true;
        // continue...
    // Service is being stopped.
    case SERVICE_CONTROL_STOP:
        ReportStatus(SERVICE_STOP_PENDING);
        SetEvent(g_StopEvent);
        break;
    // Ignoring all other events, but we must always report service status.
    default:
        ReportStatus(g_CurrentState);
        break;
    }
    return NO_ERROR;
}

That's all the code I wanted to show. Now, because service cannot be run as normal program, you must learn how to install and uninstall it. Fortunately there is a simple command line program for this distributed with Windows - sc. To install your service, enter following command (exactly like this, with "binPath=" SPACE "PATH"):

sc create SERVICE_NAME binPath= FULL_PATH_TO_EXE_FILE

To uninstall it:

sc delete SERVICE_NAME

To control your service - start it, stop it or query its status - use commands:

sc start SERVICE_NAME
sc stop SERVICE_NAME
sc query SERVICE_NAME

Or simply run Administrative Tools / Services (another way to access it is Start / Run / "services.msc").

Two kinds of command line arguments can be passed to a service. First are argc, argv parameters taken by main function. They come from a command line fixed during installation of the service. Second are argc, argv arguments taken by ServiceMain function. They are different - argv[0] is the service name and the rest are arguments that you passed as additional parameters when calling "sc start" command.

Of course there is more to be told on this subject. Service can depend on some other services, can be automatically started with the system or only on demand, can have priviledges of a selected user or one of standard ones, like "LocalSystem" (biggest priviledges on local system, the default), "LocalService" or "NetworkService". See MSDN Library for details.

Comments | #c++ #windows #winapi Share

# How to Disable Redrawing of a Control

Thu
18
Mar 2010

When coding Windows application with GUI, there is an issue about how long does it take to add lots of items (like hundreds or thousands) into a list view or tree view control. It is caused by redrawing the control after each operation. I've seen this annoying effect in may programs, including some serious, commercial ones. Apparently many programmers don't know there is a simple solution. But first a bit of background...

When coding games, we constantly spin inside a big loop and redraw whole screen every frame. Calculations are separated from rendering so we can, for example, build a list with thousands of items in the computation function and the visible part of the list will start being rendered since the first rendering function call after that. When coding windowed applications, nothing new is drawn onto the screen unless needed. We have to manually do it and we can call redrawing function any time. So how should a list control be refreshed when we add an item into it? It is done automatically after each insert, which is a good solution... unless we want to add hundreds of them.

So GUI library developers provide a functionality to temporarily disable redrawing of a control.

Comments | #.net #mfc #wxwidgets #winapi #gui Share

# Generating and Compressing AVI Video Files

Mon
28
Dec 2009

Yesterday I've decided to share all my home code using Project Hosting on Google Code, so now everyone can browse my code online by entering project called blueway. I'll be very glad to hear your opinions and suggestions about it.

Today I've researched subject of generating video data as AVI file, compressed on the fly with codecs installed in Windows. After succeeding with that I've created simple class to support this task, called VideoCompressor. You can find it in Video.hpp and Video.cpp. Test code is in ProgramMain.cpp, line 2318. It generates a 5 second video with a white horizonal line moving from bottom to top.

Here are some technical details. Functionality needed to handle video files is already inside Windows API, described in MSDN Library. The AVIFile library contains functions like AVIFileOpen, AVIFileCreateStream, AVIStreamWrite. It supports reading and writing AVI files. You need to include <Vfw.h> header and link with Vfw32.lib file. AVI is actually a container file format made of RIFF data chunks identified by 4-byte FOURCC codes (if you ever loaded 3DS models, you know what I mean). It can contain multiple streams like video and audio, which can be coded in many different formats, compressed and decompressed by codecs.

Compressing and decompressing frames of video with installed codecs can be done with Video Compression Manager library. You can display standard, system dialog window to let the user choose and configure codec with ICCompressorChoose function. Then you can just pass subsequent video frames as uncompressed RGB images to a function like ICSeqCompressFrame and you get a piece of compressed data that you can save to your AVI file.

Comments | #video #winapi Share

# Redirecting Standard I/O to Windows Console

Sat
28
Nov 2009

Every process, no matter if under Windows or Linux, has standard text streams called input, output and error. Of course it makes most sense when you deal with command line applications, where you can directly interact with it using these streams. If you use Linux, you are probably familiar with redirecting streams to file using > operator or to another application using | operator. We use these streams in C++ code with standard C library (like printf and scanf functions) or standard C++ library (like std::cout and std::cin streams). But what if we write a GUI application in Windows (like a game), which has WinMain instead of main entry point and thus doesn't have console?

There is a simple WinAPI function called AllocConsole, which opens this black system console for your Win32 application. But today I've noticed that the console opened this way doesn't handle standard I/O! I've tried to do std::cout << "Hello World" and nothing happened. So after some googling I've found a hacky solution (or maybe rather a smart code snippet? :) in an article hosted at Andrew Tucker's Home Page, published in 1997 in Windows Developer Journal: Adding Console I/O to a Win32 GUI App. Here is my version of this code with all necessary includes:

#include <windows.h>
#include <ios>
#include <cstdio>
#include <io.h>
#include <fcntl.h>

void RedirectStandardIo()
{
  /* This clever code have been found at:
  Adding Console I/O to a Win32 GUI App
  Windows Developer Journal, December 1997
  http://dslweb.nwnexus.com/~ast/dload/guicon.htm
  Andrew Tucker's Home Page */

  // redirect unbuffered STDOUT to the console
  long lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE);
  int hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
  FILE *fp = _fdopen(hConHandle, "w");
  *stdout = *fp;
  setvbuf(stdout, NULL, _IONBF, 0);

  // redirect unbuffered STDIN to the console
  lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE);
  hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
  fp = _fdopen( hConHandle, "r" );
  *stdin = *fp;
  setvbuf(stdin, NULL, _IONBF, 0);

  // redirect unbuffered STDERR to the console
  lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE);
  hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
  fp = _fdopen( hConHandle, "w" );
  *stderr = *fp;
  setvbuf(stderr, NULL, _IONBF, 0);

  // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog point to console as well
  std::ios::sync_with_stdio();
}

Comments | #winapi Share

# Executable File Path

Sat
14
Nov 2009

There have been a question recently at our forum about how to get the full path of the current executable file.

First idea proposed was to use argv[0] argument from main function, but this solution is wrong. The proof is a simple example with my program called Parametrizer. As this screenshot shows, program run from the command line with current directory equal to the directory where the executable file lies results in the argv[0] being set to only file name, without the full path.

The correct solution for Windows is to use GetModuleFileName function, just like this:

char exePath[MAX_PATH];
GetModuleFileName(NULL, exePath, _countof(exePath));

Then you can extract only the directory path and append any other file name to be sure you always access files installed with your application from the correct directory refered by the full, absolute path. I'll write more about function for path string processing and the concept of current directory soon...

Comments | #c++ #winapi Share

# Dialog Layout Manager in MFC

Sat
08
Aug 2009

Sometimes I write some tools using C++ and MFC. In the Linux world it is common that GUI windows are resizeable. In Windows its not the case, but sometimes it would be nice to be able to resize a dialog window to see more information, like more rows and colums in a list. After repositioning and resizing controls in a window with my custom code I've decided to automate this task.

There are many possible approaches to this problem. WinAPI (and thus MFC) does not provide by itself any solution to automatically align controls inside a resizeable window. Each control has just its fixed rectangle (left, top, width, height) inside parent window. Delphi VCL uses Align property to snap selected controls (like Panel containing child controls) to left, right, top or bottom edge of the window. Qt encourages to design all windows with Layouts. For example, Vertical Layout splits the window into rows and automatically adjusts controls inside, one under the other.

But the solution of my choice is the one based on .NET. Controls in Windows Forms have a property called Anchor so they can be anchored to any of four possible window edges: left, top, right and bottom. If a controls is anchored only to left and top edges, it just doesn't change its position or size. If the control is anchored to right and bottom edges (for example: a button), it changes its position as window is resized so it preserves its distance to right and bottom edge of the window. If the control is anchored to all four possible window edges, it is resized to preserve distance to all window edges same as designed (for example: a list occupying central part of the window).

I've written a class which I called DialogLayoutManager. It's very easy to use and automates control resizing and repositioning inside an MFC window. All you need to do at the beginning is to create an object of this class, register your controls with selected anchors and call Save method:

m_LayoutManager->SetControl(GetDlgItem(ID_BTN_CANCEL),
  DialogLayoutManager::ANCHOR_RIGHT | DialogLayoutManager::ANCHOR_BOTTOM);
m_LayoutManager->SetControl(GetDlgItem(ID_BTN_OK),
  DialogLayoutManager::ANCHOR_RIGHT | DialogLayoutManager::ANCHOR_BOTTOM);
m_LayoutManager->Save(this);

Layout manager remembers positions and sizes of registered controls together with starting window size. Now all you need to do when the window is resized is to call Restore method. Layout manager will adjust registered controls according to new window size and specified anchors. For example, two buttons showed above will stay in bottom-right corner of the window.

void CDialog01::OnSize(UINT nType, int cx, int cy)
{
  ...
  if (LayoutManager && LayoutManager->IsSaved())
    m_LayoutManager->Restore(this);
}

Here is the code of my DialogLayoutManager class and usage example: DialogLayoutManager.cpp. It's easy to translate this code to pure WinAPI.

Comments | #gui #mfc #winapi Share

# Efficient Finding of Duplicated Files

Tue
14
Jul 2009

I've recently wrote a tool for finding duplicated files in a given directory. I wanted to do it efficiently and here is my algoritm.

My basic idea is to first recursively enumerate all files in the directory and its subdirectories and sort their descriptions by file size. Making it this way, we can then iterate through this list and for each file look ahead to see how many other files have same size. If two files have different sizes, they are obviously not equal in terms of their content. So if there is only one file with particular size, it can just be skipped. If there are two files with same size, we must just compare them by content.

If there are many files with same size, things become more complicated, as any possible combinations of them can turn out to be identical. My solution is to compare two files by a "header" (lets say - first 1024 bytes) and if they are equal - by MD5 checksum of their whole content. Checksum of each file is lazy evaluated, so it's calculated only once, the first time its needed.

As I iterate through the sorted file list, I mark reported files not to process them again. I can do it because I ensure that if a file is reported, all other identical files are also already reported. In my real code I do the same with files I encounter errors with, but here I wanted to simplify the code.

 

 

 

Comments | #algorithms #winapi Share

Pages: > 1 2 3 >

[Download] [Dropbox] [pub] [Mirror] [Privacy policy]
Copyright © 2004-2024