Memory leak in msxml6, MRE - memory-leaks

MRE:
#include <Windows.h>
#include <MsXml2.h>
#include <atlcomcli.h>
#include <fstream>
int main() {
std::string strFileName( "xml.xml" );
std::ofstream outFile( strFileName );
outFile << "<root><n1><n2><n3><n4><n5/></n4></n3></n2></n1></root>";
outFile.close();
while ( CoInitializeEx( nullptr, COINIT_APARTMENTTHREADED ) == S_OK ) {
{
CComPtr<IXMLDOMDocument2> spIXMLDOMDocument2;
HRESULT hr = spIXMLDOMDocument2.CoCreateInstance( L"Msxml2.DOMDocument.6.0", nullptr, CLSCTX_INPROC_SERVER );
if ( hr == S_OK ) {
VARIANT_BOOL vbSuccess = VARIANT_FALSE;
CComVariant ccvarXmlSource( strFileName.c_str() );
hr = spIXMLDOMDocument2->load( ccvarXmlSource, &vbSuccess );
} else exit( 0 );
}
CoUninitialize();
Sleep( 0 );
}
}
The code is just an infinite loop of CoInitializeEx CoCreateInstance load Release and CoUninitialize, (with the help of CComPtr)
Release Build, x64, Visual Studio 2017, Windows 10 (1809).
On my laptop, this leaks several tens of KB per minute.
Process Explorer showed me private bytes at 2,5Mo at the start, and at 19Mo 3 hours later.
C:\Windows\System32\msxml6.dll version: 6.30.17763.437
UPDATE: Threaded MRE
#include <Windows.h>
#include <MsXml2.h>
#include <atlcomcli.h>
#include <fstream>
#include <thread>
void ThreadFunction( ) {
if ( CoInitializeEx( nullptr, COINIT_APARTMENTTHREADED ) != S_OK ) exit ( 0 );
{
CComPtr<IXMLDOMDocument2> spIXMLDOMDocument2;
HRESULT hr = spIXMLDOMDocument2.CoCreateInstance( L"Msxml2.DOMDocument.6.0", nullptr, CLSCTX_INPROC_SERVER );
if ( hr == S_OK ) {
VARIANT_BOOL vbSuccess = VARIANT_FALSE;
CComVariant ccvarXmlSource( "xml.xml" );
hr = spIXMLDOMDocument2->load( ccvarXmlSource, &vbSuccess );
} else exit( 0 );
}
CoUninitialize();
}
int main() {
std::ofstream outFile( "xml.xml" );
outFile << "<root><n1><n2><n3><n4><n5/></n4></n3></n2></n1></root>";
outFile.close();
while ( true ) {
std::thread oneThread( ThreadFunction );
oneThread.join();
Sleep( 0 );
}
}
Can you reproduce?

Related

dl_iterate_phdr returns empty image-name on first entry

I've developed this little C++ program for Linux
#include <iostream>
#include <vector>
#include <string>
#include <link.h>
#include <climits>
#include <dlfcn.h>
using namespace std;
template<typename Fn>
requires requires( Fn fn, dl_phdr_info *image, size_t n ) { { fn( image, n ) } -> same_as<int>; }
int dlIteratePhdr( Fn &&fn )
{
return dl_iterate_phdr(
[]( dl_phdr_info *image, size_t size, void *pFn ) -> int
{
return (*(Fn *)pFn)( image, size );
}, &fn );
};
int main()
{
size_t nImages = 0;
dlIteratePhdr( [&]( dl_phdr_info *, size_t ) -> int { ++nImages; return 0; } );
vector<string> images;
images.reserve( nImages );
if( dlIteratePhdr(
[&]( dl_phdr_info *image, size_t ) -> int
{
try
{
images.emplace_back( image->dlpi_name );
return 0;
}
catch( ... )
{
return 1;
}
} ) )
return EXIT_FAILURE;
for( string const &image : images )
cout << "\"" << image << "\"" << endl;
}
For my Ubuntu machine this prints:
""
"linux-vdso.so.1"
"/lib/x86_64-linux-gnu/libstdc++.so.6"
"/lib/x86_64-linux-gnu/libgcc_s.so.1"
"/lib/x86_64-linux-gnu/libc.so.6"
"/lib/x86_64-linux-gnu/libm.so.6"
"/lib64/ld-linux-x86-64.so.2"
Why is the name of the first image empty ?
Is this reserved for the executable itself ?
And is it really necessary to copy the information given to the callback or would this be alive after dl_iterate_phdr ?
Why is the name of the first image empty ?
Because the name of the main executable is not known to the loader.
Unlike the shared libraries, which are mmaped by the loader, the main executable is mapped by the kernel itself, and only the file descriptor is passed in to the loader.
As Hasturkun commented, this behavior is documented in the man page.
Is this reserved for the executable itself ?
Yes.
And is it really necessary to copy the information ...
The dl_phdr_info that is passed in is stack-allocated, and will get overwritten after each step (in fact, it's the same pointer every time; but this is an implementation detail).
The strings pointed by dlpi_name are dynamically allocated by the loader.
Strings corresponding to the libraries loaded during executable startup are likely to persist throughout the lifetime of the process, but strings corresponding to dlopen()ed libraries may get free()d on dlclose(). This is also an implementation detail and you are better off not relying on it.
I found a way to determine the executable path also, here's the above program which also does that:
#include <iostream>
#include <vector>
#include <string>
#include <link.h>
#include <climits>
#include <dlfcn.h>
using namespace std;
template<typename Fn>
requires requires( Fn fn, dl_phdr_info *image, size_t n ) { { fn( image, n ) } -> same_as<int>; }
int dlIteratePhdr( Fn fn )
{
return dl_iterate_phdr(
[]( dl_phdr_info *image, size_t size, void *pFn ) -> int
{
return (*(Fn *)pFn)( image, size );
}, &fn );
};
int main()
{
size_t nImages = 0;
dlIteratePhdr( [&]( dl_phdr_info *, size_t ) -> int { ++nImages; return 0; } );
vector<string> images;
images.reserve( nImages );
if( dlIteratePhdr(
[&]( dl_phdr_info *image, size_t ) -> int
{
try
{
if( *image->dlpi_name )
images.emplace_back( image->dlpi_name );
else
{
Dl_info dlInfo;
if( !dladdr( (void *)image->dlpi_addr, &dlInfo ) )
return 1;
char exePath[PATH_MAX];
if( !realpath( dlInfo.dli_fname, exePath ) )
return 1;
images.emplace_back( exePath );
}
return 0;
}
catch( bad_alloc const & )
{
return 1;
}
} ) )
return EXIT_FAILURE;
for( string const &image : images )
cout << "\"" << image << "\"" << endl;
}
I don't know why the dl_iterate_phdr doesn't supply that path by itself if I can manage to get it otherwise.

Why would recvfrom() used on a stream socket return a zero address and port?

I am using a Linux system, not a Windows system. I've posted some code, below. Please bear in mind that this code was never intended to be "production quality."
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <netdb.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 9909
void die ( const char *fmt, ... )
{
va_list vargs;
va_start( vargs, fmt );
vfprintf( stderr, fmt, vargs );
va_end( vargs );
exit( 1 );
}
int main ( int argc, char **argv )
{
/* *** */
int listener = socket( PF_INET, SOCK_STREAM, 0 );
if( listener < 0 ) die( "socket(listener)" );
int flag = 1;
if( setsockopt( listener, SOL_SOCKET, SO_REUSEADDR, (char*)&flag, sizeof(int) ) < 0 )
die( "setsockopt()" );
struct sockaddr_in svr_addr;
memset( &svr_addr, 0, sizeof(struct sockaddr) );
svr_addr.sin_family = PF_INET;
svr_addr.sin_port = htons( PORT );
svr_addr.sin_addr.s_addr = INADDR_ANY;
if( bind( listener, (struct sockaddr*)&svr_addr, (socklen_t)sizeof(struct sockaddr) ) < 0 )
die( "bind()" );
if( listen( listener, 10 ) < 0 )
die( "listen()" );
/* *** */
fd_set fd_master;
fd_set fd_select;
int fd_max = listener;
FD_ZERO( &fd_master );
FD_ZERO( &fd_select );
FD_SET( listener, &fd_master );
while( 1 )
{
fd_select = fd_master;
if( select( fd_max + 1, &fd_select, NULL, NULL, NULL ) < 0 )
die( "select()" );
for( int ifd = 0; ifd <= fd_max; ++ifd )
{
if( ! FD_ISSET( ifd, &fd_select ) ) continue;
struct sockaddr_in cli_addr; memset( &cli_addr, 0, sizeof(cli_addr) );
socklen_t cli_alen = sizeof(cli_addr);
if( ifd == listener )
{
int cli = accept( listener, (struct sockaddr*)&cli_addr, &cli_alen );
if( cli < 0 ) die( "accept()" );
FD_SET( cli, &fd_master );
if( cli > fd_max ) fd_max = cli;
printf( "new connection> %s:%u\n", inet_ntoa( cli_addr.sin_addr ), ntohs( cli_addr.sin_port ) );
fflush( stdout );
}
else
{
char buf[256];
cli_alen = sizeof(cli_addr);
ssize_t nbytes = recvfrom( ifd, buf, sizeof(buf), 0, (struct sockaddr*)&cli_addr, &cli_alen );
if( nbytes <= 0 )
{
close( ifd );
FD_CLR( ifd, &fd_master );
if( nbytes == 0 )
printf( "connection hung up> %u\n", ifd );
else
printf( "recvfrom() : %s\n", strerror( errno ) );
fflush( stdout );
}
else
{
// build a "from identifier" for each of the recipients
char msg[sizeof(buf) * 2];
sprintf( msg, "%s:%u> ", inet_ntoa( cli_addr.sin_addr ), ntohs( cli_addr.sin_port ) );
memcpy( msg + strlen( msg ), buf, nbytes );
nbytes += strlen( msg );
// send incoming data to all clients (excluding the originator)
for( int ofd = 0; ofd <= fd_max; ++ofd )
{
if( FD_ISSET( ofd, &fd_master ) )
if( ofd != listener && ofd != ifd )
if( send( ofd, msg, nbytes, 0 ) < 0 )
{ printf( "send() %s\n", strerror( errno ) ); fflush( stdout ); }
}
}
}
}
}
return 0;
}
When the code is run and you connect from two or more clients (via telnet), each message shows the sender as "0.0.0.0" with a port of 0.
The Windows documentation for recvfrom() states "[t]he from and fromlen parameters are ignored for connection-oriented sockets." The Linux and POSIX documentation make no such claim and goes as far as to say that recvfrom() "...may be used to receive data on a socket whether or not it is connection-oriented." No where does it say that src_addr and addrlen will be ignored ... so I would expect these to be filled in.
On connected sockets you have to call getpeername and then carry on with your inet_ntoa (consider using inet_ntop instead as it supports multiple address families). As per the man pages:
int getpeername(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len);
Nowhere does it say that src_addr and addrlen will be ignored.
That is simply untrue. It says
If src_addr is not NULL, and the underlying protocol provides the source address, this source address is filled in. [emphasis added]
You can argue about whether TCP can be said to provide the source address, but you can't claim 'nowhere does it say ...'.

Produser Consumer wthout semaphore

I am trying to solve producer consumer problem using threads without semaphoere.In my client i create 4 threads 2 for producer and 2 for consumer, each of them send M produce/consume messages. Here is my client code.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <pthread.h>
#define BUFSIZE 4096
#define N 4
/*
** Client
*/
int M = 10;
pthread_t threads[N];
char buf[BUFSIZE];
char *service;
char *host = "localhost";
int cc;
int csock;
int consumed,produced;
void *connect_and_handle(void *msg){
/* Create the socket to the controller */
if ( ( csock = connectsock( host, service, "tcp" )) == 0 ) {
fprintf( stderr, "Cannot connect to server.\n" );
exit( -1 );
}
printf( "The server is ready, please start entering commands.\n" );
fflush( stdout );
// Start the loop
int k;
//char msg[50];
for (k=0;k<M;k++){
strcpy(buf, msg);
// Send to the server
if ( write( csock, buf, strlen(buf) ) < 0 ) {
fprintf( stderr, "client write failed: %s\n", strerror(errno) );
exit( -1 );
}
if ( (cc = read( csock, buf, BUFSIZE )) <= 0 )
break;
buf[cc] = 0;
printf( "Server replied: %s\n", buf );
}
close( csock );
// exit thread
pthread_exit(NULL);
}
int main( int argc, char *argv[] ){
char *msg, *msg2;
switch( argc ) {
case 2:
service = argv[1];
break;
case 3:
host = argv[1];
service = argv[2];
break;
default:
fprintf( stderr, "usage: chat [host] port\n" );
exit(-1);
}
// thread code goes here
int i, n = N;
for (i=0;i<N;i++){
msg = (char*)malloc(32*sizeof(char));
msg2 = (char*)malloc(32*sizeof(char));
sprintf(msg,"PRODUCE This is the item #%i", i);
sprintf(msg2, "CONSUME");
//producer thread
produced = pthread_create( &threads[i], NULL, connect_and_handle, (void *) msg );
if ( produced != 0 ) { printf( "Error: pthread_create returned code %d.\n", produced); exit( -1 );}
//consumer thread
/*
i++;
consumed = pthread_create( &threads[i], NULL, connect_and_handle, (void *) msg2 );
if ( consumed != 0 ){ printf( "Error: pthread_create returned code %d.\n", consumed ); exit( -1 );}
*/
}
}
and server :
// This server implements part of the 333 protocol
// NUMBER - number of clients served
// NAMES - developers
// GOODBYE - close connection
// ADD - increment
// SUBTRACT- decrement
//
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <semaphore.h>
#define QLEN 5
#define BUFSIZE 4096
#define MAX 100
/*
** This server ... is threaded
*/
// Function prototypes
int passivesock( char *, char *, int, int * );
void *handle_a_client( void *arg );
// Global variables are shared by the threads
int clients = 0;
char *buffer[MAX];
char *maloc_buf;
int count=0;
int full_count=0;
int empty_count=MAX;
int main( int argc, char *argv[] ) {
char *service;
struct sockaddr_in fsin;
int alen;
int msock;
int ssock;
int rport = 0;
switch (argc) {
case 1:
// No args? let the OS choose a port and tell the user
rport = 1;
break;
case 2:
// User provides a port? then use it
service = argv[1];
break;
default:
fprintf( stderr, "usage: server [port]\n" );
exit(-1);
}
msock = passivesock( service, "tcp", QLEN, &rport );
if (rport) {
// Tell the user the selected port
printf( "server: port %d\n", rport );
fflush( stdout );
}
// Keep accepting clients until you are killed
for (;;) {
int ssock;
pthread_t pid;
alen = sizeof(fsin);
ssock = accept( msock, (struct sockaddr *)&fsin, &alen );
if (ssock < 0) {
fprintf( stderr, "accept: %s\n", strerror(errno) );
exit(-1);
}
clients++;
printf("connected , %i", clients);
// Launch a thread to manage this client
// YES, pid is getting overwritten each time, but it is unused
pthread_create( &pid, NULL, handle_a_client, (void *) ssock );
}
}
void *handle_a_client( void *arg ) {
char requestbuf[BUFSIZE];
char replybuf[BUFSIZE];
int ssock = (int) arg;
int cc;
for (;;) {
if ( (cc = read( ssock, requestbuf, BUFSIZE )) <= 0 ) {
printf( "The client has gone.\n");
(void) close(ssock);
pthread_exit(0);
break;
}
else {
// Remove the newline and null-terminate the string
requestbuf[cc] = '\0';
int size = cc-7;
printf( "The client on %d says: %s\n", ssock, requestbuf );
if ( strncasecmp( requestbuf, "goodbye", 7 ) == 0 ) {
close( ssock );
break;
}
else if ( strncasecmp( requestbuf, "PRODUCE", 7 ) == 0 ) {
if (full_count == MAX){
strcpy(replybuf,"FULL\n");
write(ssock,replybuf,strlen(replybuf));
}
else {
maloc_buf=(char*) malloc((size)*sizeof(char));
strcpy(maloc_buf, (requestbuf+8));
buffer[full_count]=maloc_buf;
int num=full_count+1;
sprintf(replybuf, "Client produced item no%i: %s",full_count, buffer[full_count]);
full_count++;
empty_count--;
}
}
else if ( strncasecmp( requestbuf, "CONSUME", 7 ) == 0 ) {
if (empty_count == MAX) {
strcpy(replybuf,"EMPTY\n");
write( ssock, replybuf, strlen(replybuf) );
}
else {
sprintf(replybuf,"OK %s", buffer
[full_count]);
free(buffer[full_count]);
full_count--;
empty_count++;
}
}
}
}
}
When i run my server and then try to connect to it in client, nothing happens. Debugging showed (i am not sure) that in client code after
if ( ( csock = connectsock( host, service, "tcp" )) == 0 ) {
i am exiting, nothing is printed to console both in client and server.

Qt with XComposite problem

I'm trying to write a simple program, which redirects all the windows to the backbuffer( as the composite manager does ), then write them to pixmap and save to disk. But I got this error:
(.text.startup+0x5e):-1: error: undefined reference to `XCompositeRedirectSubwindows'
(.text.startup+0x171):-1: error: undefined reference to `XCompositeNameWindowPixmap'
:-1: error: collect2: ld returned 1 exit status
Here is the code :
#include <QApplication>
#include <QDebug>
#include <X11/Xlib.h>
#include <QPaintDevice>
#include <QX11Info>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xrender.h>
#include <X11/extensions/Xdamage.h>
#include <QPixmap>
#include <QWidget>
int main( int argc, char *argv[] )
{
QApplication app( argc, argv );
app.setGraphicsSystem("native");
Picture frontBuffer;
XRenderPictFormat *format;
Window rootWindow;
int depth;
Display *dpy = XOpenDisplay( getenv("DISPLAY") );
rootWindow = XRootWindow( dpy, XDefaultScreen( dpy ) );
depth = DefaultDepth( dpy, DefaultScreen(dpy) );
// Redirect all the windows
XCompositeRedirectSubwindows( dpy, rootWindow, CompositeRedirectManual );
// Get the format
format = XRenderFindVisualFormat( dpy, DefaultVisual( dpy, DefaultScreen(dpy) ) );
XRenderPictureAttributes pa;
pa.subwindow_mode = IncludeInferiors;
// Creating front buffer
frontBuffer = XRenderCreatePicture( dpy, rootWindow, format, CPSubwindowMode, &pa );
uint nwindows;
Window root_return, parent_return, *windows;
XQueryTree( dpy, rootWindow, &root_return,
&parent_return, &windows, &nwindows );
for ( uint i = 0; i < nwindows; i++ ) {
XWindowAttributes attr;
if ( !XGetWindowAttributes( dpy, windows[i], &attr ) )
continue;
Pixmap pix = XCompositeNameWindowPixmap( dpy, windows[i] );
Picture pic = XRenderCreatePicture( dpy, pix, format, 0, 0 );
QPixmap pixmap(540, 900);
XRenderComposite( dpy, PictOpSrc, pic, None, pixmap.x11PictureHandle(),
0, 0, 0, 0, 0 , 0, 540, 900 );
pixmap.save( QString::number( i )+".png", "PNG" );
}
}
XFree( windows );
return app.exec();
}
Did you link your program with libXcomposite? That's the library which defines those functions.
Compile with -lXcomposite or with pkg-config --libs xcomposite.

My Own Personal MFC

I can't seem to find this on msdn been searching for a bit (described below).
Please forgive the amount of code posted, I will paste in order. You can really skip most of it. But I just want to put it all out there so my request is clear.
Lets say I wanted to make a really simple MFC. So I have the following abstract and concrete classes (pasted below) that I want in my really crappy framework.
I am also assuming (though not implemented yet) that WinMain will call a users defined main function (like Qt). What do I need to do so I can reuse my code in every other small crappy Win32 program I try to write. To be more clear, I am wondering if I compile it into a DLL, or a Library. If so how do I go about doing this? How do you include a WinMain function in a DLL?
#ifndef IAPPLICATION_H_
#define IAPPLICATION_H_
#include <Windows.h>
namespace nApplication
{
class IController;
class IWindow;
class IApplication
{
public:
virtual int Run( ) = 0;
virtual HINSTANCE gethInstance( ) = 0;
virtual int getnCmdShow( ) = 0;
virtual IController* getMainControl( ) = 0;
protected:
IWindow *main_window;
IController *main_control;
private:
virtual int MessageLoop() = 0;
};
}
#endif /* IAPPLICATION */
-
#ifndef APPLICATION_H_
#define APPLICATION_H_
#include <Windows.h>
#include "IApplication.h"
#include "IWindow.h"
#include "IController.h"
#include "Controller.h"
namespace nApplication
{
class Application : public IApplication
{
public:
Application( HINSTANCE hInstance, int nCmdShow );
virtual ~Application( );
virtual int Run( );
virtual int getnCmdShow( ) { return mnCmdShow; }
virtual HINSTANCE gethInstance( ) { return mhInstance; }
virtual IController* getMainControl( ) { return main_control; }
private:
int mnCmdShow;
HINSTANCE mhInstance;
int MessageLoop();
Application( Application &app );
Application& operator= ( const Application &app );
};
}
#endif /* IAPPLICATION */
-
#include "Application.h"
#include "MainWindow.h"
namespace nApplication
{
Application::Application( HINSTANCE hInstance, int nCmdShow )
: mhInstance( hInstance ), mnCmdShow( nCmdShow )
{
}
Application::~Application( )
{
}
int Application::Run( )
{
main_window = new MainWindow( this );
main_control = new Controller( this );
main_window->Init( );
main_window->Display( );
MessageLoop( );
delete main_window;
return 0;
}
int Application::MessageLoop()
{
MSG msg;
while(GetMessage(&msg, NULL, 0, 0) != 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
}
-
#ifndef IWINDOW_H_
#define IWINDOW_H_
#include <Windows.h>
#include "IController.h"
namespace nApplication
{
class IWindow
{
public:
virtual void Init() = 0;
virtual void Display( ) = 0;
private:
};
}
#endif /* IWINDOW_H_ */
-
#ifndef MAINWINDOW_H_
#define MAINWINDOW_H_
#include <windows.h>
#include "IWindow.h"
#include "IController.h"
#include "IApplication.h"
namespace nApplication
{
class MainWindow : public IWindow
{
public:
MainWindow( IApplication *iApp);
~MainWindow();
void Init();
void Display( );
private:
WNDCLASSEX wc;
HWND hWnd;
IApplication *iApp;
};
}
#endif //MAINWINDOW_H_
-
#include "MainWindow.h"
namespace nApplication
{
namespace
{
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HDC hDC;
PAINTSTRUCT ps;
static IController *cntrl;
cntrl = (IController*)::GetWindowLongPtr(hWnd, GWL_USERDATA);
if(uMsg == WM_NCCREATE)
{
cntrl = (IController*)(((CREATESTRUCT*)lParam)->lpCreateParams);
::SetWindowLongPtr(hWnd, GWL_USERDATA, (LONG_PTR)cntrl);
cntrl->CheckStatus();
return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
}
switch(uMsg)
{
case WM_CREATE:
{
}
case WM_PAINT:
{
hDC = BeginPaint( hWnd, &ps );
TextOut( hDC, 10, 10, TEXT("Hello, Windows!"), 15 );
EndPaint( hWnd, &ps );
return 0;
}
case WM_DESTROY:
{
PostQuitMessage( 0 );
return 0;
}
default:
{
return DefWindowProc( hWnd, uMsg, wParam, lParam );
}
}
}
}
MainWindow::MainWindow( IApplication* iApp ) : iApp( iApp )
{
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = iApp->gethInstance( );
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = TEXT( "GenericAppMenu");
wc.lpszClassName = TEXT( "myWindowClass" );
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
}
MainWindow::~MainWindow()
{
}
void MainWindow::Init()
{
if( !RegisterClassEx(&wc) )
{
MessageBox(NULL, TEXT( "Window Registration Failed!" ), TEXT( "Error!" ), MB_ICONEXCLAMATION | MB_OK);
exit(0);
}
}
void MainWindow::Display( )
{
hWnd = ::CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("myWindowClass"),
TEXT("The title of my window"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
240, 120, NULL, NULL, iApp->gethInstance( ), iApp->getMainControl( ) );
if(hWnd == NULL)
{
::MessageBox( NULL, TEXT( "Window Creation Failed!" ),
TEXT( "Error!" ), MB_ICONEXCLAMATION | MB_OK );
exit(0);
}
::ShowWindow( hWnd, iApp->getnCmdShow( ) );
::UpdateWindow(hWnd);
}
}
-
#ifndef ICONTROLLER_H_
#define ICONTROLLER_H_
#include <windows.h>
namespace nApplication
{
class IController
{
public:
virtual int CheckStatus() = 0;
};
}
#endif ICONTROLLER_H_
-
#ifndef CONTROLLER_H_
#define CONTROLLER_H_
#include <windows.h>
#include "IController.h"
#include "IApplication.h"
namespace nApplication
{
class Controller : public IController
{
public:
Controller( IApplication *iApp );
virtual ~Controller();
virtual int CheckStatus();
private:
Controller( Controller &c );
Controller& operator= ( Controller &c );
IApplication *iApp;
};
}
#endif //CONTROLLER_H_
-
#include "Controller.h"
namespace nApplication
{
Controller::Controller( IApplication *iApp ) : iApp( iApp )
{
}
Controller::~Controller()
{
}
int Controller::CheckStatus()
{
return 0;
}
}
-
#include <windows.h>
#include "Application.h"
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
nApplication::Application app( hInstance, nCmdShow );
return app.Run( );
}
-
main.exe : main.cpp
cl /EHsc main.cpp Application.cpp Controller.cpp MainWindow.cpp user32.lib gdi32.lib
del *.obj
#/link /SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup
If you are making a library, you don't have a WinMain, you have a DllMain for dynamic libraries, or nothing for static libraries.
In your case, you'd need to export all the classes functionality from your dll, then in any apps that use your library, you'd include the headers of your project and link to the .lib of the library, then have this in your app where you need the GUI functionality:
nApplication::Application app( hInstance, nCmdShow );
return app.Run( );
Of course this ignores all the side details like registering event callbacks and setup along those lines, however Qt is free and open source, you you might want to look into that before reinventing the wheel, or to help make your own wheel a little rounder.

Resources