/*--------------------------------------------------------------
   POPFILE.C -- Fonctions du menu Fichier de l’éditeur de textes
  --------------------------------------------------------------*/



//
// Modifications History
//
//$LB (7/11/2004) : add the _DLGOpenDir and _DLGrflopenDir scol function, to select a directory
//
//$LB (8/11/2004) : add the _DLGClose scol function, to force a dialog box to close
//
//$LB (8/11/2004) : add threadH and threadID fields in the structs : the user is now able to force the dialog to close
//                  with the DLGClose function. It's a polymorphic function (takes all kind of scol dialog box in argument),
//                  so we have to check that the given argument is really a dialog box, that's why we added the magicnum fields too...
//
//$LB (01/02/2005) : correct bug about multi files selection 



#include "x/version.h"
#include "x/scolplugin.h"


#include <commdlg.h>
#include <stdlib.h>
#include <stdio.h>
#include <process.h>

#include "objstr.h"

#include "popfile.h"
#include "chainedlist.h"



//$LB (8/11/2004) : in order to store the dialog box data
ObjChainedList DialogBoxes;



//$LB (8/11/2004)
#define _DLG_SET_MAGICNUM(dialog) \
  (dialog)->magicnum[0] = 20; (dialog)->magicnum[1] = 4; (dialog)->magicnum[2] = 11; (dialog)->magicnum[3] = 8;

#define _DLG_CHECK_MAGICNUM(dialog) \
	((dialog[0] == 20) && (dialog[1] == 4) && (dialog[2] == 11) && (dialog[3] == 8))





int OBJTYPDIAL;
int OBJTYPFILE;
/* reflexes type DIALOG */
#define RFLDIAL_NB      1
#define RFLDIAL_END     0

int WM_OPENFILENAME;
int WM_SAVEFILENAME;

//$LB (7/11/2004)
int WM_OPENDIRECTORY;

int WM_MBOX;

/* reflexes type FILE */
#define RFLFILE_NB      0


static OPENFILENAME ofn ;

OFNArg * GArg=NULL;
MBOXArg * BArg=NULL;

void ThreadOpenFileName (PVOID pvoid);
void ThreadSaveFileName (PVOID pvoid);
void ThreadMessageBox (PVOID pvoid);

void PopFileInitialize (HWND hwnd)
{
  static char szFilter[] = "Fichiers texte (*.TXT)\0*.txt\0"  \
                          "Fichiers ASCII (*.ASC)\0*.asc\0" \
                          "Tous les fichiers (*.*)\0*.*\0\0" ;

  ofn.lStructSize       = sizeof (OPENFILENAME) ;
  ofn.hwndOwner         = hwnd ;
  ofn.hInstance         = NULL ;
  ofn.lpstrFilter       = szFilter ;
  ofn.lpstrCustomFilter = NULL ;
  ofn.nMaxCustFilter    = 0 ;
  ofn.nFilterIndex      = 0 ;
  ofn.lpstrFile         = NULL ; // défini dans les fonctions Ouvrir et Fermer
  ofn.nMaxFile          = _MAX_PATH ;
  ofn.lpstrFileTitle    = NULL ; // défini dans les fonctions Ouvrir et Fermer
  ofn.nMaxFileTitle     = _MAX_FNAME + _MAX_EXT ;
  ofn.lpstrInitialDir   = NULL ;
  ofn.lpstrTitle        = NULL ;
  ofn.Flags             = 0 ; // défini dans les fonctions Ouvrir et Fermer
  ofn.nFileOffset       = 0 ;
  ofn.nFileExtension    = 0 ;
  ofn.lpstrDefExt       = "txt" ;
  ofn.lCustData         = 0L ;
  ofn.lpfnHook          = NULL ;
  ofn.lpTemplateName    = NULL ;
}

int DLGslashtoback(char *p)
{
	while(*p)
	{
		if ((*p)=='/') *p='\\';
		p++;
	}
	return 0;
}

//$BLG
int DLGbacktoslash(char *p)
{
	while(*p)
	{
		if ((*p)=='\\') *p='/';
		p++;
	}
	return 0;
}

int DLDialog=1;



//$LB (01/02/2005) : correct bug about multi files selection 
#define MAX_MULTI_FILENAME 32000


/* fun [Chn ObjWin S S S] Dialog */
int DLGOpenFile2 (mmachine m,int multi)
{
  const char nilstring[]="\0";
  const char deffilter[]="All Files (*.*)\0*.*\0\0";
  char *filename;
  char *szFilter;
  char *Defaultdir;

  int filter;
  int defaultdir;
  int defaultfname;
  int win;
  PtrObjVoid p;
  OFNArg * Mofn;

  ofn.Flags= OFN_HIDEREADONLY | OFN_CREATEPROMPT | OFN_EXPLORER;
  if (multi) ofn.Flags|=OFN_ALLOWMULTISELECT;

  filter=MMpull(m)>>1;
  defaultfname=MMpull(m)>>1;
  defaultdir=MMpull(m)>>1;
  win=MMpull(m)>>1;
  
  if (MMget(m, 0)==NIL) return 0;

  if (filter!=NIL)
  {
    szFilter=(char*)malloc(MMsizestr(m,filter)+1);
    if (szFilter==NULL) 
    {
	    MMset(m, 0, NIL);
      return 0;
    }
    memcpy(szFilter,MMstartstr(m,filter),MMsizestr(m,filter)+1);
  }
  else
  {
    szFilter=(char*)malloc(24);
    if (szFilter==NULL) 
    {
	    MMset(m, 0, NIL);
      return 0;
    }
    memcpy(szFilter,deffilter,24);
  }

  //$LB (01/02/2005)
  filename=(char*)malloc(MAX_MULTI_FILENAME+1);
 
  if (filename==NULL) 
  {
    free(szFilter);
    MMset(m,0,NIL);
    return 0;
  }

  filename[0]=0;
  //$LB (01/02/2005)
  filename[MAX_MULTI_FILENAME]=0;
  
  if ((defaultfname!=NIL)&&(MMsizestr(m,defaultfname)<_MAX_PATH))
	  memcpy(filename,MMstartstr(m,defaultfname),MMsizestr(m,defaultfname)+1);

  if ((packdir)SCgetExtra("FirstPack")==NULL)
  {
    Defaultdir=NULL;
  }
  else
  {
	  if (defaultdir==NIL)
  		Defaultdir=(char*)malloc(strlen(((packdir)SCgetExtra("FirstPack"))->path)+1);
	  else
	  	Defaultdir=(char*)malloc(strlen(((packdir)SCgetExtra("FirstPack"))->path)+1+MMsizestr(m,defaultdir));
	  
    if (Defaultdir==NULL)
	  {
		  free(szFilter);
      free(filename);
      MMset(m,0,NIL);
      return 0;
    }

    if (defaultdir==NIL)
		  sprintf(Defaultdir,"%s",((packdir)SCgetExtra("FirstPack"))->path);
	  else
		  sprintf(Defaultdir,"%s%s",((packdir)SCgetExtra("FirstPack"))->path,MMstartstr(m,defaultdir));

	  DLGslashtoback(Defaultdir);
  }

  if (win==NIL) ofn.hwndOwner=NULL;
  else
  {
	  p=(PtrObjVoid)MMstart(m,win);
	  ofn.hwndOwner=((PtrObjWindow)MMstart(m,p->Buffer>>1))->WHandler;
  }

  ofn.lStructSize       = sizeof (OPENFILENAME) ;
//  ofn.hwndOwner         = NULL ;
  ofn.hInstance         = NULL ;
  ofn.lpstrFilter       = szFilter ;
  ofn.lpstrCustomFilter = NULL ;
  ofn.nMaxCustFilter    = 0 ;
  ofn.nFilterIndex      = 0 ;
  ofn.lpstrFile         = filename ; 
  //$LB (01/02/2005)
  ofn.nMaxFile          = MAX_MULTI_FILENAME ;

  ofn.lpstrFileTitle    = NULL ; 
  ofn.nMaxFileTitle     = _MAX_FNAME + _MAX_EXT ;
  ofn.lpstrInitialDir   = Defaultdir ;
  ofn.lpstrTitle        = NULL ;
  ofn.nFileOffset       = 0 ;
  ofn.nFileExtension    = 0 ;
  ofn.lpstrDefExt       = NULL ;
  ofn.lCustData         = 0L ;
  ofn.lpfnHook          = NULL ;
  ofn.lpTemplateName    = NULL ;

  Mofn=(OFNArg *)malloc(sizeof (OFNArg));
  if (Mofn==NULL)
  {
    free(szFilter);
    free(filename);
    free(Defaultdir);
    MMset(m,0,NIL);
    return 0;
  }

  memcpy(&(Mofn->ofn),&ofn,sizeof (OPENFILENAME));

  //father
  //Mofn->hwnd=hscol;


  Mofn->id=DLDialog;
  Mofn->err=0;


  //$LB (8/11/2004)
  _DLG_SET_MAGICNUM(Mofn);
  Mofn->threadH = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) ThreadOpenFileName, Mofn, 0, &(Mofn->threadID));
  chainedlist_add (&DialogBoxes, Mofn->id, DLGTYPE_OPENFILE, (void*) Mofn);

  if (MMpush(m,DLDialog*2)) return MERRMEM;

  DLDialog++;
  return OBJcreate(m,OBJTYPDIAL,DLDialog-1,OBJTYPWINDOW,(int)Mofn->hwnd);
}

int DLGOpenFile (mmachine m)
{
	return DLGOpenFile2(m,0);
}

int DLGOpenFileMulti (mmachine m)
{
	return DLGOpenFile2(m,1);
}


void ThreadOpenFileName (PVOID pvoid)
{
  TCHAR saveCurrentDir[MAX_PATH];
  OFNArg * Mofn;
  BOOL res;
  DWORD errorCode;

  Mofn=(OFNArg*)pvoid;

  if (Mofn==NULL) 
  {
    Mofn->err=-1;
    PostMessage ((HWND)SCgetExtra("hscol"),WM_OPENFILENAME,(WPARAM)Mofn->id,(LPARAM)Mofn);
    ExitThread(0);
    return;
  }

  // Windows unwanted behavior, when selecting a directory, the program current working dir is changed to the selected one.
  GetCurrentDirectory(MAX_PATH, saveCurrentDir);
  res = GetOpenFileName (&(Mofn->ofn));
  SetCurrentDirectory(saveCurrentDir);
  
  if (!res)
  {
    errorCode = CommDlgExtendedError();
  
	  Mofn->err=-1; 
	  MMechostr(0, "\nDialog Error : Something went wrong in the dialog process : error code %d...\n", errorCode);

  }else Mofn->err=-0; 
 
  PostMessage ((HWND)SCgetExtra("hscol"),WM_OPENFILENAME,(WPARAM)Mofn->id,(LPARAM)Mofn);

  //$LB (8/11/2004)
  chainedlist_remove (&DialogBoxes, Mofn->id);

  ExitThread(0);  
}
 

int DLGGetOpenFileName (mmachine m,HWND h,unsigned msg,UINT id,LONG param,int *ret)
{ 
	OFNArg* Mofn=(OFNArg*)param;
  int k,i,i0,j,n;
  char buf[_MAX_PATH]; 

  if (Mofn==NULL) return 0;

  k=OBJbeginreflex(m,OBJTYPDIAL,id,RFLDIAL_END);
  if (k==0)
	{
// 		MMechostr(MSKDEBUG,"dialog %d %d %s\n",id,Mofn->err,Mofn->ofn.lpstrFile);
		if (Mofn->err==0)
		{
			if ((Mofn->ofn.Flags&OFN_ALLOWMULTISELECT)==OFN_ALLOWMULTISELECT)
			{
				i=Mofn->ofn.nFileOffset;
				i0=i-1;
				memcpy(buf,Mofn->ofn.lpstrFile,i0);
				sprintf(buf+i0,"\\%s",Mofn->ofn.lpstrFile+i);
				MMechostr(MSKDEBUG,"file :%s\n",buf);
				if (Mpushstrbloc(m,buf)) return MERRMEM;
				n=1;
				j=i+strlen(Mofn->ofn.lpstrFile+i)+1;
				while((Mofn->ofn.lpstrFile[i-1]==0)&&(Mofn->ofn.lpstrFile[j]))
				{
					i=j;
					sprintf(buf+i0,"\\%s",Mofn->ofn.lpstrFile+i);
					MMechostr(MSKDEBUG,"file :%s\n",buf);
					if (Mpushstrbloc(m,buf)) return MERRMEM;
					n++;
					j=i+strlen(Mofn->ofn.lpstrFile+i)+1;
				}
				if (MMpush(m,NIL)) return MERRMEM;

				for(i=0;i<n;i++)
				{
					if (MMpush(m,2*2)) return MERRMEM;
					if (k=MBdeftab(m)) return k;
				}
			}
			else if (Mpushstrbloc(m,Mofn->ofn.lpstrFile)) return MERRMEM;
		}
		else if (MMpush(m,NIL)) return MERRMEM;
		if (k=OBJcallreflex(m,1)) return k;
	}
  if(Mofn->ofn.lpstrFile) free((void*)Mofn->ofn.lpstrFile);
  if(Mofn->ofn.lpstrFilter) free((void*)Mofn->ofn.lpstrFilter);
  if(Mofn->ofn.lpstrInitialDir) free((void*)Mofn->ofn.lpstrInitialDir);
  free((void*)Mofn);
  OBJdelTH(m,OBJTYPDIAL,id);
  return 0;
}


/* fun [Chn ObjWin S S S] Dialog */
int DLGSaveFile (mmachine m)
{
  const char nilstring[]="\0";
  const char deffilter[]="All Files (*.*)\0*.*\0\0";
  char *filename;
  char *szFilter;
  char *Defaultdir;

  int filter;
  int defaultdir;
  int defaultfname;
  int win;
  PtrObjVoid p;
  OFNArg * Mofn;

  ofn.Flags             = OFN_HIDEREADONLY | OFN_CREATEPROMPT | OFN_EXPLORER;

  filter=MMpull(m)>>1;
  defaultfname=MMpull(m)>>1;
  defaultdir=MMpull(m)>>1;
  win=MMpull(m)>>1;
  
  if (MMget(m,0)==NIL) return 0;

  if (filter!=NIL)
  {
    szFilter=(char*)malloc(MMsizestr(m,filter)+1);
    if (szFilter==NULL) 
    {
	  MMset(m,0,NIL);
      return 0;
    }
    memcpy(szFilter,MMstartstr(m,filter),MMsizestr(m,filter)+1);
  }
  else
  {
    szFilter=(char*)malloc(24);
    if (szFilter==NULL) 
    {
	  MMset(m,0,NIL);
      return 0;
    }
    memcpy(szFilter,deffilter,24);
  }


  filename=(char*)malloc(_MAX_PATH+1);
  if (filename==NULL) 
  {
    free(szFilter);
    MMset(m,0,NIL);
    return 0;
  }
  filename[0]=0;
  filename[_MAX_PATH]=0;
  
  if ((defaultfname!=NIL)&&(MMsizestr(m,defaultfname)<_MAX_PATH))
	  memcpy(filename,MMstartstr(m,defaultfname),MMsizestr(m,defaultfname)+1);

  if (((packdir)SCgetExtra("FirstPack"))==NULL) Defaultdir=NULL;
  else
  {
	  if (defaultdir==NIL)
		Defaultdir=(char*)malloc(strlen(((packdir)SCgetExtra("FirstPack"))->path)+1);
	  else
		Defaultdir=(char*)malloc(strlen(((packdir)SCgetExtra("FirstPack"))->path)+1+MMsizestr(m,defaultdir));
	  if (Defaultdir==NULL)
	  {
		  free(szFilter);
          free(filename);
	      MMset(m,0,NIL);
          return 0;
      }
	  if (defaultdir==NIL)
		  sprintf(Defaultdir,"%s",((packdir)SCgetExtra("FirstPack"))->path);
	  else
		  sprintf(Defaultdir,"%s%s",((packdir)SCgetExtra("FirstPack"))->path,MMstartstr(m,defaultdir));
	  DLGslashtoback(Defaultdir);
  }

  if (win==NIL) ofn.hwndOwner=NULL;
  else
  {
	  p=(PtrObjVoid)MMstart(m,win);
	  ofn.hwndOwner=((PtrObjWindow)MMstart(m,p->Buffer>>1))->WHandler;
  }
  ofn.lStructSize       = sizeof (OPENFILENAME) ;
//  ofn.hwndOwner         = NULL ;
  ofn.hInstance         = NULL ;
  ofn.lpstrFilter       = szFilter ;
  ofn.lpstrCustomFilter = NULL ;
  ofn.nMaxCustFilter    = 0 ;
  ofn.nFilterIndex      = 0 ;
  ofn.lpstrFile         = filename ; 
  ofn.nMaxFile          = _MAX_PATH ;
  ofn.lpstrFileTitle    = NULL ; 
  ofn.nMaxFileTitle     = _MAX_FNAME + _MAX_EXT ;
  ofn.lpstrInitialDir   = Defaultdir ;
  ofn.lpstrTitle        = NULL ;
  ofn.nFileOffset       = 0 ;
  ofn.nFileExtension    = 0 ;
  ofn.lpstrDefExt       = NULL ;
  ofn.lCustData         = 0L ;
  ofn.lpfnHook          = NULL ;
  ofn.lpTemplateName    = NULL ;

  Mofn=(OFNArg *)malloc(sizeof (OFNArg));
  if (Mofn==NULL)
  {
    free(szFilter);
    free(filename);
    free(Defaultdir);
    MMset(m,0,NIL);
    return 0;
  }

  memcpy(&(Mofn->ofn),&ofn,sizeof (OPENFILENAME));
//  Mofn->hwnd=hscol;
  Mofn->id=DLDialog;
  Mofn->err=0;
  
  //$LB (8/11/2004)
  _DLG_SET_MAGICNUM(Mofn);
  chainedlist_add (&DialogBoxes, Mofn->id, DLGTYPE_SAVEFILE, (void*) Mofn);
  Mofn->threadH = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) ThreadSaveFileName, Mofn, 0, &(Mofn->threadID));


  if (MMpush(m,DLDialog*2)) return MERRMEM;

  DLDialog++;
  return OBJcreate(m,OBJTYPDIAL,DLDialog-1,OBJTYPWINDOW,(int)Mofn->hwnd);
}

void ThreadSaveFileName (PVOID pvoid)
{
  TCHAR saveCurrentDir[MAX_PATH];
  BOOL res;
  OFNArg * Mofn;

  Mofn=(OFNArg*)pvoid;

  if (Mofn==NULL) 
  {
    Mofn->err=-1;
    PostMessage ((HWND)SCgetExtra("hscol"),WM_SAVEFILENAME,(WPARAM)Mofn->id,(LPARAM)Mofn);
    ExitThread(0);
    return;
  }

  // Windows unwanted behavior, when selecting a directory, the program current working dir is changed to the selected one.
  GetCurrentDirectory(MAX_PATH, saveCurrentDir);
  res = GetSaveFileName (&(Mofn->ofn));
  SetCurrentDirectory(saveCurrentDir);

  if (!res)
  {
    Mofn->err=-1;
  }

  PostMessage ((HWND)SCgetExtra("hscol"),WM_SAVEFILENAME,(WPARAM)Mofn->id,(LPARAM)Mofn);

  //$LB (8/11/2004)
  chainedlist_remove (&DialogBoxes, Mofn->id);

  ExitThread(0);
}
 
int DLGGetSaveFileName (mmachine m,HWND h,unsigned msg,UINT id,LONG param,int *ret)
{ 
	OFNArg * Mofn=(OFNArg*)param;
  int k;

  if (Mofn==NULL) return 0;

  k=OBJbeginreflex(m,OBJTYPDIAL,id,RFLDIAL_END);
  if (k==0)
	{
// 		MMechostr(MSKDEBUG,"dialog %d\n",id);
		if (Mofn->err==0)
		{
			if (Mpushstrbloc(m,Mofn->ofn.lpstrFile)) return MERRMEM;
		}
		else if (MMpush(m,NIL)) return MERRMEM;
		if (k=OBJcallreflex(m,1)) return k;
	}

  if(Mofn->ofn.lpstrFile) free((void*)Mofn->ofn.lpstrFile);
  if(Mofn->ofn.lpstrFilter) free((void*)Mofn->ofn.lpstrFilter);
  if(Mofn->ofn.lpstrInitialDir) free((void*)Mofn->ofn.lpstrInitialDir);
  free((void*)Mofn);
  OBJdelTH(m,OBJTYPDIAL,id);
  return 0;
}











//
///////////////////////////////////////////////////////
//
//$LB (7/11/2004) : add _DLGOpenDir scol function
//
//



//
// _DLG_OPENDIR
//
// thread to choose a directory
//
//

DWORD WINAPI _DLG_OPENDIR (BRIArg* Mbi)
{
  TCHAR saveCurrentDir[MAX_PATH];
  LPITEMIDLIST res;

  // Windows unwanted behavior, when selecting a directory, the program current working dir is changed to the selected one.
  GetCurrentDirectory(MAX_PATH, saveCurrentDir);

  // open dialog box and wait for result
  res = SHBrowseForFolder(&(Mbi->bi));

  SetCurrentDirectory(saveCurrentDir);

  if (res == NULL)
  {
    Mbi->err = -1;
  }
  else 
  {
	  Mbi->err = 0;
	  SHGetPathFromIDList (res, &(Mbi->directory[0]));
  }

  // send message to give the result to the main process
  PostMessage ((HWND)SCgetExtra("hscol"), WM_OPENDIRECTORY, (WPARAM)Mbi->id, (LPARAM)Mbi);

  //$LB (8/11/2004)
  chainedlist_remove (&DialogBoxes, Mbi->id);

  ExitThread (0);
  return 0;
}






//
// DLGOpenDir
//
// Main scol function to choose a directory
//
// fun [Chn ObjWin S S] OpenBox 
//
//
//$BLG: Added ptitle/szTitle as 4th parameter for title localization
int DLGOpenDir (mmachine m)
{
//$BLG
int ptitle;
char *szTitle;

int ppath;
int pwin;
PtrObjVoid p;
BRIArg * Mbi;

//$BLG
LPITEMIDLIST  pidl;
LPSHELLFOLDER pDesktopFolder;
OLECHAR       olePath[MAX_PATH];
ULONG         chEaten;
ULONG         dwAttributes;
HRESULT       hr;

  //$BLG
  ptitle = MMpull(m)>>1;
  
  ppath = MMpull(m)>>1;
  pwin  = MMpull(m)>>1;

  //$BLG
  szTitle=(char*)malloc(MMsizestr(m,ptitle)+1);
  if (szTitle==NULL) 
  {
	  MMset(m,0,NIL);
    return 0;
  }
  memcpy(szTitle,MMstartstr(m,ptitle),MMsizestr(m,ptitle)+1);
  
  if (MMget(m,0)==NIL) return 0;

  // init the BROWINFO structure
  Mbi = (BRIArg*) malloc (sizeof(BRIArg));

  // store the initial path
  if ((packdir)SCgetExtra("FirstPack") == NULL) 
  {
	  Mbi->directory[0] = 0;
  }
  else
  {

	  if (ppath == NIL)
	  {
		  sprintf(&(Mbi->directory[0]), "%s", ((packdir)SCgetExtra("FirstPack"))->path);
	  }
	  else
	  {
		  sprintf(&(Mbi->directory[0]), "%s%s", ((packdir)SCgetExtra("FirstPack"))->path, MMstartstr(m, ppath));
	  }
	  DLGslashtoback(&(Mbi->directory[0]));
  }
  //MMechostr(MSKDEBUG,"OpenDirectory: %s\n", Mbi->directory);

  if (pwin==NIL) Mbi->bi.hwndOwner = NULL;
  else
  {
	  p = (PtrObjVoid) MMstart(m, pwin);
	  Mbi->bi.hwndOwner = ((PtrObjWindow) MMstart(m, p->Buffer>>1))->WHandler;
  }

  //$BLG
  //Mbi->bi.pidlRoot = NULL; // root folder
  if (SUCCEEDED(SHGetDesktopFolder(&pDesktopFolder)))
  {
    MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, &(Mbi->directory[0]), -1, olePath, MAX_PATH);
    hr = pDesktopFolder->lpVtbl->ParseDisplayName(pDesktopFolder, NULL, NULL, olePath, &chEaten, &pidl, &dwAttributes);
    if (FAILED(hr))
      pidl = NULL;
    pDesktopFolder->lpVtbl->Release(pDesktopFolder);
  }
  else
    pidl = NULL;
  Mbi->bi.pidlRoot = pidl;

  Mbi->bi.pszDisplayName = &(Mbi->directory[0]);
  
  //$BLG
  //Mbi->bi.lpszTitle = "Select a directory";
  Mbi->bi.lpszTitle = szTitle;
  
  Mbi->bi.ulFlags = BIF_EDITBOX | BIF_VALIDATE; /*| BIF_NEWDIALOGSTYLE (OleInitialize or CoInitialize) */
  Mbi->bi.lpfn = NULL;
  Mbi->bi.lParam = (long)NULL;
  Mbi->bi.iImage = (int)NULL;

  Mbi->id = DLDialog;
  Mbi->err = FALSE;

  //$LB (8/11/2004)
  _DLG_SET_MAGICNUM(Mbi);
  chainedlist_add (&DialogBoxes, Mbi->id, DLGTYPE_OPENDIR, (void*) Mbi);
  Mbi->threadH = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) _DLG_OPENDIR, Mbi, 0, &(Mbi->threadID));

  if (MMpush (m, DLDialog<<1)) return MERRMEM;
  DLDialog++;
  return OBJcreate(m, OBJTYPDIAL, DLDialog-1, OBJTYPWINDOW, (int)NULL);
}

//
// DLGGetOpenDirectory
//
// WM_OPENDIRECTORY Event Callback
//

int DLGGetOpenDirectory (mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
{ 
BRIArg * Mbi = (BRIArg*)param;
int k;

//$BLG
size_t len;
char res[MAX_PATH];

  if (Mbi==NULL) return 0;

  k = OBJbeginreflex (m, OBJTYPDIAL, id, RFLDIAL_END);

  if (k==0)
  {
		//$BLG
		len = strlen(	((packdir)SCgetExtra("FirstPack"))->path);

		if (Mbi->err == 0)
		{
			//$BLG
			//if (Mpushstrbloc (m, Mbi->directory)) return MERRMEM;
			strcpy(res, &(Mbi->directory[len]));
			DLGbacktoslash(res);
			if (Mpushstrbloc (m, res)) return MERRMEM;
		}
		else if (MMpush (m, NIL)) return MERRMEM;

		if (k = OBJcallreflex(m, 1)) return k;
  }

  free((void*)Mbi);
  OBJdelTH(m, OBJTYPDIAL, id);
  return 0;
}




////////////////////////////////////////////////////////////////////////














////////////////////////////////////////////////////////////////
/* fun [Chn ObjWin S S I] Dialog */
int DLGMessageBox (mmachine m)
{
  int i;
  int title;
  int string;
  MBOXArg *pmbox;
  MBOXArg mbox;
  int win;
  PtrObjVoid p;

  mbox.id=DLDialog;
  i=MMpull(m)>>1;
  if (i==1) mbox.flags= MB_OKCANCEL;
  else if (i==2) mbox.flags= MB_YESNO;
  else if (i==3) mbox.flags= MB_YESNOCANCEL;
  else mbox.flags= MB_OK;
  string=MMpull(m)>>1;
  title=MMpull(m)>>1;
  win=MMpull(m)>>1;

  if (MMget(m,0)==NIL) return 0;

  if (title==NIL)
  {
    MMset(m,0,NIL);
    return 0;
  }

  else
  {
    mbox.title=(char*)malloc(MMsizestr(m,title)+1);
    if (mbox.title==NULL) 
	{
		MMset(m,0,NIL);
        return 0;
    }
    memcpy(mbox.title,MMstartstr(m,title),MMsizestr(m,title));
    mbox.title[MMsizestr(m,title)]=0;
  }
  
  if (string!=NIL)
  {
    mbox.string=(char*)malloc(MMsizestr(m,string)+1);
    if (mbox.string==NULL) 
    { 
      free(mbox.title);
      MMset(m,0,NIL);
      return 0;
    }
    memcpy(mbox.string,MMstartstr(m,string),MMsizestr(m,string));
    mbox.string[MMsizestr(m,string)]=0;
  }
  else
  {
    free(mbox.title);
	MMset(m,0,NIL);
    return 0;
  }

  if (win==NIL) mbox.hwnd=NULL;
  else
  {
	  p=(PtrObjVoid)MMstart(m,win);
	  mbox.hwnd=((PtrObjWindow)MMstart(m,p->Buffer>>1))->WHandler;
  }
  mbox.err=0;
  pmbox=(MBOXArg *)malloc(sizeof (MBOXArg));
  if (pmbox==NULL)
  {
    MMset(m,0,NIL);
    return 0;
  }
  memcpy(pmbox,&mbox,sizeof(MBOXArg));

  //$LB (8/11/2004)
  _DLG_SET_MAGICNUM(pmbox);
  chainedlist_add (&DialogBoxes, pmbox->id, DLGTYPE_MESSAGEBOX, (void*) pmbox);
  pmbox->threadH = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) ThreadMessageBox, pmbox, 0, &(pmbox->threadID));


  if (MMpush(m,DLDialog*2)) return MERRMEM;

  DLDialog++;
  return OBJcreate(m,OBJTYPDIAL,DLDialog-1,OBJTYPWINDOW,(int)mbox.hwnd);
}



void ThreadMessageBox (PVOID pvoid)
{
  MBOXArg * pmbox;

  pmbox=(MBOXArg*)pvoid;

  if (pmbox==NULL)
  {
    pmbox->err=-1;
    PostMessage ((HWND)SCgetExtra("hscol"),WM_MBOX,(WPARAM)pmbox->id,(LPARAM)pmbox);
    ExitThread(0);
    return;
  }
  if (pmbox->hwnd) SetForegroundWindow(pmbox->hwnd);
  if (strlen(pmbox->string)>1023) pmbox->string[1023] = 0;
  if (strlen(pmbox->title)>255) pmbox->title[255] = 0;

  pmbox->err=MessageBox(pmbox->hwnd,pmbox->string,pmbox->title,pmbox->flags);
  if (pmbox->err==IDYES) pmbox->err = 1;
  if (pmbox->err==IDNO) pmbox->err = 0;
  if (pmbox->err==IDCANCEL) pmbox->err = (pmbox->flags == MB_YESNOCANCEL) ? 2 : 0;

  PostMessage ((HWND)SCgetExtra("hscol"),WM_MBOX,(WPARAM)pmbox->id,(LPARAM)pmbox);

  //$LB (8/11/2004)
  chainedlist_remove (&DialogBoxes, pmbox->id);

  ExitThread(0);
}
 

int DLGGetMessageBox (mmachine m,HWND h,unsigned msg,UINT id,LONG param,int *ret)
{ 
	MBOXArg * pmbox=(MBOXArg*)param;
  int k;

  if (pmbox==NULL) return 0;

  k=OBJbeginreflex(m,OBJTYPDIAL,id,RFLDIAL_END);
  if (k==0)
	{
// 		MMechostr(MSKDEBUG,"dialog %d\n",id);
		if (MMpush(m,pmbox->err<<1)) return MERRMEM;
		if (k=OBJcallreflex(m,1)) return k;
	}

  if(pmbox->title) free(pmbox->title);
  if(pmbox->string) free(pmbox->string);
  free(pmbox);
  OBJdelTH(m,OBJTYPDIAL,id);
  return 0;
}


int DLGrfldialog(mmachine m)
{
	return OBJaddreflex(m,OBJTYPDIAL,RFLDIAL_END);
}



//
//$LB (8/11/2004)
//
// fun [u0] I
//
int DLGClose(mmachine m)
{ 
	int id = MMpull(m);
	void* obj;
	int type;


	if (id == NIL)
	{
		MMechostr(MSKDEBUG, "\n_DLGClose : argument is nil!");
		return MMpush(m, NIL);
	}
	id >>= 1;

	obj = chainedlist_retreive (&DialogBoxes, id, &type);

	if (obj == NULL) 
	{
		MMechostr(MSKDEBUG, "\n_DLGClose : the dialog box has already been destroyed!");
		return MMpush(m, NIL);
	}

	switch (type)
	{
		case DLGTYPE_OPENFILE : 
		{
			OFNArg * Mofn = (OFNArg*) obj;
			
			if (TerminateThread (Mofn->threadH, 0) == 0)
			{
				LPVOID lpMsgBuf;
				
				if (!FormatMessage( 
					FORMAT_MESSAGE_ALLOCATE_BUFFER | 
					FORMAT_MESSAGE_FROM_SYSTEM | 
					FORMAT_MESSAGE_IGNORE_INSERTS,
					NULL,
					GetLastError(),
					MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
					(LPTSTR) &lpMsgBuf,
					0,
					NULL ))
				{
			   // Handle the error.
			   return 0;
				}

				// Process any inserts in lpMsgBuf.
				// ...

				// Display the string.
				MMechostr(0, "\nTerminateThread Error : ");
				MMechostr(0, (char*)lpMsgBuf);

				// Free the buffer.
				LocalFree(lpMsgBuf);
			}

			if(Mofn->ofn.lpstrFile) free((void*)Mofn->ofn.lpstrFile);
			if(Mofn->ofn.lpstrFilter) free((void*)Mofn->ofn.lpstrFilter);
			if(Mofn->ofn.lpstrInitialDir) free((void*)Mofn->ofn.lpstrInitialDir);
			free((void*)Mofn);
			OBJdelTH(m, OBJTYPDIAL, id);
			chainedlist_remove (&DialogBoxes, id);
			return MMpush(m, 0);
		}
		break;

		case DLGTYPE_SAVEFILE : 
		{
			OFNArg * Mofn = (OFNArg*) obj;
			
			TerminateThread (Mofn->threadH, 0);
			if(Mofn->ofn.lpstrFile) free((void*)Mofn->ofn.lpstrFile);
			if(Mofn->ofn.lpstrFilter) free((void*)Mofn->ofn.lpstrFilter);
			if(Mofn->ofn.lpstrInitialDir) free((void*)Mofn->ofn.lpstrInitialDir);
			free((void*)Mofn);
			OBJdelTH(m, OBJTYPDIAL, id);
			chainedlist_remove (&DialogBoxes, id);
			return MMpush(m, 0);
		}
		break;

		case DLGTYPE_OPENDIR : 
		{
			BRIArg * Mbi= (BRIArg*) obj;
				
			TerminateThread (Mbi->threadH, 0);
			free((void*)Mbi);
			OBJdelTH(m, OBJTYPDIAL, id);
			chainedlist_remove (&DialogBoxes, id);
			return MMpush(m, 0);
		}
		break;
	
		case DLGTYPE_MESSAGEBOX : 
		{
			MBOXArg * pmbox= (MBOXArg*) obj;
				
			TerminateThread (pmbox->threadH, 0);
			if (pmbox->title) free (pmbox->title);
			if (pmbox->string) free (pmbox->string);
			free (pmbox);
			OBJdelTH (m, OBJTYPDIAL, id);
			chainedlist_remove (&DialogBoxes, id);
			return MMpush(m, 0);
		}
		break;
	}

	MMechostr(MSKDEBUG, "\n_DLGClose : the dialog box type is unknown!");
    
	return MMpush(m, NIL);
}	


/**************************************************************************/

/* File fun [Chn channel P filename] */
int FILEOpen(mmachine m)
{
  int s;
  int filename;
  HANDLE f;

  filename = MMpull(m);

  if ((MMget(m, 0) == NIL) || (filename == NIL))
  {
	  MMset(m, 0, NIL);
	  return 0;
  }
  
  f = CreateFile(MMstartstr(m, filename>>1), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  MMechostr(MSKDEBUG, "\nOpening the file %s : %d\n\n", MMstartstr(m, filename>>1), f);
  if (f == INVALID_HANDLE_VALUE)
  {
	  MMset(m, 0, NIL);
	  return 0;
  }

  s = MMmalloc(m, 2, TYPEBUF); 
  if (s == NIL) 
  	return MERRMEM;
  
  *(HANDLE*)MMstart(m, s) = f;
  if (MMpush(m, s+s+1)) 
  	return MERRMEM;

  return OBJcreate(m, OBJTYPFILE, (int)f, -1, 0);
}


int FILEdelete2(mmachine m,int handsys,int objm)
{
	HANDLE f;
	
  if (objm == NIL) 
  	return 0;
  
  f = *(HANDLE*)MMstart(m, objm>>1);
  CloseHandle(f);
  *(HANDLE*)MMstart(m,objm>>1) = NULL;
  
  return 0;
}


int FILEClose(mmachine m)
{
  int p;
  HANDLE file;

  p = MMget(m, 0)>>1;
  if (p == NIL) 
  	return 0;
  
  file = *(HANDLE*)MMstart(m, p);

  MMset(m, 0, NIL);
  if (file == NULL) 
  	return 0;
  
  OBJdelTH(m, OBJTYPFILE, (int)file);
  MMset(m, 0, 0);
  return 0;
}


/* I fun [File f, I pos, I from] */
int FILESeek(mmachine m)
{
  int p;
  HANDLE file;
  int pos;
  int from;
  int res;

  from = MMpull(m)>>1;
  pos = MMpull(m)>>1;
  p = MMget(m, 0)>>1;
  if (p == NIL)
  	return 0;
  
  file = *(HANDLE*)MMstart(m, p);

  MMset(m, 0, NIL);
  if (file == NULL)
  	return 0;
  
  if (from == 0) from = FILE_BEGIN;
  else if (from == 1) from = FILE_CURRENT;
  else from = FILE_END;

  res = SetFilePointer(file, pos, NULL, from);
  MMset(m, 0, res<<1);

  return 0;
}


int FILETell(mmachine m)
{
  int p;
  HANDLE file;
  int res;

  p = MMget(m, 0)>>1;
  if (p == NIL)
  	return 0;
  
  file = *(HANDLE*)MMstart(m, p);

  MMset(m, 0, NIL);
  if (file == NULL)
  	return 0;
  
  res = SetFilePointer(file, 0, NULL, FILE_CURRENT);
  MMset(m, 0, res<<1);

  return 0;
}


int FILESize(mmachine m)
{
  int p;
  HANDLE file;
  int temp;
  int res;

  p = MMget(m, 0)>>1;
  if (p == NIL)
  	return 0;
  
  file=*(HANDLE*)MMstart(m, p);

  MMset(m, 0, NIL);
  if (file == NULL)
  	return 0;
  
  temp = SetFilePointer(file, 0, NULL, FILE_CURRENT);
  SetFilePointer(file, 0, NULL, FILE_END);
  res = SetFilePointer(file, 0, NULL, FILE_CURRENT);
  SetFilePointer(file, temp, NULL, FILE_BEGIN);
  MMset(m, 0, res<<1);

  return 0;
}


/* S fun [File f,I size] */
int FILERead(mmachine m)
{
  int p;
  HANDLE file;
  int s;
  int size;
  int res;

  size = MMpull(m)>>1;
  p = MMget(m, 0)>>1;
  if (p == NIL) 
  	return 0;
  
  file = *(HANDLE*)MMstart(m, p);

  MMset(m, 0, NIL);

  if (size < 0) 
  	return 0;
  
  if (file == NULL)
  	return 0;

  s = MMmalloc(m, ((size+5)>>2)+1, TYPEBUF);
  if (s == NIL)
  	return MERRMEM;
  	
  ReadFile(file, MMstartstr(m, s), size, &res, NULL);
  MMstore(m, s, 0, res);
  ((char*)MMstartstr(m, s))[size] = 0;
  MMset(m, 0, (s<<1)|1);

  return 0;
}


int GetFileNameFromP(mmachine m)
{
  int filename;
  int len;
  int rlen;
  char *S;
  char buf[256];

  filename = MMpull(m)>>1;

  if (filename == NIL) 
  {
    MMpush(m, NIL);
    return 0;
  }

  rlen = MMsizestr(m, filename);
  len = rlen;
  S = MMstartstr(m, filename);

  while ((len >= 0) && (S[len] != '/') && (S[len] != '\\'))
  	len--; 
  
  strcpy(buf, S+len+1);
  return Mpushstrbloc(m, buf);
}


int PtoScol(mmachine m)
{ 
  packdir p;
  int q, i, l, k;
  char *s;
  char buf[1024];
  char file[1024];

  q = MMpull(m)>>1;
  if (q == NIL)
  	return MMpush(m, NIL);
  
  s = MMstartstr(m, q);
  l = strlen(s);
  if (l >= 1023)
  	return MMpush(m, NIL);

  strcpy(file, s);

  for(i = 0; i < l; i++)
	  if (file[i] == '\\') 
	  	file[i] = '/';
	  else if ((file[i] >= 'a') && (file[i] <= 'z')) 
	  	file[i] += 'A' - 'a';

  p = ((packdir)SCgetExtra("FirstPack"));
  while(p)
  {
	  strcpy(buf, p->path);
	  k = strlen(buf);
    for(i = 0; i < k; i++) 
    	if (buf[i] == '\\')
    		buf[i] = '/';
      else if ((buf[i] >= 'a') && (buf[i] <= 'z')) 
      	buf[i] += 'A' - 'a';
	  if (!strncmp(buf, file, k))
	  {
		  strcpy(file, s);
      for (i = 0; i < l; i++) 
      	if (file[i] == '\\')
      		file[i] = '/';
		  return Mpushstrbloc(m, file+k);
	  }
      p = p->next;
	}
  return MMpush(m, NIL);
}





//$LBDEBUG
/*
int WIN32MessageBox (mmachine m)
{
int t, s;
char* title;
char* msg;
int bt = 0;
int bs = 0;

  t = MMpull(m);
  if (t == NIL)
  {
	title = (char*) malloc (4);
	bt = 1;
	sprintf (&title[0], "NIL");
  }
  else title = MMstartstr (m, t>>1);

  s = MMpull(m);

  if (s == NIL)
  {
	msg = (char*) malloc (4);
	bs = 1;
	sprintf (&msg[0], "NIL");
  }
  else msg = MMstartstr (m, s>>1);


  MessageBox (NULL, msg, title, 0);

  if (bt) free (title);
  if (bs) free (msg);

  return MMpush (m, 0);
}
*/




//$LB (7/11/2004) : add _DLGOpenDir and _DLGrflopenDir
//$LB (8/11/2004) : add _DLGClose
#define NDLGPKG 25


char* dlgname[NDLGPKG]=
{
	"OpenBox",
	"OpenBoxMulti",
	"SaveBox",
	"MessageBox",
	"_DLGOpenFile",
	"_DLGOpenFileMulti",
	"_DLGSaveFile",
	
	//$LB (7/11/2004)
	"_DLGOpenDir",
	
	"_DLGMessageBox",
	
	//$LB (8/11/2004),
	"_DLGClose",
	
	"_DLGrflopen",
	"_DLGrflopenMulti",
	"_DLGrflsave",
	
	//$LB (7/11/2004)
	"_DLGrflopenDir",
	
	"_DLGrflmessage",
	"_FILEOpen",
	"_FILEClose",
	"_FILESeek",
	"_FILETell",
	"_FILESize",
	"_FILERead",
	"_GetFileNameFromP",
	"_GetFileNameFromW",
	"_PtoScol",
	"File"
};


int (*dlgfun[NDLGPKG])(mmachine m)=
{
	NULL,
	NULL,
	NULL,
	NULL,
	DLGOpenFile,
	DLGOpenFileMulti,
	DLGSaveFile,
	
	//$LB (7/11/2004)
	DLGOpenDir,
	
	DLGMessageBox,
	
	//$LB (8/11/2004)
	DLGClose,
	
	DLGrfldialog,
	DLGrfldialog,
	DLGrfldialog,
	
	//$LB (7/11/2004)
	DLGrfldialog,
	
	DLGrfldialog,
	FILEOpen,
	FILEClose,
	FILESeek,
	FILETell,
	FILESize,
	FILERead,
	GetFileNameFromP,
	GetFileNameFromP,
	PtoScol,
	NULL
};


int dlgnarg[NDLGPKG]=
{
	TYPTYPE,
	TYPTYPE,
	TYPTYPE,
	TYPTYPE,
	5,
	5,
	5,
	
	//$LB (7/11/2004)
	4,
	
	5,
	
	//$LB (8/11/2004)
	1,
	
	3,
	3,
	3,
	
	//$LB (7/11/2004)
	3,
	
	3,
	2,
	1,
	3,
	1,
	1,
	2,
	1,
	1,
	1,
	TYPTYPE
};

 
char * dlgtype[NDLGPKG]=
{
	NULL,
	NULL,
	NULL,
	NULL,
	"fun [Chn ObjWin S S S] OpenBox",
	"fun [Chn ObjWin S S S] OpenBoxMulti",
	"fun [Chn ObjWin S S S] SaveBox",
	
	//$LB (7/11/2004) : _DLGOpenDir
	"fun [Chn ObjWin S S] OpenDirBox",
	
	"fun [Chn ObjWin S S I] MessageBox",
	
	//$LB (8/11/2004) : _DLGClose
	"fun [u0] I",
	
	"fun [OpenBox fun [OpenBox u0 P] u1 u0] OpenBox",
	"fun [OpenBoxMulti fun [OpenBoxMulti u0 [P r1]] u1 u0] OpenBoxMulti",
	"fun [SaveBox fun [SaveBox u0 W] u1 u0] SaveBox",
	
	//$LB (7/11/2004) : _DLGrflopenDir
	"fun [OpenDirBox fun [OpenDirBox u0 S] u1 u0] OpenDirBox",
	
	
	"fun [MessageBox fun [MessageBox u0 I] u1 u0] MessageBox",
	
	"fun [Chn P] File",
	"fun [File] I",
	"fun [File I I] I",
	"fun [File] I", 
	"fun [File] I",
	"fun [File I] S",
	"fun [P] S",
	"fun [W] S",
	"fun [P] S",
	NULL
};


int SCOLloadDialog(mmachine m)
{
	//$LB (8/11/2004)
	chainedlist_init (&DialogBoxes);

	OBJTYPDIAL = OBJregister(RFLDIAL_NB, 0, NULL, "OBJTYPDIAL");
	WM_OPENFILENAME=OBJgetUserEvent();
	WM_SAVEFILENAME=OBJgetUserEvent();

	//$LB (7/11/2004)
	WM_OPENDIRECTORY = OBJgetUserEvent();	

	WM_MBOX=OBJgetUserEvent();
	OBJdefEvent(WM_MBOX,DLGGetMessageBox);
	OBJdefEvent(WM_OPENFILENAME, DLGGetOpenFileName);
	OBJdefEvent(WM_SAVEFILENAME, DLGGetSaveFileName);

	//$LB (7/11/2004)
	OBJdefEvent(WM_OPENDIRECTORY, DLGGetOpenDirectory);

	OBJTYPFILE = OBJregister(RFLFILE_NB, 0, FILEdelete2, "OBJTYPFILE");

	return PKhardpak(m, "DLG.pkg", NDLGPKG, dlgname, dlgfun, dlgnarg, dlgtype);
}
