
/*
 *@@sourcefile xwpstring.c:
 *      This file contains SOM code for the following XWorkplace classes:
 *
 *      --  XWPString: a WPAbstract subclass for managing setup strings.
 *
 *      This class is new with V0.9.3.
 *
 *      Installation of this class is completely optional.
 *
 *      Every instance of XWPString should contain any setup string
 *      which can be invoked on an object. Two functions are possible:
 *
 *      1) Any object can be stored with the XWPString instance
 *         itself. This allows the same setup string to be
 *         performed on the same object. This is useful if a
 *         hotkey is also assigned to the XWPString instance,
 *         for example to control the XWP CD Player which is
 *         built into the XFldDisk class.
 *
 *      2) Any object can also be dropped onto the XWPString
 *         instance to have the setup string invoked on that
 *         object.
 *
 *@@added V0.9.3 (2000-04-25) [umoeller]
 *@@somclass XWPString xwpstr_
 *@@somclass M_XWPString xwpstrM_
 */

/*
 *      Copyright (C) 2000-2007 Ulrich M”ller.
 *      This file is part of the XWorkplace source package.
 *      XWorkplace is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published
 *      by the Free Software Foundation, in version 2 as it comes in the
 *      "COPYING" file of the XWorkplace main distribution.
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 */

/*
 *  This file was generated by the SOM Compiler and Emitter Framework.
 *  Generated using:
 *      SOM Emitter emitctm: 2.41
 */

#ifndef SOM_Module_xwpstring_Source
#define SOM_Module_xwpstring_Source
#endif
#define XWPString_Class_Source
#define M_XWPString_Class_Source

#pragma strings(readonly)

/*
 *  Suggested #include order:
 *  1)  os2.h
 *  2)  C library headers
 *  3)  setup.h (code generation and debugging options)
 *  4)  headers in helpers\
 *  5)  at least one SOM implementation header (*.ih)
 *  6)  dlgids.h, headers in shared\ (as needed)
 *  7)  headers in implementation dirs (e.g. filesys\, as needed)
 *  8)  #pragma hdrstop and then more SOM headers which crash with precompiled headers
 */

#define INCL_DOSSEMAPHORES
#define INCL_DOSPROCESS
#define INCL_DOSEXCEPTIONS
#define INCL_DOSERRORS

// #define INCL_WINWINDOWMGR
#define INCL_WINWINDOWMGR
#define INCL_WINMESSAGEMGR
#define INCL_WINMENUS           // for menu helpers
#define INCL_WINDIALOGS
#define INCL_WINBUTTONS         // for button/check box helpers
#define INCL_WINSTDCNR
#define INCL_WINMLE
#include <os2.h>

// C library headers
#include <stdio.h>              // needed for except.h
#include <setjmp.h>

// generic headers
#include "setup.h"                      // code generation and debugging options

// headers in /helpers
#include "helpers\cnrh.h"               // container helper routines
#include "helpers\except.h"             // exception handling
#include "helpers\standards.h"          // some standard macros
#include "helpers\stringh.h"            // string helper routines
#include "helpers\threads.h"            // thread helpers
#include "helpers\winh.h"               // PM helper routines
#include "helpers\xstring.h"            // extended string helpers

// SOM headers which don't crash with prec. header files
#include "xfobj.ih"
#include "xwpstring.ih"

// XWorkplace implementation headers
#include "dlgids.h"                     // all the IDs that are shared with NLS
#include "shared\common.h"              // the majestic XWorkplace include file
#include "shared\helppanels.h"          // all XWorkplace help panel IDs
#include "shared\kernel.h"              // XWorkplace Kernel
#include "shared\notebook.h"            // generic XWorkplace notebook handling
#include "shared\wpsh.h"                // some pseudo-SOM functions (WPS helper routines)

// other SOM headers
#pragma hdrstop
#include <wpfsys.h>                     // WPFileSystem, we need wpQueryFilename

/* ******************************************************************
 *
 *   Global variables
 *
 ********************************************************************/

/*
 *@@ INVOKESETUPSTRING:
 *      structure passed to xwstrfntSetupThread to
 *      invoke a setup string.
 *
 *@@added V0.9.6 (2000-11-23) [umoeller]
 */

typedef struct _INVOKESETUPSTRING
{
    XWPString       *somSelf;               // setup string object
    ULONG           cTargetObjects;         // no. of objects which follow
    WPObject        *apTargetObjects[1];    // objects to invoke setup string on
} INVOKESETUPSTRING, *PINVOKESETUPSTRING;

/*
 *@@ G_XWPStringSetupSet:
 *      XWPString setup set.
 *
 *@@added V0.9.20 (2002-07-12) [umoeller]
 */

static const XWPSETUPENTRY G_XWPStringSetupSet[] =
    {
        // type,  setup string,     offset,
        STG_BOOL, "CONFIRMINVOCATION", FIELDOFFSET(XWPStringData, fConfirm),
        //     key for wpSaveState/wpRestoreState
               3,
        //     default, ulExtra,            min, max
               TRUE,    0,                  0,   1,

        // type,  setup string,     offset,
        STG_BOOL, "NOSTRINGPAGE", FIELDOFFSET(XWPStringData, fNoStringPage),
        //     key for wpSaveState/wpRestoreState
               4,
        //     default, ulExtra,            min, max
               FALSE,   0,                  0,   1,
    };

/* ******************************************************************
 *
 *   Setup string thread
 *
 ********************************************************************/

/*
 *@@ xwstrfntSetupThread:
 *      separate short-time thread started by
 *      XWPString::wpOpen for actually invoking
 *      the setup string. Since this may take
 *      a while for certain strings, this should
 *      better not block the msg queue.
 *
 *      This receives a PINVOKESETUPSTRING pointer
 *      as the thread parameter.
 *
 *      This thread is created with a msg queue.
 *
 *@@added V0.9.3 (2000-04-27) [umoeller]
 *@@changed V0.9.6 (2000-11-23) [umoeller]: now using PINVOKESETUPSTRING
 */

STATIC void _Optlink xwstrfntSetupThread(PTHREADINFO pti)
{
    BOOL brc = FALSE;

    TRY_LOUD(excpt1)
    {
        PINVOKESETUPSTRING pInvoke = (PINVOKESETUPSTRING)(pti->ulData);
        if (pInvoke)
        {
            XWPStringData *somThis = XWPStringGetData(pInvoke->somSelf);

            /* _Pmpf(("xwstrfntSetupThread for obj %s", _wpQueryTitle(somSelf)));
            _Pmpf(("    invoking on obj %s", _wpQueryTitle(pobjStatic))); */

            if (pInvoke->cTargetObjects)
            {
                ULONG ul = 0;
                _wpCnrSetEmphasis(pInvoke->somSelf, CRA_INUSE, TRUE);
                // invoke setup string on target objects
                for (ul = 0;
                     ul < pInvoke->cTargetObjects;
                     ul++)
                {
                    brc = _wpSetup(pInvoke->apTargetObjects[ul],
                                   _pWszSetupString);
                    if (!brc)
                        break;
                }

                _wpCnrSetEmphasis(pInvoke->somSelf, CRA_INUSE, FALSE);
            }

            free(pInvoke);
        }
    }
    CATCH(excpt1)
    {
        brc = FALSE;
    } END_CATCH();

    if (!brc)
        WinAlarm(HWND_DESKTOP, WA_ERROR);
}

/* ******************************************************************
 *
 *   XWPString notebook callbacks (shared\notebook.c)
 *
 ********************************************************************/

/*
 *@@ xwstrStringInitPage:
 *      notebook callback function (notebook.c) for the
 *      XWPString instance settings page.
 *      Sets the controls on the page according to the
 *      instance settings.
 *
 *@@added V0.9.3 (2000-04-27) [umoeller]
 *@@changed V1.0.8 (2007-09-11) [pr]: fixed Undo/Default
 */

STATIC VOID xwstrStringInitPage(PNOTEBOOKPAGE pnbp,   // notebook info struct
                                ULONG flFlags)        // CBI_* flags (notebook.h)
{
    XWPStringData *somThis = XWPStringGetData(pnbp->inbp.somSelf);

    if (flFlags & CBI_INIT)
    {
        HWND hwndMLE = WinWindowFromID(pnbp->hwndDlgPage, ID_XSD_XWPSTRING_STRING_MLE);

        // copy data for "Undo"
        XWPStringData *pBackup = (XWPStringData*)malloc(sizeof(*somThis));
        memset(pBackup, 0, sizeof(*somThis));
        if (_pWszSetupString)
            pBackup->pWszSetupString = strdup(_pWszSetupString);

        pBackup->hobjStatic = _hobjStatic;
        pBackup->fConfirm = _fConfirm;
        // V1.0.8
        pBackup->fNoStringPage = _fNoStringPage;

        // store in notebook struct
        pnbp->pUser = pBackup;

        // enable word wrap
        WinSendMsg(hwndMLE,
                   MLM_SETWRAP,
                   (MPARAM)TRUE,
                   0);

        WinSendMsg(hwndMLE,
                   MLM_SETFORMATRECT,
                   (MPARAM)(PRECTL)NULL,        // current window size
                   (MPARAM)(MLFFMTRECT_MATCHWINDOW
                             /* | MLFFMTRECT_LIMITHORZ */));

        // set up container
        BEGIN_CNRINFO()
        {
            cnrhSetView(CV_NAME | CV_MINI | CA_DRAWICON);
        } END_CNRINFO(WinWindowFromID(pnbp->hwndDlgPage, ID_XSD_XWPSTRING_OBJ_CNR));
    }

    if (flFlags & CBI_SET)
    {
        HWND    hwndCnr = WinWindowFromID(pnbp->hwndDlgPage, ID_XSD_XWPSTRING_OBJ_CNR);
        WinSetDlgItemText(pnbp->hwndDlgPage, ID_XSD_XWPSTRING_STRING_MLE,
                          _pWszSetupString);
        cnrhRemoveAll(hwndCnr);
        if (_hobjStatic)
        {
            WPObject *pobj = _wpclsQueryObject(_WPObject,
                                               _hobjStatic);
            if (pobj)
            {
                PRECORDCORE precc = cnrhAllocRecords(hwndCnr,
                                                     sizeof(RECORDCORE),
                                                     1);
                precc->pszName = _wpQueryTitle(pobj);
                precc->hptrIcon
                    = precc->hptrMiniIcon
                    = _wpQueryIcon(pobj);

                cnrhInsertRecords(hwndCnr,
                                  NULL,         // parent
                                  precc,
                                  TRUE, // invalidate
                                  NULL,
                                  CRA_RECORDREADONLY,
                                  1);
            }
        }

        winhSetDlgItemChecked(pnbp->hwndDlgPage, ID_XSD_XWPSTRING_CONFIRM,
                              _fConfirm);
    }

    if (flFlags & CBI_ENABLE)
    {
        WinEnableControl(pnbp->hwndDlgPage, ID_XSD_XWPSTRING_OBJ_CLEAR,
                         (_hobjStatic != NULLHANDLE));
    }

    if (flFlags & CBI_DESTROY)
    {
        // clean up "Undo" data
        XWPStringData *pBackup = (XWPStringData*)(pnbp->pUser);
        if (pBackup)
            if (pBackup->pWszSetupString)
                free(pBackup->pWszSetupString);
            // notebook.c handles the other cleanup
    }

}

/*
 *@@ xwstrStringItemChanged:
 *      notebook callback function (notebook.c) for the
 *      XWPString instance settings page.
 *      Reacts to changes of any of the dialog controls.
 *
 *@@added V0.9.3 (2000-04-27) [umoeller]
 *@@changed V1.0.8 (2007-09-11) [pr]: fixed Undo/Default
 */

STATIC MRESULT xwstrStringItemChanged(PNOTEBOOKPAGE pnbp,
                                      ULONG ulItemID, USHORT usNotifyCode,
                                      ULONG ulExtra)      // for checkboxes: contains new state
{
    MRESULT     mrc = 0;
    XWPStringData *somThis = XWPStringGetData(pnbp->inbp.somSelf);
    BOOL        fSave = TRUE;

    static HOBJECT hobjBeingDragged = NULLHANDLE;

    switch (ulItemID)
    {
        case ID_XSD_XWPSTRING_STRING_MLE:
            if (usNotifyCode == MLN_KILLFOCUS)
            {
                PSZ pszNew = winhQueryWindowText(pnbp->hwndControl);
                _xwpSetString(pnbp->inbp.somSelf, pszNew);
                if (pszNew)
                    free(pszNew);
            }
        break;

        case ID_XSD_XWPSTRING_OBJ_CNR:
            switch (usNotifyCode)
            {
                case CN_DRAGOVER:
                    hobjBeingDragged = NULLHANDLE;
                    mrc = wpshQueryDraggedObjectCnr((PCNRDRAGINFO)ulExtra,
                                                    &hobjBeingDragged);
                break; // CN_DRAGOVER

                case CN_DROP:
                    if (hobjBeingDragged)
                    {
                        _hobjStatic = hobjBeingDragged;
                        hobjBeingDragged = NULLHANDLE;
                        pnbp->inbp.pfncbInitPage(pnbp, CBI_SET | CBI_ENABLE);
                    }
                break;
            }
        break;

        case ID_XSD_XWPSTRING_OBJ_CLEAR:
            _hobjStatic = NULLHANDLE;
            pnbp->inbp.pfncbInitPage(pnbp, CBI_SET | CBI_ENABLE);
        break;

        case ID_XSD_XWPSTRING_CONFIRM:
            _fConfirm = ulExtra;
        break;

        // V1.0.8
        case DID_UNDO:
            if (pnbp->pUser)
            {
                XWPStringData *pBackup = (pnbp->pUser);
                // "Undo" button: restore backed up instance data
                wpshStore(pnbp->inbp.somSelf, &_pWszSetupString,
                          pBackup->pWszSetupString, NULL);
                _hobjStatic = pBackup->hobjStatic;
                _fConfirm = pBackup->fConfirm;
                _fNoStringPage = pBackup->fNoStringPage;
                // have the page updated by calling the callback above
                xwstrStringInitPage(pnbp, CBI_SHOW | CBI_ENABLE);
            }
        break;

        case DID_DEFAULT:
            // "Default" button:
            wpshStore(pnbp->inbp.somSelf, &_pWszSetupString, NULL, NULL);
            _hobjStatic = NULLHANDLE;
            cmnSetupInitData(G_XWPStringSetupSet,
                             ARRAYITEMCOUNT(G_XWPStringSetupSet),
                             somThis);
            // have the page updated by calling the callback above
            xwstrStringInitPage(pnbp, CBI_SHOW | CBI_ENABLE);
        break;

        default:
            fSave = FALSE;
    }

    if (fSave)
        _wpSaveDeferred(pnbp->inbp.somSelf);

    return mrc;
}

/* ******************************************************************
 *
 *   XWPString Instance Methods
 *
 ********************************************************************/

/*
 *@@ xwpQueryString:
 *      returns the current setup string of the string
 *      object or NULL if there is none.
 *
 *      If something is returned, the caller is responsible
 *      for freeing that buffer by calling _wpFreeMem
 *      on the string object with the address that was returned.
 *
 *@@added V0.9.3 (2000-04-26) [umoeller]
 *@@changed V0.9.16 (2002-01-26) [umoeller]: modified prototype
 */

SOM_Scope PSZ  SOMLINK xwstr_xwpQueryString(XWPString *somSelf)
{
    ULONG cb;
    XWPStringData *somThis = XWPStringGetData(somSelf);
    XWPStringMethodDebug("XWPString","xwstr_xwpQueryString");

    if (    (_pWszSetupString)
         && ( cb = strlen(_pWszSetupString))
       )
    {
        ULONG rc;
        PSZ psz;
        if (psz = _wpAllocMem(somSelf, cb + 1, &rc))
        {
            memcpy(psz,
                   _pWszSetupString,
                   cb + 1);
            return (psz);
        }
    }

    return NULL;
}

/*
 *@@ xwpSetString:
 *      sets the member setup string to pszString
 *      or removes it if (pszSetupString == NULL).
 *
 *@@added V0.9.3 (2000-04-26) [umoeller]
 */

SOM_Scope BOOL  SOMLINK xwstr_xwpSetString(XWPString *somSelf,
                                           PSZ pszSetupString)
{
    BOOL brc = FALSE;
    XWPStringData *somThis = XWPStringGetData(somSelf);
    XWPStringMethodDebug("XWPString","xwstr_xwpSetString");

    wpshStore(somSelf, &_pWszSetupString, pszSetupString, NULL);

    ntbUpdateVisiblePage(somSelf, SP_XWPSTRING);

    return brc;
}

/*
 *@@ xwpQueryStaticObject:
 *      returns the static member object or NULL
 *      if none has been set yet. The static member
 *      object is optional.
 *
 *@@added V0.9.3 (2000-04-26) [umoeller]
 */

SOM_Scope WPObject*  SOMLINK xwstr_xwpQueryStaticObject(XWPString *somSelf)
{
    XWPStringData *somThis = XWPStringGetData(somSelf);
    XWPStringMethodDebug("XWPString","xwstr_xwpQueryStaticObject");

    if (_hobjStatic)
        return (_wpclsQueryObject(_WPObject, _hobjStatic));
    else
        return NULL;
}

/*
 *@@ xwpSetStaticObject:
 *      sets the static member object, if (pObject != NULL),
 *      or removes it from the instance data, if (pObject == NULL).
 *      The static member object is optional.
 *
 *@@added V0.9.3 (2000-04-26) [umoeller]
 */

SOM_Scope BOOL  SOMLINK xwstr_xwpSetStaticObject(XWPString *somSelf,
                                                 WPObject* pObject)
{
    XWPStringData *somThis = XWPStringGetData(somSelf);
    XWPStringMethodDebug("XWPString","xwstr_xwpSetStaticObject");

    if (pObject)
        _hobjStatic = _wpQueryHandle(pObject);
    else
        _hobjStatic = NULLHANDLE;

    ntbUpdateVisiblePage(somSelf, SP_XWPSTRING);

    return TRUE;
}

/*
 *@@ xwpAddXWPStringPages:
 *
 *@@changed V0.9.20 (2002-07-12) [umoeller]: no longer adding page if NOSTRINGPAGE=YES
 */

SOM_Scope ULONG  SOMLINK xwstr_xwpAddXWPStringPages(XWPString *somSelf,
                                                    HWND hwndNotebook)
{
    INSERTNOTEBOOKPAGE inbp;

    XWPStringData *somThis = XWPStringGetData(somSelf);
    XWPStringMethodDebug("XWPString","xwstr_xwpAddXWPStringPages");

    if (!_fNoStringPage)        // V0.9.20 (2002-07-12) [umoeller]
    {
        // add the "XWorkplace Startup" page on top
        memset(&inbp, 0, sizeof(INSERTNOTEBOOKPAGE));
        inbp.somSelf = somSelf;
        inbp.hwndNotebook = hwndNotebook;
        inbp.hmod = cmnQueryNLSModuleHandle(FALSE);
        inbp.usPageStyleFlags = BKA_MAJOR;
        inbp.pcszName = cmnGetString(ID_XSSI_XWPSTRING_PAGE);  // pszXWPStringPage
        inbp.ulDlgID = ID_XSD_XWPSTRING_PAGE;
        inbp.ulDefaultHelpPanel  = ID_XSH_SETTINGS_XWPSTRING_PAGE;
        inbp.ulPageID = SP_XWPSTRING;
        inbp.pfncbInitPage    = xwstrStringInitPage;
        inbp.pfncbItemChanged = xwstrStringItemChanged;
        return ntbInsertPage(&inbp);
    }

    return SETTINGS_PAGE_REMOVED;
}

/*
 *@@ xwpInvokeString:
 *      this invokes the member setup string on an object or
 *      an array of objects.
 *
 *      If (cObjects > 1), apObjects is assumed to point to
 *      an array of "cObjects" WPObject* pointers, on which
 *      the setup string is to be invoked.
 *
 *      If cObjects is 0, the array pointer is ignored, and
 *      the setup string is invoked on the static member object.
 *      If that is not present either, FALSE is returned.
 *
 *      If confirmations are enabled for this XWPString instance,
 *      a message box is displayed. If the user responds "No",
 *      FALSE is returned.
 *
 *      FALSE is also returned if invoking the setup string
 *      failed.
 *
 *@@added V0.9.6 (2000-11-23) [umoeller]
 *@@changed V0.9.20 (2002-08-08) [umoeller]: fixed trap if member object handle was broken
 */

SOM_Scope BOOL  SOMLINK xwstr_xwpInvokeString(XWPString *somSelf,
                                              ULONG cObjects,
                                              WPObject* apObjects[1])
{
    BOOL brc = FALSE;
    XWPStringData *somThis = XWPStringGetData(somSelf);
    XWPStringMethodDebug("XWPString","xwstr_xwpInvokeString");

    TRY_LOUD(excpt1)
    {
        // _PmpfF(("_pszSetupString is \"%s\"",
        //             (_pWszSetupString) ? _pWszSetupString : "<NULL>"));

        if (_pWszSetupString)
        {
            PTHREADINFO     pti = (PTHREADINFO)_pvtiSetupThread;

            if (pti == 0)
            {
                // first call: allocate memory
                _Pmpf(("  allocating new THREADINFO"));

                _pvtiSetupThread
                    = pti
                    = malloc(sizeof(THREADINFO));
            }

            if (    (pti)
                 && (_tidRunning == 0)
               )
            {
                // create struct to pass to "invoke" thread
                PINVOKESETUPSTRING pInvoke;
                if (pInvoke = (PINVOKESETUPSTRING)malloc(  sizeof(INVOKESETUPSTRING)
                                                         + (cObjects * sizeof(WPObject*))
                                                        ))
                {
                    BOOL fThreadStarted = FALSE;
                    memset(pInvoke, 0, sizeof(*pInvoke));
                    pInvoke->somSelf = somSelf;

                    if (cObjects)
                    {
                        // objects given: use those
                        pInvoke->cTargetObjects = cObjects;
                        // copy object array
                        memcpy(pInvoke->apTargetObjects,
                               apObjects,
                               cObjects * sizeof(WPObject*));
                    }
                    else
                        // no object given: use member object
                        if (_hobjStatic)
                        {
                            // fixed V0.9.20 (2002-08-08) [umoeller]:
                            // check if the member object still exists,
                            // otherwise we'll trap
                            if (pInvoke->apTargetObjects[0] = _wpclsQueryObject(_WPObject, _hobjStatic))
                                pInvoke->cTargetObjects = 1;
                        }

                    if (pInvoke->cTargetObjects)
                    {
                        BOOL fInvoke = TRUE;
                        if (_fConfirm)
                        {
                            // confirmation enabled:
                            XSTRING strObjects;
                            ULONG   ulMsg;

                            PCSZ apsz[2];
                            apsz[0] = _pWszSetupString;

                            xstrInit(&strObjects, 300);

                            if (pInvoke->cTargetObjects == 1)
                            {
                                apsz[1] = _wpQueryTitle(pInvoke->apTargetObjects[0]);
                                ulMsg = 192;        // single object msg
                            }
                            else
                            {
                                // several objects:
                                // compose array
                                ULONG ul = 0;
                                for (ul = 0;
                                     ul < pInvoke->cTargetObjects;
                                     ul++)
                                {
                                    xstrcat(&strObjects,
                                            _wpQueryTitle(pInvoke->apTargetObjects[ul]),
                                            0);
                                    xstrcatc(&strObjects, '\n');
                                }

                                apsz[1] = strObjects.psz;
                                ulMsg = 193;        // multiple objects msg
                            }

                            fInvoke = (cmnMessageBoxExt(NULLHANDLE,
                                                           191,     // XWPString
                                                           apsz,
                                                           2,
                                                           ulMsg,     // invoke %1 on %2?
                                                           MB_YESNO)
                                        == MBID_YES);

                            xstrClear(&strObjects);
                        }

                        if (fInvoke)
                        {
                            fThreadStarted = thrCreate(pti,
                                                       xwstrfntSetupThread,
                                                       &_tidRunning, // running flag
                                                       "InvokeSetupString",
                                                       THRF_PMMSGQUEUE | THRF_WAIT,
                                                       (ULONG)pInvoke);
                                // the thread frees the structure
                        }

                        brc = TRUE;
                    } // end if (pInvoke->cTargetObjects)

                    if (!fThreadStarted)
                        // error: clean up
                        free(pInvoke);
                } // end if (pInvoke)
            }
        } // end if (_pszSetupString)
    }
    CATCH(excpt1)
    {
        brc = FALSE;
    } END_CATCH();

    return brc;
}

/*
 *@@ xwpQuerySetup2:
 *      this XFldObject method is overridden to support
 *      setup strings for program files.
 *
 *      See XFldObject::xwpQuerySetup2 for details.
 *
 *@@added V0.9.12 (2001-05-20) [umoeller]
 *@@changed V0.9.16 (2001-10-11) [umoeller]: fixed memory leak
 *@@changed V0.9.16 (2001-10-11) [umoeller]: adjusted to new implementation
 */

SOM_Scope BOOL  SOMLINK xwstr_xwpQuerySetup2(XWPString *somSelf,
                                             PVOID pstrSetup)
{
    CHAR szTemp[CCHMAXPATH];
    // method pointer for parent class
    somTD_XFldObject_xwpQuerySetup2 pfn_xwpQuerySetup2 = 0;

    XWPStringData *somThis = XWPStringGetData(somSelf);
    XWPStringMethodDebug("XWPString","xwstr_xwpQuerySetup2");

    // setup string implementation
    // xstrInit(&strTemp, 1000);

    // SETUPSTRING= (encoded setup string)
    if (_pWszSetupString)
    {
        XSTRING str2;
        xstrInitCopy(&str2, _pWszSetupString, 0);
        xstrEncode(&str2, "%,();=");

        xstrcat(pstrSetup, "SETUPSTRING=", 0);
        xstrcats(pstrSetup, &str2);
        xstrcatc(pstrSetup, ';');

        xstrClear(&str2);       // was missing V0.9.16 (2001-10-11) [umoeller]
    }

    // DEFAULTOBJECT
    // this uses (in this order):
    // -- DEFAULTOBJECT=<OBJECTID>
    // -- DEFAULTOBJECT=c:\path\filename
    // -- DEFAULTOBJECT=*handle
    xstrcat(pstrSetup, "DEFAULTOBJECT=", 0);

    if (_hobjStatic)
    {
        WPObject *pobj;
        if (pobj = _wpclsQueryObject(_WPObject, _hobjStatic))
        {
            PSZ psz;
            if (psz = _wpQueryObjectID(pobj))
                // object has an ID:
                xstrcat(pstrSetup, psz, 0);
            else
                // no object ID: check if it's a WPFileSystem
                if (    (_somIsA(pobj, _WPFileSystem))
                     && (_wpQueryFilename(pobj, szTemp, TRUE))
                   )
                    xstrcat(pstrSetup, szTemp, 0);
                else
                    // no WPFileSystem: append handle then
                    pobj = NULL;
        }

        if (!pobj)
        {
            sprintf(szTemp, "*%lX", _hobjStatic);
            xstrcat(pstrSetup, szTemp, 0);
        }

        xstrcatc(pstrSetup, ';');
    }
    else
        // no member object:
        xstrcat(pstrSetup, "NONE;", 0);

    // V0.9.20 (2002-07-12) [umoeller]
    cmnSetupBuildString(G_XWPStringSetupSet,
                        ARRAYITEMCOUNT(G_XWPStringSetupSet),
                        somThis,
                        pstrSetup);

    // manually resolve parent method
    return wpshParentQuerySetup2(somSelf,
                                 _somGetParent(_XWPString),
                                 pstrSetup);
}

/*
 *@@ wpInitData:
 *      this WPObject instance method gets called when the
 *      object is being initialized (on wake-up or creation).
 *      We initialize our additional instance data here.
 *      Always call the parent first.
 *
 *@@added V0.9.3 (2000-04-26) [umoeller]
 *@@changed V0.9.20 (2002-07-12) [umoeller]: added cmnSetupInitData for setup set
 */

SOM_Scope void  SOMLINK xwstr_wpInitData(XWPString *somSelf)
{
    XWPStringData *somThis = XWPStringGetData(somSelf);
    XWPStringMethodDebug("XWPString","xwstr_wpInitData");

    XWPString_parent_WPAbstract_wpInitData(somSelf);

    _pWszSetupString = NULL;
    _hobjStatic = NULLHANDLE;
    _pvtiSetupThread = NULL;

    _tidRunning = 0;

    // V0.9.20 (2002-07-12) [umoeller]
    cmnSetupInitData(G_XWPStringSetupSet,
                     ARRAYITEMCOUNT(G_XWPStringSetupSet),
                     somThis);
}

/*
 *@@ wpUnInitData:
 *      this WPObject instance method is called when the object
 *      is destroyed as a SOM object, either because it's being
 *      made dormant or being deleted. All allocated resources
 *      should be freed here.
 *      The parent method must always be called last.
 *
 *@@added V0.9.3 (2000-04-26) [umoeller]
 */

SOM_Scope void  SOMLINK xwstr_wpUnInitData(XWPString *somSelf)
{
    XWPStringData *somThis = XWPStringGetData(somSelf);
    XWPStringMethodDebug("XWPString","xwstr_wpUnInitData");

    wpshStore(somSelf, &_pWszSetupString, NULL, NULL);

    if (_pvtiSetupThread)
    {
        free(_pvtiSetupThread);
        _pvtiSetupThread = NULL;
    }

    XWPString_parent_WPAbstract_wpUnInitData(somSelf);
}

/*
 *@@ wpObjectReady:
 *      this WPObject notification method gets called by the
 *      WPS when object instantiation is complete, for any reason.
 *      ulCode and refObject signify why and where from the
 *      object was created.
 *      The parent method must be called first.
 *
 *      See XFldObject::wpObjectReady for remarks about using
 *      this method as a copy constructor.
 *
 *@@added V0.9.3 (2000-04-27) [umoeller]
 */

SOM_Scope void  SOMLINK xwstr_wpObjectReady(XWPString *somSelf,
                                            ULONG ulCode,
                                            WPObject* refObject)
{
    XWPStringData *somThis = XWPStringGetData(somSelf);
    XWPStringMethodDebug("XWPString","xwstr_wpObjectReady");

    XWPString_parent_WPAbstract_wpObjectReady(somSelf, ulCode,
                                              refObject);

    if (ulCode & OR_REFERENCE)
    {
        // according to wpobject.h, this flag is set for
        // OR_FROMTEMPLATE, OR_FROMCOPY, OR_SHADOW; this
        // means that refObject is valid
        if (refObject)
            if (_somIsA(refObject, _XWPString))
            {
                XWPStringData *somThat = XWPStringGetData(refObject);
                // somSelf was copied from refObject
                /* _Pmpf(("OR_FROMCOPY: self's _pszSetupString: %s (0x%lX)",
                        (_pszSetupString) ? _pszSetupString : "NULL",
                        _pszSetupString));
                _Pmpf(("OR_FROMCOPY: original _pszSetupString: %s (0x%lX)",
                        (somThat->pszSetupString) ? somThat->pszSetupString : "NULL",
                        _pszSetupString)); */
                wpshStore(somSelf, &_pWszSetupString, somThat->pWszSetupString, NULL);

                _pvtiSetupThread = NULL;
            }
    }
}

/*
 *@@ wpSetup:
 *      this WPObject instance method is called to allow an
 *      object to set itself up according to setup strings.
 *      As opposed to wpSetupOnce, this gets called any time
 *      a setup string is invoked.
 *
 *      We examine the XWPString setup strings here.
 *
 *@@added V0.9.12 (2001-05-20) [umoeller]
 *@@changed V1.0.6 (2006-08-22) [pr]: handle DEFAULTOBJECT object IDs properly @@fixes 823
 */

SOM_Scope BOOL  SOMLINK xwstr_wpSetup(XWPString *somSelf, PSZ pszSetupString)
{
    BOOL brc;
    CHAR        szValue[CCHMAXPATH + 1];
    ULONG       cbValue;

    XWPStringData *somThis = XWPStringGetData(somSelf);
    XWPStringMethodDebug("XWPString","xwstr_wpSetup");

    brc = XWPString_parent_WPAbstract_wpSetup(somSelf, pszSetupString);

    if (brc)
    {
        TRY_LOUD(excpt1)
        {
            // SETUPSTRING= (encoded setup string)
            cbValue = 0;
            // get size of buffer first
            if (_wpScanSetupString(somSelf, pszSetupString,
                                   "SETUPSTRING", NULL, &cbValue))
            {
                PSZ psz;
                if (psz = (PSZ)malloc(cbValue))
                {
                    if (_wpScanSetupString(somSelf, pszSetupString,
                                           "SETUPSTRING", psz, &cbValue))
                    {
                        XSTRING str;
                        xstrInitSet2(&str, psz, cbValue - 1);

                        xstrDecode(&str);

                        _xwpSetString(somSelf, str.psz);

                        xstrClear(&str);
                    }
                    else
                    {
                        free(psz);
                        brc = FALSE;
                    }
                }
            }

            // DEFAULTOBJECT
            // this uses (in this order):
            // -- DEFAULTOBJECT=<OBJECTID>
            // -- DEFAULTOBJECT=c:\path\filename
            // -- DEFAULTOBJECT=*handle
            // -- DEFAULTOBJECT=NONE
            cbValue = sizeof(szValue);
            if (_wpScanSetupString(somSelf, pszSetupString,
                                   "DEFAULTOBJECT", szValue, &cbValue))
            {
                WPObject *pobj = NULL;

                if (szValue[0] == '*')
                    // this is a handle:
                    pobj = _wpclsQueryObject(_WPObject, strtol(&szValue[1], NULL, 16));
                else
                    // V1.0.6 (2006-08-22) [pr]: handle object IDs properly @@fixes 823
                    if (szValue[0] == '<')
                    {
                        // this is an object ID:
                        HOBJECT hObj = WinQueryObject(szValue);
                        pobj = _wpclsQueryObject(_WPObject, hObj);
                    }
                    else
                        // full path:
                        pobj = _wpclsQueryObjectFromPath(_WPFileSystem, szValue);
                        // returns NULL for "NONE"

                _xwpSetStaticObject(somSelf,
                                    pobj);       // can be NULL
            }

            brc = cmnSetupScanString(somSelf,
                                     G_XWPStringSetupSet,
                                     ARRAYITEMCOUNT(G_XWPStringSetupSet),
                                     somThis,
                                     pszSetupString,
                                     NULL);
        }
        CATCH(excpt1)
        {
            brc = FALSE;
        } END_CATCH();
    }

    return brc;
}

/*
 *@@ wpSaveState:
 *      this WPObject instance method saves an object's state
 *      persistently so that it can later be re-initialized
 *      with wpRestoreState. This gets called during wpClose,
 *      wpSaveImmediate or wpSaveDeferred processing.
 *      All persistent instance variables should be stored here.
 *
 *@@added V0.9.3 (2000-04-26) [umoeller]
 *@@changed V0.9.7 (2000-12-17) [umoeller]: fConfirm was never saved, fixed
 */

SOM_Scope BOOL  SOMLINK xwstr_wpSaveState(XWPString *somSelf)
{
    BOOL brc = FALSE;
    XWPStringData *somThis = XWPStringGetData(somSelf);
    XWPStringMethodDebug("XWPString","xwstr_wpSaveState");

    brc = XWPString_parent_WPAbstract_wpSaveState(somSelf);

    if (_pWszSetupString)
        _wpSaveString(somSelf, (PSZ)G_pcszXWPString, 1, _pWszSetupString);

    if (_hobjStatic)
        _wpSaveLong(somSelf, (PSZ)G_pcszXWPString, 2, (ULONG)_hobjStatic);

    // _wpSaveLong(somSelf, (PSZ)G_pcszXWPString, 3, _fConfirm);

    // V0.9.20 (2002-07-12) [umoeller]
    cmnSetupSave(somSelf,
                 G_XWPStringSetupSet,
                 ARRAYITEMCOUNT(G_XWPStringSetupSet),
                 G_pcszXWPString,
                 somThis);

    return brc;
}

/*
 *@@ wpRestoreState:
 *      this WPObject instance method gets called during object
 *      initialization (after wpInitData) to restore the data
 *      which was stored with wpSaveState.
 *
 *@@added V0.9.3 (2000-04-26) [umoeller]
 */

SOM_Scope BOOL  SOMLINK xwstr_wpRestoreState(XWPString *somSelf,
                                             ULONG ulReserved)
{
    CHAR    sz[2000];
    ULONG   ul,
            cbsz;
    BOOL    brc = FALSE;
    XWPStringData *somThis = XWPStringGetData(somSelf);
    XWPStringMethodDebug("XWPString","xwstr_wpRestoreState");

    brc = XWPString_parent_WPAbstract_wpRestoreState(somSelf,
                                                     ulReserved);
    cbsz = sizeof(sz);
    if (_wpRestoreString(somSelf, (PSZ)G_pcszXWPString, 1, sz, &cbsz))
        wpshStore(somSelf, &_pWszSetupString, sz, NULL);

    if (_wpRestoreLong(somSelf, (PSZ)G_pcszXWPString, 2, &ul))
        _hobjStatic = (HOBJECT)ul;

    // if (_wpRestoreLong(somSelf, (PSZ)G_pcszXWPString, 3, &ul))
    //     _fConfirm = (BOOL)ul;

    // V0.9.20 (2002-07-12) [umoeller]
    cmnSetupRestore(somSelf,
                    G_XWPStringSetupSet,
                    ARRAYITEMCOUNT(G_XWPStringSetupSet),
                    G_pcszXWPString,
                    somThis);

    return brc;
}

/*
 *@@ wpModifyPopupMenu:
 *      this WPObject instance methods gets called by the WPS
 *      when a context menu needs to be built for the object
 *      and allows the object to manipulate its context menu.
 *      This gets called _after_ wpFilterPopupMenu.
 *
 *      We need to modify the "Open" submenu for the WPS class
 *      list so that our new "Invoke setup string" is shown.
 *
 *@@added V0.9.3 (2000-04-27) [umoeller]
 */

SOM_Scope BOOL  SOMLINK xwstr_wpModifyPopupMenu(XWPString *somSelf,
                                                HWND hwndMenu,
                                                HWND hwndCnr,
                                                ULONG iPosition)
{
    BOOL brc = FALSE;
    XWPStringData *somThis = XWPStringGetData(somSelf);
    XWPStringMethodDebug("XWPString","xwstr_wpModifyPopupMenu");

    if (brc = XWPString_parent_WPAbstract_wpModifyPopupMenu(somSelf,
                                                            hwndMenu,
                                                            hwndCnr,
                                                            iPosition))
    {
        if ((_hobjStatic) && (_pWszSetupString))
        {
            // we have a member object:
            MENUITEM mi;
            // get handle to the "Open" submenu in the
            // the popup menu
            if (winhQueryMenuItem(hwndMenu,
                                  WPMENUID_OPEN,
                                  TRUE,
                                  &mi))
            {
                // mi.hwndSubMenu now contains "Open" submenu handle,
                // which we add items to now
                winhInsertMenuItem(mi.hwndSubMenu, MIT_END,
                                   *G_pulVarMenuOfs + ID_XFMI_OFS_XWPVIEW,
                                   cmnGetString(ID_XSSI_XWPSTRING_OPENMENU),  // pszXWPStringOpenMenu
                                   MIS_TEXT, 0);
            }
        }
    }

    return brc;
}

/*
 *@@ wpMenuItemSelected:
 *      this WPObject method processes menu selections.
 *      This must be overridden to support new menu
 *      items which have been added in wpModifyPopupMenu.
 *
 *      See XFldObject::wpMenuItemSelected for additional
 *      remarks.
 *
 *      We react to the "invoke setup string" menu item here.
 *
 *@@added V0.9.3 (2000-04-27) [umoeller]
 */

SOM_Scope BOOL  SOMLINK xwstr_wpMenuItemSelected(XWPString *somSelf,
                                                 HWND hwndFrame,
                                                 ULONG ulMenuId)
{
    BOOL brc = FALSE;
    // XWPStringData *somThis = XWPStringGetData(somSelf);
    XWPStringMethodDebug("XWPString","xwstr_wpMenuItemSelected");

    if (ulMenuId == *G_pulVarMenuOfs + ID_XFMI_OFS_XWPVIEW)
    {
        // "invoke setup string":
        brc = _wpOpen(somSelf,
                      NULLHANDLE,
                      ulMenuId,
                      0);
    }
    else
        brc = XWPString_parent_WPAbstract_wpMenuItemSelected(somSelf,
                                                             hwndFrame,
                                                             ulMenuId);

    return brc;
}

/*
 *@@ wpMenuItemHelpSelected:
 *
 *@@added V0.9.3 (2000-04-27) [umoeller]
 */

SOM_Scope BOOL  SOMLINK xwstr_wpMenuItemHelpSelected(XWPString *somSelf,
                                                     ULONG MenuId)
{
    BOOL brc = FALSE;
    // XWPStringData *somThis = XWPStringGetData(somSelf);
    XWPStringMethodDebug("XWPString","xwstr_wpMenuItemHelpSelected");

    if (MenuId == *G_pulVarMenuOfs + ID_XFMI_OFS_XWPVIEW)
        brc = cmnDisplayHelp(somSelf,
                             ID_XSH_SETTINGS_XWPSTRING_MAIN);
    else
        brc = XWPString_parent_WPAbstract_wpMenuItemHelpSelected(somSelf,
                                                                 MenuId);
    return brc;
}

/*
 *@@ wpOpen:
 *      this WPObject instance method gets called when
 *      a new view needs to be opened. Normally, this
 *      gets called after wpViewObject has scanned the
 *      object's USEITEMs and has determined that a new
 *      view is needed.
 *
 *      This _normally_ runs on thread 1 of the WPS, but
 *      this is not always the case. If this gets called
 *      in response to a menu selection from the "Open"
 *      submenu or a double-click in the folder, this runs
 *      on the thread of the folder (which _normally_ is
 *      thread 1). However, if this results from WinOpenObject
 *      or an OPEN setup string, this will not be on thread 1.
 *
 *      The "view" of setup strings is to invoke the setup
 *      string on a separate thread.
 *
 *@@added V0.9.3 (2000-04-27) [umoeller]
 */

SOM_Scope HWND  SOMLINK xwstr_wpOpen(XWPString *somSelf,
                                     HWND hwndCnr,
                                     ULONG ulView,
                                     ULONG param)
{
    HWND hwnd = NULLHANDLE;
    // XWPStringData *somThis = XWPStringGetData(somSelf);
    XWPStringMethodDebug("XWPString","xwstr_wpOpen");

    if (ulView == *G_pulVarMenuOfs + ID_XFMI_OFS_XWPVIEW)
    {
        // invoke setup string
        if (!_xwpInvokeString(somSelf,
                              0,
                              NULL))         // default member object
            // error:
            WinAlarm(HWND_DESKTOP, WA_ERROR);
    }
    else
        hwnd = XWPString_parent_WPAbstract_wpOpen(somSelf, hwndCnr,
                                                  ulView, param);

    return (hwnd);
}

/*
 *@@ wpQueryDefaultView:
 *      this WPObject method returns the default view of an object,
 *      that is, which view is opened if the program file is
 *      double-clicked upon. This is also used to mark
 *      the default view in the "Open" context submenu.
 *
 *      This must be overridden for direct WPAbstract subclasses,
 *      because otherwise double-clicks on the object won't
 *      work.
 *
 *      If a member object has been assigned, double-clicking
 *      should invoke the setup string on the member object.
 *
 *      Otherwise we'll open the settings.
 */

SOM_Scope ULONG  SOMLINK xwstr_wpQueryDefaultView(XWPString *somSelf)
{
    XWPStringData *somThis = XWPStringGetData(somSelf);
    XWPStringMethodDebug("XWPString","xwstr_wpQueryDefaultView");

    if (_hobjStatic)
        return *G_pulVarMenuOfs + ID_XFMI_OFS_XWPVIEW;

    return OPEN_SETTINGS;     // settings view is default
}

/*
 *@@ wpAddObjectWindowPage:
 *      this WPObject instance method normally adds the
 *      "Standard Options" page to the settings notebook
 *      (that's what the WPS reference calls it; it's actually
 *      the "Window" page).
 *
 *      We don't want that page in XWPString, so we remove it.
 */

SOM_Scope ULONG  SOMLINK xwstr_wpAddObjectWindowPage(XWPString *somSelf,
                                                     HWND hwndNotebook)
{
    /* XWPStringData *somThis = XWPStringGetData(somSelf); */
    XWPStringMethodDebug("XWPString","xwstr_wpAddObjectWindowPage");

    return SETTINGS_PAGE_REMOVED;
}

/*
 *@@ wpAddSettingsPages:
 *      this WPObject instance method gets called by the WPS
 *      when the Settings view is opened to have all the
 *      settings page inserted into hwndNotebook.
 *
 *      We call XWPString::xwpAddXWPStringPages to have the
 *      "String" pages inserted on top.
 */

SOM_Scope BOOL  SOMLINK xwstr_wpAddSettingsPages(XWPString *somSelf,
                                                 HWND hwndNotebook)
{
    /* XWPStringData *somThis = XWPStringGetData(somSelf); */
    XWPStringMethodDebug("XWPString","xwstr_wpAddSettingsPages");

    if (XWPString_parent_WPAbstract_wpAddSettingsPages(somSelf,
                                                       hwndNotebook))
    {
        _xwpAddXWPStringPages(somSelf, hwndNotebook);
        return TRUE;
    }

    return FALSE;
}

/*
 *@@ wpDragOver:
 *      this instance method is called to inform the object
 *      that other objects are being dragged over it.
 *      This corresponds to the DM_DRAGOVER message received by
 *      the object.
 *
 *@@added V0.9.6 (2000-11-23) [umoeller]
 */

SOM_Scope MRESULT  SOMLINK xwstr_wpDragOver(XWPString *somSelf,
                                            HWND hwndCnr,
                                            PDRAGINFO pdrgInfo)
{
    USHORT      usDrop = DOR_NEVERDROP,
                usDefaultOp = DO_LINK;
    // XWPStringData *somThis = XWPStringGetData(somSelf);
    XWPStringMethodDebug("XWPString","xwstr_wpDragOver");

    if (DrgAccessDraginfo(pdrgInfo))
    {
        if (pdrgInfo->usOperation != DO_DEFAULT)
            usDrop = DOR_NODROP;
            // but try again
        else
        {
            ULONG ulItemNow = 0;
            BOOL fError = FALSE;

            for (;
                 ulItemNow < pdrgInfo->cditem;
                 ulItemNow++)
            {
                DRAGITEM    drgItem;
                if (!DrgQueryDragitem(pdrgInfo,
                                      sizeof(drgItem),
                                      &drgItem,
                                      ulItemNow))
                {
                    // error:
                    fError = TRUE;
                    break;
                }
                else
                {
                    // store SOM pointer in array
                    WPObject *pobjTemp = 0;
                    if (wpshQueryDraggedObject(&drgItem,
                                               &pobjTemp)
                            == 0)
                    {
                        // error:
                        fError = TRUE;
                        break;
                    }
                }
            }

            if (!fError)
                // no error:
                // allow drop
                usDrop = DOR_DROP;
        }
    }

    return (MRFROM2SHORT(usDrop, usDefaultOp));
}

/*
 *@@ wpDrop:
 *      this instance method is called to inform an object that
 *      another object has been dropped on it.
 *      This corresponds to the DM_DROP message received by
 *      the object.
 *
 *      We collect the object(s) being dropped and call
 *      XWPString::xwpInvokeString with a proper object array.
 *      Note that we process all objects at once and return
 *      RC_DROP_DROPCOMPLETE to tell the WPS not to call this
 *      method again for the next object.
 *
 *@@added V0.9.6 (2000-11-23) [umoeller]
 *@@changed V1.0.6 (2006-09-30) [erdmann]: cleanup drag structures correctly @@fixes 817
 */

SOM_Scope MRESULT  SOMLINK xwstr_wpDrop(XWPString *somSelf,
                                        HWND hwndCnr,
                                        PDRAGINFO pdrgInfo,
                                        PDRAGITEM pdrgItem)
{
    MRESULT mrc = MRFROMLONG(RC_DROP_ERROR);
    // XWPStringData *somThis = XWPStringGetData(somSelf);
    // allocate memory for xwpInvokeString object array
    WPObject **paObjects = (WPObject**)malloc(pdrgInfo->cditem * sizeof(WPObject*));
    XWPStringMethodDebug("XWPString","xwstr_wpDrop");

    if (paObjects)
    {
        ULONG ulItemNow = 0;
        BOOL fError = FALSE;

        for (;
             ulItemNow < pdrgInfo->cditem;
             ulItemNow++)
        {
             DRAGITEM    drgItem;
            if (!DrgQueryDragitem(pdrgInfo,
                                  sizeof(drgItem),
                                  &drgItem,
                                  ulItemNow))
            {
                // error:
                fError = TRUE;
                break;
            }
            else
            {
                // store SOM pointer in array
                if (wpshQueryDraggedObject(&drgItem,
                                           &paObjects[ulItemNow])
                        == 0)
                {
                    // error:
                    fError = TRUE;
                    break;
                }
            }
        }

        if (!fError)
        {
            // success so far:
            // invoke setup string
            _xwpInvokeString(somSelf,
                             pdrgInfo->cditem,
                             paObjects);

            DrgDeleteDraginfoStrHandles(pdrgInfo); // V1.0.6 (2006-09-30) [erdmann]: @@fixes 817
            DrgFreeDraginfo(pdrgInfo);
            mrc = MRFROMLONG(RC_DROP_DROPCOMPLETE);
        }

        free(paObjects);

    } // end if (paObjects)

    return mrc;
}


/* ******************************************************************
 *
 *   XWPString Class Methods
 *
 ********************************************************************/

/*
 *@@ wpclsInitData:
 *      this WPObject class method gets called when a class
 *      is loaded by the WPS (probably from within a
 *      somFindClass call) and allows the class to initialize
 *      itself.
 */

SOM_Scope void  SOMLINK xwstrM_wpclsInitData(M_XWPString *somSelf)
{
    /* M_XWPStringData *somThis = M_XWPStringGetData(somSelf); */
    M_XWPStringMethodDebug("M_XWPString","xwstrM_wpclsInitData");

    M_XWPString_parent_M_WPAbstract_wpclsInitData(somSelf);

    krnClassInitialized(G_pcszXWPString);
}

/*
 *@@ wpclsQueryStyle:
 *      prevent print, but allow template.
 *
 *@@changed V0.9.16 (2001-11-25) [umoeller]: fixed nevertemplate
 */

SOM_Scope ULONG  SOMLINK xwstrM_wpclsQueryStyle(M_XWPString *somSelf)
{
    /* M_XWPStringData *somThis = M_XWPStringGetData(somSelf); */
    M_XWPStringMethodDebug("M_XWPString","xwstrM_wpclsQueryStyle");

    return ((M_XWPString_parent_M_WPAbstract_wpclsQueryStyle(somSelf)
                & ~CLSSTYLE_NEVERTEMPLATE)      // V0.9.16 (2001-11-25) [umoeller]
                | CLSSTYLE_NEVERPRINT);
}

/*
 *@@ wpclsQueryTitle:
 *      this WPObject class method tells the WPS the clear
 *      name of a class, which is shown in the third column
 *      of a Details view and also used as the default title
 *      for new objects of a class.
 */

SOM_Scope PSZ  SOMLINK xwstrM_wpclsQueryTitle(M_XWPString *somSelf)
{
    /* M_XWPStringData *somThis = M_XWPStringGetData(somSelf); */
    M_XWPStringMethodDebug("M_XWPString","xwstrM_wpclsQueryTitle");

    return ("Setup string");
}

/*
 *@@ wpclsQueryDefaultHelp:
 *      this WPObject class method returns the default help
 *      panel for objects of this class. This gets called
 *      from WPObject::wpQueryDefaultHelp if no instance
 *      help settings (HELPLIBRARY, HELPPANEL) have been
 *      set for an individual object. It is thus recommended
 *      to override this method instead of the instance
 *      method to change the default help panel for a class
 *      in order not to break instance help settings (fixed
 *      with 0.9.20).
 *
 *      We return default help for string objects here.
 *
 *@@added V0.9.20 (2002-07-12) [umoeller]
 */

SOM_Scope BOOL  SOMLINK xwstrM_wpclsQueryDefaultHelp(M_XWPString *somSelf,
                                                     PULONG pHelpPanelId,
                                                     PSZ pszHelpLibrary)
{
    /* XWPStringData *somThis = XWPStringGetData(somSelf); */
    XWPStringMethodDebug("XWPString","xwstr_wpQueryDefaultHelp");

    strcpy(pszHelpLibrary, cmnQueryHelpLibrary());
    *pHelpPanelId = ID_XSH_SETTINGS_XWPSTRING_MAIN;
    return TRUE;
}

/*
 *@@ wpclsQueryIconData:
 *      this WPObject class method must return information
 *      about how to build the default icon for objects
 *      of a class. This gets called from various other
 *      methods whenever a class default icon is needed;
 *      most importantly, M_WPObject::wpclsQueryIcon
 *      calls this to build a class default icon, which
 *      is then cached in the class's instance data.
 *      If a subclass wants to change a class default icon,
 *      it should always override _this_ method instead of
 *      wpclsQueryIcon.
 *
 *      Note that the default WPS implementation does not
 *      allow for specifying the ICON_FILE format here,
 *      which is why we have overridden
 *      M_XFldObject::wpclsQueryIcon too. This allows us
 *      to return icon _files_ for theming too. For details
 *      about the WPS's crappy icon management, refer to
 *      src\filesys\icons.c.
 *
 *      We override this to give XWPString object a new
 *      icon (src\shared\xwpstring.ico).
 */

SOM_Scope ULONG  SOMLINK xwstrM_wpclsQueryIconData(M_XWPString *somSelf,
                                                   PICONINFO pIconInfo)
{
    /* M_XWPStringData *somThis = M_XWPStringGetData(somSelf); */
    M_XWPStringMethodDebug("M_XWPString","xwstrM_wpclsQueryIconData");

    if (pIconInfo)
    {
        pIconInfo->fFormat = ICON_RESOURCE;
        pIconInfo->resid   = ID_ICONXWPSTRING;
        pIconInfo->hmod    = cmnQueryMainResModuleHandle();
    }

    return (sizeof(ICONINFO));
}

/*
 *@@ wpclsQuerySettingsPageSize:
 *      this WPObject class method should return the
 *      size of the largest settings page in dialog
 *      units; if a settings notebook is initially
 *      opened, i.e. no window pos has been stored
 *      yet, the WPS will use this size, to avoid
 *      truncated settings pages.
 */

SOM_Scope BOOL  SOMLINK xwstrM_wpclsQuerySettingsPageSize(M_XWPString *somSelf,
                                                          PSIZEL pSizl)
{
    /* M_XWPStringData *somThis = M_XWPStringGetData(somSelf); */
    M_XWPStringMethodDebug("M_XWPString","xwstrM_wpclsQuerySettingsPageSize");

    return (M_XWPString_parent_M_WPAbstract_wpclsQuerySettingsPageSize(somSelf,
                                                                       pSizl));
}


/*
 *@@ wpclsCreateDefaultTemplates:
 *      this WPObject class method is called by the
 *      Templates folder to allow a class to
 *      create its default templates.
 *
 *      The default WPS behavior is to create new templates
 *      if the class default title is different from the
 *      existing templates.
 *
 *@@added V0.9.3 (2000-04-26) [umoeller]
 */

SOM_Scope BOOL  SOMLINK xwstrM_wpclsCreateDefaultTemplates(M_XWPString *somSelf,
                                                           WPObject* Folder)
{
    /* M_XWPStringData *somThis = M_XWPStringGetData(somSelf); */
    M_XWPStringMethodDebug("M_XWPString","xwstrM_wpclsCreateDefaultTemplates");

    // DosBeep(5000, 1000);

    return (M_XWPString_parent_M_WPAbstract_wpclsCreateDefaultTemplates(somSelf,
                                                                        Folder));
}



