/******************************************************************************
 *
 *  TBHELP_C.C
 *
 * mit cl <file.c> -c -Zl kompilieren
 *
 ******************************************************************************/
#include <windows.h>
#include <shellapi.h>
#include <xpppar.h>
#include <xppcon.h>
#include <error.ch>

// Von Xbase++ übernommene Event-Codes
#define xbeP_User              134217728
#define xbeB_Event		       1048576

// Generische Nachrichten
#define xbeP_None                  (001 + xbeB_Event)

// Maus Nachrichten (für VIO und PM Mode)
#define xbeM_LbUp                  (10 + xbeB_Event)
#define xbeM_LbDown                ( 7 + xbeB_Event)
#define xbeM_LbDblClick            (16 + xbeB_Event)

#define xbeM_RbUp                  (12 + xbeB_Event)
#define xbeM_RbDown                ( 9 + xbeB_Event)
#define xbeM_RbDblClick            (18 + xbeB_Event)

#define xbeM_MbUp                  (11 + xbeB_Event)
#define xbeM_MbDown                ( 8 + xbeB_Event)
#define xbeM_MbDblClick            (17 + xbeB_Event)

#define xbeM_LbMotion              (19 + xbeB_Event)
#define xbeM_MbMotion              (20 + xbeB_Event)
#define xbeM_RbMotion              (21 + xbeB_Event)

#define xbeM_Motion                (22 + xbeB_Event)


static WNDPROC pWP=NULL;              /* Pointer für Window-Prozedur */
static short   Counter=0;             /* Zähler für SetWindowLong() */
static ULONG   UserMessage;           /* Benutzerdefinierte Nachricht */

// Erzeugen einer Benutzerdefinierten Nachricht, wenn ein Taskbarereignis
// Eintritt.
// (ACHTUNG, das folgende gilt nur wenn msg = WM_USER + 1966 ; siehe dazu XADDICON() )
//   mp1 ist die numerische ID des Taskbar Icons
//   mp2 ist die MW_ Id der Mausnachricht
LRESULT CALLBACK MyWinProc( HWND hWnd, UINT msg, WPARAM mp1, LPARAM mp2 )
{
   POINT MousePosition;                 /* Mouse-Coordinates */
   XPPAPIRET xr;
   LONG lMsg;
   ContainerHandle chResult, chMousePos, chNum;

   // Taskbar-Nachrichten abfangen und in die Xbase++ EventQueue stellen
   // falls die Nachricht WM_USER+1966 eintrifft
   if ( msg == WM_USER + 1966 ) {

      /* Mausposition ermitteln */
      GetCursorPos( &MousePosition );

      /* Y-Koordinate in Xbase++ Koordinatensystem umrechnen */
      MousePosition.y = GetSystemMetrics( SM_CYSCREEN ) - MousePosition.y;

      /* Windows Mausnachrichten in Xbase++ konforme Werte übersetzen */
      lMsg = xbeP_None;

      // mp2 enthält den Windows-API Messageparameter
      switch( mp2 )
      {
        case WM_LBUTTONUP:
            lMsg = xbeM_LbUp;
            break;

        case WM_LBUTTONDOWN:
            lMsg = xbeM_LbDown;
            break;

        case WM_LBUTTONDBLCLK:
            lMsg = xbeM_LbDblClick;
            break;

        case WM_RBUTTONUP:
            lMsg = xbeM_RbUp;
            break;

        case WM_RBUTTONDOWN:
            lMsg = xbeM_RbDown;
            break;

        case WM_RBUTTONDBLCLK:
            lMsg = xbeM_RbDblClick;
            break;

        case WM_MBUTTONUP:
            lMsg = xbeM_MbUp;
            break;

        case WM_MBUTTONDOWN:
            lMsg = xbeM_MbDown;
            break;

        case WM_MBUTTONDBLCLK:
            lMsg = xbeM_MbDblClick;
            break;

        case WM_MOUSEMOVE:
            lMsg = xbeM_Motion;
            break;
      }

      /* Daten in Array-Container ablegen, Arraystruktur :
       * [1] = Numerische Icon-ID aus mp1-Parameter
       * [2] = bereits in Xbase++ Id´s "übersetzte" Mausnachricht
       * [3] = X-Koordinate des Mauszeigers
       * [4] = Y-Koordinate des Mauszeigers
       */

      // neuen Array-Container erzeugen
      chMousePos = _conNewArray(1,4);

      // Icon-Id in Element 1 ablegen
      chNum = _conPutNL( NULLCONTAINER, mp1 );
      xr    = _conArrayPut( chMousePos, chNum, 1, 0);

      // Xbase++ Nachricht in Element 2 ablegen
      chNum = _conPutNL( chNum, lMsg );
      xr    = _conArrayPut( chMousePos, chNum, 2, 0);

      // X-Position der Maus in Element 3 ablegen
      chNum = _conPutNL( chNum, MousePosition.x );
      xr    = _conArrayPut( chMousePos, chNum, 3, 0);

      // Y-Position der Maus in Element 4 ablegen
      chNum = _conPutNL( chNum, MousePosition.y );
      xr    = _conArrayPut( chMousePos, chNum, 4, 0);

      // Temporären Container für Messageparameter verwenden
      _conPutNL( chNum, (LONG)( UserMessage ) );

      // Event mit PostAppEvent() in XBase++ Eventhandling "einschleusen"
      chResult  = _conNew(NULLCONTAINER);
      xr        = _conCall( chResult, "PostAppEvent", 2, chNum, chMousePos );

      // Container zur GC freigeben
      xr = _conRelease( chNum );
      xr = _conRelease( chResult );
      xr = _conRelease( chMousePos );
      return 0;
   }
   return CallWindowProc( pWP, hWnd, (ULONG)msg, (WPARAM)mp1, (LPARAM)mp2 );
}



// TBADDICON - fügt dem Taskbar ein Icon hinzu
XPPRET XPPENTRY XADDICON(XppParamList paramList)
{
    HWND hwnd;                          // Window-Handle
    UINT uID;                           // numerische Id des TB Icons
    HICON hicon;                        // Handle der Icon-Resource
    LPSTR lpszTip;                      // String, enthält Tooltip-Text
    NOTIFYICONDATA tnid;                // struct als Parameter für Shell_NotifyIcon()
    CHAR buffer[64];                    // Puffervariable für _parc()
    // ULONG uParType;
    // LPCSTR lpIconName;

    // Fensterhandle aus erstem Parameter holen
    hwnd = (HWND)  _parnl( paramList, 1 );

    /* Numerische ID des Taskbar-Icons, wird z.B. verwendet um
     * bei einem bereits eingerichteten Icon die Bitmap oder
     * den ToolTip zu ändern
     */
    uID = (UINT)  _parnl( paramList, 2 );

    // Ressourcen-Handle des Icon-Bitmaps
    hicon = LoadIcon( GetModuleHandle(NULL), MAKEINTRESOURCE(_parnl( paramList, 3 )) );

    // Text des Tooltips
    _parc(buffer, sizeof(buffer), paramList, 4);
    lpszTip = buffer;

    // Struktur aufbereiten
    tnid.cbSize           = sizeof(NOTIFYICONDATA);
    tnid.hWnd             = hwnd;
    tnid.uID              = uID;
    tnid.uFlags           = NIF_MESSAGE | NIF_ICON | NIF_TIP;
    tnid.uCallbackMessage = WM_USER + 1966;
    tnid.hIcon            = hicon;
    if (lpszTip)
        lstrcpyn(tnid.szTip, lpszTip, sizeof(tnid.szTip));
    else
        tnid.szTip[0] = '\0';

    // Falls die Windowprozedur noch nicht "umgebogen" wurde
    if ( ! pWP)
        pWP = (WNDPROC)SetWindowLong( hwnd, GWL_WNDPROC, (LONG)MyWinProc );

    // Icon in Taskbar registrieren
    if ( Shell_NotifyIcon(NIM_ADD, &tnid) ){
        // Zähler erhöhen
        Counter++;
        _retl(paramList, TRUE );
        }
    else
        _retl(paramList, FALSE );

    // Icon Resource freigeben
    if (hicon)
        DestroyIcon(hicon);


    return;
}

// entfernt ein Icon aus dem Taskbar
XPPRET XPPENTRY XDELICON(XppParamList paramList)
{
    HWND hwnd;                          // Windowhandle
    UINT uID;                           // Icon-Id
    NOTIFYICONDATA tnid;                // struct für Shell_NotifyIcon()

    // Paramater zuweisen
    hwnd = (HWND) _parnl( paramList, 1 );
    uID  = (UINT) _parnl( paramList, 2 );

    // Struktur belegen
    tnid.cbSize = sizeof(NOTIFYICONDATA);
    tnid.hWnd   = hwnd;
    tnid.uID    = uID;

    // Icon aus Taskbar entfernen
    if ( Shell_NotifyIcon(NIM_DELETE, &tnid) ){
        // Zähler erniedrigen
        Counter--;
        _retl(paramList, TRUE );
        }
    else
        _retl(paramList, FALSE );

    // Wenn der Zähler auf Null ist, ursprüngliche Windowprozedur wiederherstellen
    if ( ! Counter )
        if ( pWP){
            SetWindowLong( hwnd, GWL_WNDPROC, (LONG)pWP );
            pWP = NULL;
            }

    return;
}


// TBCHANGEICON - ändert ein Icon im Taskbar
XPPRET XPPENTRY XCHANGEICON(XppParamList paramList)
{
    HWND hwnd;                          // Windowhandle
    UINT uID;                           // numerische Icon-Id
    HICON hicon;                        // Icon Resourcen-Handle
    LPSTR lpszTip;                      // Pointer auf Text des Tooltip
    NOTIFYICONDATA tnid;                // Struct für Shell_NotifyIcon()
    CHAR buffer[64];                    // Puffer für _parc()
    // ULONG uParType;
    // LPCSTR lpIconName;

    // Nur wenn überhaupt Icons registriert sind
    if ( Counter ) {

        hwnd = (HWND) _parnl( paramList, 1 );  /* Fenster-Handle */

        /* Numerische ID des Taskbar-Icons, wird z.B. verwendet um
        * bei einem bereits eingerichteten Icon die Bitmap oder
        * den ToolTip zu ändern
        */
        uID = (UINT) _parnl( paramList, 2 );

        // Ressourcen-Handle des Icon-Bitmaps, das Bitmap muß an die EXE gebunden
        // sein.
        hicon = LoadIcon( GetModuleHandle(NULL), MAKEINTRESOURCE(_parnl( paramList, 3 )) );

        // Text des Tooltips
        _parc(buffer, sizeof(buffer), paramList, 4);
        lpszTip = buffer;

        tnid.cbSize           = sizeof(NOTIFYICONDATA);
        tnid.hWnd             = hwnd;
        tnid.uID              = uID;
        tnid.uFlags           = NIF_MESSAGE | NIF_ICON | NIF_TIP;
        tnid.uCallbackMessage = WM_USER + 1966;
        tnid.hIcon            = hicon;
        if (lpszTip)
            lstrcpyn(tnid.szTip, lpszTip, sizeof(tnid.szTip));
        else
            tnid.szTip[0] = '\0';

        // Icon ändern
        if ( Shell_NotifyIcon(NIM_MODIFY, &tnid) )
            _retl( paramList, TRUE );
        else
            _retl( paramList, FALSE );

        // Icon-resource freigeben
        if (hicon)
            DestroyIcon(hicon);
    }
    else {
        _retl(paramList, FALSE);
    }
    return;
}

// XICONINIT - Initialisiert die
XPPRET XPPENTRY XICONINIT(XppParamList paramList)
{
    if ( _partype( paramList, 0) == 1 )
        UserMessage = (ULONG) _parnl( paramList, 1 );  /* User-Nachricht */

    _ret( paramList );
    return;
}


/*
**-----------------------------------------------------------------------------
**  Name:       CheckPreviousApp
**  Purpose:   Check for previous instance of this application
 *
 * Param1 : ClassName of the applications main window
 * Param2 : optional windowname (title of the window)
**-----------------------------------------------------------------------------
*/

XPPRET XPPENTRY XCHKPREVAPP(XppParamList paramList)
{
    HWND hwndFind;
    HWND hwndLast;
    HWND hwndForeGround;
    DWORD dwFindID;
    DWORD dwForeGroundID;
    CHAR buffer1[250];
    CHAR buffer2[250];
    LPCSTR classname;
    LPCSTR windowname;

    windowname = NULL;

    _parc(buffer1, sizeof(buffer1), paramList, 1, NULL);
    classname = buffer1;

    if ( _partype( paramList, 2) & XPP_CHARACTER  ){
       _parc(buffer2, sizeof(buffer2), paramList, 2, NULL);
       windowname = buffer2;
       }

    // Check if application is already running
    hwndFind = FindWindow (classname, windowname);
    if (hwndFind)
    {
        // Bring previously running application's main
        // window to the user's attention
        hwndForeGround = GetForegroundWindow ();
        dwForeGroundID = GetWindowThreadProcessId (hwndForeGround, NULL);
        dwFindID = GetWindowThreadProcessId (hwndFind, NULL);

        // Don't do anything if window is already in foreground
        // Unless it is iconized.
        if ((dwFindID != dwForeGroundID) || (IsIconic (hwndFind)))
        {
            hwndLast = GetLastActivePopup (hwndFind);
            if (IsIconic (hwndLast))
            {
                ShowWindow (hwndLast, SW_RESTORE);
            }

            BringWindowToTop (hwndLast);
            SetForegroundWindow (hwndLast);
        }

        // Prevent additional instance's of this application
        // from running

        _retl( paramList, TRUE );
        return;
    }

    _retl( paramList, FALSE );
    return;
} // End CheckPreviousApp