
/*
 *@@sourcefile xwpstring.c:
 *      This file contains SOM code for the following XWorkplace classes:
 *
 *      --  XWPMedia: a WPAbstract subclass for multimedia settings.
 *
 *      This class is new with V0.9.3.
 *
 *      Installation of XWPString is completely optional.
 *
 *      Note: Those G_mmio* and G_mci* identifiers are global
 *      variables containing MMPM/2 API entries. Those are
 *      resolved by xmmInit (mmthread.c) and must only be used
 *      after checking xmmQueryStatus.
 *
 *@@added V0.9.3 (2000-04-29) [umoeller]
 *@@somclass XWPMedia xwmm_
 *@@somclass M_XWPMedia xwmmM_
 */

/*
 *      Copyright (C) 2000-2003 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_xwpmedia_Source
#define SOM_Module_xwpmedia_Source
#endif
#define XWPMedia_Class_Source
#define M_XWPMedia_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_WINMESSAGEMGR
#define INCL_WINMENUS           // for menu helpers
#define INCL_WINDIALOGS
#define INCL_WINBUTTONS         // for button/check box helpers
#define INCL_WINSTDCNR
#define INCL_WINMLE

#define INCL_GPI                // required for INCL_MMIO_CODEC
#define INCL_GPIBITMAPS         // required for INCL_MMIO_CODEC
#include <os2.h>

// multimedia includes
#define INCL_MCIOS2
#define INCL_MMIOOS2
#define INCL_MMIO_CODEC
#include <os2me.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\mmpmh.h"              // MMPM/2 helpers
#include "helpers\stringh.h"            // string helper routines
#include "helpers\threads.h"            // thread helpers

// SOM headers which don't crash with prec. header files
#include "xwpmedia.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 "media\media.h"                // XWorkplace multimedia support

// other SOM headers

#pragma hdrstop

/* ******************************************************************
 *
 *   Global variables
 *
 ********************************************************************/

static THREADINFO   G_tiInsertDevices = {0},
                    G_tiInsertCodecs = {0},
                    G_tiInsertIOProcs = {0};

/* ******************************************************************
 *
 *   XWPMedia "Device" page notebook callbacks (notebook.c)
 *
 ********************************************************************/

/*
 *@@ MMDEVRECORD:
 *
 *@@added V0.9.3 (2000-04-28) [umoeller]
 */

typedef struct _MMDEVRECORD
{
    RECORDCORE  recc;

    PXMMDEVICE  pDevice;

    PSZ         pszDeviceType;
    ULONG       ulDeviceIndex;

    PSZ         pszInstallName,
                pszLogicalName,
                pszAliasName;

    PSZ         pszInfo;
} MMDEVRECORD, *PMMDEVRECORD;

/*
 *@@ fntInsertDevices:
 *      transient thread started by xwmmDevicesInitPage
 *      to insert devices into the "Devices" container.
 *
 *      This thread is created with a msg queue.
 *
 *@@changed V0.9.7 (2000-12-17) [umoeller]: added exit flag
 *@@changed V0.9.13 (2001-06-14) [umoeller]: added more info
 */

void _Optlink fntInsertDevices(PTHREADINFO pti)
{
    PNOTEBOOKPAGE pnbp = (PNOTEBOOKPAGE)(pti->ulData);

    TRY_LOUD(excpt1)
    {
        ULONG       cDevices = 0,
                    ul;
        PXMMDEVICE  paDevices;

        pnbp->fShowWaitPointer = TRUE;

        paDevices = xmmQueryDevices(&cDevices);

        if (paDevices)
        {
            for (ul = 0;
                 ul < cDevices;
                 ul++)
            {
                HWND        hwndCnr = WinWindowFromID(pnbp->hwndDlgPage, ID_XFDI_CNR_CNR);

                if (pti->fExit)     // V0.9.7 (2000-12-17) [umoeller]
                    break;

                if (!hwndCnr)
                    break;
                else
                {
                    PMMDEVRECORD precc
                        = (PMMDEVRECORD)cnrhAllocRecords(hwndCnr,
                                                         sizeof(MMDEVRECORD),
                                                         1);
                    if (!precc)
                        break;
                    else
                    {
                        PXMMDEVICE pDeviceThis = &paDevices[ul];

                        precc->pszDeviceType = (PSZ)pDeviceThis->pcszDeviceType;
                        precc->ulDeviceIndex = pDeviceThis->ulDeviceIndex;

                        precc->pszInstallName = pDeviceThis->szInstallName;
                        precc->pszLogicalName = pDeviceThis->szLogicalName;
                        precc->pszAliasName = pDeviceThis->szAliasName;

                        precc->pszInfo = pDeviceThis->pszInfo;  // can be NULL

                        precc->pDevice = pDeviceThis;

                        if (!cnrhInsertRecords(hwndCnr,
                                               NULL,
                                               (PRECORDCORE)precc,
                                               TRUE, // invalidate
                                               NULL,
                                               CRA_RECORDREADONLY,
                                               1))
                            break;
                    }
                }
            }
        }

        // store devices
        if (!pti->fExit)     // V0.9.7 (2000-12-17) [umoeller]
        {
            if (pnbp->pUser)
                // already set:
                xmmFreeDevices(pnbp->pUser); // V0.9.7 (2000-12-20) [umoeller]
            pnbp->pUser = paDevices;
        }
    }
    CATCH(excpt1) {}  END_CATCH();

    if (!pti->fExit)
        pnbp->fShowWaitPointer = FALSE;
}

/*
 *@@ xwmmDevicesInitPage:
 *      notebook callback function (notebook.c) for the
 *      XWPMedia "Devices" page.
 *      Sets the controls on the page according to the
 *      Global Settings.
 *
 *@@changed V0.9.4 (2000-06-13) [umoeller]: group title was missing; fixed
 *@@changed V0.9.7 (2000-12-17) [umoeller]: fixed hang on close while thread was running
 *@@changed V0.9.13 (2001-06-14) [umoeller]: added more info
 */

VOID xwmmDevicesInitPage(PNOTEBOOKPAGE pnbp,   // notebook info struct
                         ULONG flFlags)        // CBI_* flags (notebook.h)
{
    if (flFlags & CBI_INIT)
    {
        // PNLSSTRINGS     pNLSStrings = cmnQueryNLSStrings();
        HWND hwndCnr = WinWindowFromID(pnbp->hwndDlgPage, ID_XFDI_CNR_CNR);

        XFIELDINFO      xfi[8];
        PFIELDINFO      pfi = NULL;
        int             i = 0;

        // set group title V0.9.4 (2000-06-13) [umoeller]
        WinSetDlgItemText(pnbp->hwndDlgPage, ID_XFDI_CNR_GROUPTITLE,
                          (PSZ)cmnGetString(ID_MMSI_PAGETITLE_DEVICES)) ; // pszPagetitleDevices

        // set up cnr details view
        xfi[i].ulFieldOffset = FIELDOFFSET(MMDEVRECORD, pszDeviceType);
        xfi[i].pszColumnTitle = cmnGetString(ID_MMSI_DEVICETYPE);  // pszDeviceType
        xfi[i].ulDataType = CFA_STRING;
        xfi[i++].ulOrientation = CFA_LEFT | CFA_TOP;

        xfi[i].ulFieldOffset = FIELDOFFSET(MMDEVRECORD, ulDeviceIndex);
        xfi[i].pszColumnTitle = cmnGetString(ID_MMSI_DEVICEINDEX);  // pszDeviceIndex
        xfi[i].ulDataType = CFA_ULONG;
        xfi[i++].ulOrientation = CFA_CENTER | CFA_TOP;

        // V0.9.13 (2001-06-14) [umoeller]
        xfi[i].ulFieldOffset = FIELDOFFSET(MMDEVRECORD, pszInstallName);
        xfi[i].pszColumnTitle = cmnGetString(ID_MMSI_INSTALLNAME); // "install name";
        xfi[i].ulDataType = CFA_STRING;
        xfi[i++].ulOrientation = CFA_LEFT | CFA_TOP;

        xfi[i].ulFieldOffset = FIELDOFFSET(MMDEVRECORD, pszLogicalName);
        xfi[i].pszColumnTitle = cmnGetString(ID_MMSI_LOGICALNAME); // "logical name";
        xfi[i].ulDataType = CFA_STRING;
        xfi[i++].ulOrientation = CFA_LEFT | CFA_TOP;

        xfi[i].ulFieldOffset = FIELDOFFSET(MMDEVRECORD, pszAliasName);
        xfi[i].pszColumnTitle = cmnGetString(ID_MMSI_ALIAS); // "alias";
        xfi[i].ulDataType = CFA_STRING;
        xfi[i++].ulOrientation = CFA_LEFT | CFA_TOP;
        // end V0.9.13 (2001-06-14) [umoeller]

        xfi[i].ulFieldOffset = FIELDOFFSET(MMDEVRECORD, pszInfo);
        xfi[i].pszColumnTitle = cmnGetString(ID_MMSI_DEVICEINFO);  // pszDeviceInfo
        xfi[i].ulDataType = CFA_STRING;
        xfi[i++].ulOrientation = CFA_LEFT | CFA_TOP;

        pfi = cnrhSetFieldInfos(hwndCnr,
                                xfi,
                                i,             // array item count
                                TRUE,          // draw lines
                                2);            // return third column

        BEGIN_CNRINFO()
        {
            cnrhSetView(CV_DETAIL | CA_DETAILSVIEWTITLES);
            cnrhSetSplitBarAfter(pfi);
            cnrhSetSplitBarPos(250);
        } END_CNRINFO(hwndCnr);
    }

    if (flFlags & CBI_SET)
    {
        thrCreate(&G_tiInsertDevices,
                  fntInsertDevices,
                  NULL, // running flag
                  "InsertDevices",
                  THRF_PMMSGQUEUE,
                  (ULONG)pnbp);
    }

    if (flFlags & CBI_DESTROY)
    {
        // reversed order V0.9.7 (2000-12-17) [umoeller]
        thrClose(&G_tiInsertDevices);

        if (pnbp->pUser)
            xmmFreeDevices(pnbp->pUser);
        pnbp->pUser = NULL;
    }
}

/* ******************************************************************
 *
 *   XWPMedia "IOProcs" page notebook callbacks (notebook.c)
 *
 ********************************************************************/

/*
 *@@ DescribeMediaType:
 *
 *@@added V0.9.3 (2000-04-29) [umoeller]
 */

VOID DescribeMediaType(PSZ pszBuf,          // out: description
                       ULONG cbBuf,         // in: sizeof(*pszBuf)
                       ULONG ulMediaType)   // in: MMIO_MEDIATYPE_* id
{
    // PNLSSTRINGS     pNLSStrings = cmnQueryNLSStrings();

    switch (ulMediaType)
    {
        case MMIO_MEDIATYPE_IMAGE:
            strhncpy0(pszBuf, cmnGetString(ID_MMSI_TYPE_IMAGE),  cbBuf); // pszTypeImage
        break;

        case MMIO_MEDIATYPE_AUDIO:
            strhncpy0(pszBuf, cmnGetString(ID_MMSI_TYPE_AUDIO),  cbBuf); // pszTypeAudio
        break;

        case MMIO_MEDIATYPE_MIDI:
            strhncpy0(pszBuf, cmnGetString(ID_MMSI_TYPE_MIDI),  cbBuf); // pszTypeMIDI
        break;

        case MMIO_MEDIATYPE_COMPOUND:
            strhncpy0(pszBuf, cmnGetString(ID_MMSI_TYPE_COMPOUND),  cbBuf); // pszTypeCompound
        break;

        case MMIO_MEDIATYPE_OTHER:
            strhncpy0(pszBuf, cmnGetString(ID_MMSI_TYPE_OTHER),  cbBuf); // pszTypeOther
        break;

        case MMIO_MEDIATYPE_UNKNOWN:
            strhncpy0(pszBuf, cmnGetString(ID_MMSI_TYPE_UNKNOWN),  cbBuf); // pszTypeUnknown
        break;

        case MMIO_MEDIATYPE_DIGITALVIDEO:
            strhncpy0(pszBuf, cmnGetString(ID_MMSI_TYPE_VIDEO),  cbBuf); // pszTypeVideo
        break;

        case MMIO_MEDIATYPE_ANIMATION:
            strhncpy0(pszBuf, cmnGetString(ID_MMSI_TYPE_ANIMATION),  cbBuf); // pszTypeAnimation
        break;

        case MMIO_MEDIATYPE_MOVIE:
            strhncpy0(pszBuf, cmnGetString(ID_MMSI_TYPE_MOVIE),  cbBuf); // pszTypeMovie
        break;

        default:
            sprintf(pszBuf, "unknown (%d)", ulMediaType);
    }
}

/*
 *@@ IOPROCRECORD:
 *
 *@@added V0.9.3 (2000-04-29) [umoeller]
 */

typedef struct _IOPROCRECORD
{
    RECORDCORE  recc;

    ULONG       ulIndex;

    CHAR        szFourCC[5];
    PSZ         pszFourCC;      // points to szFourCC

    CHAR        szFormatName[200];
    PSZ         pszFormatName;  // points to szFormatName

    CHAR        szIOProcType[30];
    PSZ         pszIOProcType;   // points to szIOProcType

    CHAR        szMediaType[30];
    PSZ         pszMediaType;   // points to szMediaType

    CHAR        szExtension[5];
    PSZ         pszExtension;  // szExtension

} IOPROCRECORD, *PIOPROCRECORD;

/*
 *@@ fntInsertIOProcs:
 *      transient thread started by xwmmCodecsInitPage
 *      to insert devices into the "Devices" container.
 *
 *      This thread is created with a msg queue.
 *
 *@@changed V0.9.6 (2000-11-12) [umoeller]: fixed memory leak
 *@@changed V0.9.7 (2000-12-17) [umoeller]: added exit flag
 */

void _Optlink fntInsertIOProcs(PTHREADINFO pti)
{
    PNOTEBOOKPAGE pnbp = (PNOTEBOOKPAGE)(pti->ulData);

    TRY_LOUD(excpt1)
    {
        PMMFORMATINFO   pammfi;
        LONG            cFormatsRead;

        pnbp->fShowWaitPointer = TRUE;

        // exported this code to the helpers V1.0.1 (2003-01-25) [umoeller]
        if (!mmhGetIOProcs(0,
                           &pammfi,
                           &cFormatsRead))
        {
            ULONG ul;
            PMMFORMATINFO pmmfiThis = pammfi;

            for (ul = 0;
                 ul < cFormatsRead;
                 ul++)
            {
                HWND    hwndCnr;
                PIOPROCRECORD precc;

                if (pti->fExit)     // V0.9.7 (2000-12-17) [umoeller]
                    break;

                if (    (!(hwndCnr = WinWindowFromID(pnbp->hwndDlgPage, ID_XFDI_CNR_CNR)))
                     || (!(precc = (PIOPROCRECORD)cnrhAllocRecords(hwndCnr,
                                                                   sizeof(IOPROCRECORD),
                                                                   1)))
                   )
                    break;
                else
                {
                    PSZ     pszFormatName;
                    ULONG   idString;
                    // index
                    precc->ulIndex = ul;

                    // FourCC
                    memcpy(&precc->szFourCC, &pmmfiThis->fccIOProc, sizeof(ULONG));
                    precc->szFourCC[4] = 0;
                    precc->pszFourCC = precc->szFourCC;

                    // format name
                    if (    (pmmfiThis->lNameLength)
                         && (pszFormatName = malloc(pmmfiThis->lNameLength + 1))
                       )
                    {
                        LONG lWritten;
                        G_mmioGetFormatName(pmmfiThis,
                                            pszFormatName,
                                            &lWritten,
                                            0,
                                            0);
                        if (lWritten)
                            strhncpy0(precc->szFormatName,
                                      pszFormatName,
                                      sizeof(precc->szFormatName) - 1);
                        free(pszFormatName);
                    }

                    precc->pszFormatName = precc->szFormatName;

                    // IOProc type
                    switch(pmmfiThis->ulIOProcType)
                    {
                        case MMIO_IOPROC_STORAGESYSTEM:
                            idString = ID_MMSI_TYPE_STORAGE;
                        break;

                        case MMIO_IOPROC_FILEFORMAT:
                            idString = ID_MMSI_TYPE_FILE;
                        break;

                        case MMIO_IOPROC_DATAFORMAT:
                            idString = ID_MMSI_TYPE_DATA;
                        break;

                        default:
                            idString = 0;
                    }

                    if (idString)
                        cmnGetString2(precc->szIOProcType,
                                      idString,
                                      sizeof(precc->szIOProcType));
                    else
                        sprintf(precc->szIOProcType,
                                "unknown (%d)",     // @@todo localize
                                pmmfiThis->ulIOProcType);

                    precc->pszIOProcType = precc->szIOProcType;

                    // media type
                    DescribeMediaType(precc->szMediaType,
                                      sizeof(precc->szMediaType),
                                      pmmfiThis->ulMediaType);
                    precc->pszMediaType = precc->szMediaType;

                    // extension
                    memcpy(&precc->szExtension, &pmmfiThis->szDefaultFormatExt,
                           5);
                    precc->pszExtension = precc->szExtension;

                    if (!cnrhInsertRecords(hwndCnr,
                                           NULL,
                                           (PRECORDCORE)precc,
                                           TRUE, // invalidate
                                           NULL,
                                           CRA_RECORDREADONLY,
                                           1))
                        break;
                }

                pmmfiThis++;
            } // end for (ul = 0;

            free(pammfi); // V0.9.6 (2000-11-12) [umoeller]

        } // end if (G_mmioGetFormats(&mmfi,
    }
    CATCH(excpt1) {}  END_CATCH();

    if (!pti->fExit)
        pnbp->fShowWaitPointer = FALSE;
}

/*
 *@@ xwmmIOProcsInitPage:
 *      notebook callback function (notebook.c) for the
 *      XWPMedia "Co2decs" page.
 *      Sets the controls on the page according to the
 *      Global Settings.
 *
 *@@changed V0.9.4 (2000-06-13) [umoeller]: group title was missing; fixed
 *@@changed V0.9.7 (2000-12-17) [umoeller]: now terminating thread on early close
 *@@changed V0.9.7 (2000-12-17) [umoeller]: this used the same global var as the codes page, fixed
 */

VOID xwmmIOProcsInitPage(PNOTEBOOKPAGE pnbp,   // notebook info struct
                        ULONG flFlags)        // CBI_* flags (notebook.h)
{
    if (flFlags & CBI_INIT)
    {
        // PNLSSTRINGS     pNLSStrings = cmnQueryNLSStrings();
        HWND hwndCnr = WinWindowFromID(pnbp->hwndDlgPage, ID_XFDI_CNR_CNR);

        XFIELDINFO      xfi[6];
        PFIELDINFO      pfi = NULL;
        int             i = 0;

        // set group title V0.9.4 (2000-06-13) [umoeller]
        WinSetDlgItemText(pnbp->hwndDlgPage, ID_XFDI_CNR_GROUPTITLE,
                          (PSZ)cmnGetString(ID_MMSI_PAGETITLE_IOPROCS)) ; // pszPagetitleIOProcs

        // set up cnr details view
        xfi[i].ulFieldOffset = FIELDOFFSET(IOPROCRECORD, ulIndex);
        xfi[i].pszColumnTitle = ""; // Index";
        xfi[i].ulDataType = CFA_ULONG;
        xfi[i++].ulOrientation = CFA_CENTER;

        xfi[i].ulFieldOffset = FIELDOFFSET(IOPROCRECORD, pszFourCC);
        xfi[i].pszColumnTitle = cmnGetString(ID_MMSI_COLMN_FOURCC);  // pszColmnFourCC
        xfi[i].ulDataType = CFA_STRING;
        xfi[i++].ulOrientation = CFA_LEFT;

        xfi[i].ulFieldOffset = FIELDOFFSET(IOPROCRECORD, pszFormatName);
        xfi[i].pszColumnTitle = cmnGetString(ID_MMSI_COLMN_NAME);  // pszColmnName
        xfi[i].ulDataType = CFA_STRING;
        xfi[i++].ulOrientation = CFA_LEFT;

        xfi[i].ulFieldOffset = FIELDOFFSET(IOPROCRECORD, pszIOProcType);
        xfi[i].pszColumnTitle = cmnGetString(ID_MMSI_COLMN_IOPROC_TYPE);  // pszColmnIOProcType
        xfi[i].ulDataType = CFA_STRING;
        xfi[i++].ulOrientation = CFA_LEFT;

        xfi[i].ulFieldOffset = FIELDOFFSET(IOPROCRECORD, pszMediaType);
        xfi[i].pszColumnTitle = cmnGetString(ID_MMSI_COLMN_MEDIA_TYPE);  // pszColmnMediaType
        xfi[i].ulDataType = CFA_STRING;
        xfi[i++].ulOrientation = CFA_LEFT;

        xfi[i].ulFieldOffset = FIELDOFFSET(IOPROCRECORD, pszExtension);
        xfi[i].pszColumnTitle = cmnGetString(ID_MMSI_COLMN_EXTENSION);  // pszColmnExtension
        xfi[i].ulDataType = CFA_STRING;
        xfi[i++].ulOrientation = CFA_LEFT;

        pfi = cnrhSetFieldInfos(hwndCnr,
                                xfi,
                                i,             // array item count
                                TRUE,          // draw lines
                                2);            // return third column

        BEGIN_CNRINFO()
        {
            cnrhSetView(CV_DETAIL | CA_DETAILSVIEWTITLES);
            cnrhSetSplitBarAfter(pfi);
            cnrhSetSplitBarPos(300);
        } END_CNRINFO(hwndCnr);
    }

    if (flFlags & CBI_SET)
    {
        thrCreate(&G_tiInsertIOProcs,
                  fntInsertIOProcs,
                  NULL, // running flag
                  "InsertIOProcs",
                  THRF_PMMSGQUEUE,
                  (ULONG)pnbp);
    }

    if (flFlags & CBI_DESTROY)
    {
        // added V0.9.7 (2000-12-17) [umoeller]
        thrClose(&G_tiInsertIOProcs);
    }
}

/* ******************************************************************
 *
 *   XWPMedia "Codecs" page notebook callbacks (notebook.c)
 *
 ********************************************************************/

/*
 *@@ CODECRECORD:
 *
 *@@added V0.9.3 (2000-04-29) [umoeller]
 */

typedef struct _CODECRECORD
{
    RECORDCORE  recc;

    ULONG       ulIndex;

    CHAR        szFourCC[5];
    PSZ         pszFourCC;      // points to szFourCC

    CHAR        szCodecName[200];
    PSZ         pszCodecName;      // points to szCodecName

    CHAR        szMediaType[30];
    PSZ         pszMediaType;   // points to szMediaType

    CHAR        szDLLName[DLLNAME_SIZE];
    PSZ         pszDLLName;     // points to szDLLName

    CHAR        szProcName[PROCNAME_SIZE];
    PSZ         pszProcName;    // points to szProcName

} CODECRECORD, *PCODECRECORD;

/*
 *@@ fntInsertCodecs:
 *      transient thread started by xwmmCodecsInitPage
 *      to insert devices into the "Devices" container.
 *
 *      This thread is created with a msg queue.
 *
 *@@changed V0.9.7 (2000-12-17) [umoeller]: added exit flag
 */

void _Optlink fntInsertCodecs(PTHREADINFO pti)
{
    PNOTEBOOKPAGE pnbp = (PNOTEBOOKPAGE)(pti->ulData);

    TRY_LOUD(excpt1)
    {
        CODECINIFILEINFO    cifi;
        BOOL                fContinue = TRUE;
        ULONG               ulIndex = 0,
                            ulFlags = MMIO_FINDPROC | MMIO_MATCHFIRST;

        pnbp->fShowWaitPointer = TRUE;

        memset(&cifi, 0, sizeof(cifi));
        cifi.ulStructLen = sizeof(cifi);

        do
        {
            if (pti->fExit)     // V0.9.7 (2000-12-17) [umoeller]
                break;

            if (G_mmioIniFileCODEC(&cifi,
                                   ulFlags) // initially MMIO_FINDPROC | MMIO_MATCHFIRST
                        != MMIO_SUCCESS)
                fContinue = FALSE;
            else
            {
                // success:
                HWND        hwndCnr = WinWindowFromID(pnbp->hwndDlgPage, ID_XFDI_CNR_CNR);

                if (!hwndCnr)
                    break;
                else
                {
                    PCODECRECORD precc
                        = (PCODECRECORD)cnrhAllocRecords(hwndCnr,
                                                         sizeof(CODECRECORD),
                                                         1);
                    if (!precc)
                        break;
                    else
                    {
                        ULONG   cb = 0;

                        // index
                        precc->ulIndex = ulIndex;

                        // FourCC
                        memcpy(&precc->szFourCC, &cifi.fcc, sizeof(ULONG));
                        precc->szFourCC[4] = 0;
                        precc->pszFourCC = precc->szFourCC;

                        // codec name
                        if (G_mmioQueryCODECNameLength(&cifi,
                                                       &cb)
                                == MMIO_SUCCESS)
                        {
                            PSZ pszCodecName;
                            if (pszCodecName = malloc(cb + 1))
                            {
                                // LONG lWritten;
                                if (G_mmioQueryCODECName(&cifi,
                                                         pszCodecName,
                                                         &cb) // excluding null term.
                                            == MMIO_SUCCESS)
                                {
                                    strlcpy(precc->szCodecName,
                                            pszCodecName,
                                            sizeof(precc->szCodecName));
                                    precc->pszCodecName = precc->szCodecName;
                                }
                                #ifdef __DEBUG__
                                else
                                    precc->pszCodecName = "mmioQueryCODECName failed.";
                                #endif

                                free(pszCodecName);
                            }
                        }
                        #ifdef __DEBUG__
                        else
                            precc->pszCodecName = "mmioQueryCODECNameLength failed.";
                        #endif

                        // media type
                        DescribeMediaType(precc->szMediaType,
                                          sizeof(precc->szMediaType),
                                          cifi.ulMediaType);
                        precc->pszMediaType = precc->szMediaType;

                        strhncpy0(precc->szDLLName, cifi.szDLLName, sizeof(precc->szDLLName));
                        precc->pszDLLName = precc->szDLLName;

                        strhncpy0(precc->szProcName, cifi.szProcName, sizeof(precc->szProcName));
                        precc->pszProcName = precc->szProcName;

                        if (!cnrhInsertRecords(hwndCnr,
                                               NULL,
                                               (PRECORDCORE)precc,
                                               TRUE, // invalidate
                                               NULL,
                                               CRA_RECORDREADONLY,
                                               1))
                            break;
                    } // end if (precc)
                } // end if (hwndCnr)
            } // end if (G_mmioIniFileCODEC(&cifi...

            ulIndex++;
            ulFlags = MMIO_FINDPROC | MMIO_MATCHNEXT;
        } while (fContinue);
    }
    CATCH(excpt1) {}  END_CATCH();

    if (!pti->fExit)
        pnbp->fShowWaitPointer = FALSE;
}

/*
 *@@ xwmmCodecsInitPage:
 *      notebook callback function (notebook.c) for the
 *      XWPMedia "Codecs" page.
 *      Sets the controls on the page according to the
 *      Global Settings.
 *
 *@@changed V0.9.4 (2000-06-13) [umoeller]: group title was missing; fixed
 *@@changed V0.9.7 (2000-12-17) [umoeller]: now terminating thread on early close
 */

VOID xwmmCodecsInitPage(PNOTEBOOKPAGE pnbp,   // notebook info struct
                        ULONG flFlags)        // CBI_* flags (notebook.h)
{
    if (flFlags & CBI_INIT)
    {
        HWND hwndCnr = WinWindowFromID(pnbp->hwndDlgPage, ID_XFDI_CNR_CNR);

        XFIELDINFO      xfi[6];
        PFIELDINFO      pfi = NULL;
        int             i = 0;

        // set group title V0.9.4 (2000-06-13) [umoeller]
        WinSetDlgItemText(pnbp->hwndDlgPage, ID_XFDI_CNR_GROUPTITLE,
                          (PSZ)cmnGetString(ID_MMSI_PAGETITLE_CODECS)) ; // pszPagetitleCodecs

        // set up cnr details view
        xfi[i].ulFieldOffset = FIELDOFFSET(CODECRECORD, ulIndex);
        xfi[i].pszColumnTitle = ""; // Index";
        xfi[i].ulDataType = CFA_ULONG;
        xfi[i++].ulOrientation = CFA_CENTER;

        xfi[i].ulFieldOffset = FIELDOFFSET(CODECRECORD, pszFourCC);
        xfi[i].pszColumnTitle = cmnGetString(ID_MMSI_COLMN_FOURCC);  // pszColmnFourCC
        xfi[i].ulDataType = CFA_STRING;
        xfi[i++].ulOrientation = CFA_LEFT;

        xfi[i].ulFieldOffset = FIELDOFFSET(CODECRECORD, pszCodecName);
        xfi[i].pszColumnTitle = cmnGetString(ID_MMSI_COLMN_NAME);  // pszColmnName
        xfi[i].ulDataType = CFA_STRING;
        xfi[i++].ulOrientation = CFA_LEFT;

        xfi[i].ulFieldOffset = FIELDOFFSET(CODECRECORD, pszMediaType);
        xfi[i].pszColumnTitle = cmnGetString(ID_MMSI_COLMN_MEDIA_TYPE);  // pszColmnMediaType
        xfi[i].ulDataType = CFA_STRING;
        xfi[i++].ulOrientation = CFA_LEFT;

        xfi[i].ulFieldOffset = FIELDOFFSET(CODECRECORD, pszDLLName);
        xfi[i].pszColumnTitle = cmnGetString(ID_MMSI_COLMN_DLL);  // pszColmnDLL
        xfi[i].ulDataType = CFA_STRING;
        xfi[i++].ulOrientation = CFA_LEFT;

        xfi[i].ulFieldOffset = FIELDOFFSET(CODECRECORD, pszProcName);
        xfi[i].pszColumnTitle = cmnGetString(ID_MMSI_COLMN_PROCEDURE);  // pszColmnProcedure
        xfi[i].ulDataType = CFA_STRING;
        xfi[i++].ulOrientation = CFA_LEFT;

        pfi = cnrhSetFieldInfos(hwndCnr,
                                xfi,
                                i,             // array item count
                                TRUE,          // draw lines
                                2);            // return third column

        BEGIN_CNRINFO()
        {
            cnrhSetView(CV_DETAIL | CA_DETAILSVIEWTITLES);
            cnrhSetSplitBarAfter(pfi);
            cnrhSetSplitBarPos(300);
        } END_CNRINFO(hwndCnr);
    }

    if (flFlags & CBI_SET)
    {
        thrCreate(&G_tiInsertCodecs,
                  fntInsertCodecs,
                  NULL, // running flag
                  "InsertCodecs",
                  THRF_PMMSGQUEUE,
                  (ULONG)pnbp);
    }

    if (flFlags & CBI_DESTROY)
    {
        // added V0.9.7 (2000-12-17) [umoeller]
        thrClose(&G_tiInsertCodecs);
    }
}

/* ******************************************************************
 *
 *   XWPMedia Instance Methods
 *
 ********************************************************************/

/*
 *@@ xwpAddXWPMediaPages:
 *
 */

SOM_Scope ULONG  SOMLINK xwmm_xwpAddXWPMediaPages(XWPMedia *somSelf,
                                                  HWND hwndDlg)
{
    INSERTNOTEBOOKPAGE inbp;
    HMODULE         savehmod = cmnQueryNLSModuleHandle(FALSE);
    // PNLSSTRINGS     pNLSStrings = cmnQueryNLSStrings();
    /* XWPMediaData *somThis = XWPMediaGetData(somSelf); */
    XWPMediaMethodDebug("XWPMedia","xwmm_xwpAddXWPMediaPages");

    // insert "Multimedia" page
    if (xmmQueryStatus() == MMSTAT_WORKING)
    {
        // Codecs
        memset(&inbp, 0, sizeof(INSERTNOTEBOOKPAGE));
        inbp.somSelf = somSelf;
        inbp.hwndNotebook = hwndDlg;
        inbp.hmod = savehmod;
        inbp.usPageStyleFlags = BKA_MAJOR;
        inbp.pcszName = cmnGetString(ID_MMSI_PAGETITLE_CODECS);  // pszPagetitleCodecs
        inbp.ulDlgID = ID_XFD_CONTAINERPAGE; // generic cnr page
        inbp.ulDefaultHelpPanel  = ID_XSH_MEDIA_CODECS;
        inbp.ulPageID = SP_MEDIA_CODECS;
        inbp.pampControlFlags = G_pampGenericCnrPage;
        inbp.cControlFlags = G_cGenericCnrPage;
        inbp.pfncbInitPage    = xwmmCodecsInitPage;
        ntbInsertPage(&inbp);

        // IOProcs
        memset(&inbp, 0, sizeof(INSERTNOTEBOOKPAGE));
        inbp.somSelf = somSelf;
        inbp.hwndNotebook = hwndDlg;
        inbp.hmod = savehmod;
        inbp.usPageStyleFlags = BKA_MAJOR;
        inbp.pcszName = cmnGetString(ID_MMSI_PAGETITLE_IOPROCS);  // pszPagetitleIOProcs
        inbp.ulDlgID = ID_XFD_CONTAINERPAGE; // generic cnr page
        inbp.ulDefaultHelpPanel  = ID_XSH_MEDIA_IOPROCS;
        inbp.ulPageID = SP_MEDIA_IOPROCS;
        inbp.pampControlFlags = G_pampGenericCnrPage;
        inbp.cControlFlags = G_cGenericCnrPage;
        inbp.pfncbInitPage    = xwmmIOProcsInitPage;
        ntbInsertPage(&inbp);

        // "Devices" above that
        memset(&inbp, 0, sizeof(INSERTNOTEBOOKPAGE));
        inbp.somSelf = somSelf;
        inbp.hwndNotebook = hwndDlg;
        inbp.hmod = savehmod;
        inbp.usPageStyleFlags = BKA_MAJOR;
        inbp.pcszName = cmnGetString(ID_MMSI_PAGETITLE_DEVICES);  // pszPagetitleDevices
        inbp.ulDlgID = ID_XFD_CONTAINERPAGE; // generic cnr page
        inbp.ulDefaultHelpPanel  = ID_XSH_MEDIA_DEVICES;
        inbp.ulPageID = SP_MEDIA_DEVICES;
        inbp.pampControlFlags = G_pampGenericCnrPage;
        inbp.cControlFlags = G_cGenericCnrPage;
        inbp.pfncbInitPage    = xwmmDevicesInitPage;
        ntbInsertPage(&inbp);
    }

    return TRUE;
}

/*
 *@@ wpFilterPopupMenu:
 *      this WPObject instance method allows the object to
 *      filter out unwanted menu items from the context menu.
 *      This gets called before wpModifyPopupMenu.
 *
 *      We remove the "Create another" menu item.
 */

SOM_Scope ULONG  SOMLINK xwmm_wpFilterPopupMenu(XWPMedia *somSelf,
                                                ULONG ulFlags,
                                                HWND hwndCnr,
                                                BOOL fMultiSelect)
{
    /* XWPMediaData *somThis = XWPMediaGetData(somSelf); */
    XWPMediaMethodDebug("XWPMedia","xwmm_wpFilterPopupMenu");

    return (XWPMedia_parent_WPAbstract_wpFilterPopupMenu(somSelf,
                                                         ulFlags,
                                                         hwndCnr,
                                                         fMultiSelect)
            & ~CTXT_NEW
           );
}

/*
 *@@ 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.
 *
 *      We return the Settings view always.
 */

SOM_Scope ULONG  SOMLINK xwmm_wpQueryDefaultView(XWPMedia *somSelf)
{
    /* XWPMediaData *somThis = XWPMediaGetData(somSelf); */
    XWPMediaMethodDebug("XWPMedia","xwmm_wpQueryDefaultView");

    return OPEN_SETTINGS;
}

/*
 *@@ 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 XWPMedia, so we remove it.
 */

SOM_Scope ULONG  SOMLINK xwmm_wpAddObjectWindowPage(XWPMedia *somSelf,
                                                    HWND hwndNotebook)
{
    /* XWPMediaData *somThis = XWPMediaGetData(somSelf); */
    XWPMediaMethodDebug("XWPMedia","xwmm_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. Override
 *      this method to add new settings pages to either the
 *      top or the bottom of notebooks of a given class.
 */

SOM_Scope BOOL  SOMLINK xwmm_wpAddSettingsPages(XWPMedia *somSelf,
                                                HWND hwndNotebook)
{
    BOOL brc;
    /* XWPMediaData *somThis = XWPMediaGetData(somSelf); */
    XWPMediaMethodDebug("XWPMedia","xwmm_wpAddSettingsPages");

    brc = (XWPMedia_parent_WPAbstract_wpAddSettingsPages(somSelf,
                                                         hwndNotebook));
    if (brc)
        _xwpAddXWPMediaPages(somSelf, hwndNotebook);

    return brc;
}

/* ******************************************************************
 *
 *   XWPMedia Class Methods
 *
 ********************************************************************/

/*
 *@@ wpclsInitData:
 *      this M_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 xwmmM_wpclsInitData(M_XWPMedia *somSelf)
{
    /* M_XWPMediaData *somThis = M_XWPMediaGetData(somSelf); */
    M_XWPMediaMethodDebug("M_XWPMedia","xwmmM_wpclsInitData");

    M_XWPMedia_parent_M_WPAbstract_wpclsInitData(somSelf);

    krnClassInitialized(G_pcszXWPMedia);
}

/*
 *@@ wpclsQueryStyle:
 *
 */

SOM_Scope ULONG  SOMLINK xwmmM_wpclsQueryStyle(M_XWPMedia *somSelf)
{
    /* M_XWPMediaData *somThis = M_XWPMediaGetData(somSelf); */
    M_XWPMediaMethodDebug("M_XWPMedia","xwmmM_wpclsQueryStyle");

    return (M_XWPMedia_parent_M_WPAbstract_wpclsQueryStyle(somSelf)
                | CLSSTYLE_NEVERPRINT
                | CLSSTYLE_NEVERCOPY
                | CLSSTYLE_NEVERDELETE);
}

/*
 *@@ wpclsQueryTitle:
 *      this M_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 xwmmM_wpclsQueryTitle(M_XWPMedia *somSelf)
{
    /* M_XWPMediaData *somThis = M_XWPMediaGetData(somSelf); */
    M_XWPMediaMethodDebug("M_XWPMedia","xwmmM_wpclsQueryTitle");

    return "Multimedia";
}

/*
 *@@ wpclsQueryDefaultHelp:
 *      this M_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 the default help for the "Multimedia"
 *      object here.
 *
 *@@added V0.9.20 (2002-07-12) [umoeller]
 */

SOM_Scope BOOL  SOMLINK xwmmM_wpclsQueryDefaultHelp(M_XWPMedia *somSelf,
                                                    PULONG pHelpPanelId,
                                                    PSZ pszHelpLibrary)
{
    /* M_XWPMediaData *somThis = M_XWPMediaGetData(somSelf); */
    M_XWPMediaMethodDebug("M_XWPMedia","xwmmM_wpclsQueryDefaultHelp");

    strcpy(pszHelpLibrary, cmnQueryHelpLibrary());
    *pHelpPanelId = ID_XSH_XWPMEDIA;
    return TRUE;
}

/*
 *@@ wpclsQueryIconData:
 *      this M_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 give the "Multimedia" object a new standard
 *      icon here.
 */

SOM_Scope ULONG  SOMLINK xwmmM_wpclsQueryIconData(M_XWPMedia *somSelf,
                                                  PICONINFO pIconInfo)
{
    /* M_XWPMediaData *somThis = M_XWPMediaGetData(somSelf); */
    M_XWPMediaMethodDebug("M_XWPMedia","xwmmM_wpclsQueryIconData");

    if (pIconInfo)
    {
        pIconInfo->fFormat = ICON_RESOURCE;
        pIconInfo->resid   = ID_ICONXWPMEDIA;
        pIconInfo->hmod    = cmnQueryMainResModuleHandle();
    }

    return sizeof(ICONINFO);
}


