FAQ

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
User avatar
Ryan Norton
Moderator
Moderator
Posts: 1319
Joined: Mon Aug 30, 2004 6:01 pm

Post by Ryan Norton » Thu Mar 03, 2005 10:11 am

How do I make a dll for use with wxWidgets?

The following sample shows how to implement a DLL using wxWidgets. When called it will initialize wxWidgets and clean it on unload. The DLL exports two functions "DLLFunction" and "TestReport". DLLFunction displays a simple dialog with a button and handles the button event. "TestReport" shows a small dialog with a wxHTML page.

wxDLL.h

Code: Select all

// wxDLL is a simple DLL which demonstrates how to use
// wxWindows in a DLL which is called from another
// application (not using wxWindows)
//
//
// Tony Edgecombe
// (C) 2004 Frogmore Computer Services
// www.frogmorecs.com
// Edited by upCASE

#pragma once

#include "wx/wx.h"

#include "windows.h"


#ifdef DLLFUNCTIONS_EXPORTS
#define DLLFUNCTIONS_API __declspec(dllexport)
#else
#define DLLFUNCTIONS_API __declspec(dllimport)
#endif

extern "C" DLLFUNCTIONS_API void DLLFunction(HWND);
extern "C" DLLFUNCTIONS_API void TestReport(HWND handle);

class wxDLLApp : public wxApp
{
	bool OnInit();
	void OnButton(wxCommandEvent& evt);
	DECLARE_EVENT_TABLE()
};
wxDLL.cpp

Code: Select all

// wxDLL is a simple DLL which demonstrates how to use
// wxWindows in a DLL which is called from another
// application (not using wxWindows)

// Edited by upCASE

#include "wx/wx.h"

#include "wxDLL.h"
#include "wx/wxhtml.h"

// We use IMPLEMENT_APP_NO_MAIN so we can start the app from DllMain
// as we don't have a WinMain or main entry point
//
BEGIN_EVENT_TABLE(wxDLLApp, wxApp)
	EVT_BUTTON(123,wxDLLApp::OnButton)
END_EVENT_TABLE()

IMPLEMENT_APP_NO_MAIN(wxDLLApp) 

BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
					 )
{
	switch (ul_reason_for_call)
	{
		case DLL_PROCESS_ATTACH:
		{	//use wxInitialize() if you don't want GUI instead of the following 12 lines
                        wxSetInstance((HINSTANCE)hModule);
			int argc = 0;
			char **argv = NULL;
			wxEntryStart(argc, argv);
			if ( !wxTheApp || !wxTheApp->CallOnInit() )
				return FALSE; 
		}
		break;

		case DLL_THREAD_ATTACH:
		break;

		case DLL_THREAD_DETACH:
		break;

		case DLL_PROCESS_DETACH:
		 wxEntryCleanup(); //use wxUninitialize() if you don't want GUI
		break;
	}
    return TRUE;
}

// extern "C" so we don't need a DEF file

// This is the function to be called from the host app
extern "C" DLLFUNCTIONS_API void DLLFunction(HWND handle)
{
// Create a dummy wxWindow so we can use the HWND passed from the
// host application

	wxWindow win;
	win.SetHWND((WXHWND)handle);
	win.Enable(false);

	wxDialog dlg(&win, -1, "wxDialog in DLL", wxDefaultPosition, wxSize(150,150));
	wxButton b(&dlg, 123,"Press me please");
	dlg.ShowModal();

// Clean up else the caller can't use its window
	win.Enable(true);
	win.SetHWND(0);
}

extern "C" DLLFUNCTIONS_API void TestReport(HWND handle)
{
	wxWindow win;

	win.SetHWND((WXHWND)handle);
	win.Enable(false);

	wxDialog dlg(&win, wxID_ANY, wxString(_("About")), wxDefaultPosition, wxSize(400,180));
	
	wxHtmlWindow html1(&dlg,wxID_ANY, wxDefaultPosition, wxSize(380, 160), wxHW_SCROLLBAR_NEVER);
	html1.SetPage("<html><body>"
                     "<h1>Error</h1>"
					"Some error occurred :-))"
					"</body></hmtl>");

	dlg.ShowModal();

	// Clean up else the caller can't use its window
	win.Enable(true);
	win.SetHWND(0);
}

bool wxDLLApp::OnInit()
{
	return true;
}
void wxDLLApp::OnButton(wxCommandEvent& evt)
{
	wxMessageBox("You really did it.... I don't believe it!");
}
Note that the above is for 2.5.4 and up. For lower versions try

Code: Select all

BOOL APIENTRY DllMain( HINSTANCE hModule, 
                       DWORD  fdwReason, 
                       LPVOID lpReserved 
                                        ) 
{ 
   switch (fdwReason) 
   { 
   case DLL_PROCESS_ATTACH: 
       { 
           wxEntry(hModule, 0, NULL, 0, false);
       } 
       break; 

   case DLL_PROCESS_DETACH: 
       { 
           wxTheApp->OnExit();
           wxApp::CleanUp(); 
       } 
   } 

    return TRUE; 
}
The following snippet is a simple "loader" for the DLL that does NOT use wxWidgets.
DLLCaller.cpp

Code: Select all

// This is a simple Windows app which loads and calls our DLL on request
//
// Tony Edgecombe
// (C) 2004 Frogmore Computer Services Ltd
// www.frogmorecs.com
// Edited by upCASE

#pragma once

#include "windows.h"

int APIENTRY WinMain(HINSTANCE hInstance,
					   HINSTANCE hPrevInstance,
					   LPTSTR    lpCmdLine,
					   int       nCmdShow);

// Just a test app no real need for seperate .h file
// #include "DLLTestApp.h"

#include "assert.h"

typedef void (*DLLFunctionPtr) (HWND);
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM); 

// Entry point
int APIENTRY WinMain(HINSTANCE hInstance,
					   HINSTANCE hPrevInstance,
					   LPTSTR    lpCmdLine,
					   int       nCmdShow)
{
	WNDCLASSEX wcx; 

	wcx.cbSize = sizeof(wcx);
	wcx.style = CS_HREDRAW | CS_VREDRAW;
	wcx.lpfnWndProc = MainWndProc;
	wcx.cbClsExtra = 0;
	wcx.cbWndExtra = 0;
	wcx.hInstance = hInstance;
	wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
	wcx.hbrBackground = (HBRUSH)( COLOR_WINDOW+1 );
	wcx.lpszMenuName =  "MainMenu";
	wcx.lpszClassName = "MainWClass";
	wcx.hIconSm = NULL;

	ATOM a = RegisterClassEx(&wcx); 
	assert(a);

	HWND hwnd = CreateWindow("MainWClass",
							"Test DLL",
							WS_OVERLAPPEDWINDOW,
							CW_USEDEFAULT,
							CW_USEDEFAULT,
							CW_USEDEFAULT,
							CW_USEDEFAULT,
							(HWND) NULL,
							(HMENU) NULL,
							hInstance,
							(LPVOID) NULL);
	assert(hwnd);

	ShowWindow(hwnd, nCmdShow); 
	UpdateWindow(hwnd); 

	long bRet;
	MSG msg;
	while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0 ) 
	{
		if (bRet != -1)
		{
			TranslateMessage( &msg );
			DispatchMessage( &msg );
		}
	}

	return 0;
}

// Windows Callback Procedure
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	PAINTSTRUCT ps;
	HDC hDC;

	switch( msg ) {
	  case WM_PAINT:
		  hDC = BeginPaint( hWnd, &ps );
		  TextOut( hDC, 10, 10, "Left Click on this form to launch function: DLLFunction", 55 );
		  TextOut( hDC, 10, 30, "Right Click on this form to launch function: TestReport", 55 );
		  EndPaint( hWnd, &ps );
		  break;

	  case WM_DESTROY:
		  PostQuitMessage( 0 );
		  break;

	  case WM_LBUTTONUP:
		  {
			  // Load up the DLL and call DLLFunction(
				HMODULE hModule = LoadLibrary("Test.dll");
				assert(hModule);
				DLLFunctionPtr pProc = (DLLFunctionPtr)GetProcAddress(hModule, "DLLFunction");
				assert(pProc);
				(pProc)(hWnd);
				FreeLibrary(hModule);
		  }
		  break;

	  case WM_RBUTTONUP:
		  {
			  // Load up the DLL and call DLLFunction(
				HMODULE hModule = LoadLibrary("Test.dll");
				assert(hModule);
				DLLFunctionPtr pProc = (DLLFunctionPtr)GetProcAddress(hModule, "TestReport");
				assert(pProc);
				(pProc)(hWnd);
				FreeLibrary(hModule);
		  }
		  break;

	  default:
		  return( DefWindowProc( hWnd, msg, wParam, lParam ));
	}
	return 0;
}
Edited by upCASE: Added new code sample and description.

You may download the sources and a VC 7 project file here:
http://www.upcase.de/stuff/wxDLL_App.zip
Last edited by Ryan Norton on Tue Jul 12, 2005 9:56 pm, edited 8 times in total.

User avatar
Ryan Norton
Moderator
Moderator
Posts: 1319
Joined: Mon Aug 30, 2004 6:01 pm

Post by Ryan Norton » Thu Mar 03, 2005 10:21 am

How do I use wxThread/wxTimer? Is there an example using wxThread that's easy to understand? What's the difference Between wxThread and wxTimer?

First off, the difference between wxThread and wxTimer is that wxTimer generally runs over and over again easily and usually gets executed in the same thread using the OS's event loop (GUI calls are generally safe with a wxTimer, not so with a wxThread on non-msw platforms).

There is an example using wxThread in the wx lib, but its kind of bulky if you just want a basic understanding of it, plus it doesn't point out the likely problems you'll have with it...

Basically for wxThread all you need to do is dynamically create (via new) a wxThread derived class, call Create then Run (no params usually)- and in your derived class overload

Code: Select all

virtual ExitCode Entry();
And do all you want in Entry. Just make sure you call TestDestroy in there over and over again and return if TestDestroy returns true.

Deleting a running thread is iffy, but you can sorta do it by Delete() of wxThread.

wxTimer is much easier - you still should either dynamically allocate it or make sure it doesn't destruct when you don't want it to - but it isn't as dangerous as a wxThread. To use a wxTimer all you need to do is override Notify

Code: Select all

virtual void Notify();
then call Start in your code with the time you want the timer to be called and whether or not you want it to be called more than once (you can always call Stop() later to end the repeating behaviour).

Also see http://lists.wxwidgets.org/cgi-bin/ezml ... jggjimdhha.
[Mostly retired moderator, still check in to clean up some stuff]

User avatar
Ryan Norton
Moderator
Moderator
Posts: 1319
Joined: Mon Aug 30, 2004 6:01 pm

Post by Ryan Norton » Tue Mar 22, 2005 2:03 am

When I call wxWindow::Destroy() it isn't closing and I'm getting a ton of events!

You're probably doing something funky with one of the wx events. In particular you ABSOLUTELY HAVE TO USE A wxPaintDC IN A PAINT EVENT! If you do not bad things will happen, especially on windows.

Just make sure to read about the particular event types and you should be OK.
[Mostly retired moderator, still check in to clean up some stuff]

User avatar
Ryan Norton
Moderator
Moderator
Posts: 1319
Joined: Mon Aug 30, 2004 6:01 pm

Post by Ryan Norton » Fri Jun 03, 2005 5:32 am

How do I get Microsoft Office/Visual Studio-type toolbars/windows?

There is nothing really in the base of wxWidgets to help you, but there are a few contrib and third-party APIs for doing dockable and other types of windows
Last edited by Ryan Norton on Wed May 10, 2006 6:57 pm, edited 1 time in total.

User avatar
Ryan Norton
Moderator
Moderator
Posts: 1319
Joined: Mon Aug 30, 2004 6:01 pm

Post by Ryan Norton » Fri Jun 17, 2005 8:55 am

How do I get my frame that uses sizers to resize?

Normally the window is supposed to automatically resize when using sizers... however there appears to be a rare-case bug that hits some people (including myself), normally in these cases Layout() works, but in rare cases sometimes it doesn't.

For wxMediaCtrl I use this all-purpose sizer-resizing hack that forces the parent of a control to resize itself.

Code: Select all

// ctrl is the control with a parent to have sizer sizing algorithms forcibly
// applied to it
ctrl->InvalidateBestSize();
ctrl->GetParent()->Layout();
ctrl->GetParent()->Refresh();
ctrl->GetParent()->Update();
ctrl->SetSize(ctrl->GetSize());
[Mostly retired moderator, still check in to clean up some stuff]

User avatar
Ryan Norton
Moderator
Moderator
Posts: 1319
Joined: Mon Aug 30, 2004 6:01 pm

Post by Ryan Norton » Fri Jun 17, 2005 9:20 am

What classes in wxWidgets are thread-safe?

Basically none, not even wxString. If you use STL (wxUSE_STL) then if your stl is thread-safe then a lot of things should be thread-safe except gdi objects (they ref count but there's no spin lock so its not thread-safe)
[Mostly retired moderator, still check in to clean up some stuff]

GianT
Earned some good credits
Earned some good credits
Posts: 124
Joined: Wed Mar 16, 2005 5:44 pm
Location: Guadeloupe, French West Indies
Contact:

Post by GianT » Mon Jun 20, 2005 10:42 pm

How do I convert a BMP/JPG/PNG/etc image into an xpm file?

You can use softs like xnview (there must be others, just search on google).
For those who don't know, xpm is a format used by wxDev-cpp and other development softs to deal with images. It converts it from an image file, but you might want to convert the images manually, instead of letting the soft doing it.
Last edited by GianT on Tue Jun 21, 2005 10:53 pm, edited 4 times in total.

User avatar
Ryan Norton
Moderator
Moderator
Posts: 1319
Joined: Mon Aug 30, 2004 6:01 pm

Post by Ryan Norton » Tue Jun 21, 2005 7:27 pm

What are these things called a patch?

"Patches" are a text file generated by the "diff" program which gets the differences between two files. Developers on a project later use the program "patch" to merge in the changes from the patch file into thier repository. Some projects like wx have specific ways they want you to use patches... you can find the info here -

http://www.wxwidgets.org/technote/patches.htm

Note that if you're on windows you can use tortoisecvs's "make patch" option under "unedit" under the cvs menu in windows explorer.
[Mostly retired moderator, still check in to clean up some stuff]

Sami Hamlaoui
In need of some credit
In need of some credit
Posts: 6
Joined: Mon Jul 11, 2005 1:35 pm

Post by Sami Hamlaoui » Mon Jul 11, 2005 2:02 pm

Why does my program crash at this line in list.cpp?

Code: Select all

 if ( key == current->m_key )
[/size][/b]

It crashes there because you compiled wxWidgets with the default structure alignment in your compiler/IDE, but then in your project set it to some fixed value (1 byte, 2byte, 4byte, etc). You must either compile wxWidgets with the same structure alignment as your app, or keep both set as default.

The options box in MSVC7.1 is at Project -> xxx Properties -> C++ -> Code Generation -> Struct Member Alignment.


If you are loading a lot of binary files directly into structures as opposed to per-variable then you will need Struct Member Alignment at 1 in both wxWidgets and your application, otherwise extra bytes are added into the struct, buggering up the loading.

User avatar
Ryan Norton
Moderator
Moderator
Posts: 1319
Joined: Mon Aug 30, 2004 6:01 pm

Post by Ryan Norton » Thu Oct 27, 2005 8:32 pm

Why is my program so big?

An unfortunate side-effect of using wxWidgets is that you'll have big applications. Even the smallest application can run close to a megabyte. You're best bet is to use UPX or a similar program to compress your program if that is a problem for you.

Or in the future use upCASE's wxWidgets setup compiler. It can switch off specific components and compile the library smaller and tailored to your design.
[Mostly retired moderator, still check in to clean up some stuff]

upCASE
Site Admin
Site Admin
Posts: 3176
Joined: Mon Aug 30, 2004 6:55 am
Location: Germany, Cologne

Post by upCASE » Fri Mar 17, 2006 8:55 am

How do I take a screenshot?

In order to take a screenshot of the whole screen, a specific window, or just a part of one of them, you'll need to use at least two wxDCs.
This example takes a screenshot of the whole screen and saves it as a JPEG image named screenshot.jpg afterwards.

Code: Select all

	//Create a DC for the whole screen area
	wxScreenDC dcScreen;

	//Get the size of the screen/DC
	wxCoord screenWidth, screenHeight;
	dcScreen.GetSize(&screenWidth, &screenHeight);

	//Create a Bitmap that will later on hold the screenshot image
	//Note that the Bitmap must have a size big enough to hold the screenshot
	//-1 means using the current default colour depth
	wxBitmap screenshot(screenWidth, screenHeight,-1);

	//Create a memory DC that will be used for actually taking the screenshot
	wxMemoryDC memDC;
	//Tell the memory DC to use our Bitmap
	//all drawing action on the memory DC will go to the Bitmap now
	memDC.SelectObject(screenshot);
	//Blit (in this case copy) the actual screen on the memory DC
	//and thus the Bitmap
	memDC.Blit( 0, //Copy to this X coordinate
				0, //Copy to this Y coordinate
				screenWidth, //Copy this width
				screenHeight, //Copy this height
				&dcScreen, //From where do we copy?
				0, //What's the X offset in the original DC?
				0  //What's the Y offset in the original DC?
			);
	//Select the Bitmap out of the memory DC by selecting a new
	//uninitialized Bitmap
	memDC.SelectObject(wxNullBitmap);

	//Our Bitmap now has the screenshot, so let's save it :-)
	screenshot.SaveFile("screenshot.jpg",wxBITMAP_TYPE_JPEG);
Note that for saving the bitmap as a JPEG image you'll need to initialize the JPEG handler first.

To create a screenshot of a window you would go about the same way. Instead of a wxScreenDC you'd use a wxWindowDC for the window you want to take a screenshot of.
OS: OpenSuSE, Ubuntu, Win XP Pro
wx: svn
Compiler: gcc 4.5.1, VC 2008, eVC 4

"If it was hard to write it should be hard to read..." - the unknown coder
"Try not! Do. Or do not. There is no try." - Yoda

User avatar
Ryan Norton
Moderator
Moderator
Posts: 1319
Joined: Mon Aug 30, 2004 6:01 pm

Post by Ryan Norton » Thu Jun 15, 2006 5:55 pm

Why does wxSocket/wxURL/wxFileSystem/wxHTMLWindow not work in wxApp::OnInit on Windows?

In wxWidgets, there is a global instance of a class called wxEventLoop. While this class is "running", it handles both platform-specific events and wxWidgets events.

However, the global event loop is not run until after wxApp::OnInit is done.

Normally, this isn't a problem, as events just get queued. The problem with the wxSocket implementation on windows is that it uses a WinAPI windows callback to handle certain messages, and expects the events at times to be handled immediately. If they don't, it may fail, hang, and/or crash.

The gist of it is - you can't use wxSocket-related stuff in wxApp::OnInit on Windows.

See this thread on the developer's mailing list:
http://lists.wxwidgets.org/cgi-bin/ezml ... hgbaehcf#b
[Mostly retired moderator, still check in to clean up some stuff]

Sof_T
Can't get richer than this
Can't get richer than this
Posts: 864
Joined: Thu Jul 28, 2005 9:48 pm
Location: New Forest, United Kingdom
Contact:

Post by Sof_T » Thu Oct 05, 2006 2:12 pm

I came across a problem while trying to compile an application that was built using an ANSI build with a Unicode build. The project used XRC and the compiler complained about pasting 'L' or 'LL'. I found the answer here http://litwindow.blogspot.com/2005/12/c ... de-vc.html

I reproduce the text here in case the site is down.

You are using wxWidgets XRC Resources and compile a Unicode application (which is default on Visual Studio 8.0 Express) and are getting an error similar to

xrcdemo.cpp:63:1: pasting "LL" and "L"UsernameField"" does not give a valid preprocessing token
xrcdemo.cpp: In member function `void LoginDialog::InitWidgetsFromXRC()':

The error is in how you are using the XRC macros. XRC macros don't accept string constants enclosed in _T(). Use string contants without _T(), even in Unicode builds.

Summary: Use _T() with XRC methods, do not use _T() with XRC macros.


Suppose you have

wxXmlResource::Get()->LoadDialog(this, NULL, _T("LoginDialog"));
UsernameField = XRCCTRL(*this, _T("UsernameField"), wxTextCtrl);



You must enclose strings in _T(), if you want to be able to compile your application in both, ANSI and Unicode builds. So LoadDialog(this, NULL, _T("LoginDialog")); is the correct way to specify 'LoginDialog' as the XRC resource.

But, the XRC macros that take a string use _T() internally already. So XRCCTRL(*this, _T("UsernameField"), wxTextCtrl) is wrong, because XRCCTRL is a macro and it adds _T() to the 'UsernameField' parameter itself. The compiler then sees something like

xrcctrl_function(*this, _T( _T("UsernameField") ), wxTextCtrl)



and prints an error.

The correct use of the XRCCTRL and similar macros is to pass in strings without _T(), even in Unicode builds.

UsernameField = XRCCTRL(*this, "UsernameField"), wxTextCtrl);


Some more background for the interested: _T() is a simple macro that simply adds the literal 'L' in front of a quoted string in Unicode builds and does nothing in ANSI builds. Unicode strings are wide-character strings (wchar_t). Wide-character string constants must be preceded by an L in C++.

"This is a char string (1byte), or ANSI string"
L"This is a wide-char string (2byte/4byte under linux), or Unicode string"



Using XRCCTRL(*this, _T("UsernameField"), wxTextCtrl) would expand to xrcctrl_function(*this, LL"UsernameField", wxTextCtrl), which is what the compiler error message says.
The home of Sof.T http://www.sof-t.site88.net/
Author of Programming with wxDevC++
http://sourceforge.net/projects/wxdevcpp-book/

Abysmalk
In need of some credit
In need of some credit
Posts: 2
Joined: Thu May 22, 2008 3:31 pm

Widgets in DLLs

Post by Abysmalk » Mon May 26, 2008 8:04 pm

Following is Ryan Norton's guide on how to make a dll in wxWdigets, however there have been some changes in recent version so my question is two fold. First how do I make changes to allow the code to work with wxWidgets 2.8.7. And second how would I post a wx widget like a combo box to the window that is pointed to by HWND?

Ryan Norton wrote:How do I make a dll for use with wxWidgets?

The following sample shows how to implement a DLL using wxWidgets. When called it will initialize wxWidgets and clean it on unload. The DLL exports two functions "DLLFunction" and "TestReport". DLLFunction displays a simple dialog with a button and handles the button event. "TestReport" shows a small dialog with a wxHTML page.

wxDLL.h

Code: Select all

// wxDLL is a simple DLL which demonstrates how to use
// wxWindows in a DLL which is called from another
// application (not using wxWindows)
//
//
// Tony Edgecombe
// (C) 2004 Frogmore Computer Services
// www.frogmorecs.com
// Edited by upCASE

#pragma once

#include "wx/wx.h"

#include "windows.h"


#ifdef DLLFUNCTIONS_EXPORTS
#define DLLFUNCTIONS_API __declspec(dllexport)
#else
#define DLLFUNCTIONS_API __declspec(dllimport)
#endif

extern "C" DLLFUNCTIONS_API void DLLFunction(HWND);
extern "C" DLLFUNCTIONS_API void TestReport(HWND handle);

class wxDLLApp : public wxApp
{
	bool OnInit();
	void OnButton(wxCommandEvent& evt);
	DECLARE_EVENT_TABLE()
};
wxDLL.cpp

Code: Select all

// wxDLL is a simple DLL which demonstrates how to use
// wxWindows in a DLL which is called from another
// application (not using wxWindows)

// Edited by upCASE

#include "wx/wx.h"

#include "wxDLL.h"
#include "wx/wxhtml.h"

// We use IMPLEMENT_APP_NO_MAIN so we can start the app from DllMain
// as we don't have a WinMain or main entry point
//
BEGIN_EVENT_TABLE(wxDLLApp, wxApp)
	EVT_BUTTON(123,wxDLLApp::OnButton)
END_EVENT_TABLE()

IMPLEMENT_APP_NO_MAIN(wxDLLApp) 

BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
					 )
{
	switch (ul_reason_for_call)
	{
		case DLL_PROCESS_ATTACH:
		{	//use wxInitialize() if you don't want GUI instead of the following 12 lines
                        wxSetInstance((HINSTANCE)hModule);
			int argc = 0;
			char **argv = NULL;
			wxEntryStart(argc, argv);
			if ( !wxTheApp || !wxTheApp->CallOnInit() )
				return FALSE; 
		}
		break;

		case DLL_THREAD_ATTACH:
		break;

		case DLL_THREAD_DETACH:
		break;

		case DLL_PROCESS_DETACH:
		 wxEntryCleanup(); //use wxUninitialize() if you don't want GUI
		break;
	}
    return TRUE;
}

// extern "C" so we don't need a DEF file

// This is the function to be called from the host app
extern "C" DLLFUNCTIONS_API void DLLFunction(HWND handle)
{
// Create a dummy wxWindow so we can use the HWND passed from the
// host application

	wxWindow win;
	win.SetHWND((WXHWND)handle);
	win.Enable(false);

	wxDialog dlg(&win, -1, "wxDialog in DLL", wxDefaultPosition, wxSize(150,150));
	wxButton b(&dlg, 123,"Press me please");
	dlg.ShowModal();

// Clean up else the caller can't use its window
	win.Enable(true);
	win.SetHWND(0);
}

extern "C" DLLFUNCTIONS_API void TestReport(HWND handle)
{
	wxWindow win;

	win.SetHWND((WXHWND)handle);
	win.Enable(false);

	wxDialog dlg(&win, wxID_ANY, wxString(_("About")), wxDefaultPosition, wxSize(400,180));
	
	wxHtmlWindow html1(&dlg,wxID_ANY, wxDefaultPosition, wxSize(380, 160), wxHW_SCROLLBAR_NEVER);
	html1.SetPage("<html><body>"
                     "<h1>Error</h1>"
					"Some error occurred :-))"
					"</body></hmtl>");

	dlg.ShowModal();

	// Clean up else the caller can't use its window
	win.Enable(true);
	win.SetHWND(0);
}

bool wxDLLApp::OnInit()
{
	return true;
}
void wxDLLApp::OnButton(wxCommandEvent& evt)
{
	wxMessageBox("You really did it.... I don't believe it!");
}
Note that the above is for 2.5.4 and up. For lower versions try

Code: Select all

BOOL APIENTRY DllMain( HINSTANCE hModule, 
                       DWORD  fdwReason, 
                       LPVOID lpReserved 
                                        ) 
{ 
   switch (fdwReason) 
   { 
   case DLL_PROCESS_ATTACH: 
       { 
           wxEntry(hModule, 0, NULL, 0, false);
       } 
       break; 

   case DLL_PROCESS_DETACH: 
       { 
           wxTheApp->OnExit();
           wxApp::CleanUp(); 
       } 
   } 

    return TRUE; 
}
The following snippet is a simple "loader" for the DLL that does NOT use wxWidgets.
DLLCaller.cpp

Code: Select all

// This is a simple Windows app which loads and calls our DLL on request
//
// Tony Edgecombe
// (C) 2004 Frogmore Computer Services Ltd
// www.frogmorecs.com
// Edited by upCASE

#pragma once

#include "windows.h"

int APIENTRY WinMain(HINSTANCE hInstance,
					   HINSTANCE hPrevInstance,
					   LPTSTR    lpCmdLine,
					   int       nCmdShow);

// Just a test app no real need for seperate .h file
// #include "DLLTestApp.h"

#include "assert.h"

typedef void (*DLLFunctionPtr) (HWND);
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM); 

// Entry point
int APIENTRY WinMain(HINSTANCE hInstance,
					   HINSTANCE hPrevInstance,
					   LPTSTR    lpCmdLine,
					   int       nCmdShow)
{
	WNDCLASSEX wcx; 

	wcx.cbSize = sizeof(wcx);
	wcx.style = CS_HREDRAW | CS_VREDRAW;
	wcx.lpfnWndProc = MainWndProc;
	wcx.cbClsExtra = 0;
	wcx.cbWndExtra = 0;
	wcx.hInstance = hInstance;
	wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
	wcx.hbrBackground = (HBRUSH)( COLOR_WINDOW+1 );
	wcx.lpszMenuName =  "MainMenu";
	wcx.lpszClassName = "MainWClass";
	wcx.hIconSm = NULL;

	ATOM a = RegisterClassEx(&wcx); 
	assert(a);

	HWND hwnd = CreateWindow("MainWClass",
							"Test DLL",
							WS_OVERLAPPEDWINDOW,
							CW_USEDEFAULT,
							CW_USEDEFAULT,
							CW_USEDEFAULT,
							CW_USEDEFAULT,
							(HWND) NULL,
							(HMENU) NULL,
							hInstance,
							(LPVOID) NULL);
	assert(hwnd);

	ShowWindow(hwnd, nCmdShow); 
	UpdateWindow(hwnd); 

	long bRet;
	MSG msg;
	while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0 ) 
	{
		if (bRet != -1)
		{
			TranslateMessage( &msg );
			DispatchMessage( &msg );
		}
	}

	return 0;
}

// Windows Callback Procedure
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	PAINTSTRUCT ps;
	HDC hDC;

	switch( msg ) {
	  case WM_PAINT:
		  hDC = BeginPaint( hWnd, &ps );
		  TextOut( hDC, 10, 10, "Left Click on this form to launch function: DLLFunction", 55 );
		  TextOut( hDC, 10, 30, "Right Click on this form to launch function: TestReport", 55 );
		  EndPaint( hWnd, &ps );
		  break;

	  case WM_DESTROY:
		  PostQuitMessage( 0 );
		  break;

	  case WM_LBUTTONUP:
		  {
			  // Load up the DLL and call DLLFunction(
				HMODULE hModule = LoadLibrary("Test.dll");
				assert(hModule);
				DLLFunctionPtr pProc = (DLLFunctionPtr)GetProcAddress(hModule, "DLLFunction");
				assert(pProc);
				(pProc)(hWnd);
				FreeLibrary(hModule);
		  }
		  break;

	  case WM_RBUTTONUP:
		  {
			  // Load up the DLL and call DLLFunction(
				HMODULE hModule = LoadLibrary("Test.dll");
				assert(hModule);
				DLLFunctionPtr pProc = (DLLFunctionPtr)GetProcAddress(hModule, "TestReport");
				assert(pProc);
				(pProc)(hWnd);
				FreeLibrary(hModule);
		  }
		  break;

	  default:
		  return( DefWindowProc( hWnd, msg, wParam, lParam ));
	}
	return 0;
}
Edited by upCASE: Added new code sample and description.

You may download the sources and a VC 7 project file here:
http://www.upcase.de/stuff/wxDLL_App.zip

Post Reply