#include <windows.h>

#include <stdio.h>
#include <io.h>
#include <errno.h>
#include <stdlib.h>

#include "windefs.h"
#include "restok.h"
#include "projdata.h"
#include "showerrs.h"
#include "rlmsgtbl.h"
#include "commbase.h"
#include "custres.h"
#include "rlstrngs.h"
#include "resource.h"
#include "resourc2.h"
#include "resread.h"
#include "langlist.h"
#include "exentres.h"

extern MSTRDATA  gMstr;
extern PROJDATA  gProj;
extern UCHAR     szDHW[];
extern BOOL      fCodePageGiven;
extern BOOL      gfReplace;
extern HWND      hMainWnd;

BOOL   bRLGui;			//FALSE=RLMan TRUE=RLAdmin RLEdit RLquiked

#ifdef RLRES32
extern PLANGLIST pLangIDList;
#endif

static PLANGDATA pLangList = NULL;



//............................................................

                                //...RLtools are localized so we would like
                                //...to get correct locale's Version stamp
BOOL MyVerQueryValue(
LPVOID pBlock,
LPTSTR lpSubBlock,
LPVOID *lplpBuffer,
PUINT  puLen)
{

    LPWORD lpXlate;         // ptr to translations data

    DWORD cbValueTranslation=0;
    TCHAR szVersionKey[60]; // big enough for anything we need

    if( VerQueryValue( pBlock, TEXT("\\VarFileInfo\\Translation"),
       (LPVOID*)&lpXlate, &cbValueTranslation) )
    {

        wsprintf( szVersionKey, TEXT("\\StringFileInfo\\%04X04B0\\%s"),
            *lpXlate, lpSubBlock );

        if( VerQueryValue ( pBlock, szVersionKey, lplpBuffer, puLen) )
            return TRUE;

    }

    wsprintf( szVersionKey, TEXT("\\StringFileInfo\\%04X04B0\\%s"),
        LANGIDFROMLCID(GetThreadLocale()), lpSubBlock );

    if( !VerQueryValue (pBlock, szVersionKey, lplpBuffer, puLen) )
    {

        wsprintf( szVersionKey, TEXT("\\StringFileInfo\\040904B0\\%s"),
            lpSubBlock );

        if( !VerQueryValue (pBlock, szVersionKey, lplpBuffer, puLen) )
            return FALSE;
    }

    return TRUE;

}


int GetMasterProjectData(

CHAR * pszMasterFile,   //... Master Project file name
CHAR * pszSrc,          //... Resource source file name or NULL
CHAR * pszMtk,          //... Master token file name or NULL
BOOL   fLanguageGiven)
{
    int nRC = SUCCESS;  //... Return code

                                //... check for the special case where Master
                                //... Project File does not exist. If it doesn't
                                //... go ahead and create it.

    memset(&gMstr, '\0', sizeof(gMstr));

    if ( _access( pszMasterFile, 0) != 0 )
    {
        if ( ! (pszSrc && pszMtk) )
        {
            ShowErr( IDS_ERR_03, pszMasterFile, NULL);
            nRC = IDS_ERR_03;
        }
        else
        {
                                //... Get source resource file name

            if ( _fullpath( gMstr.szSrc, pszSrc, sizeof( gMstr.szSrc)-1) )
            {
                                //... Get Master token file name and its
                                //... modification date. Use that same date as
                                //... the initial date the master project was
                                //... last updated.

                if ( _fullpath( gMstr.szMtk, pszMtk, sizeof( gMstr.szMtk)-1) )
                {
                    SzDateFromFileName( gMstr.szSrcDate, gMstr.szSrc);
                    lstrcpyA( gMstr.szMpjLastRealUpdate, gMstr.szSrcDate);

                                //... Create the new Master Project file.

                    nRC = PutMasterProjectData( pszMasterFile);
                }
                else
                {
                    ShowErr( IDS_ERR_13, pszMtk, NULL);
                    nRC = IDS_ERR_13;
                }
            }
            else
            {
                ShowErr( IDS_ERR_13, pszSrc, NULL);
                nRC = IDS_ERR_13;
            }
        }
    }
    else
    {
        FILE *pfMpj = NULL;


        if ( (pfMpj = fopen( pszMasterFile, "rt")) == NULL )
        {
            ShowErr( IDS_ERR_07, pszMasterFile, NULL);
            nRC = IDS_ERR_07;
        }
        else
        {
                                //... Get resource source file name
                                //... and master token file name

            if ( fgets( gMstr.szSrc, sizeof( gMstr.szSrc), pfMpj)
              && fgets( gMstr.szMtk, sizeof( gMstr.szMtk), pfMpj) )
            {
								//... Make sure these two files exist
                if ( pszSrc )
                {
				    if ( !_fullpath(gMstr.szSrc,pszSrc,sizeof( gMstr.szSrc)-1) )
					{
                        ShowErr( IDS_ERR_07, pszSrc, NULL);
                        fclose( pfMpj );
						return( IDS_ERR_07 );
					}
                }

                if ( pszMtk )
				{
				    if ( !_fullpath(gMstr.szMtk,pszMtk,sizeof( gMstr.szMtk)-1) )
					{
                        ShowErr( IDS_ERR_07, pszMtk, NULL);
                        fclose( pfMpj );
						return( IDS_ERR_07 );
                    }
                }
                                //... If -c flag not given, get RDF file name
                                //... from master project file, else use name
                                //... from the -c cmd line arg.

                if ( gMstr.szRdfs[0] == '\0' )
                {
                    if ( ! fgets( gMstr.szRdfs, sizeof( gMstr.szRdfs), pfMpj) )
                    {
                        ShowErr( IDS_ERR_21,
                                 "Master Project",
                                 pszMasterFile);
                        nRC = IDS_ERR_21;
                    }
                }
                else
                {
                    if ( ! fgets( szDHW, DHWSIZE, pfMpj) )
                    {
                        ShowErr( IDS_ERR_21,
                                 "Master Project",
                                 pszMasterFile);
                        nRC = IDS_ERR_21;
                    }
                }
                                //... Get stored date of source file and
                                //... date of last master token file update

                if ( nRC == 0
                  && fgets( gMstr.szSrcDate, sizeof( gMstr.szSrcDate), pfMpj)
                  && fgets( gMstr.szMpjLastRealUpdate,
                            sizeof( gMstr.szMpjLastRealUpdate),
                            pfMpj) )
                {
                    WORD  wPriID = 0;
                    WORD  wSubID = 0;
                    UINT  uTmpCP = 0;

                                //... Strip any trailing new-lines from data

                    StripNewLineA( gMstr.szSrc);
                    StripNewLineA( gMstr.szMpjLastRealUpdate);
                    StripNewLineA( gMstr.szMtk);
                    StripNewLineA( gMstr.szRdfs);
                    StripNewLineA( gMstr.szSrcDate);

                                //... Try to get the.MPJ file's Language line.
                                //... If we find it and the -i arg was not
                                //... given, use the one found in the file.

                    if ( fgets( szDHW, DHWSIZE, pfMpj) != NULL //... CP line
                      && sscanf( szDHW, "Language %hx %hx", &wPriID, &wSubID) == 2 )
                    {
                        WORD  wTmpID = 0;

                        wTmpID = MAKELANGID( wPriID, wSubID);

                        if ( ! fLanguageGiven )
                        {
                            gMstr.wLanguageID = wTmpID;
                        }
                    }
                                //... Try to get the.MPJ file's Code Page line.
                                //... If we find it and the -p arg was not
                                //... given, use the one found in the file.

                    if ( fgets( szDHW, DHWSIZE, pfMpj) != NULL //... CP line
                      && sscanf( szDHW, "CodePage %u", &uTmpCP) == 1 )
                    {
                        if ( uTmpCP != gProj.uCodePage && ! fCodePageGiven )
                        {
                            gMstr.uCodePage = uTmpCP;
                        }
                    }
                    nRC = SUCCESS;
                }
                else
                {
                    ShowErr( IDS_ERR_21,
                             "Master Project",
                             pszMasterFile);
                    nRC = IDS_ERR_21;
                }
            }
            else
            {
                ShowErr( IDS_ERR_22, pszMasterFile, NULL);
                nRC = IDS_ERR_22;
            }
            fclose( pfMpj);
        }
    }
    return( nRC);
}

//............................................................

int PutMasterProjectData(

CHAR *pszMasterFile)    //... Master Project File name
{
    int   nRC   = SUCCESS;
    FILE *pfMpj = NULL;


    if ( (pfMpj = fopen( pszMasterFile, "wt")) == NULL )
    {
        ShowErr( IDS_ERR_06, pszMasterFile, NULL);
        nRC = -1;
    }
    else
    {
        fprintf( pfMpj, "%s\n%s\n%s\n%s\n%s\nLanguage %#04hx %#04hx\nCodePage %u",
                        gMstr.szSrc,
                        gMstr.szMtk,
                        gMstr.szRdfs,
                        gMstr.szSrcDate,
                        gMstr.szMpjLastRealUpdate,
                        PRIMARYLANGID( gMstr.wLanguageID),
                        SUBLANGID( gMstr.wLanguageID),
                        gMstr.uCodePage);

        fclose( pfMpj);
    }
    return( nRC);
}


//............................................................

int GetProjectData(

CHAR *pszPrj,       //... Project file name
CHAR *pszMpj,       //... Master Project file name or NULL
CHAR *pszTok,       //... Project token file name or NULL
BOOL  fCodePageGiven,
BOOL  fLanguageGiven)
{
    int nRC     = SUCCESS;
	int	iUpdate = 0;


    if ( _access( pszPrj, 0) != 0 )
    {
        if ( ! (pszMpj && pszTok) )
        {
            ShowErr( IDS_ERR_19, pszPrj, NULL);
            Usage();
            nRC = IDS_ERR_19;
        }
        else if ( ! fLanguageGiven )
        {
            ShowErr( IDS_ERR_24, pszPrj, NULL);
            Usage();
            nRC = IDS_ERR_24;
        }
        else
        {
            if ( _fullpath( gProj.szMpj,
                            pszMpj,
                            sizeof( gProj.szMpj)-1) )
            {
                if ( _fullpath( gProj.szTok,
                                pszTok,
                                sizeof( gProj.szTok)-1) )
                {
                    nRC = SUCCESS;
                }
                else
                {
                    ShowErr( IDS_ERR_13, pszTok, NULL);
                    nRC = IDS_ERR_13;
                }
            }
            else
            {
                ShowErr( IDS_ERR_13, pszMpj, NULL);
                nRC = IDS_ERR_13;
            }
        }
    }
    else
    {
        FILE *fpPrj = fopen( pszPrj, "rt");

        if ( fpPrj != NULL )
        {
            if ( fgets( gProj.szMpj,     sizeof( gProj.szMpj),     fpPrj)
              && fgets( gProj.szTok,     sizeof( gProj.szTok),     fpPrj)
              && fgets( gProj.szGlo,     sizeof( gProj.szGlo),     fpPrj)
              && fgets( gProj.szTokDate, sizeof( gProj.szTokDate), fpPrj) )
            {
                UINT  uTmpCP = 0;
                WORD  wPriID = 0;
                WORD  wSubID = 0;
								//... If named, make sure MPJ and TOK files exist
                if ( pszMpj )
                {
				    if ( !_fullpath( gProj.szMpj, pszMpj, sizeof( gProj.szMpj)-1) )
					{
                        ShowErr( IDS_ERR_21, pszMpj, NULL);
                        fclose( fpPrj );
						return( IDS_ERR_21);
                     }
				}

                if ( pszTok )
                {
                    if ( !_fullpath( gProj.szTok, pszTok, sizeof( gProj.szTok)-1) )
					{
                        ShowErr( IDS_ERR_21, pszTok, NULL);
                        fclose( fpPrj );
						return( IDS_ERR_21);
                    }
				}

                StripNewLineA( gProj.szMpj);
                StripNewLineA( gProj.szTok);
                StripNewLineA( gProj.szGlo);
                StripNewLineA( gProj.szTokDate);

                                //... Try to get the.PRJ file's Code Page line.
                                //... If we find it and the -p arg was not
                                //... given, use the one found in the file.

                if ( ! fgets( szDHW, DHWSIZE, fpPrj) )	//... CP line
				{
					iUpdate++;
				}
				else if ( sscanf( szDHW, "CodePage %u", &uTmpCP) == 1 )
                {
                    if ( uTmpCP != gProj.uCodePage && ! fCodePageGiven )
                    {
                        gProj.uCodePage = uTmpCP;
                    }
                }
                                //... Try to get the.PRJ file's Language line.
                                //... If we find it and the -i arg was not
                                //... given, use the one found in the file.

                if ( ! fgets( szDHW, DHWSIZE, fpPrj) ) //... LANGID line
				{
					iUpdate++;
				}
				else if ( sscanf( szDHW, "Language %hx %hx", &wPriID, &wSubID) == 2 )
                {
                    WORD  wTmpID = 0;

                    wTmpID = MAKELANGID( wPriID, wSubID);

                    if ( ! fLanguageGiven )
                    {
                        gProj.wLanguageID = wTmpID;
                    }
                }
                                //... Try to get the.PRJ file's Target File line

                if ( fgets( szDHW, DHWSIZE, fpPrj) != NULL )
                {
                    lstrcpyA( gProj.szBld, szDHW);
                    StripNewLineA( gProj.szBld);
                }
                                //... Try to get the.PRJ file's append/replace line

                if ( fgets( szDHW, DHWSIZE, fpPrj) != NULL )
                {
                    gfReplace = (*szDHW == 'R') ? TRUE : FALSE;
                }
                else
                {
                    gfReplace = TRUE;
                }
                nRC = SUCCESS;

				if ( iUpdate )
				{
					static TCHAR title[50];
					static TCHAR szMes[100];

					if ( bRLGui )
					{
								//Ask Update prj for 1.7? //RLadmin RLedit RLquiked

						LoadString( NULL,
									IDS_UPDATE_YESNO,
									szMes,
									TCHARSIN( sizeof( szMes)) );
						LoadString( NULL,
									IDS_UPDATE_TITLE,
									title,
									TCHARSIN( sizeof( title)) );
						
						if ( MessageBox( hMainWnd,
										 szMes,title,
										 MB_ICONQUESTION|MB_YESNO) == IDNO )
						{
								//User says no, then finish the job.
							LoadString( NULL,
										IDS_UPDATE_CANCEL,
										szMes,
										TCHARSIN( sizeof( szMes)) );
											
							MessageBox( hMainWnd,
										szMes,
										title,
										MB_ICONSTOP|MB_OK);
								//bye!
							nRC = IDS_UPDATE_CANCEL;
						}
						else
						{
								//replace Glossary <=> Bins
  	    	          		lstrcpyA( szDHW, gProj.szGlo );
							lstrcpyA( gProj.szGlo, gProj.szBld );
							lstrcpyA( gProj.szBld, szDHW );
						}
					}
					else		//For RLMan
					{
								//Update Message
						RLMessageBoxA( "Updating 1.0 files..." );
								//replace Glossary <=> Bins
              			lstrcpyA( szDHW, gProj.szGlo );
						lstrcpyA( gProj.szGlo, gProj.szBld );
						lstrcpyA( gProj.szBld, szDHW );
					}
				}
            }
            else
            {
                ShowErr( IDS_ERR_21, pszPrj, NULL);
                nRC = IDS_ERR_21;
            }
            fclose( fpPrj);
        }
        else
        {
            ShowErr( IDS_ERR_19, pszPrj, NULL);
            nRC = IDS_ERR_19;
        }
    }
    return( nRC);
}

//............................................................

int PutProjectData(

CHAR *pszPrj)       //... Project file name
{
    int   nRC   = 0;
    FILE *fpPrj = NULL;


    fpPrj = fopen( pszPrj, "wt");

    if ( fpPrj != NULL )
    {
        fprintf( fpPrj,
                 "%s\n%s\n%s\n%s\nCodePage %u\nLanguage %#04x %#04x\n%s\n%s",
                 gProj.szMpj,                       // Master Project file
                 gProj.szTok,                       // Project Token file
                 gProj.szGlo,                       // Project Glossary file
                 gProj.szTokDate,                   // Date token file changed
                 gProj.uCodePage,                   // Code Page of token file
                 PRIMARYLANGID( gProj.wLanguageID), // Project resource language
                 SUBLANGID( gProj.wLanguageID),
                 gProj.szBld,                       // Project target file
                 gfReplace ? "Replace" : "Append"); // Replace master lang?

        fclose( fpPrj);

        _fullpath( gProj.szPRJ, pszPrj, sizeof( gProj.szPRJ)-1);
    }
    else
    {
        ShowErr( IDS_ERR_21, pszPrj, NULL);
        nRC = IDS_ERR_21;
    }
    return( nRC);
}

//............................................................

WORD GetCopyright(

CHAR *pszProg,      //... Program name (argv[0])
CHAR *pszOutBuf,    //... Buffer for results
WORD  wBufLen)      //... Length of pszOutBuf
{
    BOOL    fRC       = FALSE;
    DWORD   dwRC      = 0L;
    DWORD   dwVerSize = 0L;         //... Size of file version info buffer
    LPSTR  *plpszFile = NULL;
    LPSTR   pszExt    = NULL;
    WCHAR  *pszVer    = NULL;
    PVOID   lpVerBuf  = NULL;       //... Version info buffer
    static CHAR  szFile[  MAXFILENAME+3] = "";

                                //... Figure out the full-path name of prog
                                //... so GetFileVersionInfoSize() will work.

    dwRC = lstrlenA( pszProg);

    if ( dwRC < 4 || lstrcmpiA( &pszProg[ dwRC - 4], ".exe") != 0 )
    {
        pszExt = ".exe";
    }

    dwRC = SearchPathA( NULL, pszProg, pszExt, sizeof( szFile), szFile, plpszFile);

    if ( dwRC == 0 )
    {
        return( IDS_ERR_25);
    }
    else if ( dwRC > sizeof( szFile) )
    {
        return( IDS_ERR_27);
    }

    // append the extension since SearchPath will not return it
    // if we have no extensio then a directory with the same name was returned
    // try to append the ext and hope that file will be there
    if ( lstrcmpiA( &szFile[dwRC - 4], ".exe") != 0 )
    {
        lstrcatA( szFile, pszExt );
    }


    //... Get # bytes in file version info

    if ( (dwVerSize = GetFileVersionInfoSizeA( szFile, &dwRC)) == 0L )
    {
        return( IDS_ERR_26);
    }
    lpVerBuf = (LPVOID)FALLOC( dwVerSize);

                                //... Retrieve version info
                                //... and get the file description

    if ( (dwRC = GetFileVersionInfoA( szFile, 0L, dwVerSize, lpVerBuf)) == 0L )
    {
        RLFREE( lpVerBuf);
        return( IDS_ERR_26);
    }

    if ( (fRC = MyVerQueryValue( lpVerBuf,
                               TEXT("FileDescription"),
                               &pszVer,
                               &dwVerSize)) == FALSE
      || (dwRC = WideCharToMultiByte( CP_ACP,
                                      0,
                                      pszVer,
                                      dwVerSize,
                                      pszOutBuf,
                                      dwVerSize,
                                      NULL,
                                      NULL)) == 0L )
    {
        RLFREE( lpVerBuf);
        return( IDS_ERR_26);
    }

    strcat( pszOutBuf, " ");

                                //... Get the file version

    if ( (fRC = MyVerQueryValue( lpVerBuf,
                                 TEXT("ProductVersion"),
                                 &pszVer,
                                 &dwVerSize)) == FALSE
    || (dwRC = WideCharToMultiByte( CP_ACP,
                                      0,
                                      pszVer,
                                      dwVerSize,
                                      &pszOutBuf[ lstrlenA( pszOutBuf)],
                                      dwVerSize,
                                      NULL,
                                      NULL)) == 0L )
    {
        RLFREE( lpVerBuf);
        return( IDS_ERR_26);
    }

    strcat( pszOutBuf, "\n");

                                //... Get the copyright statement

    if ( (fRC = MyVerQueryValue( lpVerBuf,
                                 TEXT("LegalCopyright"),
                                 &pszVer,
                                 &dwVerSize)) == FALSE
      || (dwRC = WideCharToMultiByte( CP_ACP,
                                      0,
                                      pszVer,
                                      dwVerSize,
                                      &pszOutBuf[ lstrlenA( pszOutBuf)],
                                      dwVerSize,
                                      NULL,
                                      NULL)) == 0L )
    {
        RLFREE( lpVerBuf);
        return( IDS_ERR_26);
    }
    RLFREE( lpVerBuf);
    return( SUCCESS);
}

//............................................................

WORD GetInternalName(

CHAR *pszProg,      //... Program name (argv[0])
CHAR *pszOutBuf,    //... Buffer for results
WORD  wBufLen)      //... Length of pszOutBuf
{
    BOOL    fRC       = FALSE;
    DWORD   dwRC      = 0L;
    DWORD   dwVerSize = 0L;         //... Size of file version info buffer
    LPSTR  *plpszFile = NULL;
    LPSTR   pszExt    = NULL;
    WCHAR  *pszVer    = NULL;
    PVOID   lpVerBuf  = NULL;       //... Version info buffer
    static CHAR  szFile[  MAXFILENAME+3] = "";

                                //... Figure out the full-path name of prog
                                //... so GetFileVersionInfoSize() will work.

    dwRC = lstrlenA( pszProg);

    if ( dwRC < 4 || lstrcmpiA( &pszProg[ dwRC - 4], ".exe") != 0 )
    {
        pszExt = ".exe";
    }

    dwRC = SearchPathA( NULL, pszProg, pszExt, sizeof( szFile), szFile, plpszFile);

    if ( dwRC == 0 )
    {
        return( IDS_ERR_25);
    }
    else if ( dwRC > sizeof( szFile) )
    {
        return( IDS_ERR_27);
    }

                                //... Get # bytes in file version info

    if ( (dwVerSize = GetFileVersionInfoSizeA( szFile, &dwVerSize)) == 0L )
    {
        return( IDS_ERR_26);
    }
    lpVerBuf = (LPVOID)FALLOC( dwVerSize);

                               //... Retrieve version info
                                //... and get the file description

    if ( (dwRC = GetFileVersionInfoA( szFile, 0L, dwVerSize, lpVerBuf)) == 0L )
    {
        RLFREE( lpVerBuf);
        return( IDS_ERR_26);
    }

    if ( (fRC = MyVerQueryValue( lpVerBuf,
                                 TEXT("InternalName"),
                                 &pszVer,
                                 &dwVerSize)) == FALSE
      || (dwRC = WideCharToMultiByte( CP_ACP,
                                      0,
                                      pszVer,
                                      dwVerSize,
                                      pszOutBuf,
                                      dwVerSize,
                                      NULL,
                                      NULL)) == 0L )
    {
        RLFREE( lpVerBuf);
        return( IDS_ERR_26);
    }
    RLFREE( lpVerBuf);
    return( SUCCESS);
}


//............................................................

int MyAtoi( CHAR *pStr)
{
    if ( lstrlenA( pStr) > 2
      && pStr[0] == '0'
      && tolower( pStr[1]) == 'x' )
    {
        return( atoihex( &pStr[2]));    //... in custres.c
    }
    else
    {
        return( atoi( pStr));
    }
}



//DWORD GetLanguageID( HWND hDlg, PMSTRDATA pMaster, PPROJDATA pProject)
//{
//    DWORD dwRC = SUCCESS;       //... Assume success
//    WORD wPriLangID = 0;
//    WORD wSubLangID = 0;
//
//
//    if ( pMaster )
//    {
//        GetDlgItemTextA( hDlg, IDD_PRI_LANG_ID, szDHW, DHWSIZE);
//        wPriLangID = MyAtoi( szDHW);
//
//        GetDlgItemTextA( hDlg, IDD_SUB_LANG_ID, szDHW, DHWSIZE);
//        wSubLangID = MyAtoi( szDHW);
//
//        pMaster->wLanguageID = MAKELANGID( wPriLangID, wSubLangID);
//    }
//
//    if ( pProject )
//    {
//        GetDlgItemTextA( hDlg, IDD_PROJ_PRI_LANG_ID, szDHW, DHWSIZE);
//        wPriLangID = MyAtoi( szDHW);
//
//        GetDlgItemTextA( hDlg, IDD_PROJ_SUB_LANG_ID, szDHW, DHWSIZE);
//        wSubLangID = MyAtoi( szDHW);
//
//        pProject->wLanguageID = MAKELANGID( wPriLangID, wSubLangID);
//    }
//    return( dwRC);
//}

//.................................................................
//... Set the language component names into the dlg box fields
//
//DWORD SetLanguageID( HWND hDlg, PMSTRDATA pMaster, PPROJDATA pProject)
//{
//    DWORD  dwRC = SUCCESS;      //... Assume success
//    WORD   wPriLangID  = 0;
//    WORD   wSubLangID  = 0;
//    LPTSTR pszLangName = NULL;
//
//                                //... Did we already load the data from
//                                //... the resources? If not, do so now.
//    if ( ! pLangList )
//    {
//        pLangList = GetLangList();
//    }
//
//    if ( pMaster )
//    {
//        wPriLangID = PRIMARYLANGID( pMaster->wLanguageID);
//        wSubLangID = SUBLANGID(     pMaster->wLanguageID);
//
//        if ( (pszLangName = GetLangName( wPriLangID, wSubLangID)) )
//        {
//            SetDlgItemText( hDlg, IDD_MSTR_LANG_NAME, pszLangName);
//        }
//        sprintf( szDHW, "%#04x", wPriLangID);
//        SetDlgItemTextA( hDlg, IDD_PRI_LANG_ID, szDHW);
//
//        sprintf( szDHW, "%#04x", wSubLangID);
//        SetDlgItemTextA( hDlg, IDD_SUB_LANG_ID, szDHW);
//    }
//
//    if ( pProject )
//    {
//        wPriLangID = PRIMARYLANGID( pProject->wLanguageID);
//        wSubLangID = SUBLANGID(     pProject->wLanguageID);
//
//        if ( (pszLangName = GetLangName( wPriLangID, wSubLangID)) )
//        {
//            SetDlgItemText( hDlg, IDD_PROJ_LANG_NAME, pszLangName);
//        }
//        sprintf( szDHW, "%#04x", wPriLangID);
//        SetDlgItemTextA( hDlg, IDD_PROJ_PRI_LANG_ID, szDHW);
//
//        sprintf( szDHW, "%#04x", wSubLangID);
//        SetDlgItemTextA( hDlg, IDD_PROJ_SUB_LANG_ID, szDHW);
//    }
//    return( dwRC);
//}

//...............................................................
//...
//... Build the list of Language names and component ID values

PLANGDATA GetLangList( void)
{
    PLANGDATA pRC = NULL;
    HRSRC hResource = FindResourceEx( NULL,
                                      (LPCTSTR)RT_RCDATA,
                                      (LPCTSTR)ID_LANGID_LIST,
                                      MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL));

    if ( hResource )
    {
        HGLOBAL hRes = LoadResource( NULL, hResource);

        if ( hRes )
        {
            PBYTE pRes = (PBYTE)LockResource( hRes);

            if ( pRes )
            {
                int nNameLen   = 0;
                PLANGDATA pTmp = NULL;

                nNameLen = lstrlenA( (LPSTR)pRes);
                pRC  = (PLANGDATA)FALLOC( sizeof( LANGDATA));
                pTmp = pRC;

                while ( nNameLen )
                {
                    MultiByteToWideChar( CP_ACP,
                                         MB_PRECOMPOSED,
                                         (LPSTR)pRes,
                                         -1,
                                         pTmp->szLangName,
                                         NAMELENBUFSIZE - 1);
                    pRes += ++nNameLen;

                    pTmp->wPriLang = MAKEWORD( *pRes, *(pRes+1) );
                    pRes += sizeof(WORD);
                    pTmp->wSubLang = MAKEWORD( *pRes, *(pRes+1) );
                    pRes += sizeof(WORD);

                    if ( (nNameLen = lstrlenA( (LPSTR)pRes)) )
                    {
                        PLANGDATA pNew = (PLANGDATA)FALLOC( sizeof( LANGDATA));
                        pTmp->pNext = pNew;
                        pTmp = pNew;
                    }
                }       //... END while( nNameLen )
            }           //... END if ( pRes )
            else
            {
                DWORD dwErr = GetLastError();
            }
        }               //... END if ( hRes )
        else
        {
            DWORD dwErr = GetLastError();
        }
    }                   //... END if ( hSrc )
    else
    {
        DWORD dwErr = GetLastError();
    }
    return( pRC);
}


//...............................................................
//...
//... Return the name of a language based on the given components

LPTSTR GetLangName( WORD wPriLangID, WORD wSubLangID)
{
    LPTSTR    pszRC = NULL;
    PLANGDATA pLang = NULL;

    if ( ! pLangList )
    {
        pLangList = GetLangList();
    }

    for ( pLang = pLangList; pLang && ! pszRC; pLang = pLang->pNext )
    {
        if ( pLang->wPriLang == wPriLangID && pLang->wSubLang == wSubLangID )
        {
            pszRC = pLang->szLangName;
        }
    }
    return( pszRC);
}

//...............................................................
//...
//... Return the language ID components based on the given name

BOOL GetLangIDs( LPTSTR pszName, PWORD pwPri, PWORD pwSub )
{
    BOOL fRC = FALSE;
    PLANGDATA pLang = NULL;

    if ( ! pLangList )
    {
        pLangList = GetLangList();
    }

    for ( pLang = pLangList; pLang && ! fRC; pLang = pLang->pNext )
    {
        if ( lstrcmp( pLang->szLangName, pszName) == 0 )
        {
            *pwPri = pLang->wPriLang;
            *pwSub = pLang->wSubLang;

            fRC = TRUE;
        }
    }
    return( fRC);
}


//...............................................................
//...
//... Fill the given combobox with the names of supported the languages.

LONG FillLangNameBox( HWND hDlg, int nControl)
{
    PLANGDATA pLang = NULL;
    PLANGLIST pID   = NULL;
    LONG lRC = -1;
    BOOL fListIt = TRUE;
    WORD wAddLang = 0;


    if ( nControl == IDD_MSTR_LANG_NAME )
    {
        if ( GetListOfResLangIDs( gMstr.szSrc) != SUCCESS )
        {
            return( lRC);
        }
    }

    if ( ! pLangList )
    {
        pLangList = GetLangList();
    }

    for ( pLang = pLangList; pLang; pLang = pLang->pNext )
    {
        fListIt = TRUE;

        if ( nControl == IDD_MSTR_LANG_NAME )
        {
            wAddLang = MAKELANGID( pLang->wPriLang, pLang->wSubLang);

            fListIt = FALSE;

            for ( pID = pLangIDList; pID; pID = pID->pNext )
            {
                if ( pID->wLang == wAddLang )
                {
                    fListIt = TRUE;
                    break;
                }
            }
        }

        if ( fListIt )
        {
            lRC = (LONG)SendDlgItemMessage( hDlg,
                                      nControl,
                                      CB_ADDSTRING,
                                      0,
                                      (LPARAM)pLang->szLangName);

            if ( lRC == CB_ERR || lRC == CB_ERRSPACE )
            {
                QuitT( IDS_ERR_16, NULL, NULL);
            }
        }
    }

    if ( nControl == IDD_MSTR_LANG_NAME )
    {
        FreeLangIDList();
    }
    return( lRC);
}


void FreeLangList( void)
{
    PLANGDATA pTmp = NULL;

    while ( pLangList )
    {
        pTmp = pLangList->pNext;
        RLFREE( pLangList);
        pLangList = pTmp;
    }

#ifdef RLRES32

    FreeLangIDList();

#endif

}


//...................................................................

void FillListAndSetLang(

HWND  hDlg,
WORD  wLangNameList,    //... IDD_MSTR_LANG_NAME or IDD_PROJ_LANG_NAME
WORD *pLangID,          //... Ptr to gMstr.wLanguageID or gProj.wLanguageID
BOOL *pfSelected)       //... Did we select a language here? (Can be NULL)
{
    int nSel =  FillLangNameBox( hDlg, wLangNameList);

    if ( nSel > 0L )
    {
        LPTSTR pszLangName = NULL;
                                //... See if the default master language is in the list

        if ( (pszLangName = GetLangName( (WORD)(PRIMARYLANGID( *pLangID)),
                                         (WORD)(SUBLANGID( *pLangID)))) != NULL )
        {
            if ( (nSel = (int)SendDlgItemMessage( hDlg,
                                             wLangNameList,
                                             CB_FINDSTRINGEXACT,
                                             (WPARAM)-1,
                                             (LPARAM)pszLangName)) != CB_ERR )
            {
                                //... default master language is in  list

                SendDlgItemMessage( hDlg,
                                    wLangNameList,
                                    CB_SETCURSEL,
                                    (WPARAM)nSel,
                                    (LPARAM)0);

                if ( pfSelected )
                {
                    *pfSelected = TRUE;
                }
            }
        }
    }
    else if ( nSel == 0 )
    {
                                //... Use first entry in the list

        SendDlgItemMessage( hDlg,
                            wLangNameList,
                            CB_SETCURSEL,
                            (WPARAM)nSel,
                            (LPARAM)0);

        if ( (nSel = (int)SendDlgItemMessage( hDlg,
                                         wLangNameList,
                                         CB_GETLBTEXT,
                                         (WPARAM)nSel,
                                         (LPARAM)(LPTSTR)szDHW)) != CB_ERR )
        {
            WORD wPri = 0;
            WORD wSub = 0;

            if ( GetLangIDs( (LPTSTR)szDHW, &wPri, &wSub) )
            {
                *pLangID   = MAKELANGID( wPri, wSub);

                if ( pfSelected )
                {
                    *pfSelected = TRUE;
                }
            }
            else
            {
                nSel = CB_ERR;
            }
        }
    }

    if ( nSel == CB_ERR )
    {
        SetDlgItemText( hDlg, wLangNameList, TEXT("UNKNOWN"));
    }
}