From 5bd3a2da9573f270564cd035e0cfbf6902cf8750 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin <vadim@wxwidgets.org> Date: Tue, 18 Jan 2000 01:22:56 +0000 Subject: [PATCH] 1. small fix in wxDirDialog: SHBrowseForFolder() doesn't like '/'s 2. streamlined DDE code (better error handling, range checking) 3. hack in wxExecute to allow launching DDE servers 4. changed wxTreeCtrl::m_filename scope from private to protected 5. corrected creating wxBitmaps from XBMs 6. wxListCtrl no longer sends bogus ACTIVATED events git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@5488 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/textctrl.h | 2 +- src/common/mimetype.cpp | 64 +- src/gtk/window.cpp | 4 +- src/gtk1/window.cpp | 4 +- src/msw/bitmap.cpp | 54 +- src/msw/control.cpp | 7 +- src/msw/dde.cpp | 1255 +++++++++++++++++++++++---------------- src/msw/dirdlg.cpp | 1 + src/msw/listctrl.cpp | 9 +- src/msw/statbox.cpp | 5 +- src/msw/utilsexc.cpp | 90 ++- 11 files changed, 928 insertions(+), 567 deletions(-) diff --git a/include/wx/textctrl.h b/include/wx/textctrl.h index 5e7d35a11f..223403b1c8 100644 --- a/include/wx/textctrl.h +++ b/include/wx/textctrl.h @@ -155,7 +155,7 @@ public: bool Modified() const { return IsModified(); } #endif -private: +protected: // the name of the last file loaded with LoadFile() which will be used by // SaveFile() by default wxString m_filename; diff --git a/src/common/mimetype.cpp b/src/common/mimetype.cpp index 592606ec2d..57eacdb803 100644 --- a/src/common/mimetype.cpp +++ b/src/common/mimetype.cpp @@ -355,8 +355,8 @@ class wxMimeTypeIconHandler { public: virtual bool GetIcon(const wxString& mimetype, wxIcon *icon) = 0; - - // this function fills manager with MIME types information gathered + + // this function fills manager with MIME types information gathered // (as side effect) when searching for icons. This may be particularly // useful if mime.types is incomplete (e.g. RedHat distributions). virtual void GetMimeInfoRecords(wxMimeTypesManagerImpl *manager) = 0; @@ -370,7 +370,7 @@ class wxGNOMEIconHandler : public wxMimeTypeIconHandler public: virtual bool GetIcon(const wxString& mimetype, wxIcon *icon); virtual void GetMimeInfoRecords(wxMimeTypesManagerImpl *manager) {} - + private: void Init(); void LoadIconsFromKeyFile(const wxString& filename); @@ -397,7 +397,7 @@ private: void LoadLinksForMimeType(const wxString& dirbase, const wxString& subdir, const wxArrayString& icondirs); - void LoadLinkFilesFromDir(const wxString& dirbase, + void LoadLinkFilesFromDir(const wxString& dirbase, const wxArrayString& icondirs); void Init(); @@ -758,13 +758,15 @@ wxString wxFileTypeImpl::GetCommand(const wxChar *verb) const return wxEmptyString; } - strKey << wxT("\\shell\\") << verb << wxT("\\command"); - wxRegKey key(wxRegKey::HKCR, strKey); + strKey << wxT("\\shell\\") << verb; + wxRegKey key(wxRegKey::HKCR, strKey + _T("\\command")); wxString command; if ( key.Open() ) { // it's the default value of the key if ( key.QueryValue(wxT(""), command) ) { - // transform it from '%1' to '%s' style format string + // transform it from '%1' to '%s' style format string (now also + // test for %L - apparently MS started using it as well for the + // same purpose) // NB: we don't make any attempt to verify that the string is valid, // i.e. doesn't contain %2, or second %1 or .... But we do make @@ -773,7 +775,9 @@ wxString wxFileTypeImpl::GetCommand(const wxChar *verb) const size_t len = command.Len(); for ( size_t n = 0; (n < len) && !foundFilename; n++ ) { if ( command[n] == wxT('%') && - (n + 1 < len) && command[n + 1] == wxT('1') ) { + (n + 1 < len) && + (command[n + 1] == wxT('1') || + command[n + 1] == wxT('L')) ) { // replace it with '%s' command[n + 1] = wxT('s'); @@ -781,8 +785,33 @@ wxString wxFileTypeImpl::GetCommand(const wxChar *verb) const } } - if ( !foundFilename ) { - // we didn't find any '%1'! + // look whether we must issue some DDE requests to the application + // (and not just launch it) + strKey += _T("\\DDEExec"); + wxRegKey keyDDE(wxRegKey::HKCR, strKey); + if ( keyDDE.Open() ) { + wxString ddeCommand, ddeServer, ddeTopic; + keyDDE.QueryValue(_T(""), ddeCommand); + ddeCommand.Replace(_T("%1"), _T("%s")); + + wxRegKey(wxRegKey::HKCR, strKey + _T("\\Application")). + QueryValue(_T(""), ddeServer); + wxRegKey(wxRegKey::HKCR, strKey + _T("\\Topic")). + QueryValue(_T(""), ddeTopic); + + // HACK: we use a special feature of wxExecute which exists + // just because we need it here: it will establish DDE + // conversation with the program it just launched + command.Prepend(_T("WX_DDE#")); + command << _T('#') << ddeServer + << _T('#') << ddeTopic + << _T('#') << ddeCommand; + } + else if ( !foundFilename ) { + // we didn't find any '%1' - the application doesn't know which + // file to open (note that we only do it if there is no DDEExec + // subkey) + // // HACK: append the filename at the end, hope that it will do command << wxT(" %s"); } @@ -1445,7 +1474,7 @@ void wxKDEIconHandler::LoadLinksForMimeSubtype(const wxString& dirbase, wxString mime_extension, mime_desc; - pos = wxNOT_FOUND; + pos = wxNOT_FOUND; if (wxGetLocale() != NULL) mime_desc = _T("Comment[") + wxGetLocale()->GetName() + _T("]="); if (pos == wxNOT_FOUND) mime_desc = _T("Comment="); @@ -1466,7 +1495,7 @@ void wxKDEIconHandler::LoadLinksForMimeSubtype(const wxString& dirbase, while ( *pc && *pc != _T('\n') ) exts += *pc++; wxStringTokenizer tokenizer(exts, _T(";")); wxString e; - + while (tokenizer.HasMoreTokens()) { e = tokenizer.GetNextToken(); @@ -1476,7 +1505,7 @@ void wxKDEIconHandler::LoadLinksForMimeSubtype(const wxString& dirbase, } mime_extension.RemoveLast(); } - + ms_infoTypes.Add(mimetype); ms_infoDescriptions.Add(mime_desc); ms_infoExtensions.Add(mime_extension); @@ -1640,7 +1669,7 @@ bool wxKDEIconHandler::GetIcon(const wxString& mimetype, wxIcon *icon) void wxKDEIconHandler::GetMimeInfoRecords(wxMimeTypesManagerImpl *manager) { if ( !m_inited ) Init(); - + size_t cnt = ms_infoTypes.GetCount(); for (unsigned i = 0; i < cnt; i++) manager -> AddMimeTypeInfo(ms_infoTypes[i], ms_infoExtensions[i], ms_infoDescriptions[i]); @@ -1779,7 +1808,8 @@ wxMimeTypesManagerImpl::wxMimeTypesManagerImpl() }; // first read the system wide file(s) - for ( size_t n = 0; n < WXSIZEOF(aStandardLocations); n++ ) { + size_t n; + for ( n = 0; n < WXSIZEOF(aStandardLocations); n++ ) { wxString dir = aStandardLocations[n]; wxString file = dir + wxT("/mailcap"); @@ -1806,11 +1836,11 @@ wxMimeTypesManagerImpl::wxMimeTypesManagerImpl() if ( wxFile::Exists(strUserMimeTypes) ) { ReadMimeTypes(strUserMimeTypes); } - + // read KDE/GNOME tables ArrayIconHandlers& handlers = GetIconHandlers(); size_t count = handlers.GetCount(); - for ( size_t n = 0; n < count; n++ ) + for ( n = 0; n < count; n++ ) handlers[n]->GetMimeInfoRecords(this); } diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp index a3774d64d7..2d3fc4c7ab 100644 --- a/src/gtk/window.cpp +++ b/src/gtk/window.cpp @@ -1627,7 +1627,7 @@ static void gtk_window_hscroll_change_callback( GtkWidget *WXUNUSED(widget), wxW static gint gtk_scrollbar_button_press_callback( GtkRange *WXUNUSED(widget), GdkEventButton *WXUNUSED(gdk_event), - wxWindow *win ) + wxWindow *WXUNUSED(win)) { DEBUG_MAIN_THREAD @@ -1650,7 +1650,7 @@ static gint gtk_scrollbar_button_press_callback( GtkRange *WXUNUSED(widget), static gint gtk_scrollbar_button_release_callback( GtkRange *WXUNUSED(widget), GdkEventButton *WXUNUSED(gdk_event), - wxWindow *win ) + wxWindow *WXUNUSED(win)) { DEBUG_MAIN_THREAD diff --git a/src/gtk1/window.cpp b/src/gtk1/window.cpp index a3774d64d7..2d3fc4c7ab 100644 --- a/src/gtk1/window.cpp +++ b/src/gtk1/window.cpp @@ -1627,7 +1627,7 @@ static void gtk_window_hscroll_change_callback( GtkWidget *WXUNUSED(widget), wxW static gint gtk_scrollbar_button_press_callback( GtkRange *WXUNUSED(widget), GdkEventButton *WXUNUSED(gdk_event), - wxWindow *win ) + wxWindow *WXUNUSED(win)) { DEBUG_MAIN_THREAD @@ -1650,7 +1650,7 @@ static gint gtk_scrollbar_button_press_callback( GtkRange *WXUNUSED(widget), static gint gtk_scrollbar_button_release_callback( GtkRange *WXUNUSED(widget), GdkEventButton *WXUNUSED(gdk_event), - wxWindow *win ) + wxWindow *WXUNUSED(win)) { DEBUG_MAIN_THREAD diff --git a/src/msw/bitmap.cpp b/src/msw/bitmap.cpp index e74cf073a4..8eba1311e5 100644 --- a/src/msw/bitmap.cpp +++ b/src/msw/bitmap.cpp @@ -227,25 +227,63 @@ wxBitmap::~wxBitmap() wxTheBitmapList->DeleteObject(this); } -wxBitmap::wxBitmap(const char bits[], int the_width, int the_height, int no_bits) +wxBitmap::wxBitmap(const char bits[], int width, int height, int depth) { Init(); wxBitmapRefData *refData = new wxBitmapRefData; m_refData = refData; - refData->m_width = the_width; - refData->m_height = the_height; - refData->m_depth = no_bits; + refData->m_width = width; + refData->m_height = height; + refData->m_depth = depth; refData->m_numColors = 0; refData->m_selectedInto = NULL; - HBITMAP hbmp = ::CreateBitmap(the_width, the_height, 1, no_bits, bits); + char *data; + if ( depth == 1 ) + { + // we assume that it is in XBM format which is not quite the same as + // the format CreateBitmap() wants because the order of bytes in the + // line is inversed! + static const size_t bytesPerLine = (width + 7) / 8; + static const size_t padding = bytesPerLine % 2; + static const size_t len = height * ( padding + bytesPerLine ); + data = (char *)malloc(len); + const char *src = bits; + char *dst = data; + + for ( int rows = 0; rows < height; rows++ ) + { + // note that offset cannot be size_t due to >= 0 test! + for ( int offset = bytesPerLine - 1; offset >= 0; offset-- ) + { + *dst++ = *(src + offset); + } + + if ( padding ) + *dst++ = 0; + + src += bytesPerLine; + } + } + else + { + // bits should already be in Windows standard format + data = (char *)bits; // const_cast is harmless + } + + HBITMAP hbmp = ::CreateBitmap(width, height, 1, depth, data); if ( !hbmp ) { wxLogLastError("CreateBitmap"); } + if ( data != bits ) + { + free(data); + } + SetHBITMAP((WXHBITMAP)hbmp); } @@ -253,14 +291,14 @@ wxBitmap::wxBitmap(const char bits[], int the_width, int the_height, int no_bits wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const { wxCHECK_MSG( Ok() && - (rect.x >= 0) && (rect.y >= 0) && + (rect.x >= 0) && (rect.y >= 0) && (rect.x+rect.width <= GetWidth()) && (rect.y+rect.height <= GetHeight()), wxNullBitmap, wxT("Invalid bitmap or bitmap region") ); - + wxBitmap ret( rect.width, rect.height, GetDepth() ); wxASSERT_MSG( ret.Ok(), wxT("GetSubBitmap error") ); - + // copy bitmap data HDC dcSrc = ::CreateCompatibleDC(NULL); HDC dcDst = ::CreateCompatibleDC(NULL); diff --git a/src/msw/control.cpp b/src/msw/control.cpp index ea72d9e9f3..89ddd5c546 100644 --- a/src/msw/control.cpp +++ b/src/msw/control.cpp @@ -204,10 +204,9 @@ bool wxControl::MSWOnNotify(int idCtrl, void wxControl::OnEraseBackground(wxEraseEvent& event) { - // In general, you don't want to erase the background of a control, - // or you'll get a flicker. - // TODO: move this 'null' function into each control that - // might flicker. + // notice that this 'dumb' implementation may cause flicker for some of the + // controls in which case they should intercept wxEraseEvent and process it + // themselves somehow RECT rect; ::GetClientRect(GetHwnd(), &rect); diff --git a/src/msw/dde.cpp b/src/msw/dde.cpp index 275f56144f..0d084650d7 100644 --- a/src/msw/dde.cpp +++ b/src/msw/dde.cpp @@ -1,81 +1,106 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: dde.cpp +// Name: msw/dde.cpp // Purpose: DDE classes // Author: Julian Smart // Modified by: // Created: 01/02/97 // RCS-ID: $Id$ // Copyright: (c) Julian Smart and Markus Holzem -// Licence: wxWindows licence +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + #ifdef __GNUG__ -#pragma implementation "dde.h" + #pragma implementation "dde.h" #endif // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ -#pragma hdrstop -#endif - -#ifndef WX_PRECOMP -#include "wx/defs.h" + #pragma hdrstop #endif #if wxUSE_IPC #ifndef WX_PRECOMP -#include "wx/utils.h" -#include "wx/app.h" + #include "wx/utils.h" + #include "wx/app.h" #endif #include "wx/module.h" #include "wx/dde.h" #include "wx/msw/private.h" + +#include <string.h> #include <windows.h> #include <ddeml.h> -#ifndef __TWIN32__ -#if !wxUSE_NORLANDER_HEADERS -#ifdef __GNUWIN32__ -#include "wx/msw/gnuwin32/extra.h" -#endif -#endif +#if defined(__TWIN32__) || defined(__GNUWIN32_OLD__) + #include "wx/msw/gnuwin32/extra.h" #endif -#include <string.h> +// ---------------------------------------------------------------------------- +// macros and constants +// ---------------------------------------------------------------------------- #ifdef __WIN32__ -#define _EXPORT /**/ + #define _EXPORT #else -#define _EXPORT _export + #define _EXPORT _export #endif -IMPLEMENT_DYNAMIC_CLASS(wxDDEServer, wxServerBase) -IMPLEMENT_DYNAMIC_CLASS(wxDDEClient, wxClientBase) -IMPLEMENT_CLASS(wxDDEConnection, wxConnectionBase) +#if wxUSE_UNICODE + #define DDE_CP CP_WINUNICODE +#else + #define DDE_CP CP_WINANSI +#endif + +#define GetHConv() ((HCONV)m_hConv) + +// default timeout for DDE operations (5sec) +#define DDE_TIMEOUT 5000 + +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- static wxDDEConnection *DDEFindConnection(HCONV hConv); static void DDEDeleteConnection(HCONV hConv); static wxDDEServer *DDEFindServer(const wxString& s); -extern "C" HDDEDATA EXPENTRY _EXPORT _DDECallback( -WORD wType, -WORD wFmt, -HCONV hConv, -HSZ hsz1, -HSZ hsz2, -HDDEDATA hData, -DWORD lData1, -DWORD lData2); +extern "C" HDDEDATA EXPENTRY _EXPORT _DDECallback(WORD wType, + WORD wFmt, + HCONV hConv, + HSZ hsz1, + HSZ hsz2, + HDDEDATA hData, + DWORD lData1, + DWORD lData2); // Add topic name to atom table before using in conversations static HSZ DDEAddAtom(const wxString& string); static HSZ DDEGetAtom(const wxString& string); -static void DDEPrintError(void); + +// string handles +static HSZ DDEAtomFromString(const wxString& s); +static wxString DDEStringFromAtom(HSZ hsz); + +// error handling +static wxString DDEGetErrorMsg(UINT error); +static void DDELogError(const wxString& s, UINT error = DMLERR_NO_ERROR); + +// ---------------------------------------------------------------------------- +// global variables +// ---------------------------------------------------------------------------- static DWORD DDEIdInst = 0L; static wxDDEConnection *DDECurrentlyConnecting = NULL; @@ -86,56 +111,76 @@ static wxList wxDDEServerObjects; char *DDEDefaultIPCBuffer = NULL; int DDEDefaultIPCBufferSize = 0; +static bool DDEInitialized = FALSE; -/* - * Initialization - * - */ +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- -static bool DDEInitialized = FALSE; +// A module to allow DDE cleanup without calling these functions +// from app.cpp or from the user's application. -void wxDDEInitialize() +class wxDDEModule : public wxModule { - if (DDEInitialized) - return; - DDEInitialized = TRUE; +public: + wxDDEModule() {} + bool OnInit() { return TRUE; } + void OnExit() { wxDDECleanUp(); } - // Should insert filter flags - DdeInitialize(&DDEIdInst, (PFNCALLBACK)MakeProcInstance( - (FARPROC)_DDECallback, wxGetInstance()), - APPCLASS_STANDARD, - 0L); -} +private: + DECLARE_DYNAMIC_CLASS(wxDDEModule) +}; -/* - * CleanUp - */ +// ---------------------------------------------------------------------------- +// wxWin macros +// ---------------------------------------------------------------------------- -void wxDDECleanUp() +IMPLEMENT_DYNAMIC_CLASS(wxDDEServer, wxServerBase) +IMPLEMENT_DYNAMIC_CLASS(wxDDEClient, wxClientBase) +IMPLEMENT_CLASS(wxDDEConnection, wxConnectionBase) +IMPLEMENT_DYNAMIC_CLASS(wxDDEModule, wxModule) + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// initialization and cleanup +// ---------------------------------------------------------------------------- + +extern void wxDDEInitialize() { - if (DDEIdInst != 0) - { - DdeUninitialize(DDEIdInst); - DDEIdInst = 0; - } - if (DDEDefaultIPCBuffer) - delete [] DDEDefaultIPCBuffer ; + if ( !DDEInitialized ) + { + // Should insert filter flags + PFNCALLBACK callback = (PFNCALLBACK) + MakeProcInstance((FARPROC)_DDECallback, wxGetInstance()); + UINT rc = DdeInitialize(&DDEIdInst, callback, APPCLASS_STANDARD, 0L); + if ( rc != DMLERR_NO_ERROR ) + { + DDELogError(_T("Failed to initialize DDE"), rc); + } + else + { + DDEInitialized = TRUE; + } + } } -// A module to allow DDE initialization/cleanup -// without calling these functions from app.cpp or from -// the user's application. - -class wxDDEModule: public wxModule +void wxDDECleanUp() { -DECLARE_DYNAMIC_CLASS(wxDDEModule) -public: - wxDDEModule() {} - bool OnInit() { wxDDEInitialize(); return TRUE; }; - void OnExit() { wxDDECleanUp(); }; -}; + if ( DDEIdInst != 0 ) + { + DdeUninitialize(DDEIdInst); + DDEIdInst = 0; + } -IMPLEMENT_DYNAMIC_CLASS(wxDDEModule, wxModule) + delete [] DDEDefaultIPCBuffer; +} + +// ---------------------------------------------------------------------------- +// functions working with the global connection list(s) +// ---------------------------------------------------------------------------- // Global find connection static wxDDEConnection *DDEFindConnection(HCONV hConv) @@ -149,7 +194,7 @@ static wxDDEConnection *DDEFindConnection(HCONV hConv) node = node->Next(); } if (found) - return found; + return found; node = wxDDEClientObjects.First(); while (node && !found) @@ -173,7 +218,7 @@ static void DDEDeleteConnection(HCONV hConv) node = node->Next(); } if (found) - return; + return; node = wxDDEClientObjects.First(); while (node && !found) @@ -192,7 +237,7 @@ static wxDDEServer *DDEFindServer(const wxString& s) while (node && !found) { wxDDEServer *object = (wxDDEServer *)node->Data(); - + if (object->GetServiceName() == s) found = object; else node = node->Next(); @@ -200,604 +245,762 @@ static wxDDEServer *DDEFindServer(const wxString& s) return found; } -/* - * Server - * - */ +// ---------------------------------------------------------------------------- +// wxDDEServer +// ---------------------------------------------------------------------------- -wxDDEServer::wxDDEServer(void) +wxDDEServer::wxDDEServer() { - m_serviceName = ""; - wxDDEServerObjects.Append(this); + wxDDEInitialize(); + + wxDDEServerObjects.Append(this); } -bool wxDDEServer::Create(const wxString& server_name) +bool wxDDEServer::Create(const wxString& server) { - m_serviceName = server_name; - HSZ serviceName = DdeCreateStringHandle(DDEIdInst, WXSTRINGCAST server_name, CP_WINANSI); + m_serviceName = server; - if (DdeNameService(DDEIdInst, serviceName, (HSZ) NULL, DNS_REGISTER) == 0) - { - DDEPrintError(); - return FALSE; - } - return TRUE; + if ( !DdeNameService(DDEIdInst, DDEAtomFromString(server), (HSZ)NULL, DNS_REGISTER) ) + { + DDELogError(wxString::Format(_("Failed to register DDE server '%s'"), + server.c_str())); + + return FALSE; + } + + return TRUE; } -wxDDEServer::~wxDDEServer(void) +wxDDEServer::~wxDDEServer() { - if (m_serviceName != wxT("")) - { - HSZ serviceName = DdeCreateStringHandle(DDEIdInst, WXSTRINGCAST m_serviceName, CP_WINANSI); - if (DdeNameService(DDEIdInst, serviceName, NULL, DNS_UNREGISTER) == 0) + if ( !!m_serviceName ) { - DDEPrintError(); + if ( !DdeNameService(DDEIdInst, DDEAtomFromString(m_serviceName), + (HSZ)NULL, DNS_UNREGISTER) ) + { + DDELogError(wxString::Format(_("Failed to unregister DDE server '%s'"), + m_serviceName.c_str())); + } } - } - wxDDEServerObjects.DeleteObject(this); - wxNode *node = m_connections.First(); - while (node) - { - wxDDEConnection *connection = (wxDDEConnection *)node->Data(); - wxNode *next = node->Next(); - connection->OnDisconnect(); // May delete the node implicitly - node = next; - } + wxDDEServerObjects.DeleteObject(this); - // If any left after this, delete them - node = m_connections.First(); - while (node) - { - wxDDEConnection *connection = (wxDDEConnection *)node->Data(); - wxNode *next = node->Next(); - delete connection; - node = next; - } + wxNode *node = m_connections.First(); + while (node) + { + wxDDEConnection *connection = (wxDDEConnection *)node->Data(); + wxNode *next = node->Next(); + connection->OnDisconnect(); // May delete the node implicitly + node = next; + } + + // If any left after this, delete them + node = m_connections.First(); + while (node) + { + wxDDEConnection *connection = (wxDDEConnection *)node->Data(); + wxNode *next = node->Next(); + delete connection; + node = next; + } } wxConnectionBase *wxDDEServer::OnAcceptConnection(const wxString& /* topic */) { - return new wxDDEConnection; + return new wxDDEConnection; } wxDDEConnection *wxDDEServer::FindConnection(WXHCONV conv) { - wxNode *node = m_connections.First(); - wxDDEConnection *found = NULL; - while (node && !found) - { - wxDDEConnection *connection = (wxDDEConnection *)node->Data(); - if (connection->m_hConv == conv) - found = connection; - else node = node->Next(); - } - return found; + wxNode *node = m_connections.First(); + wxDDEConnection *found = NULL; + while (node && !found) + { + wxDDEConnection *connection = (wxDDEConnection *)node->Data(); + if (connection->m_hConv == conv) + found = connection; + else node = node->Next(); + } + return found; } // Only delete the entry in the map, not the actual connection bool wxDDEServer::DeleteConnection(WXHCONV conv) { - wxNode *node = m_connections.First(); - bool found = FALSE; - while (node && !found) - { - wxDDEConnection *connection = (wxDDEConnection *)node->Data(); - if (connection->m_hConv == conv) + wxNode *node = m_connections.First(); + bool found = FALSE; + while (node && !found) { - found = TRUE; - delete node; + wxDDEConnection *connection = (wxDDEConnection *)node->Data(); + if (connection->m_hConv == conv) + { + found = TRUE; + delete node; + } + else node = node->Next(); } - else node = node->Next(); - } - return found; + return found; } +// ---------------------------------------------------------------------------- +// wxDDEClient +// ---------------------------------------------------------------------------- -/* - * Client - * - */ - - -wxDDEClient::wxDDEClient(void) +wxDDEClient::wxDDEClient() { - wxDDEClientObjects.Append(this); + wxDDEInitialize(); + + wxDDEClientObjects.Append(this); } -wxDDEClient::~wxDDEClient(void) +wxDDEClient::~wxDDEClient() { - wxDDEClientObjects.DeleteObject(this); - wxNode *node = m_connections.First(); - while (node) - { - wxDDEConnection *connection = (wxDDEConnection *)node->Data(); - delete connection; // Deletes the node implicitly (see ~wxDDEConnection) - node = m_connections.First(); - } + wxDDEClientObjects.DeleteObject(this); + wxNode *node = m_connections.First(); + while (node) + { + wxDDEConnection *connection = (wxDDEConnection *)node->Data(); + delete connection; // Deletes the node implicitly (see ~wxDDEConnection) + node = m_connections.First(); + } } bool wxDDEClient::ValidHost(const wxString& /* host */) { - return TRUE; + return TRUE; } -wxConnectionBase *wxDDEClient::MakeConnection(const wxString& /* host */, const wxString& server_name, const wxString& topic) +wxConnectionBase *wxDDEClient::MakeConnection(const wxString& WXUNUSED(host), + const wxString& server, + const wxString& topic) { - HSZ serviceName = DdeCreateStringHandle(DDEIdInst, WXSTRINGCAST server_name, CP_WINANSI); - HSZ topic_atom = DdeCreateStringHandle(DDEIdInst, WXSTRINGCAST topic, CP_WINANSI); - - HCONV hConv = DdeConnect(DDEIdInst, serviceName, topic_atom, (PCONVCONTEXT)NULL); - if (hConv == (HCONV) NULL) - return (wxConnectionBase*) NULL; - else - { - wxDDEConnection *connection = (wxDDEConnection*) OnMakeConnection(); - if (connection) + HCONV hConv = DdeConnect(DDEIdInst, DDEAtomFromString(server), DDEAtomFromString(topic), + (PCONVCONTEXT)NULL); + if ( !hConv ) { - connection->m_hConv = (WXHCONV) hConv; - connection->m_topicName = topic; - connection->m_client = this; - m_connections.Append(connection); - return connection; + DDELogError(wxString::Format(_("Failed to create connection to " + "server '%s' on topic '%s'"), + server.c_str(), topic.c_str())); } - else return (wxConnectionBase*) NULL; - } + else + { + wxDDEConnection *connection = (wxDDEConnection*) OnMakeConnection(); + if (connection) + { + connection->m_hConv = (WXHCONV) hConv; + connection->m_topicName = topic; + connection->m_client = this; + m_connections.Append(connection); + return connection; + } + } + + return (wxConnectionBase*) NULL; } -wxConnectionBase *wxDDEClient::OnMakeConnection(void) +wxConnectionBase *wxDDEClient::OnMakeConnection() { - return new wxDDEConnection; + return new wxDDEConnection; } wxDDEConnection *wxDDEClient::FindConnection(WXHCONV conv) { - wxNode *node = m_connections.First(); - wxDDEConnection *found = NULL; - while (node && !found) - { - wxDDEConnection *connection = (wxDDEConnection *)node->Data(); - if (connection->m_hConv == conv) - found = connection; - else node = node->Next(); - } - return found; + wxNode *node = m_connections.First(); + wxDDEConnection *found = NULL; + while (node && !found) + { + wxDDEConnection *connection = (wxDDEConnection *)node->Data(); + if (connection->m_hConv == conv) + found = connection; + else node = node->Next(); + } + return found; } // Only delete the entry in the map, not the actual connection bool wxDDEClient::DeleteConnection(WXHCONV conv) { - wxNode *node = m_connections.First(); - bool found = FALSE; - while (node && !found) - { - wxDDEConnection *connection = (wxDDEConnection *)node->Data(); - if (connection->m_hConv == conv) + wxNode *node = m_connections.First(); + bool found = FALSE; + while (node && !found) { - found = TRUE; - delete node; + wxDDEConnection *connection = (wxDDEConnection *)node->Data(); + if (connection->m_hConv == conv) + { + found = TRUE; + delete node; + } + else node = node->Next(); } - else node = node->Next(); - } - return found; + return found; } -/* - * Connection - */ +// ---------------------------------------------------------------------------- +// wxDDEConnection +// ---------------------------------------------------------------------------- wxDDEConnection::wxDDEConnection(char *buffer, int size) { - if (buffer == NULL) - { - if (DDEDefaultIPCBuffer == NULL) - DDEDefaultIPCBuffer = new char[DDEDefaultIPCBufferSize]; - m_bufPtr = DDEDefaultIPCBuffer; - m_bufSize = DDEDefaultIPCBufferSize; - } - else - { - m_bufPtr = buffer; - m_bufSize = size; - } - - m_topicName = ""; + if (buffer == NULL) + { + if (DDEDefaultIPCBuffer == NULL) + DDEDefaultIPCBuffer = new char[DDEDefaultIPCBufferSize]; + m_bufPtr = DDEDefaultIPCBuffer; + m_bufSize = DDEDefaultIPCBufferSize; + } + else + { + m_bufPtr = buffer; + m_bufSize = size; + } - m_client = NULL; - m_server = NULL; + m_client = NULL; + m_server = NULL; - m_hConv = 0; - m_sendingData = NULL; + m_hConv = 0; + m_sendingData = NULL; } -wxDDEConnection::wxDDEConnection(void) +wxDDEConnection::wxDDEConnection() { - m_hConv = 0; - m_sendingData = NULL; - m_server = NULL; - m_client = NULL; - if (DDEDefaultIPCBuffer == NULL) - DDEDefaultIPCBuffer = new char[DDEDefaultIPCBufferSize]; + m_hConv = 0; + m_sendingData = NULL; + m_server = NULL; + m_client = NULL; + if (DDEDefaultIPCBuffer == NULL) + DDEDefaultIPCBuffer = new char[DDEDefaultIPCBufferSize]; - m_bufPtr = DDEDefaultIPCBuffer; - m_bufSize = DDEDefaultIPCBufferSize; - m_topicName = ""; + m_bufPtr = DDEDefaultIPCBuffer; + m_bufSize = DDEDefaultIPCBufferSize; } -wxDDEConnection::~wxDDEConnection(void) +wxDDEConnection::~wxDDEConnection() { - if (m_server) - m_server->GetConnections().DeleteObject(this); - else - m_client->GetConnections().DeleteObject(this); + if (m_server) + m_server->GetConnections().DeleteObject(this); + else + m_client->GetConnections().DeleteObject(this); } // Calls that CLIENT can make -bool wxDDEConnection::Disconnect(void) +bool wxDDEConnection::Disconnect() { - DDEDeleteConnection((HCONV) m_hConv); - return (DdeDisconnect((HCONV) m_hConv) != 0); + DDEDeleteConnection(GetHConv()); + + bool ok = DdeDisconnect(GetHConv()) != 0; + if ( !ok ) + { + DDELogError(_T("Failed to disconnect from DDE server gracefully")); + } + + return ok; } bool wxDDEConnection::Execute(const wxChar *data, int size, wxIPCFormat format) { - DWORD result; - if (size < 0) - size = wxStrlen(data); + DWORD result; + if (size < 0) + { + size = wxStrlen(data) + 1; + } - size ++; + bool ok = DdeClientTransaction((LPBYTE)data, size, + GetHConv(), + NULL, + format, + XTYP_EXECUTE, + DDE_TIMEOUT, + &result) != 0; + if ( !ok ) + { + DDELogError(_T("DDE execute request failed")); + } - return (DdeClientTransaction((LPBYTE)data, size, (HCONV) m_hConv, - NULL, format, XTYP_EXECUTE, 5000, &result) ? TRUE : FALSE); + return ok; } char *wxDDEConnection::Request(const wxString& item, int *size, wxIPCFormat format) { - DWORD result; - HSZ atom = DDEGetAtom(item); + DWORD result; + HSZ atom = DDEGetAtom(item); + + HDDEDATA returned_data = DdeClientTransaction(NULL, 0, + GetHConv(), + atom, format, + XTYP_REQUEST, + DDE_TIMEOUT, + &result); + if ( !returned_data ) + { + DDELogError(_T("DDE data request failed")); + + return NULL; + } - HDDEDATA returned_data = DdeClientTransaction(NULL, 0, (HCONV) m_hConv, - atom, format, XTYP_REQUEST, 5000, &result); + DWORD len = DdeGetData(returned_data, (LPBYTE)m_bufPtr, m_bufSize, 0); - DWORD len = DdeGetData(returned_data, (LPBYTE)(m_bufPtr), m_bufSize, 0); + DdeFreeDataHandle(returned_data); - DdeFreeDataHandle(returned_data); + if (size) + *size = (int)len; - if (size) *size = (int)len; - if (len > 0) - { return m_bufPtr; - } - else return NULL; } bool wxDDEConnection::Poke(const wxString& item, wxChar *data, int size, wxIPCFormat format) { - DWORD result; - if (size < 0) - size = wxStrlen(data); + DWORD result; + if (size < 0) + { + size = wxStrlen(data) + 1; + } - size ++; + HSZ item_atom = DDEGetAtom(item); + bool ok = DdeClientTransaction((LPBYTE)data, size, + GetHConv(), + item_atom, format, + XTYP_POKE, + DDE_TIMEOUT, + &result) != 0; + if ( !ok ) + { + DDELogError(_("DDE poke request failed")); + } - HSZ item_atom = DDEGetAtom(item); - return (DdeClientTransaction((LPBYTE)data, size, (HCONV) m_hConv, - item_atom, format, XTYP_POKE, 5000, &result) ? TRUE : FALSE); + return ok; } bool wxDDEConnection::StartAdvise(const wxString& item) { - DWORD result; - HSZ atom = DDEGetAtom(item); + DWORD result; + HSZ atom = DDEGetAtom(item); - return (DdeClientTransaction(NULL, 0, (HCONV) m_hConv, - atom, CF_TEXT, XTYP_ADVSTART, 5000, &result) ? TRUE : FALSE); + bool ok = DdeClientTransaction(NULL, 0, + GetHConv(), + atom, CF_TEXT, + XTYP_ADVSTART, + DDE_TIMEOUT, + &result) != 0; + if ( !ok ) + { + DDELogError(_("Failed to establish an advise loop with DDE server")); + } + + return ok; } bool wxDDEConnection::StopAdvise(const wxString& item) { - DWORD result; - HSZ atom = DDEGetAtom(item); + DWORD result; + HSZ atom = DDEGetAtom(item); - return (DdeClientTransaction(NULL, 0, (HCONV) m_hConv, - atom, CF_TEXT, XTYP_ADVSTOP, 5000, &result) ? TRUE : FALSE); + bool ok = DdeClientTransaction(NULL, 0, + GetHConv(), + atom, CF_TEXT, + XTYP_ADVSTOP, + DDE_TIMEOUT, + &result) != 0; + if ( !ok ) + { + DDELogError(_("Failed to terminate the advise loop with DDE server")); + } + + return ok; } // Calls that SERVER can make -bool wxDDEConnection::Advise(const wxString& item, wxChar *data, int size, wxIPCFormat format) +bool wxDDEConnection::Advise(const wxString& item, + wxChar *data, + int size, + wxIPCFormat format) { - if (size < 0) - size = wxStrlen(data); + if (size < 0) + { + size = wxStrlen(data) + 1; + } - size ++; + HSZ item_atom = DDEGetAtom(item); + HSZ topic_atom = DDEGetAtom(m_topicName); + m_sendingData = data; + m_dataSize = size; + m_dataType = format; - HSZ item_atom = DDEGetAtom(item); - HSZ topic_atom = DDEGetAtom(m_topicName); - m_sendingData = data; - m_dataSize = size; - m_dataType = format; - return (DdePostAdvise(DDEIdInst, topic_atom, item_atom) != 0); + bool ok = DdePostAdvise(DDEIdInst, topic_atom, item_atom) != 0; + if ( !ok ) + { + DDELogError(_("Failed to send DDE advise notification")); + } + + return ok; } -bool wxDDEConnection::OnDisconnect(void) +bool wxDDEConnection::OnDisconnect() { - delete this; - return TRUE; + delete this; + return TRUE; } +// ---------------------------------------------------------------------------- +// _DDECallback +// ---------------------------------------------------------------------------- #define DDERETURN HDDEDATA -HDDEDATA EXPENTRY _EXPORT _DDECallback( -WORD wType, -WORD wFmt, -HCONV hConv, -HSZ hsz1, -HSZ hsz2, -HDDEDATA hData, -DWORD /* lData1 */, -DWORD /* lData2 */) -{ - switch (wType) - { - case XTYP_CONNECT: +HDDEDATA EXPENTRY _EXPORT +_DDECallback(WORD wType, + WORD wFmt, + HCONV hConv, + HSZ hsz1, + HSZ hsz2, + HDDEDATA hData, + DWORD WXUNUSED(lData1), + DWORD WXUNUSED(lData2)) +{ + switch (wType) { - wxChar topic_buf[100]; - wxChar server_buf[100]; - DdeQueryString(DDEIdInst, hsz1, (LPTSTR)topic_buf, WXSIZEOF(topic_buf), - CP_WINANSI); - DdeQueryString(DDEIdInst, hsz2, (LPTSTR)server_buf, WXSIZEOF(topic_buf), - CP_WINANSI); - wxDDEServer *server = DDEFindServer(server_buf); - if (server) - { - wxDDEConnection *connection = - (wxDDEConnection*) server->OnAcceptConnection(wxString(topic_buf)); - if (connection) - { - connection->m_server = server; - server->GetConnections().Append(connection); - connection->m_hConv = 0; - connection->m_topicName = topic_buf; - DDECurrentlyConnecting = connection; - return (DDERETURN)(DWORD)TRUE; - } - } - else return (DDERETURN)0; - break; + case XTYP_CONNECT: + { + wxString topic = DDEStringFromAtom(hsz1), + srv = DDEStringFromAtom(hsz2); + wxDDEServer *server = DDEFindServer(srv); + if (server) + { + wxDDEConnection *connection = + (wxDDEConnection*) server->OnAcceptConnection(topic); + if (connection) + { + connection->m_server = server; + server->GetConnections().Append(connection); + connection->m_hConv = 0; + connection->m_topicName = topic; + DDECurrentlyConnecting = connection; + return (DDERETURN)(DWORD)TRUE; + } + } + break; + } + + case XTYP_CONNECT_CONFIRM: + { + if (DDECurrentlyConnecting) + { + DDECurrentlyConnecting->m_hConv = (WXHCONV) hConv; + DDECurrentlyConnecting = NULL; + return (DDERETURN)(DWORD)TRUE; + } + break; + } + + case XTYP_DISCONNECT: + { + wxDDEConnection *connection = DDEFindConnection(hConv); + if (connection && connection->OnDisconnect()) + { + DDEDeleteConnection(hConv); // Delete mapping: hConv => connection + return (DDERETURN)(DWORD)TRUE; + } + break; + } + + case XTYP_EXECUTE: + { + wxDDEConnection *connection = DDEFindConnection(hConv); + + if (connection) + { + DWORD len = DdeGetData(hData, + (LPBYTE)connection->m_bufPtr, + connection->m_bufSize, + 0); + DdeFreeDataHandle(hData); + if ( connection->OnExecute(connection->m_topicName, + connection->m_bufPtr, + (int)len, + (wxIPCFormat) wFmt) ) + { + return (DDERETURN)(DWORD)DDE_FACK; + } + } + + return (DDERETURN)DDE_FNOTPROCESSED; + } + + case XTYP_REQUEST: + { + wxDDEConnection *connection = DDEFindConnection(hConv); + + if (connection) + { + wxString item_name = DDEStringFromAtom(hsz2); + + int user_size = -1; + char *data = connection->OnRequest(connection->m_topicName, + item_name, + &user_size, + (wxIPCFormat) wFmt); + if (data) + { + if (user_size < 0) + user_size = wxStrlen(data) + 1; + + HDDEDATA handle = DdeCreateDataHandle(DDEIdInst, + (LPBYTE)data, + user_size, + 0, + hsz2, + wFmt, + 0); + return (DDERETURN)handle; + } + } + break; + } + + case XTYP_POKE: + { + wxDDEConnection *connection = DDEFindConnection(hConv); + + if (connection) + { + wxString item_name = DDEStringFromAtom(hsz2); + + DWORD len = DdeGetData(hData, + (LPBYTE)connection->m_bufPtr, + connection->m_bufSize, + 0); + DdeFreeDataHandle(hData); + + connection->OnPoke(connection->m_topicName, + item_name, + connection->m_bufPtr, + (int)len, + (wxIPCFormat) wFmt); + + return (DDERETURN)DDE_FACK; + } + else + { + return (DDERETURN)DDE_FNOTPROCESSED; + } + } + + case XTYP_ADVSTART: + { + wxDDEConnection *connection = DDEFindConnection(hConv); + + if (connection) + { + wxString item_name = DDEStringFromAtom(hsz2); + + return (DDERETURN)connection-> + OnStartAdvise(connection->m_topicName, item_name); + } + + break; + } + + case XTYP_ADVSTOP: + { + wxDDEConnection *connection = DDEFindConnection(hConv); + + if (connection) + { + wxString item_name = DDEStringFromAtom(hsz2); + + return (DDERETURN)connection-> + OnStopAdvise(connection->m_topicName, item_name); + } + + break; + } + + case XTYP_ADVREQ: + { + wxDDEConnection *connection = DDEFindConnection(hConv); + + if (connection && connection->m_sendingData) + { + HDDEDATA data = DdeCreateDataHandle + ( + DDEIdInst, + (LPBYTE)connection->m_sendingData, + connection->m_dataSize, + 0, + hsz2, + connection->m_dataType, + 0 + ); + + connection->m_sendingData = NULL; + + return (DDERETURN)data; + } + + break; + } + + case XTYP_ADVDATA: + { + wxDDEConnection *connection = DDEFindConnection(hConv); + + if (connection) + { + wxString item_name = DDEStringFromAtom(hsz2); + + DWORD len = DdeGetData(hData, + (LPBYTE)connection->m_bufPtr, + connection->m_bufSize, + 0); + DdeFreeDataHandle(hData); + if ( connection->OnAdvise(connection->m_topicName, + item_name, + connection->m_bufPtr, + (int)len, + (wxIPCFormat) wFmt) ) + { + return (DDERETURN)(DWORD)DDE_FACK; + } + } + + return (DDERETURN)DDE_FNOTPROCESSED; + } } - case XTYP_CONNECT_CONFIRM: - { - if (DDECurrentlyConnecting) - { - DDECurrentlyConnecting->m_hConv = (WXHCONV) hConv; - DDECurrentlyConnecting = NULL; - return (DDERETURN)(DWORD)TRUE; - } - else return 0; - break; - } + return (DDERETURN)0; +} - case XTYP_DISCONNECT: - { - wxDDEConnection *connection = DDEFindConnection(hConv); - if (connection && connection->OnDisconnect()) - { - DDEDeleteConnection(hConv); // Delete mapping: hConv => connection - return (DDERETURN)(DWORD)TRUE; - } - else return (DDERETURN)0; - break; - } +// ---------------------------------------------------------------------------- +// DDE strings and atoms +// ---------------------------------------------------------------------------- - case XTYP_EXECUTE: - { - wxDDEConnection *connection = DDEFindConnection(hConv); - - if (connection) - { - DWORD len = DdeGetData(hData, (LPBYTE)(connection->m_bufPtr), connection->m_bufSize, 0); - DdeFreeDataHandle(hData); - if (connection->OnExecute(connection->m_topicName, connection->m_bufPtr, (int)len, (wxIPCFormat) wFmt)) - return (DDERETURN)(DWORD)DDE_FACK; - else - return (DDERETURN)DDE_FNOTPROCESSED; - } else return (DDERETURN)DDE_FNOTPROCESSED; - break; - } +// Atom table stuff +static HSZ DDEAddAtom(const wxString& string) +{ + HSZ atom = DDEAtomFromString(string); + wxAtomTable.Append(string, (wxObject *)atom); + return atom; +} - case XTYP_REQUEST: +static HSZ DDEGetAtom(const wxString& string) +{ + wxNode *node = wxAtomTable.Find(string); + if (node) + return (HSZ)node->Data(); + else { - wxDDEConnection *connection = DDEFindConnection(hConv); - - if (connection) - { - wxChar item_name[200]; - DdeQueryString(DDEIdInst, hsz2, (LPTSTR)item_name, WXSIZEOF(item_name), - CP_WINANSI); - - int user_size = -1; - char *data = connection->OnRequest(connection->m_topicName, wxString(item_name), &user_size, (wxIPCFormat) wFmt); - if (data) - { - if (user_size < 0) user_size = strlen(data); - - HDDEDATA handle = DdeCreateDataHandle(DDEIdInst, - (LPBYTE)data, user_size + 1, 0, hsz2, wFmt, 0); - return (DDERETURN)handle; - } else return (DDERETURN)0; - } else return (DDERETURN)0; - break; + DDEAddAtom(string); + return (HSZ)(wxAtomTable.Find(string)->Data()); } +} - case XTYP_POKE: +// atom <-> strings +static HSZ DDEAtomFromString(const wxString& s) +{ + wxASSERT_MSG( DDEIdInst, _T("DDE not initialized") ); + + HSZ hsz = DdeCreateStringHandle(DDEIdInst, s, DDE_CP); + if ( !hsz ) { - wxDDEConnection *connection = DDEFindConnection(hConv); - - if (connection) - { - wxChar item_name[200]; - DdeQueryString(DDEIdInst, hsz2, (LPTSTR)item_name, WXSIZEOF(item_name), - CP_WINANSI); - DWORD len = DdeGetData(hData, (LPBYTE)(connection->m_bufPtr), connection->m_bufSize, 0); - DdeFreeDataHandle(hData); - connection->OnPoke(connection->m_topicName, wxString(item_name), connection->m_bufPtr, (int)len, (wxIPCFormat) wFmt); - return (DDERETURN)(DWORD)DDE_FACK; - } else return (DDERETURN)DDE_FNOTPROCESSED; - break; + DDELogError(_("Failed to create DDE string")); } - case XTYP_ADVSTART: - { - wxDDEConnection *connection = DDEFindConnection(hConv); + return hsz; +} - if (connection) - { - wxChar item_name[200]; - DdeQueryString(DDEIdInst, hsz2, (LPTSTR)item_name, WXSIZEOF(item_name), - CP_WINANSI); +static wxString DDEStringFromAtom(HSZ hsz) +{ + // all DDE strings are normally limited to 255 bytes + static const size_t len = 256; - return (DDERETURN)(DWORD)connection->OnStartAdvise(connection->m_topicName, wxString(item_name)); - } else return (DDERETURN)0; - break; - } + wxString s; + (void)DdeQueryString(DDEIdInst, hsz, s.GetWriteBuf(len), len, DDE_CP); + s.UngetWriteBuf(); - case XTYP_ADVSTOP: - { - wxDDEConnection *connection = DDEFindConnection(hConv); - - if (connection) - { - wxChar item_name[200]; - DdeQueryString(DDEIdInst, hsz2, (LPTSTR)item_name, WXSIZEOF(item_name), - CP_WINANSI); - return (DDERETURN)(DWORD)connection->OnStopAdvise(connection->m_topicName, wxString(item_name)); - } else return (DDERETURN)0; - break; - } + return s; +} - case XTYP_ADVREQ: - { - wxDDEConnection *connection = DDEFindConnection(hConv); - - if (connection && connection->m_sendingData) - { - HDDEDATA data = DdeCreateDataHandle(DDEIdInst, - (LPBYTE)connection->m_sendingData, - connection->m_dataSize, 0, hsz2, connection->m_dataType, 0); - connection->m_sendingData = NULL; - return (DDERETURN)data; - } else return (DDERETURN)NULL; - break; - } +// ---------------------------------------------------------------------------- +// error handling +// ---------------------------------------------------------------------------- - case XTYP_ADVDATA: +static void DDELogError(const wxString& s, UINT error) +{ + if ( !error ) { - wxDDEConnection *connection = DDEFindConnection(hConv); - - if (connection) - { - wxChar item_name[200]; - DdeQueryString(DDEIdInst, hsz2, (LPTSTR)item_name, WXSIZEOF(item_name), - CP_WINANSI); - - DWORD len = DdeGetData(hData, (LPBYTE)(connection->m_bufPtr), connection->m_bufSize, 0); - DdeFreeDataHandle(hData); - if (connection->OnAdvise(connection->m_topicName, wxString(item_name), connection->m_bufPtr, (int)len, (wxIPCFormat) wFmt)) - return (DDERETURN)(DWORD)DDE_FACK; - else - return (DDERETURN)DDE_FNOTPROCESSED; - } else return (DDERETURN)DDE_FNOTPROCESSED; - break; + error = DdeGetLastError(DDEIdInst); } - } - return 0; -} -// Atom table stuff -static HSZ DDEAddAtom(const wxString& string) -{ - HSZ atom = DdeCreateStringHandle(DDEIdInst, WXSTRINGCAST string, CP_WINANSI); - wxAtomTable.Append(string, (wxObject *)atom); - return atom; + wxLogError(s + _T(": ") + DDEGetErrorMsg(error)); } -static HSZ DDEGetAtom(const wxString& string) +static wxString DDEGetErrorMsg(UINT error) { - wxNode *node = wxAtomTable.Find(string); - if (node) - return (HSZ)node->Data(); - else - { - DDEAddAtom(string); - return (HSZ)(wxAtomTable.Find(string)->Data()); - } -} + wxString err; + switch ( error ) + { + case DMLERR_NO_ERROR: + err = _("no DDE error."); + break; + + case DMLERR_ADVACKTIMEOUT: + err = _("a request for a synchronous advise transaction has timed out."); + break; + case DMLERR_BUSY: + err = _("the response to the transaction caused the DDE_FBUSY bit to be set."); + break; + case DMLERR_DATAACKTIMEOUT: + err = _("a request for a synchronous data transaction has timed out."); + break; + case DMLERR_DLL_NOT_INITIALIZED: + err = _("a DDEML function was called without first calling the DdeInitialize function,\n\ror an invalid instance identifier\n\rwas passed to a DDEML function."); + break; + case DMLERR_DLL_USAGE: + err = _("an application initialized as APPCLASS_MONITOR has\n\rattempted to perform a DDE transaction,\n\ror an application initialized as APPCMD_CLIENTONLY has \n\rattempted to perform server transactions."); + break; + case DMLERR_EXECACKTIMEOUT: + err = _("a request for a synchronous execute transaction has timed out."); + break; + case DMLERR_INVALIDPARAMETER: + err = _("a parameter failed to be validated by the DDEML."); + break; + case DMLERR_LOW_MEMORY: + err = _("a DDEML application has created a prolonged race condition."); + break; + case DMLERR_MEMORY_ERROR: + err = _("a memory allocation failed."); + break; + case DMLERR_NO_CONV_ESTABLISHED: + err = _("a client's attempt to establish a conversation has failed."); + break; + case DMLERR_NOTPROCESSED: + err = _("a transaction failed."); + break; + case DMLERR_POKEACKTIMEOUT: + err = _("a request for a synchronous poke transaction has timed out."); + break; + case DMLERR_POSTMSG_FAILED: + err = _("an internal call to the PostMessage function has failed. "); + break; + case DMLERR_REENTRANCY: + err = _("reentrancy problem."); + break; + case DMLERR_SERVER_DIED: + err = _("a server-side transaction was attempted on a conversation\n\rthat was terminated by the client, or the server\n\rterminated before completing a transaction."); + break; + case DMLERR_SYS_ERROR: + err = _("an internal error has occurred in the DDEML."); + break; + case DMLERR_UNADVACKTIMEOUT: + err = _("a request to end an advise transaction has timed out."); + break; + case DMLERR_UNFOUND_QUEUE_ID: + err = _("an invalid transaction identifier was passed to a DDEML function.\n\rOnce the application has returned from an XTYP_XACT_COMPLETE callback,\n\rthe transaction identifier for that callback is no longer valid."); + break; + default: + err.Printf(_("Unknown DDE error %08x"), error); + } -void DDEPrintError(void) -{ - wxChar *err = NULL; - switch (DdeGetLastError(DDEIdInst)) - { - case DMLERR_ADVACKTIMEOUT: - err = wxT("A request for a synchronous advise transaction has timed out."); - break; - case DMLERR_BUSY: - err = wxT("The response to the transaction caused the DDE_FBUSY bit to be set."); - break; - case DMLERR_DATAACKTIMEOUT: - err = wxT("A request for a synchronous data transaction has timed out."); - break; - case DMLERR_DLL_NOT_INITIALIZED: - err = wxT("A DDEML function was called without first calling the DdeInitialize function,\n\ror an invalid instance identifier\n\rwas passed to a DDEML function."); - break; - case DMLERR_DLL_USAGE: - err = wxT("An application initialized as APPCLASS_MONITOR has\n\rattempted to perform a DDE transaction,\n\ror an application initialized as APPCMD_CLIENTONLY has \n\rattempted to perform server transactions."); - break; - case DMLERR_EXECACKTIMEOUT: - err = wxT("A request for a synchronous execute transaction has timed out."); - break; - case DMLERR_INVALIDPARAMETER: - err = wxT("A parameter failed to be validated by the DDEML."); - break; - case DMLERR_LOW_MEMORY: - err = wxT("A DDEML application has created a prolonged race condition."); - break; - case DMLERR_MEMORY_ERROR: - err = wxT("A memory allocation failed."); - break; - case DMLERR_NO_CONV_ESTABLISHED: - err = wxT("A client's attempt to establish a conversation has failed."); - break; - case DMLERR_NOTPROCESSED: - err = wxT("A transaction failed."); - break; - case DMLERR_POKEACKTIMEOUT: - err = wxT("A request for a synchronous poke transaction has timed out."); - break; - case DMLERR_POSTMSG_FAILED: - err = wxT("An internal call to the PostMessage function has failed. "); - break; - case DMLERR_REENTRANCY: - err = wxT("Reentrancy problem."); - break; - case DMLERR_SERVER_DIED: - err = wxT("A server-side transaction was attempted on a conversation\n\rthat was terminated by the client, or the server\n\rterminated before completing a transaction."); - break; - case DMLERR_SYS_ERROR: - err = wxT("An internal error has occurred in the DDEML."); - break; - case DMLERR_UNADVACKTIMEOUT: - err = wxT("A request to end an advise transaction has timed out."); - break; - case DMLERR_UNFOUND_QUEUE_ID: - err = wxT("An invalid transaction identifier was passed to a DDEML function.\n\rOnce the application has returned from an XTYP_XACT_COMPLETE callback,\n\rthe transaction identifier for that callback is no longer valid."); - break; - default: - err = wxT("Unrecognised error type."); - break; - } - MessageBox((HWND) NULL, (LPCTSTR)err, wxT("DDE Error"), MB_OK | MB_ICONINFORMATION); + return err; } #endif diff --git a/src/msw/dirdlg.cpp b/src/msw/dirdlg.cpp index 7f76a6c7cd..abd115bf9a 100644 --- a/src/msw/dirdlg.cpp +++ b/src/msw/dirdlg.cpp @@ -88,6 +88,7 @@ wxDirDialog::wxDirDialog(wxWindow *parent, m_message = message; m_parent = parent; m_path = defaultPath; + m_path.Replace(_T("/"), _T("\\")); // SHBrowseForFolder doesn't like '/'s } int wxDirDialog::ShowModal() diff --git a/src/msw/listctrl.cpp b/src/msw/listctrl.cpp index b74816ce5b..34649103cc 100644 --- a/src/msw/listctrl.cpp +++ b/src/msw/listctrl.cpp @@ -1420,9 +1420,16 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) } // else translate it into wxEVT_COMMAND_LIST_ITEM_ACTIVATED event + // if it happened on an item (and not on empty place) { - eventType = wxEVT_COMMAND_LIST_ITEM_ACTIVATED; NM_LISTVIEW* hdr = (NM_LISTVIEW*)lParam; + if ( hdr->iItem == -1 ) + { + // not on item + return FALSE; + } + + eventType = wxEVT_COMMAND_LIST_ITEM_ACTIVATED; event.m_itemIndex = hdr->iItem; } break; diff --git a/src/msw/statbox.cpp b/src/msw/statbox.cpp index da2eac0ecc..40c1fc0aa4 100644 --- a/src/msw/statbox.cpp +++ b/src/msw/statbox.cpp @@ -41,7 +41,7 @@ // wxWin macros // ---------------------------------------------------------------------------- - IMPLEMENT_DYNAMIC_CLASS(wxStaticBox, wxControl) +IMPLEMENT_DYNAMIC_CLASS(wxStaticBox, wxControl) // ============================================================================ // implementation @@ -102,8 +102,6 @@ long wxStaticBox::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) } break; - // VZ: I will remove (or change) this soon... (15.11.99) -#if 0 case WM_ERASEBKGND: // prevent wxControl from processing this message because it will // erase the background incorrectly and there is no way for us to @@ -112,7 +110,6 @@ long wxStaticBox::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) // without painting over other controls - and if we don't, // wxControl still gets it) return MSWDefWindowProc(nMsg, wParam, lParam); -#endif } return wxControl::MSWWindowProc(nMsg, wParam, lParam); diff --git a/src/msw/utilsexc.cpp b/src/msw/utilsexc.cpp index 5cbd5a4957..6f2ee55757 100644 --- a/src/msw/utilsexc.cpp +++ b/src/msw/utilsexc.cpp @@ -74,6 +74,8 @@ #endif #include <stdarg.h> +#include "wx/dde.h" // for WX_DDE hack in wxExecute + // ---------------------------------------------------------------------------- // constants // ---------------------------------------------------------------------------- @@ -177,9 +179,78 @@ LRESULT APIENTRY _EXPORT wxExecuteWindowCbk(HWND hWnd, UINT message, } #endif -long wxExecute(const wxString& command, bool sync, wxProcess *handler) +long wxExecute(const wxString& cmd, bool sync, wxProcess *handler) { - wxCHECK_MSG( !!command, 0, wxT("empty command in wxExecute") ); + wxCHECK_MSG( !!cmd, 0, wxT("empty command in wxExecute") ); + + // DDE hack: this is really not pretty, but we need to allow this for + // transparent handling of DDE servers in wxMimeTypesManager. Usually it + // returns the command which should be run to view/open/... a file of the + // given type. Sometimes, however, this command just launches the server + // and an additional DDE request must be made to really open the file. To + // keep all this well hidden from the application, we allow a special form + // of command: WX_DDE:<command>:DDE_SERVER:DDE_TOPIC:DDE_COMMAND in which + // case we execute just <command> and process the rest below + wxString command, ddeServer, ddeTopic, ddeCommand; + static const size_t lenDdePrefix = 7; // strlen("WX_DDE:") + if ( cmd.Left(lenDdePrefix) == _T("WX_DDE#") ) + { + const wxChar *p = cmd.c_str() + 7; + while ( *p && *p != _T('#') ) + { + command += *p++; + } + + if ( *p ) + { + // skip '#' + p++; + } + else + { + wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute")); + } + + while ( *p && *p != _T('#') ) + { + ddeServer += *p++; + } + + if ( *p ) + { + // skip '#' + p++; + } + else + { + wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute")); + } + + while ( *p && *p != _T('#') ) + { + ddeTopic += *p++; + } + + if ( *p ) + { + // skip '#' + p++; + } + else + { + wxFAIL_MSG(_T("invalid WX_DDE command in wxExecute")); + } + + while ( *p ) + { + ddeCommand += *p++; + } + } + else + { + // no DDE + command = cmd; + } #if defined(__WIN32__) && !defined(__TWIN32__) // the old code is disabled because we really need a process handle @@ -237,6 +308,7 @@ long wxExecute(const wxString& command, bool sync, wxProcess *handler) return result; #else // 1 + // create the process STARTUPINFO si; wxZeroMemory(si); @@ -338,6 +410,20 @@ long wxExecute(const wxString& command, bool sync, wxProcess *handler) return pi.dwProcessId; } + // second part of DDE hack: now establish the DDE conversation with the + // just launched process + if ( !!ddeServer ) + { + wxDDEClient client; + wxConnectionBase *conn = client.MakeConnection(_T(""), + ddeServer, + ddeTopic); + if ( !conn || !conn->Execute(ddeCommand) ) + { + wxLogError(_("Couldn't launch DDE server '%s'."), command.c_str()); + } + } + if ( !sync ) { // clean up will be done when the process terminates -- 2.47.2