+}
+
+void wxHelpProvider::AddHelp(wxWindowID WXUNUSED(id),
+                             const wxString& WXUNUSED(text))
+{
+}
+
+// removes the association
+void wxHelpProvider::RemoveHelp(wxWindowBase* WXUNUSED(window))
+{
+}
+
+wxHelpProvider::~wxHelpProvider()
+{
+}
+
+wxString wxHelpProvider::GetHelpTextMaybeAtPoint(wxWindowBase *window)
+{
+    if ( m_helptextAtPoint != wxDefaultPosition ||
+            m_helptextOrigin != wxHelpEvent::Origin_Unknown )
+    {
+        wxCHECK_MSG( window, wxEmptyString, wxT("window must not be NULL") );
+
+        wxPoint pt = m_helptextAtPoint;
+        wxHelpEvent::Origin origin = m_helptextOrigin;
+
+        m_helptextAtPoint = wxDefaultPosition;
+        m_helptextOrigin = wxHelpEvent::Origin_Unknown;
+
+        return window->GetHelpTextAtPoint(pt, origin);
+    }
+
+    return GetHelp(window);
+}
+
+// ----------------------------------------------------------------------------
+// wxSimpleHelpProvider
+// ----------------------------------------------------------------------------
+
+#define WINHASH_KEY(w) wxPtrToUInt(w)
+
+wxString wxSimpleHelpProvider::GetHelp(const wxWindowBase *window)
+{
+    wxSimpleHelpProviderHashMap::iterator it = m_hashWindows.find(WINHASH_KEY(window));
+
+    if ( it == m_hashWindows.end() )
+    {
+        it = m_hashIds.find(window->GetId());
+        if ( it == m_hashIds.end() )
+            return wxEmptyString;
+    }
+
+    return it->second;
+}
+
+void wxSimpleHelpProvider::AddHelp(wxWindowBase *window, const wxString& text)
+{
+    m_hashWindows.erase(WINHASH_KEY(window));
+    m_hashWindows[WINHASH_KEY(window)] = text;
+}
+
+void wxSimpleHelpProvider::AddHelp(wxWindowID id, const wxString& text)
+{
+    wxSimpleHelpProviderHashMap::key_type key = (wxSimpleHelpProviderHashMap::key_type)id;
+    m_hashIds.erase(key);
+    m_hashIds[key] = text;
+}
+
+// removes the association
+void wxSimpleHelpProvider::RemoveHelp(wxWindowBase* window)
+{
+    m_hashWindows.erase(WINHASH_KEY(window));
+}
+
+bool wxSimpleHelpProvider::ShowHelp(wxWindowBase *window)
+{
+#if wxUSE_MS_HTML_HELP || wxUSE_TIPWINDOW
+#if wxUSE_MS_HTML_HELP
+    // m_helptextAtPoint will be reset by GetHelpTextMaybeAtPoint(), stash it
+    const wxPoint posTooltip = m_helptextAtPoint;
+#endif // wxUSE_MS_HTML_HELP
+
+    const wxString text = GetHelpTextMaybeAtPoint(window);
+
+    if ( !text.empty() )
+    {
+        // use the native help popup style if it's available
+#if wxUSE_MS_HTML_HELP
+        if ( !wxCHMHelpController::ShowContextHelpPopup
+                                   (
+                                        text,
+                                        posTooltip,
+                                        (wxWindow *)window
+                                   ) )
+#endif // wxUSE_MS_HTML_HELP
+        {
+#if wxUSE_TIPWINDOW
+            static wxTipWindow* s_tipWindow = NULL;
+
+            if ( s_tipWindow )
+            {
+                // Prevent s_tipWindow being nulled in OnIdle, thereby removing
+                // the chance for the window to be closed by ShowHelp
+                s_tipWindow->SetTipWindowPtr(NULL);
+                s_tipWindow->Close();
+            }
+
+            s_tipWindow = new wxTipWindow((wxWindow *)window, text,
+                                            100, &s_tipWindow);
+#else // !wxUSE_TIPWINDOW
+            // we tried wxCHMHelpController but it failed and we don't have
+            // wxTipWindow to fall back on, so
+            return false;
+#endif // wxUSE_TIPWINDOW
+        }
+
+        return true;
+    }
+#else // !wxUSE_MS_HTML_HELP && !wxUSE_TIPWINDOW
+    wxUnusedVar(window);
+#endif // wxUSE_MS_HTML_HELP || wxUSE_TIPWINDOW
+
+    return false;
+}
+
+// ----------------------------------------------------------------------------
+// wxHelpControllerHelpProvider
+// ----------------------------------------------------------------------------
+
+wxHelpControllerHelpProvider::wxHelpControllerHelpProvider(wxHelpControllerBase* hc)
+{
+    m_helpController = hc;
+}
+
+bool wxHelpControllerHelpProvider::ShowHelp(wxWindowBase *window)
+{
+    const wxString text = GetHelpTextMaybeAtPoint(window);
+
+    if ( text.empty() )
+        return false;
+
+    if ( m_helpController )
+    {
+        // if it's a numeric topic, show it
+        long topic;
+        if ( text.ToLong(&topic) )
+            return m_helpController->DisplayContextPopup(topic);
+
+        // otherwise show the text directly
+        if ( m_helpController->DisplayTextPopup(text, wxGetMousePosition()) )
+            return true;
+    }
+
+    // if there is no help controller or it's not capable of showing the help,
+    // fallback to the default method
+    return wxSimpleHelpProvider::ShowHelp(window);
+}
+
+// Convenience function for turning context id into wxString
+wxString wxContextId(int id)
+{
+    return wxString::Format(wxT("%d"), id);
+}
+
+// ----------------------------------------------------------------------------
+// wxHelpProviderModule: module responsible for cleaning up help provider.
+// ----------------------------------------------------------------------------
+
+class wxHelpProviderModule : public wxModule
+{
+public:
+    bool OnInit();
+    void OnExit();
+
+private:
+    DECLARE_DYNAMIC_CLASS(wxHelpProviderModule)
+};
+
+IMPLEMENT_DYNAMIC_CLASS(wxHelpProviderModule, wxModule)
+
+bool wxHelpProviderModule::OnInit()
+{
+    // Probably we don't want to do anything by default,
+    // since it could pull in extra code
+    // wxHelpProvider::Set(new wxSimpleHelpProvider);
+
+    return true;
+}
+
+void wxHelpProviderModule::OnExit()
+{
+    if (wxHelpProvider::Get())
+    {
+        delete wxHelpProvider::Get();
+        wxHelpProvider::Set(NULL);
+    }