summaryrefslogtreecommitdiffstats
path: root/win32caml
diff options
context:
space:
mode:
authorXavier Leroy <xavier.leroy@inria.fr>2001-11-06 12:36:24 +0000
committerXavier Leroy <xavier.leroy@inria.fr>2001-11-06 12:36:24 +0000
commit2f391a02b894fcf9d2580a04ab9ac66ed8040862 (patch)
tree565d50a408f3cc517a0c94843181fe76013f7b70 /win32caml
parent839a289aa108482e203053488863d622985bc8b0 (diff)
GUI Win32 pour le toplevel (J.Navia)
git-svn-id: http://caml.inria.fr/svn/ocaml/trunk@3988 f963ae5c-01c2-4b8c-9fe0-0dff7051ff02
Diffstat (limited to 'win32caml')
-rw-r--r--win32caml/Makefile22
-rw-r--r--win32caml/inria.h112
-rw-r--r--win32caml/inriares.h47
-rw-r--r--win32caml/libgraph.h107
-rw-r--r--win32caml/menu.c508
-rw-r--r--win32caml/ocaml.c791
-rw-r--r--win32caml/ocaml.icobin0 -> 766 bytes
-rw-r--r--win32caml/ocaml.rc112
-rw-r--r--win32caml/startocaml.c317
9 files changed, 2016 insertions, 0 deletions
diff --git a/win32caml/Makefile b/win32caml/Makefile
new file mode 100644
index 000000000..efb548d2b
--- /dev/null
+++ b/win32caml/Makefile
@@ -0,0 +1,22 @@
+CC=cl /nologo
+CFLAGS=/MT -O /Zi
+
+OBJS=startocaml.obj ocaml.res ocaml.obj menu.obj
+
+LIBS=kernel32.lib advapi32.lib gdi32.lib user32.lib comdlg32.lib comctl32.lib
+
+ocaml.exe: $(OBJS)
+ $(CC) $(CFLAGS) -o ocaml.exe $(OBJS) $(LIBS)
+
+ocaml.res: ocaml.rc ocaml.ico
+ rc ocaml.rc
+
+$(OBJS): inria.h inriares.h
+
+clean:
+ rm -f ocaml.exe ocaml.res *.obj
+
+.SUFFIXES: .c .obj
+
+.c.obj:
+ $(CC) $(CFLAGS) -c $*.c
diff --git a/win32caml/inria.h b/win32caml/inria.h
new file mode 100644
index 000000000..8ac701e41
--- /dev/null
+++ b/win32caml/inria.h
@@ -0,0 +1,112 @@
+/***********************************************************************/
+/* */
+/* Objective Caml */
+/* */
+/* Developed by Jacob Navia. */
+/* Copyright 2001 Institut National de Recherche en Informatique et */
+/* en Automatique. All rights reserved. This file is distributed */
+/* under the terms of the GNU Library General Public License. */
+/* */
+/***********************************************************************/
+
+/* $Id$ */
+
+/*------------------------------------------------------------------------
+ Module: D:\lcc\inria\inria.h
+ Author: Jacob
+ Project:
+ State:
+ Creation Date: June 2001
+ Description: The user interface works as follows:
+ 1: At startup it will look for the path to the
+ ocaml interpreter in the registry using the
+ key HKEY_CURRENT_USER\SOFTWARE\ocaml. If not
+ found will prompt the user.
+ 2: It will start the ocaml interpreter with
+ its standard output and standard input
+ connected to two pipes in a dedicated thread.
+ 3: It will open a window containing an edit
+ field. The output from the interpreter will be
+ shown in the edit field, and the input of the
+ user in the edit field will be sent to the
+ interpreter when the user types return.
+ 4: Line editing is provided by moving to the
+ desired line with the arrows, then pressing
+ return; If we aren't in the last input line,
+ the input will be copied to the last line and
+ sent to the interpreter.
+ 5: The GUI ensures that when we exit the ocaml
+ interpreter is stopped by sending the
+ character string "#quit;;\nCtrl-Z"
+ 6: A history of all lines sent to the interpreter
+ is maintained in a simple linked list. The
+ History dialog box shows that, and allows the
+ user to choose a given input line.
+ 7: Memory limits. The edit buffer can be of an
+ arbitrary length, i.e. maybe 7-8MB or more,
+ there are no fixed limits. The History list
+ will always grow too, so memory consumption
+ could be "high" after several days of
+ uninterrupted typing at the keyboard. For that
+ cases it is recommended to stop the GUI and
+ get some sleep...
+ 9: The GUI will start a timer, looking 4 times a
+ second if the interpreter has written
+ something in the pipe. This is enough for most
+ applications.
+------------------------------------------------------------------------*/
+
+#include <windows.h>
+
+// In this structure should go eventually all global variables scattered
+// through the program.
+typedef struct _programParams {
+ HFONT hFont; // The handle of the current font
+ COLORREF TextColor; // The text color
+ char CurrentWorkingDir[MAX_PATH];// The current directory
+} PROGRAM_PARAMS;
+
+//**************** Global variables ***********************
+extern PROGRAM_PARAMS ProgramParams;
+
+extern COLORREF BackColor; // The background color
+extern HBRUSH BackgroundBrush; // A brush built with the background color
+extern char LibDir[]; // The lib directory
+extern char OcamlPath[]; // The Path to ocaml.exe
+extern HANDLE hInst; // The instance handle for this application
+extern HWND hwndSession; // The current session window handle
+extern LOGFONT CurrentFont; // The current font characteristics
+extern HWND hwndMain,hwndMDIClient; // Window handles of frame and mdi window
+
+// ***************** Function prototypes ******************
+int WriteToPipe(char *data); // Writes to the pipe
+int ReadFromPipe(char *data,int len);// Reads from the pipe
+int AskYesOrNo(char *msg); //Ditto!
+int BrowseForFile(char *fname,char *path);
+void GotoEOF(void); // Positions the cursor at the end of the text
+void ShowDbgMsg(char *msg); // Shows an error message
+void HandleCommand(HWND hwnd, WPARAM wParam,LPARAM lParam);
+int GetOcamlPath(void); // Finds where ocaml.exe is
+void ForceRepaint(void); // Ditto.
+void AddLineToControl(char *buf);
+char *GetHistoryLine(int n); // Gets the nth history line base 1.
+int StartOcaml(void);
+// **************** User defined window messages *************
+#define WM_NEWLINE (WM_USER+6000)
+#define WM_TIMERTICK (WM_USER+6001)
+#define WM_QUITOCAML (WM_USER+6002)
+// ********************** Structures ***********************
+typedef struct tagPosition {
+ int line;
+ int col;
+} POSITION;
+
+// Simple linked list for holding the history lines
+typedef struct tagHistory {
+ struct tagHistory *Next;
+ char *Text;
+} HISTORYLINE;
+
+extern void *SafeMalloc(int);
+extern HISTORYLINE *History; // The root of the history lines
+
diff --git a/win32caml/inriares.h b/win32caml/inriares.h
new file mode 100644
index 000000000..45d835211
--- /dev/null
+++ b/win32caml/inriares.h
@@ -0,0 +1,47 @@
+/* Weditres generated include file. Do NOT edit */
+#define IDD_ABOUT 100
+#define IDM_NEW 200
+#define IDM_OPEN 210
+#define IDM_SAVE 220
+#define IDM_SAVEAS 230
+#define IDM_CLOSE 240
+#define IDM_PRINT 250
+#define IDM_PRINTSU 260
+#define IDM_PRINTPRE 265
+#define IDM_PAGESETUP 267
+#define IDM_EXIT 270
+#define IDM_HISTORY 281
+#define IDM_GC 282
+#define IDD_HISTORY 300
+#define IDLIST 301
+#define IDM_EDITUNDO 310
+#define IDM_EDITCUT 320
+#define IDM_EDITCOPY 330
+#define IDM_EDITPASTE 340
+#define IDM_EDITCLEAR 350
+#define IDM_EDITDELETE 360
+#define IDM_EDITREPLACE 370
+#define IDM_EDITREDO 380
+#define IDM_WINDOWTILE 410
+#define IDM_WINDOWCASCADE 420
+#define IDM_WINDOWICONS 430
+#define IDM_WINDOWCLOSEALL 440
+#define IDM_PROPERTIES 450
+#define IDM_ABOUT 500
+#define IDM_HELP 510
+#define IDMAINMENU 600
+#define IDM_FIND 700
+#define IDAPPLICON 710
+#define IDI_CHILDICON 800
+#define IDAPPLCURSOR 810
+#define OCAML_ICON 1000
+#define IDS_FILEMENU 2000
+#define IDS_HELPMENU 2010
+#define IDS_SYSMENU 2030
+#define IDM_STATUSBAR 3000
+#define IDM_WINDOWCHILD 3010
+#define ID_TOOLBAR 5000
+#define IDACCEL 10000
+#define IDM_FONT 40002
+#define IDM_COLORTEXT 40004
+#define IDM_BACKCOLOR 40005
diff --git a/win32caml/libgraph.h b/win32caml/libgraph.h
new file mode 100644
index 000000000..1248d3037
--- /dev/null
+++ b/win32caml/libgraph.h
@@ -0,0 +1,107 @@
+/***********************************************************************/
+/* */
+/* Objective Caml */
+/* */
+/* Jacob Navia, after Xavier Leroy */
+/* */
+/* Copyright 2001 Institut National de Recherche en Informatique et */
+/* en Automatique. All rights reserved. This file is distributed */
+/* under the terms of the GNU Library General Public License. */
+/* */
+/***********************************************************************/
+
+/* $Id$ */
+
+#include <stdio.h>
+#include <windows.h>
+
+struct canvas {
+ int w, h; /* Dimensions of the drawable */
+ HWND win; /* The drawable itself */
+ HDC gc; /* The associated graphics context */
+};
+
+extern HWND grdisplay; /* The display connection */
+//extern int grscreen; /* The screen number */
+//extern Colormap grcolormap; /* The color map */
+//extern struct canvas grwindow; /* The graphics window */
+//extern struct canvas grbstore; /* The pixmap used for backing store */
+//extern int grwhite, grblack; /* Black and white pixels for X */
+//extern int grbackground; /* Background color for X
+// (used for CAML color -1) */
+extern COLORREF grbackground;
+extern BOOL grdisplay_mode; /* Display-mode flag */
+extern BOOL grremember_mode; /* Remember-mode flag */
+extern int grx, gry; /* Coordinates of the current point */
+extern int grcolor; /* Current *CAML* drawing color (can be -1) */
+extern HFONT * grfont; /* Current font */
+
+extern BOOL direct_rgb;
+extern int byte_order;
+extern int bitmap_unit;
+extern int bits_per_pixel;
+
+#define Wcvt(y) (grwindow.height - 1 - (y))
+#define Bcvt(y) (grwindow.height - 1 - (y))
+#define WtoB(y) ((y) + WindowRect.bottom - grwindow.h)
+//#define BtoW(y) ((y) + WindowRect.bottom - grbstore.h)
+
+#define DEFAULT_SCREEN_WIDTH 1024
+#define DEFAULT_SCREEN_HEIGHT 768
+#define BORDER_WIDTH 2
+#define WINDOW_NAME "Caml graphics"
+#define ICON_NAME "Caml graphics"
+#define DEFAULT_EVENT_MASK \
+ (ExposureMask | KeyPressMask | StructureNotifyMask)
+#define DEFAULT_FONT "fixed"
+#define SIZE_QUEUE 256
+
+/* To handle events asynchronously */
+#ifdef HAS_ASYNC_IO
+#define USE_ASYNC_IO
+#define EVENT_SIGNAL SIGIO
+#else
+#ifdef HAS_SETITIMER
+#define USE_INTERVAL_TIMER
+#define EVENT_SIGNAL SIGALRM
+#else
+#define USE_ALARM
+#define EVENT_SIGNAL SIGALRM
+#endif
+#endif
+
+void gr_fail(char *fmt, char *arg);
+void gr_check_open(void);
+unsigned long gr_pixel_rgb(int rgb);
+int gr_rgb_pixel(long unsigned int pixel);
+void gr_enqueue_char(unsigned char c);
+void gr_init_color_cache(void);
+
+// Windows specific definitions
+extern RECT WindowRect;
+extern int grCurrentColor;
+
+typedef struct tagWindow {
+ HDC gc;
+ HDC gcBitmap;
+ HWND hwnd;
+ HBRUSH CurrentBrush;
+ HPEN CurrentPen;
+ DWORD CurrentColor;
+ int width;
+ int height;
+ int grx;
+ int gry;
+ HBITMAP hBitmap;
+ HFONT CurrentFont;
+ int CurrentFontSize;
+ HDC tempDC; // For image operations;
+} GR_WINDOW;
+
+extern GR_WINDOW grwindow;
+HFONT CreationFont(char *name);
+extern int MouseLbuttonDown,MouseMbuttonDown,MouseRbuttonDown;
+extern HANDLE EventHandle;
+extern int InspectMessages;
+extern MSG msg;
+
diff --git a/win32caml/menu.c b/win32caml/menu.c
new file mode 100644
index 000000000..d0ffbc7e0
--- /dev/null
+++ b/win32caml/menu.c
@@ -0,0 +1,508 @@
+/***********************************************************************/
+/* */
+/* Objective Caml */
+/* */
+/* Developed by Jacob Navia. */
+/* Copyright 2001 Institut National de Recherche en Informatique et */
+/* en Automatique. All rights reserved. This file is distributed */
+/* under the terms of the GNU Library General Public License. */
+/* */
+/***********************************************************************/
+
+/* $Id$ */
+
+#include <stdio.h>
+#include <windows.h>
+#include "inria.h"
+#include "inriares.h"
+
+LOGFONT CurrentFont;
+int CurrentFontFamily = (FIXED_PITCH | FF_MODERN);
+int CurrentFontStyle;
+char CurrentFontName[64] = "Courier";
+/*------------------------------------------------------------------------
+ Procedure: OpenMlFile ID:1
+ Purpose: Opens a file, either a source file (*.ml) or an *.cmo
+ file.
+ Input: A buffer where the name will be stored, and its
+ length
+ Output: The user's choice will be stored in the buffer.
+ Errors: None
+------------------------------------------------------------------------*/
+int OpenMlFile(char *fname,int lenbuf)
+{
+ OPENFILENAME ofn;
+ int r;
+ char *p,defext[5],tmp[512];
+
+ memset(&ofn,0,sizeof(OPENFILENAME));
+ memset(tmp,0,sizeof(tmp));
+ fname[0] = 0;
+ strcpy(tmp,"ocaml sources|*.ml|bytecode object files|*.cmo|All files|*.*");
+ p = tmp;
+ while (*p) {
+ if (*p == '|')
+ *p = 0;
+ p++;
+ }
+ strcpy(defext,"ml");
+ ofn.lStructSize = sizeof(OPENFILENAME);
+ ofn.hwndOwner = hwndMain;
+ ofn.lpstrFilter = tmp;
+ ofn.nFilterIndex = 1;
+ ofn.hInstance = hInst;
+ ofn.lpstrFile = fname;
+ ofn.lpstrTitle = "Open file";
+ ofn.lpstrInitialDir = LibDir;
+ ofn.nMaxFile = lenbuf;
+ ofn.Flags = OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR | OFN_LONGNAMES |
+ OFN_HIDEREADONLY |OFN_EXPLORER;
+ r = GetOpenFileName(&ofn);
+ if (r == 0)
+ return 0;
+ else return 1;
+}
+/*------------------------------------------------------------------------
+ Procedure: GetSaveName ID:1
+ Purpose: Get a name to save the current session (Save as menu
+ item)
+ Input: A buffer where the name of the file will be stored,
+ and its length
+ Output: The name of the file choosen by the user will be
+ stored in the buffer
+ Errors: none
+------------------------------------------------------------------------*/
+int GetSaveName(char *fname,int lenbuf)
+{
+ OPENFILENAME ofn;
+ int r;
+ char *p,defext[5],tmp[512];
+
+ memset(&ofn,0,sizeof(OPENFILENAME));
+ memset(tmp,0,sizeof(tmp));
+ fname[0] = 0;
+ strcpy(tmp,"Text files|*.txt");
+ p = tmp;
+ while (*p) {
+ if (*p == '|')
+ *p = 0;
+ p++;
+ }
+ strcpy(defext,"txt");
+ ofn.lStructSize = sizeof(OPENFILENAME);
+ ofn.hwndOwner = hwndMain;
+ ofn.lpstrFilter = tmp;
+ ofn.nFilterIndex = 1;
+ ofn.hInstance = hInst;
+ ofn.lpstrFile = fname;
+ ofn.lpstrTitle = "Save as";
+ ofn.lpstrInitialDir = LibDir;
+ ofn.nMaxFile = lenbuf;
+ ofn.Flags = OFN_NOCHANGEDIR | OFN_LONGNAMES |
+ OFN_HIDEREADONLY |OFN_EXPLORER;
+ r = GetSaveFileName(&ofn);
+ if (r == 0)
+ return 0;
+ else return 1;
+}
+/*------------------------------------------------------------------------
+ Procedure: BrowseForFile ID:1
+ Purpose: Let's the user browse for a certain kind of file.
+ Currently this is only used when browsing for
+ ocaml.exe.
+ Input: The name of the file to browse for, and the path
+ where the user's choice will be stored.
+ Output: 1 if user choosed a path, zero otherwise
+ Errors: None
+------------------------------------------------------------------------*/
+int BrowseForFile(char *fname,char *path)
+{
+ OPENFILENAME ofn;
+ char *p,tmp[512],browsefor[512];
+ int r;
+
+ memset(tmp,0,sizeof(tmp));
+ strncpy(tmp,fname,sizeof(tmp)-1);
+ p = tmp;
+ while (*p) {
+ if (*p == '|')
+ *p = 0;
+ p++;
+ }
+ memset(&ofn,0,sizeof(OPENFILENAME));
+ ofn.lpstrFilter = tmp;
+ ofn.nFilterIndex = 1;
+ ofn.lStructSize = sizeof(OPENFILENAME);
+ ofn.hwndOwner = hwndMain;
+ ofn.hInstance = hInst;
+ ofn.lpstrFilter = tmp;
+ ofn.lpstrFile = path;
+ wsprintf(browsefor,"Open %s",fname);
+ ofn.lpstrTitle = browsefor;
+ ofn.lpstrInitialDir = "c:\\";
+ ofn.nMaxFile = MAX_PATH;
+ ofn.Flags = OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR | OFN_LONGNAMES |
+ OFN_HIDEREADONLY |OFN_EXPLORER;
+ r = GetOpenFileName(&ofn);
+ if (r == 0)
+ return 0;
+ else return 1;
+}
+
+/*------------------------------------------------------------------------
+ Procedure: CallChangeFont ID:1
+ Purpose: Calls the standard windows font change dialog. If the
+ user validates a font, it will destroy the current
+ font, and recreate a new font with the given
+ parameters.
+ Input: The calling window handle
+ Output: Zero if the user cancelled, 1 otherwise.
+ Errors: None
+------------------------------------------------------------------------*/
+static int CallChangeFont(HWND hwnd)
+{
+ LOGFONT lf;
+ CHOOSEFONT cf;
+ int r;
+ HWND hwndChild;
+
+ memset(&cf, 0, sizeof(CHOOSEFONT));
+ memcpy(&lf, &CurrentFont, sizeof(LOGFONT));
+ cf.lStructSize = sizeof(CHOOSEFONT);
+ cf.hwndOwner = hwnd;
+ cf.lpLogFont = &lf;
+ cf.Flags = CF_SCREENFONTS | CF_EFFECTS | CF_APPLY | CF_INITTOLOGFONTSTRUCT;
+ cf.nFontType = SCREEN_FONTTYPE;
+ r = ChooseFont(&cf);
+ if (!r)
+ return (0);
+ DeleteObject(ProgramParams.hFont);
+ memcpy(&CurrentFont, &lf, sizeof(LOGFONT));
+ ProgramParams.hFont = CreateFontIndirect(&CurrentFont);
+ strcpy(CurrentFontName, CurrentFont.lfFaceName);
+ CurrentFontFamily = lf.lfPitchAndFamily;
+ CurrentFontStyle = lf.lfWeight;
+ hwndChild = (HWND) GetWindowLong(hwndSession, DWL_USER);
+ SendMessage(hwndChild,WM_SETFONT,(WPARAM)ProgramParams.hFont,0);
+ ForceRepaint();
+ return (1);
+}
+
+/*------------------------------------------------------------------------
+ Procedure: CallDlgProc ID:1
+ Purpose: Calls a dialog box procedure
+ Input: The function to call, and the numerical ID of the
+ resource where the dialog box is stored
+ Output: Returns the result of the dialog box.
+ Errors: None
+------------------------------------------------------------------------*/
+int CallDlgProc(BOOL (CALLBACK *fn)(HWND,UINT,WPARAM,LPARAM), int id)
+{
+ int result;
+
+ result = DialogBoxParam(hInst, MAKEINTRESOURCE(id), GetActiveWindow(),
+ fn, 0);
+ return result;
+}
+
+
+/*------------------------------------------------------------------------
+ Procedure: CallChangeColor ID:1
+ Purpose: Calls the standard color dialog of windows, starting
+ with the given color reference. The result is the
+ same as the input if the user cancels, or another
+ color if the user validates another one.
+ Input: The starting color
+ Output: The color the user has choosen.
+ Errors: None
+------------------------------------------------------------------------*/
+static COLORREF CallChangeColor(COLORREF InitialColor)
+{
+ CHOOSECOLOR CC;
+ COLORREF CustColors[16];
+ int r, g, b, i;
+ memset(&CC, 0, sizeof(CHOOSECOLOR));
+ r = g = b = 0;
+ for (i = 0; i < 16; i++) {
+ CustColors[i] = RGB(r, g, b);
+ if (r < 255)
+ r += 127;
+ else if (g < 255)
+ g += 127;
+ else if (b < 255)
+ g += 127;
+ }
+ CC.lStructSize = sizeof(CHOOSECOLOR);
+ CC.hwndOwner = hwndMain;
+ CC.hInstance = hInst;
+ CC.rgbResult = InitialColor;
+ CC.lpCustColors = CustColors;
+ CC.Flags = CC_RGBINIT;
+ if (!ChooseColor(&CC))
+ return (InitialColor);
+ return (CC.rgbResult);
+}
+
+/*------------------------------------------------------------------------
+ Procedure: CallPrintSetup ID:1
+ Purpose: Calls the printer setup dialog. Currently it is not
+ connected to the rest of the software, since printing
+ is not done yet
+ Input: None
+ Output: 1 if OK, 0, user cancelled
+ Errors: None
+------------------------------------------------------------------------*/
+static int CallPrintSetup(void)
+{
+ PAGESETUPDLG sd;
+ int r;
+
+ memset(&sd,0,sizeof(sd));
+ sd.lStructSize = sizeof(sd);
+ sd.Flags = PSD_RETURNDEFAULT;
+ r = PageSetupDlg(&sd);
+ if (!r)
+ return 0;
+ sd.Flags = 0;
+ r = PageSetupDlg(&sd);
+ return r;
+}
+
+
+/*------------------------------------------------------------------------
+ Procedure: Undo ID:1
+ Purpose: Send an UNDO command to the edit field.
+ Input: The parent window of the control
+ Output: None
+ Errors: None
+------------------------------------------------------------------------*/
+void Undo(HWND hwnd)
+{
+ HWND hEdit;
+
+ hEdit = (HWND)GetWindowLong(hwnd,DWL_USER);
+ SendMessage(hEdit,EM_UNDO,0,0);
+}
+
+/*------------------------------------------------------------------------
+ Procedure: ForceRepaint ID:1
+ Purpose: Forces a complete redraw of the edit control of the
+ current session.
+ Input: None
+ Output: None
+ Errors: None
+------------------------------------------------------------------------*/
+void ForceRepaint(void)
+{
+ HWND hwndEdit = (HWND)GetWindowLong(hwndSession,DWL_USER);
+ InvalidateRect(hwndEdit,NULL,1);
+}
+
+/*------------------------------------------------------------------------
+ Procedure: AddLineToControl ID:1
+ Purpose: It will ad the given text at the end of the edit
+ control, then it will send a return character to it.
+ This simulates user input. The history will not be
+ modified by this procedure.
+ Input: The text to be added
+ Output: None
+ Errors: If the line is empty, nothing will be done
+------------------------------------------------------------------------*/
+void AddLineToControl(char *buf)
+{
+ HWND hEditCtrl;
+
+ if (*buf == 0)
+ return;
+ hEditCtrl = (HWND)GetWindowLong(hwndSession,DWL_USER);
+ GotoEOF();
+ SendMessage(hEditCtrl,EM_REPLACESEL,0,(LPARAM)buf);
+ SendMessage(hEditCtrl,WM_CHAR,'\r',0);
+}
+
+/*------------------------------------------------------------------------
+ Procedure: AboutDlgProc ID:1
+ Purpose: Shows the "About" dialog box
+ Input:
+ Output:
+ Errors:
+------------------------------------------------------------------------*/
+static BOOL CALLBACK AboutDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ if (message == WM_CLOSE)
+ EndDialog(hDlg,1);
+ return 0;
+}
+/*------------------------------------------------------------------------
+ Procedure: HistoryDlgProc ID:1
+ Purpose: Shows the history of the session. Only input lines
+ are shown. A double click in a line will make this
+ dialog box procedure return the index of the selected
+ line (1 based). If the windows is closed (what is
+ equivalent to cancel), the return value is zero.
+ Input: Normal windows callback
+ Output:
+ Errors:
+------------------------------------------------------------------------*/
+static BOOL CALLBACK HistoryDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ HISTORYLINE *rvp;
+ int idx;
+ RECT rc;
+
+ switch (message) {
+ case WM_INITDIALOG:
+ SendDlgItemMessage(hDlg,IDLIST,WM_SETFONT,(WPARAM)ProgramParams.hFont,0);
+ rvp = History;
+ idx = 0;
+ while (rvp) {
+ SendDlgItemMessage(hDlg,IDLIST,LB_INSERTSTRING,0,(LPARAM)rvp->Text);
+ SendDlgItemMessage(hDlg,IDLIST,LB_SETITEMDATA,0,(LPARAM)idx);
+ rvp = rvp->Next;
+ idx++;
+ }
+ SendDlgItemMessage(hDlg,IDLIST,LB_SETCURSEL,(LPARAM)idx-1,0);
+ return 1;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDLIST:
+ switch(HIWORD(wParam)) {
+ case LBN_DBLCLK:
+ idx = SendDlgItemMessage(hDlg,IDLIST,LB_GETCURSEL,0,0);
+ if (idx == LB_ERR)
+ break;
+ idx = SendDlgItemMessage(hDlg,IDLIST,LB_GETITEMDATA,idx,0);
+ EndDialog(hDlg,idx+1);
+ return 1;
+ }
+ break;
+ }
+ break;
+ case WM_SIZE:
+ GetClientRect(hDlg,&rc);
+ MoveWindow(GetDlgItem(hDlg,IDLIST),0,0,rc.right,rc.bottom,1);
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hDlg,0);
+ break;
+ }
+ return 0;
+}
+/*------------------------------------------------------------------------
+ Procedure: SaveText ID:1
+ Purpose: Saves the contents of the session transcript. It will
+ loop for each line and write it to the specified file
+ Input: The name of the file where the session will be saved
+ Output: The session is saved
+ Errors: If it can't open the file for writing it will show an
+ error box
+------------------------------------------------------------------------*/
+static void SaveText(char *fname)
+{
+ int i,len;
+ HWND hEdit = (HWND)GetWindowLong(hwndSession,DWL_USER);
+ int linesCount = SendMessage(hEdit,EM_GETLINECOUNT,0,0);
+ FILE *f;
+ char *buf = SafeMalloc(8192);
+
+ f = fopen(fname,"wb");
+ if (f == NULL) {
+ wsprintf("Impossible to open %s for writing",fname);
+ ShowDbgMsg(buf);
+ return;
+ }
+ for (i=0; i<linesCount;i++) {
+ *(unsigned short *)buf = 8100;
+ len = SendMessage(hEdit,EM_GETLINE,i,(LPARAM)buf);
+ buf[len] = 0;
+ strcat(buf,"\r\n");
+ fwrite(buf,1,len+2,f);
+ }
+ fclose(f);
+ free(buf);
+}
+
+/*------------------------------------------------------------------------
+ Procedure: HandleCommand ID:1
+ Purpose: Handles all menu commands.
+ Input:
+ Output:
+ Errors:
+------------------------------------------------------------------------*/
+void HandleCommand(HWND hwnd, WPARAM wParam,LPARAM lParam)
+{
+ char *fname;
+ int r;
+
+ switch(LOWORD(wParam)) {
+ case IDM_OPEN:
+ fname = SafeMalloc(512);
+ if (OpenMlFile(fname,512)) {
+ char *buf = SafeMalloc(512);
+ char *p = strrchr(fname,'.');
+ if (p && !stricmp(p,".ml")) {
+ wsprintf(buf,"#use \"%s\";;",fname);
+ AddLineToControl(buf);
+ }
+ else if (p && !stricmp(p,".cmo")) {
+ wsprintf(buf,"#load \"%s\";;",fname);
+ AddLineToControl(buf);
+ }
+ free(buf);
+ }
+ free(fname);
+ break;
+ case IDM_GC:
+ AddLineToControl("Gc.full_major();;");
+ break;
+ case IDM_SAVE:
+ fname = SafeMalloc(512);
+ if (GetSaveName(fname,512)) {
+ SaveText(fname);
+ }
+ free(fname);
+ break;
+ case IDM_HISTORY:
+ r = CallDlgProc(HistoryDlgProc,IDD_HISTORY);
+ if (r) {
+ AddLineToControl(GetHistoryLine(r-1));
+ }
+ break;
+ case IDM_PRINTSU:
+ CallPrintSetup();
+ break;
+ case IDM_FONT:
+ CallChangeFont(hwndMain);
+ break;
+ case IDM_COLORTEXT:
+ ProgramParams.TextColor = CallChangeColor(ProgramParams.TextColor);
+ ForceRepaint();
+ break;
+ case IDM_BACKCOLOR:
+ BackColor = CallChangeColor(BackColor);
+ DeleteObject(BackgroundBrush);
+ BackgroundBrush = CreateSolidBrush(BackColor);
+ ForceRepaint();
+ break;
+ case IDM_EDITUNDO:
+ Undo(hwnd);
+ break;
+ case IDM_WINDOWTILE:
+ SendMessage(hwndMDIClient,WM_MDITILE,0,0);
+ break;
+ case IDM_WINDOWCASCADE:
+ SendMessage(hwndMDIClient,WM_MDICASCADE,0,0);
+ break;
+ case IDM_WINDOWICONS:
+ SendMessage(hwndMDIClient,WM_MDIICONARRANGE,0,0);
+ break;
+ case IDM_EXIT:
+ PostMessage(hwnd,WM_CLOSE,0,0);
+ break;
+ case IDM_ABOUT:
+ CallDlgProc(AboutDlgProc,IDD_ABOUT);
+ break;
+ }
+}
+
diff --git a/win32caml/ocaml.c b/win32caml/ocaml.c
new file mode 100644
index 000000000..cddbbcbe8
--- /dev/null
+++ b/win32caml/ocaml.c
@@ -0,0 +1,791 @@
+/***********************************************************************/
+/* */
+/* Objective Caml */
+/* */
+/* Developed by Jacob Navia. */
+/* Copyright 2001 Institut National de Recherche en Informatique et */
+/* en Automatique. All rights reserved. This file is distributed */
+/* under the terms of the GNU Library General Public License. */
+/* */
+/***********************************************************************/
+
+/* $Id$ */
+
+/*@@ Wedit generated application. Written Sat Jun 02 18:22:38 2001
+ @@header: D:\lcc\inria\inriares.h
+ @@resources: D:\lcc\inria\inria.rc
+ Do not edit outside the indicated areas */
+/*<---------------------------------------------------------------------->*/
+/*<---------------------------------------------------------------------->*/
+#include <windows.h>
+#include <windowsx.h>
+#include <commctrl.h>
+#include <string.h>
+#include <direct.h>
+#include <Richedit.h>
+#include "inriares.h"
+#include "inria.h"
+int EditControls = 10000;
+static WNDPROC lpEProc;
+static char lineBuffer[1024*32];
+int ReadToLineBuffer(void);
+int AddLineBuffer(void);
+static int busy;
+static DWORD TimerId;
+POSITION LastPromptPosition;
+char LibDir[512];
+char OcamlPath[512];
+HBRUSH BackgroundBrush;
+COLORREF BackColor = RGB(255,255,255);
+PROGRAM_PARAMS ProgramParams;
+HISTORYLINE *History;
+/*<----------------- global variables --------------------------------------->*/
+HANDLE hInst; // Instance handle
+HWND hwndMain; //Main window handle
+HWND hwndSession;
+HWND hwndMDIClient; //Mdi client window handle
+static LRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam);
+static LRESULT CALLBACK MdiChildWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam);
+PROCESS_INFORMATION pi;
+HWND hWndStatusbar;
+
+/*------------------------------------------------------------------------
+ Procedure: UpdateStatusBar ID:1
+ Purpose: Updates the statusbar control with the appropiate
+ text
+ Input: lpszStatusString: Charactar string that will be shown
+ partNumber: index of the status bar part number.
+ displayFlags: Decoration flags
+ Output: none
+ Errors: none
+
+------------------------------------------------------------------------*/
+void UpdateStatusBar(LPSTR lpszStatusString, WORD partNumber, WORD displayFlags)
+{
+ SendMessage(hWndStatusbar,
+ SB_SETTEXT,
+ partNumber | displayFlags,
+ (LPARAM)lpszStatusString);
+}
+
+
+/*------------------------------------------------------------------------
+ Procedure: MsgMenuSelect ID:1
+ Purpose: Shows in the status bar a descriptive explaation of
+ the purpose of each menu item.The message
+ WM_MENUSELECT is sent when the user starts browsing
+ the menu for each menu item where the mouse passes.
+ Input: Standard windows.
+ Output: The string from the resources string table is shown
+ Errors: If the string is not found nothing will be shown.
+------------------------------------------------------------------------*/
+LRESULT MsgMenuSelect(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
+{
+ static char szBuffer[256];
+ UINT nStringID = 0;
+ UINT fuFlags = GET_WM_MENUSELECT_FLAGS(wparam, lparam) & 0xffff;
+ UINT uCmd = GET_WM_MENUSELECT_CMD(wparam, lparam);
+ HMENU hMenu = GET_WM_MENUSELECT_HMENU(wparam, lparam);
+
+ szBuffer[0] = 0; // First reset the buffer
+ if (fuFlags == 0xffff && hMenu == NULL) // Menu has been closed
+ nStringID = 0;
+
+ else if (fuFlags & MFT_SEPARATOR) // Ignore separators
+ nStringID = 0;
+
+ else if (fuFlags & MF_POPUP) // Popup menu
+ {
+ if (fuFlags & MF_SYSMENU) // System menu
+ nStringID = IDS_SYSMENU;
+ else
+ // Get string ID for popup menu from idPopup array.
+ nStringID = 0;
+ } // for MF_POPUP
+ else // Must be a command item
+ nStringID = uCmd; // String ID == Command ID
+
+ // Load the string if we have an ID
+ if (0 != nStringID)
+ LoadString(hInst, nStringID, szBuffer, sizeof(szBuffer));
+ // Finally... send the string to the status bar
+ UpdateStatusBar(szBuffer, 0, 0);
+ return 0;
+}
+
+/*------------------------------------------------------------------------
+ Procedure: TimerProc ID:1
+ Purpose: This procedure will be called by windows about 4
+ times a second. It will just send a message to the
+ mdi child window to look at the pipe.
+ Input:
+ Output:
+ Errors:
+------------------------------------------------------------------------*/
+static VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
+{
+ SendMessage(hwndSession, WM_TIMERTICK, 0, 0);
+}
+
+/*------------------------------------------------------------------------
+ Procedure: InitializeStatusBar ID:1
+ Purpose: Initialize the status bar
+ Input: hwndParent: the parent window
+ nrOfParts: The status bar can contain more than one
+ part. What is difficult, is to figure out how this
+ should be drawn. So, for the time being only one is
+ being used...
+ Output: The status bar is created
+ Errors:
+------------------------------------------------------------------------*/
+void InitializeStatusBar(HWND hwndParent,int nrOfParts)
+{
+ const int cSpaceInBetween = 8;
+ int ptArray[40]; // Array defining the number of parts/sections
+ RECT rect;
+ HDC hDC;
+
+ /* * Fill in the ptArray... */
+
+ hDC = GetDC(hwndParent);
+ GetClientRect(hwndParent, &rect);
+
+ ptArray[nrOfParts-1] = rect.right;
+ //---TODO--- Add code to calculate the size of each part of the status
+ // bar here.
+
+ ReleaseDC(hwndParent, hDC);
+ SendMessage(hWndStatusbar,
+ SB_SETPARTS,
+ nrOfParts,
+ (LPARAM)(LPINT)ptArray);
+
+ UpdateStatusBar("Ready", 0, 0);
+}
+
+
+/*------------------------------------------------------------------------
+ Procedure: CreateSBar ID:1
+ Purpose: Calls CreateStatusWindow to create the status bar
+ Input: hwndParent: the parent window
+ initial text: the initial contents of the status bar
+ Output:
+ Errors:
+------------------------------------------------------------------------*/
+static BOOL CreateSBar(HWND hwndParent,char *initialText,int nrOfParts)
+{
+ hWndStatusbar = CreateStatusWindow(WS_CHILD | WS_VISIBLE | WS_BORDER|SBARS_SIZEGRIP,
+ initialText,
+ hwndParent,
+ IDM_STATUSBAR);
+ if(hWndStatusbar)
+ {
+ InitializeStatusBar(hwndParent,nrOfParts);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+/*------------------------------------------------------------------------
+ Procedure: InitApplication ID:1
+ Purpose: Registers two window classes: the "inria" window
+ class with the main window, and the mdi child
+ window's window class.
+ Input:
+ Output:
+ Errors:
+------------------------------------------------------------------------*/
+static BOOL InitApplication(void)
+{
+ WNDCLASS wc;
+
+ memset(&wc,0,sizeof(WNDCLASS));
+ wc.style = CS_HREDRAW|CS_VREDRAW |CS_DBLCLKS ;
+ wc.lpfnWndProc = (WNDPROC)MainWndProc;
+ wc.hInstance = hInst;
+ wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+ wc.lpszClassName = "inriaWndClass";
+ wc.lpszMenuName = MAKEINTRESOURCE(IDMAINMENU);
+ wc.hCursor = LoadCursor(NULL,IDC_ARROW);
+ wc.hIcon = LoadIcon(hInst,MAKEINTRESOURCE(OCAML_ICON));
+ if (!RegisterClass(&wc))
+ return 0;
+ wc.style = 0;
+ wc.lpfnWndProc = (WNDPROC)MdiChildWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 20;
+ wc.hInstance = hInst; // Owner of this class
+ wc.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(OCAML_ICON));
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); // Default color
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = "MdiChildWndClass";
+ if (!RegisterClass((LPWNDCLASS)&wc))
+ return FALSE;
+ return 1;
+}
+
+/*------------------------------------------------------------------------
+ Procedure: CreateinriaWndClassWnd ID:1
+ Purpose: Creates the main window
+ Input:
+ Output:
+ Errors:
+------------------------------------------------------------------------*/
+HWND CreateinriaWndClassWnd(void)
+{
+ return CreateWindow("inriaWndClass","Ocaml",
+ WS_MINIMIZEBOX|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_MAXIMIZEBOX|WS_CAPTION|WS_BORDER|WS_SYSMENU|WS_THICKFRAME,
+ CW_USEDEFAULT,0,CW_USEDEFAULT,0,
+ NULL,
+ NULL,
+ hInst,
+ NULL);
+}
+
+/*------------------------------------------------------------------------
+ Procedure: MDICmdFileNew ID:1
+ Purpose: Creates a new session window. Note that multiple
+ windows with multiple sessions are possible.
+ Input:
+ Output:
+ Errors:
+------------------------------------------------------------------------*/
+static HWND MDICmdFileNew(char *title, int show)
+{
+ HWND hwndChild;
+ char rgch[150];
+ static int cUntitled;
+ MDICREATESTRUCT mcs;
+
+ if (title == NULL)
+ wsprintf(rgch,"Session%d", cUntitled++);
+ else {
+ strncpy(rgch,title,149);
+ rgch[149] = 0;
+ }
+
+ // Create the MDI child window
+
+ mcs.szClass = "MdiChildWndClass"; // window class name
+ mcs.szTitle = rgch; // window title
+ mcs.hOwner = hInst; // owner
+ mcs.x = CW_USEDEFAULT; // x position
+ mcs.y = CW_USEDEFAULT; // y position
+ mcs.cx = CW_USEDEFAULT; // width
+ mcs.cy = CW_USEDEFAULT; // height
+ mcs.style = 0; // window style
+ mcs.lParam = 0; // lparam
+
+ hwndChild = (HWND) SendMessage(hwndMDIClient,
+ WM_MDICREATE,
+ 0,
+ (LPARAM)(LPMDICREATESTRUCT) &mcs);
+
+ if (hwndChild != NULL && show)
+ ShowWindow(hwndChild, SW_SHOW);
+
+ return hwndChild;
+}
+static HWND CreateMdiClient(HWND hwndparent)
+{
+ CLIENTCREATESTRUCT ccs = {0};
+ HWND hwndMDIClient;
+ int icount = GetMenuItemCount(GetMenu(hwndparent));
+
+ // Find window menu where children will be listed
+ ccs.hWindowMenu = GetSubMenu(GetMenu(hwndparent), icount-2);
+ ccs.idFirstChild = IDM_WINDOWCHILD;
+
+ // Create the MDI client filling the client area
+ hwndMDIClient = CreateWindow("mdiclient",
+ NULL,
+ WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL |
+ WS_HSCROLL,
+ 0, 0, 0, 0,
+ hwndparent,
+ (HMENU)0xCAC,
+ hInst,
+ (LPVOID)&ccs);
+
+ ShowWindow(hwndMDIClient, SW_SHOW);
+
+ return hwndMDIClient;
+}
+
+void GotoEOF(void)
+{
+ HWND hEdit = (HWND)GetWindowLong(hwndSession,DWL_USER);
+ int linesCount = SendMessage(hEdit,EM_GETLINECOUNT,0,0);
+ int lineindex = SendMessage(hEdit,EM_LINEINDEX,linesCount-1,0);
+ int lastLineLength = SendMessage(hEdit,EM_LINELENGTH,linesCount-1,0);
+
+ lineindex += lastLineLength;
+ SendMessage(hEdit,EM_SETSEL,lineindex,lineindex);
+}
+
+int GetCurLineIndex(HWND hEdit)
+{
+ return SendMessage(hEdit,EM_LINEFROMCHAR,(WPARAM)-1,0);
+}
+
+int GetNumberOfLines(HWND hEdit)
+{
+ return SendMessage(hEdit,EM_GETLINECOUNT,0,0);
+}
+
+static int GetWordUnderCursor(HWND hwndEditControl,char *buf,int len)
+{
+ char *line,*p,*pstart,*pend;
+ int lineidx,start,end,length,offset,cursorpos,startingChar;
+
+ SendMessage(hwndEditControl,EM_GETSEL,(WPARAM)&start,(LPARAM)&end);
+ lineidx = SendMessage(hwndEditControl,EM_EXLINEFROMCHAR,0,start);
+ startingChar = SendMessage(hwndEditControl,EM_LINEINDEX,lineidx,0);
+ start -= startingChar;
+ end -= startingChar;
+ lineidx = SendMessage(hwndEditControl,EM_LINEFROMCHAR,start,0);
+ length = SendMessage(hwndEditControl,EM_LINELENGTH,lineidx,0);
+ offset = SendMessage(hwndEditControl,EM_LINEINDEX,lineidx,0);
+ line = SafeMalloc(length+1);
+ memset(line,0,length+1);
+ *(unsigned short *)line = length;
+ SendMessage(hwndEditControl,EM_GETLINE,lineidx,(LPARAM)line);
+ cursorpos = start-offset;
+ p = line + cursorpos;
+ pstart = p;
+ while (*pstart
+ && *pstart != ' '
+ && *pstart != '\t'
+ && *pstart != '('
+ && pstart > line)
+ pstart--;
+ pend = p;
+ while (*pend
+ && *pend != ' '
+ && *pend != '\t'
+ && *pend != '('
+ && pend < line + length)
+ pend++;
+ if (*pstart == ' ' || *pstart == '\t')
+ pstart++;
+ if (*pend == ' ' || *pend == '\t')
+ pend--;
+ memcpy(buf,pstart,1+pend-pstart);
+ buf[pend-pstart] = 0;
+ free(line);
+ return 1;
+}
+
+void DoHelp(HWND hwnd)
+{
+ char word[256];
+ GetWordUnderCursor(hwnd,word,sizeof(word));
+ MessageBox(NULL,word,"Aide pour:",MB_OK);
+}
+
+
+static LRESULT CALLBACK SubClassEdit(HWND hwnd, UINT msg, WPARAM mp1, LPARAM mp2)
+{
+ LRESULT r;
+ int postit=0,nl;
+ if (msg == WM_CHAR && mp1 == '\r') {
+ if (!busy) {
+ CallWindowProc(lpEProc,hwnd,WM_KEYDOWN,VK_END,1);
+ CallWindowProc(lpEProc,hwnd,WM_KEYUP,VK_END,1);
+ r = GetCurLineIndex(hwnd);
+ nl = GetNumberOfLines(hwnd);
+ if (r != nl-1) {
+ PostMessage(GetParent(hwnd),WM_NEWLINE,0,0);
+ return 0;
+ }
+ postit = 1;
+ }
+
+ }
+ else if (msg == WM_KEYDOWN && mp1 == VK_F1) {
+ DoHelp(hwnd);
+ }
+ r = CallWindowProc(lpEProc, hwnd, msg, mp1, mp2);
+ if (postit)
+ PostMessage(GetParent(hwnd),WM_NEWLINE,0,0);
+ return r;
+}
+
+static void SubClassEditField(HWND hwnd)
+{
+ if (lpEProc == NULL) {
+ lpEProc = (WNDPROC) GetWindowLong(hwnd, GWL_WNDPROC);
+ }
+ SetWindowLong(hwnd, GWL_WNDPROC, (DWORD) SubClassEdit);
+}
+
+void AddToHistory(char *text)
+{
+ HISTORYLINE *newLine;
+
+ while (*text == ' ')
+ text++; // skip leading blanks
+ if (*text == 0)
+ return;
+ if (History && !strstr(History->Text,";;")) {
+ char *p = History->Text;
+ int len = strlen(p)+strlen(text) + 1 + 1; // space and zero terminator
+ History->Text = SafeMalloc(len);
+ strcpy(History->Text,p);
+ strcat(History->Text," ");
+ strcat(History->Text,text);
+ free(p);
+ return;
+ }
+ newLine = SafeMalloc(sizeof(HISTORYLINE));
+ newLine->Next = History;
+ newLine->Text = SafeMalloc(strlen(text)+1);
+ strcpy(newLine->Text,text);
+ History = newLine;
+}
+
+char *GetHistoryLine(int n)
+{
+ HISTORYLINE *rvp = History;
+ int i;
+
+ for (i=0; i<n; i++) {
+ rvp = rvp->Next;
+ }
+ if (rvp)
+ return &rvp->Text[0];
+ else
+ return "";
+}
+
+/*------------------------------------------------------------------------
+ Procedure: SendLastLine ID:1
+ Purpose: Sends the data in the line containing the cursor to
+ the interpreter. If this is NOT the last line, copy
+ the line to the end of the text.
+ Input: The edit control window handle
+ Output: None explicit
+ Errors: None
+------------------------------------------------------------------------*/
+void SendLastLine(HWND hEdit)
+{
+ int curline = GetCurLineIndex(hEdit);
+ char *p,linebuffer[2048];
+ int linescount = GetNumberOfLines(hEdit);
+
+ memset(linebuffer,0,sizeof(linebuffer));
+ *(unsigned short *)linebuffer = sizeof(linebuffer)-1;
+ if (curline != linescount-1)
+ SendMessage(hEdit,EM_GETLINE,curline,(LPARAM)linebuffer);
+ else
+ SendMessage(hEdit,EM_GETLINE,curline-1,(LPARAM)linebuffer);
+ if (linebuffer[0] == '#' && linebuffer[1] == ' ')
+ memmove(linebuffer,linebuffer+2,strlen(linebuffer)+1);
+ // Record user input!
+ AddToHistory(linebuffer);
+ strcat(linebuffer,"\n");
+ WriteToPipe(linebuffer);
+ if (curline != linescount-1) {
+ // Copy the line sent to the end of the text
+ p = strrchr(linebuffer,'\n');
+ if (p) {
+ *p = 0;
+ }
+ busy = 1;
+ AddLineToControl(linebuffer);
+ busy = 0;
+ }
+}
+/*------------------------------------------------------------------------
+ Procedure: SetLastPrompt ID:1
+ Purpose: Record the position of the last prompt ("# ") sent by
+ the interpreter. This isn't really used yet.
+ Input:
+ Output:
+ Errors:
+------------------------------------------------------------------------*/
+void SetLastPrompt(HWND hEdit)
+{
+ DWORD startpos,endpos;
+ SendMessage(hEdit,EM_GETSEL,(WPARAM)&startpos,(LPARAM)&endpos);
+ LastPromptPosition.line = SendMessage(hEdit,EM_LINEFROMCHAR,(WPARAM)-1,0);
+ LastPromptPosition.col = startpos;
+}
+
+/*------------------------------------------------------------------------
+ Procedure: MdiChildWndProc ID:1
+ Purpose: The edit control is enclosed in a normal MDI window.
+ This is the window procedure for that window. When it
+ receives the WM_CREATE message, it will create the
+ edit control.
+ Input:
+ Output:
+ Errors:
+------------------------------------------------------------------------*/
+static LRESULT CALLBACK MdiChildWndProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)
+{
+ HWND hwndChild;
+ RECT rc;
+ HDC hDC;
+
+ switch(msg) {
+ case WM_CREATE:
+ GetClientRect(hwnd,&rc);
+ hwndChild= CreateWindow("EDIT",
+ NULL,
+ WS_CHILD | WS_VISIBLE |
+ ES_MULTILINE |
+ WS_VSCROLL | WS_HSCROLL |
+ ES_AUTOHSCROLL | ES_AUTOVSCROLL,
+ 0,
+ 0,
+ (rc.right-rc.left),
+ (rc.bottom-rc.top),
+ hwnd,
+ (HMENU) EditControls++,
+ hInst,
+ NULL);
+ SetWindowLong(hwnd, DWL_USER, (DWORD) hwndChild);
+ SendMessage(hwndChild, WM_SETFONT, (WPARAM) ProgramParams.hFont, 0L);
+ SubClassEditField(hwndChild);
+ break;
+ // Resize the edit control
+ case WM_SIZE:
+ hwndChild = (HWND) GetWindowLong(hwnd, DWL_USER);
+ MoveWindow(hwndChild, 0, 0, LOWORD(lparam), HIWORD(lparam), TRUE);
+ break;
+ // Always set the focus to the edit control.
+ case WM_SETFOCUS:
+ hwndChild = (HWND) GetWindowLong(hwnd, DWL_USER);
+ SetFocus(hwndChild);
+ break;
+ // Repainting of the edit control about to happen.
+ // Set the text color and the background color
+ case WM_CTLCOLOREDIT:
+ hDC = (HDC)wparam;
+ SetTextColor(hDC,ProgramParams.TextColor);
+ SetBkColor(hDC,BackColor);
+ return (LRESULT)BackgroundBrush;
+ // Take care of erasing the background color to avoid flicker
+ case WM_ERASEBKGND:
+ GetWindowRect(hwnd,&rc);
+ hDC = (HDC)wparam;
+ FillRect(hDC,&rc,BackgroundBrush);
+ return 1;
+ // A carriage return has been pressed. Send the data to the interpreted.
+ // This message is posted by the subclassed edit field.
+ case WM_NEWLINE:
+ if (busy)
+ break;
+ hwndChild = (HWND) GetWindowLong(hwnd, DWL_USER);
+ SendLastLine(hwndChild);
+ break;
+ // The timer will call us 4 times a second. Look if the interpreter
+ // has written something in its end of the pipe.
+ case WM_TIMERTICK:
+ hwndChild = (HWND) GetWindowLong(hwnd, DWL_USER);
+ if (ReadToLineBuffer()) {
+ char *p;
+ // Ok we read something. Display it.
+ AddLineBuffer();
+ p = strrchr(lineBuffer,'\r');
+ if (p && !strcmp(p,"\r\n# ")) {
+ if (p[4] == 0) {
+ SetLastPrompt(hwndChild);
+ }
+ }
+
+ }
+ break;
+
+ }
+ return DefMDIChildProc(hwnd, msg, wparam, lparam);
+}
+
+
+/*------------------------------------------------------------------------
+ Procedure: MainWndProc ID:1
+ Purpose: Window procedure for the frame window, that contains
+ the menu. The messages handled are:
+ WM_CREATE: Creates the mdi child window
+ WM_SIZE: resizes the status bar and the mdi child
+ window
+ WM_COMMAND: Sends the command to the dispatcher
+ WM_CLOSE: If the user confirms, it exists the program
+ WM_QUITOCAML: Stops the program unconditionally.
+ Input: Standard windows callback
+ Output:
+ Errors:
+------------------------------------------------------------------------*/
+static LRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+ switch (msg) {
+ // Create the MDI client invisible window
+ case WM_CREATE:
+ hwndMDIClient = CreateMdiClient(hwnd);
+ TimerId = SetTimer((HWND) 0, 0, 100, (TIMERPROC) TimerProc);
+ break;
+ // Move the child windows
+ case WM_SIZE:
+ SendMessage(hWndStatusbar,msg,wParam,lParam);
+ InitializeStatusBar(hWndStatusbar,1);
+ // Position the MDI client window between the tool and status bars
+ if (wParam != SIZE_MINIMIZED) {
+ RECT rc, rcClient;
+
+ GetClientRect(hwnd, &rcClient);
+ GetWindowRect(hWndStatusbar, &rc);
+ ScreenToClient(hwnd, (LPPOINT)&rc.left);
+ rcClient.bottom = rc.top;
+ MoveWindow(hwndMDIClient,rcClient.left,rcClient.top,rcClient.right-rcClient.left, rcClient.bottom-rcClient.top, TRUE);
+ }
+
+ return 0;
+ // Dispatch the menu commands
+ case WM_COMMAND:
+ HandleCommand(hwnd, wParam,lParam);
+ return 0;
+ // If user confirms close
+ case WM_CLOSE:
+ if (!AskYesOrNo("Quit Ocaml?"))
+ return 0;
+ break;
+ // End application
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+ // The interpreter has exited. Force close of the application
+ case WM_QUITOCAML:
+ DestroyWindow(hwnd);
+ return 0;
+ case WM_USER+1000:
+ // TestGraphics();
+ break;
+ default:
+ return DefFrameProc(hwnd,hwndMDIClient,msg,wParam,lParam);
+ }
+ return DefFrameProc(hwnd,hwndMDIClient,msg,wParam,lParam);
+}
+
+/*------------------------------------------------------------------------
+ Procedure: CreationCourier ID:1
+ Purpose: Creates the courier font
+ Input:
+ Output:
+ Errors:
+------------------------------------------------------------------------*/
+static HFONT CreationCourier(int flag)
+{
+ LOGFONT CurrentFont;
+ memset(&CurrentFont, 0, sizeof(LOGFONT));
+ CurrentFont.lfCharSet = ANSI_CHARSET;
+ CurrentFont.lfWeight = FW_NORMAL;
+ if (flag)
+ CurrentFont.lfHeight = 18;
+ else
+ CurrentFont.lfHeight = 15;
+ CurrentFont.lfPitchAndFamily = (BYTE) (FIXED_PITCH | FF_MODERN);
+ strcpy(CurrentFont.lfFaceName, "Courier"); /* Courier */
+ return (CreateFontIndirect(&CurrentFont));
+}
+
+/*------------------------------------------------------------------------
+ Procedure: ReadToLineBuffer ID:1
+ Purpose: Reads into the line buffer the characters written by
+ the interpreter
+ Input: None
+ Output: The number of characters read
+ Errors: None
+------------------------------------------------------------------------*/
+int ReadToLineBuffer(void)
+{
+ memset(lineBuffer,0,sizeof(lineBuffer));
+ return ReadFromPipe(lineBuffer,sizeof(lineBuffer));
+}
+
+/*------------------------------------------------------------------------
+ Procedure: AddLineBuffer ID:1
+ Purpose: Sends the contents of the line buffer to the edit
+ control
+ Input: None
+ Output:
+ Errors:
+------------------------------------------------------------------------*/
+int AddLineBuffer(void)
+{
+ HWND hEditCtrl;
+
+ hEditCtrl = (HWND)GetWindowLong(hwndSession,DWL_USER);
+ return SendMessage(hEditCtrl,EM_REPLACESEL,0,(LPARAM)lineBuffer);
+
+}
+
+/*------------------------------------------------------------------------
+ Procedure: Setup ID:1
+ Purpose: Handles GUI initialization (Fonts, brushes, colors,
+ etc)
+ Input:
+ Output:
+ Errors:
+------------------------------------------------------------------------*/
+static int Setup(HANDLE *phAccelTable)
+{
+ if (!InitApplication())
+ return 0;
+ ProgramParams.hFont = CreationCourier(1);
+ ProgramParams.TextColor = RGB(0,0,0);
+ GetObject(ProgramParams.hFont,sizeof(LOGFONT),&CurrentFont);
+ BackgroundBrush = CreateSolidBrush(BackColor);
+ *phAccelTable = LoadAccelerators(hInst,MAKEINTRESOURCE(IDACCEL));
+ return 1;
+}
+
+
+/*------------------------------------------------------------------------
+ Procedure: WinMain ID:1
+ Purpose: Entry point for windows programs.
+ Input:
+ Output:
+ Errors:
+------------------------------------------------------------------------*/
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow)
+{
+ MSG msg;
+ HANDLE hAccelTable;
+
+ // Setup the hInst global
+ hInst = hInstance;
+ // Do the setup
+ if (!Setup(&hAccelTable))
+ return 0;
+ // Create main window and exit if this fails
+ if ((hwndMain = CreateinriaWndClassWnd()) == (HWND)0)
+ return 0;
+ // Create the status bar
+ CreateSBar(hwndMain,"Ready",2);
+ // Show the window
+ ShowWindow(hwndMain,SW_SHOW);
+ // Create the session window
+ hwndSession = MDICmdFileNew("Session transcript",0);
+ // Get the path to ocaml.exe
+ GetOcamlPath();
+ // Start the interpreter
+ StartOcaml();
+ // Show the session window
+ ShowWindow(hwndSession, SW_SHOW);
+ // Maximize it
+ SendMessage(hwndMDIClient, WM_MDIMAXIMIZE, (WPARAM) hwndSession, 0);
+
+ PostMessage(hwndMain,WM_USER+1000,0,0);
+ while (GetMessage(&msg,NULL,0,0)) {
+ if (!TranslateMDISysAccel(hwndMDIClient, &msg))
+ if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
+ TranslateMessage(&msg); // Translates virtual key codes
+ DispatchMessage(&msg); // Dispatches message to window
+ }
+ }
+ WriteToPipe("#quit;;\r\n\032");
+ KillTimer((HWND) 0, TimerId);
+ return msg.wParam;
+}
diff --git a/win32caml/ocaml.ico b/win32caml/ocaml.ico
new file mode 100644
index 000000000..13560db45
--- /dev/null
+++ b/win32caml/ocaml.ico
Binary files differ
diff --git a/win32caml/ocaml.rc b/win32caml/ocaml.rc
new file mode 100644
index 000000000..7865b1b40
--- /dev/null
+++ b/win32caml/ocaml.rc
@@ -0,0 +1,112 @@
+/***********************************************************************/
+/* */
+/* Objective Caml */
+/* */
+/* Developed by Jacob Navia. */
+/* Copyright 2001 Institut National de Recherche en Informatique et */
+/* en Automatique. All rights reserved. This file is distributed */
+/* under the terms of the GNU Library General Public License. */
+/* */
+/***********************************************************************/
+
+/* $Id$ */
+
+/* Wedit generated resource file */
+#include <windows.h>
+#include "inriares.h"
+
+1000 ICON "ocaml.ico"
+IDMAINMENU MENU
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "&Open...", IDM_OPEN
+ MENUITEM "&Save", IDM_SAVE
+ MENUITEM "Save &As...", IDM_SAVEAS
+ MENUITEM "&Close", IDM_CLOSE
+ MENUITEM SEPARATOR
+ MENUITEM "&Print", IDM_PRINT
+ MENUITEM "P&rint Setup...", IDM_PRINTSU
+ MENUITEM SEPARATOR
+ MENUITEM "E&xit", IDM_EXIT
+ END
+ POPUP "&Edit"
+ BEGIN
+ MENUITEM "&Undo Alt+BkSp", IDM_EDITUNDO
+ MENUITEM SEPARATOR
+ MENUITEM "Cu&t Shift+Del", IDM_EDITCUT
+ MENUITEM "&Copy Ctrl+Ins", IDM_EDITCOPY
+ MENUITEM "&Paste Shift+Ins", IDM_EDITPASTE
+ MENUITEM "&Delete Del", IDM_EDITCLEAR
+ END
+ POPUP "Workspace"
+ BEGIN
+ MENUITEM "Font", IDM_FONT
+ MENUITEM "Text Color", IDM_COLORTEXT
+ MENUITEM "Background color", IDM_BACKCOLOR
+ MENUITEM SEPARATOR
+ MENUITEM "&History", IDM_HISTORY
+ MENUITEM "&Garbage collect", IDM_GC
+ END
+ POPUP "&Window"
+ BEGIN
+ MENUITEM "&Tile", IDM_WINDOWTILE
+ MENUITEM "&Cascade", IDM_WINDOWCASCADE
+ MENUITEM "Arrange &Icons", IDM_WINDOWICONS
+ MENUITEM "Close &All", IDM_WINDOWCLOSEALL
+ END
+ POPUP "&Help"
+ BEGIN
+ MENUITEM "&About...", IDM_ABOUT
+ END
+END
+BARMDI ACCELERATORS
+BEGIN
+ 81, IDM_EXIT, VIRTKEY, CONTROL
+END
+
+IDD_ABOUT DIALOGEX 7, 29, 236, 81
+STYLE DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CLIENTEDGE | WS_EX_TOOLWINDOW
+CAPTION "About Ocaml"
+FONT 8, "MS Sans Serif"
+BEGIN
+ LTEXT "The Objective Caml system for windows", 101, 56, 9, 126, 12
+ LTEXT "Windows Interface 2.0", 102, 78, 21, 72, 12
+ LTEXT "Copyright 1996-2001", 103, 84, 42, 66, 10
+ CTEXT "Institut National de Recherche en Informatique et Automatique", 104, 15, 56, 211, 10
+ CTEXT "Réalisé par Jacob Navia 2001", 105, 19, 66, 207, 12
+END
+
+IDD_HISTORY DIALOGEX 6, 18, 261, 184
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+EXSTYLE WS_EX_TOOLWINDOW
+CAPTION "Session History"
+FONT 8, "MS Sans Serif"
+BEGIN
+ LISTBOX IDLIST, 7, 7, 247, 173, LBS_USETABSTOPS | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
+END
+STRINGTABLE
+BEGIN
+ 3010, "Switches to "
+ 2010, "Get help"
+ 2000, "Create, open, save, or print documents"
+ 500, "Displays information about this application"
+ 440, "Closes all open windows"
+ 430, "Arranges minimized window icons"
+ 420, "Arranges windows as overlapping tiles"
+ 410, "Arranges windows as non-overlapping tiles"
+ 350, "Removes the selection without putting it on the clipboard"
+ 340, "Inserts the clipboard contents at the insertion point"
+ 330, "Copies the selection and puts it on the clipboard"
+ 320, "Cuts the selection and puts it on the clipboard"
+ 310, "Reverses the last action"
+ 270, "Quits this application"
+ 260, "Changes the printer selection or configuration"
+ 250, "Prints the active document"
+ 240, "Closes the active document"
+ 230, "Saves the active document under a different name"
+ 220, "Saves the active document"
+ 210, "Opens an existing document"
+ 200, "Creates a new session"
+END
diff --git a/win32caml/startocaml.c b/win32caml/startocaml.c
new file mode 100644
index 000000000..7d3d12f2d
--- /dev/null
+++ b/win32caml/startocaml.c
@@ -0,0 +1,317 @@
+/***********************************************************************/
+/* */
+/* Objective Caml */
+/* */
+/* Developed by Jacob Navia. */
+/* Copyright 2001 Institut National de Recherche en Informatique et */
+/* en Automatique. All rights reserved. This file is distributed */
+/* under the terms of the GNU Library General Public License. */
+/* */
+/***********************************************************************/
+
+/* $Id$ */
+
+#include <windows.h>
+#include <stdio.h>
+#include <windows.h>
+#include <direct.h>
+#include "inria.h"
+extern int _get_osfhandle(int);
+PROCESS_INFORMATION pi;
+#define BUFSIZE 4096
+STARTUPINFO startInfo;
+
+/*------------------------------------------------------------------------
+ Procedure: ShowDbgMsg ID:1
+ Purpose: Puts up a dialog box with a message, forcing it to
+ the foreground.
+ Input:
+ Output:
+ Errors:
+------------------------------------------------------------------------*/
+void ShowDbgMsg(char *str)
+{
+ HWND hWnd;
+ char p[20], message[255];
+ hWnd = hwndMain;
+ if (IsIconic(hWnd)){
+ ShowWindow(hWnd,SW_RESTORE);
+ }
+ strncpy(message, str, 254);
+ message[254] = 0;
+ strcpy(p, "Error");
+ MessageBox(hWnd, message, p, MB_OK | MB_ICONHAND|MB_TASKMODAL|MB_SETFOREGROUND);
+}
+
+int AskYesOrNo(char *msg)
+{
+ HWND hwnd;
+ int r;
+
+ hwnd = hwndMain;
+ r = MessageBox(hwnd, msg, "Ocaml", MB_YESNO | MB_SETFOREGROUND);
+ if (r == IDYES)
+ return (TRUE);
+ return (FALSE);
+}
+
+
+static DWORD OcamlStatus;
+
+static int RegistryError(void)
+{
+ char buf[512];
+
+ wsprintf(buf,"Error %d writing to the registry",GetLastError());
+ ShowDbgMsg(buf);
+ return 0;
+}
+
+static int DoCreateKey(HANDLE hkey,char *name,HKEY *hresult)
+{
+ unsigned long disp;
+
+ return RegCreateKeyEx(hkey,name,0,NULL,0,KEY_ALL_ACCESS,NULL,hresult,&disp);
+}
+
+/*------------------------------------------------------------------------
+ Procedure: GetOcamlPath ID:1
+ Purpose: Reads the registry key
+ HKEY_CURRENT_USER\Software\Ocaml, and creates it if
+ it doesn't exists. If any error occurs, i.e. the
+ given path doesn't exist, or the key didn't exist, it
+ will put up a browse dialog box to allow the user to
+ enter the path. The path will be verified that it
+ points to a file that exists. If that file is in a
+ directory called 'bin', it will look for another
+ directory in the same level called lib' and set the
+ Lib path to that.
+ Input: None explicit
+ Output: 1 means sucess, zero failure
+ Errors: Almost all system calls will be verified
+------------------------------------------------------------------------*/
+int GetOcamlPath(void)
+{
+ HKEY hkeySoftware,hkeyOcaml;
+ DWORD dwType;
+ unsigned long siz;
+ char *p,buf[512];
+ FILE *f;
+
+ if (RegOpenKeyExA(HKEY_CURRENT_USER,"Software",0,KEY_QUERY_VALUE,&hkeySoftware) != ERROR_SUCCESS)
+ return 0;
+ if (DoCreateKey(hkeySoftware,"ocaml",&hkeyOcaml) != ERROR_SUCCESS) {
+ return RegistryError();
+ }
+ dwType = REG_SZ;
+ siz = sizeof(buf);
+ memset(buf,0,sizeof(buf));
+ RegQueryValueExA(hkeyOcaml,"InterpreterPath",0,&dwType,buf,&siz);
+ if (buf[0] == 0) {
+ if (!BrowseForFile("Ocaml interpreter|ocaml.exe",buf)) {
+ ShowDbgMsg("Impossible to find ocaml.exe. I quit");
+ RegCloseKey(hkeyOcaml);
+ RegCloseKey(hkeySoftware);
+ exit(0);
+ }
+ RegSetValueEx(hkeyOcaml,"InterpreterPath",0,REG_SZ,buf,strlen(buf)+1);
+ }
+ f = fopen(buf,"r");
+ if (f == NULL) {
+ char *errormsg = malloc(1024);
+ wsprintf(errormsg,"Incorrect path for ocaml.exe:\n%s",buf);
+ ShowDbgMsg(errormsg);
+ free(errormsg);
+ buf[0] = 0;
+ RegSetValueEx(hkeyOcaml,"InterpreterPath",0,REG_SZ,buf,1);
+ RegCloseKey(hkeyOcaml);
+ RegCloseKey(hkeySoftware);
+ return GetOcamlPath();
+ }
+ else fclose(f);
+ RegCloseKey(hkeyOcaml);
+ RegCloseKey(hkeySoftware);
+ strcpy(OcamlPath,buf);
+ p = strrchr(OcamlPath,'\\');
+ if (p) {
+ *p = 0;
+ strcpy(LibDir,OcamlPath);
+ *p = '\\';
+ p = strrchr(LibDir,'\\');
+ if (p && !stricmp(p,"\\bin")) {
+ *p = 0;
+ strcat(LibDir,"\\lib");
+ }
+ }
+ return 1;
+}
+
+static HANDLE hChildStdinRd, hChildStdinWr,hChildStdoutRd, hChildStdoutWr;
+/*------------------------------------------------------------------------
+ Procedure: IsWindowsNT ID:1
+ Purpose: Returns 1 if we are running under windows NT, zero
+ otherwise.
+ Input: None
+ Output: 1 or zero
+ Errors:
+------------------------------------------------------------------------*/
+int IsWindowsNT(void)
+{
+ OSVERSIONINFO osv;
+
+ osv.dwOSVersionInfoSize = sizeof(osv);
+ GetVersionEx(&osv);
+ return(osv.dwPlatformId == VER_PLATFORM_WIN32_NT);
+}
+
+/*------------------------------------------------------------------------
+ Procedure: DoStartOcaml ID:1
+ Purpose: Starts the ocaml interpreter ocaml.exe. The standard
+ input of the interpreter will be connected to a pipe,
+ and the standard output and standard error to another
+ pipe. The interpreter starts as a hidden process,
+ showing only in the task list. Since this is in an
+ own thread, its workings are independent of the rest
+ of the program. After starting the interpreter, the
+ thread waits in case the interpreter exits, for
+ instance if the user or some program types #quit;;.
+ In this case, the waiting thread awakens and exits
+ the user interface.
+ Input: Not used. It uses the OcamlPath global variable, that
+ is supposed to be correct, no test for its validity
+ are done here.
+ Output: None visible
+ Errors: If any system call for whatever reason fails, the
+ thread will exit. No error message is shown.
+------------------------------------------------------------------------*/
+int _stdcall DoStartOcaml(HWND hwndParent)
+{
+ char *cmdline;
+ int processStarted;
+ LPSECURITY_ATTRIBUTES lpsa=NULL;
+ SECURITY_ATTRIBUTES sa;
+ SECURITY_DESCRIPTOR sd;
+
+ sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+ // Under windows NT/2000/Whistler we have to initialize the security descriptors
+ // This is not necessary under windows 98/95.
+ if (IsWindowsNT()) {
+ InitializeSecurityDescriptor(&sd,SECURITY_DESCRIPTOR_REVISION);
+ SetSecurityDescriptorDacl(&sd,TRUE,NULL,FALSE);
+ sa.bInheritHandle = TRUE;
+ sa.lpSecurityDescriptor = &sd;
+ lpsa = &sa;
+ }
+ memset(&startInfo,0,sizeof(STARTUPINFO));
+ startInfo.cb = sizeof(STARTUPINFO);
+ // Create a pipe for the child process's STDOUT.
+ if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &sa, 0))
+ return 0;
+ // Create a pipe for the child process's STDIN.
+ if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &sa, 0))
+ return 0;
+ // Setup the start info structure
+ startInfo.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
+ startInfo.wShowWindow = SW_HIDE;
+ startInfo.hStdOutput = hChildStdoutWr;
+ startInfo.hStdError = hChildStdoutWr;
+ startInfo.hStdInput = hChildStdinRd;
+ cmdline = OcamlPath;
+ // Let's go: start the ocaml interpreter
+ processStarted = CreateProcess(NULL,cmdline,lpsa,lpsa,1,
+ CREATE_NEW_PROCESS_GROUP|NORMAL_PRIORITY_CLASS,
+ NULL,ProgramParams.CurrentWorkingDir,&startInfo,&pi);
+ if (processStarted) {
+ WaitForSingleObject(pi.hProcess,INFINITE);
+ GetExitCodeProcess(pi.hProcess,(unsigned long *)&OcamlStatus);
+ CloseHandle(pi.hProcess);
+ PostMessage(hwndMain,WM_QUITOCAML,0,0);
+ }
+ else {
+ char *msg = malloc(1024);
+ wsprintf(msg,"Impossible to start ocaml.exe in:\n%s",cmdline);
+ ShowDbgMsg(msg);
+ free(msg);
+ }
+ return 0;
+}
+
+/*------------------------------------------------------------------------
+ Procedure: WriteToPipe ID:1
+ Purpose: Writes the given character string to the standard
+ input of the interpreter
+ Input: The character string (zero terminated) to be written
+ Output: The number of characters written or zero if an error
+ occurs
+ Errors: None
+------------------------------------------------------------------------*/
+int WriteToPipe(char *data)
+{
+ DWORD dwWritten;
+ if (! WriteFile(hChildStdinWr, data, strlen(data),
+ &dwWritten, NULL))
+ return 0;
+ return dwWritten;
+
+}
+
+/*------------------------------------------------------------------------
+ Procedure: ReadFromPipe ID:1
+ Purpose: Reads from the standard output of the interpreter and
+ stores the data in the given buffer up to the given
+ length. This is done in a non-blocking manner, i.e.
+ it is safe to call this even if there is no data
+ available.
+ Input: The buffer to be used and its length.
+ Output: Returns the number of characters read from the pipe.
+ Errors: None explicit
+------------------------------------------------------------------------*/
+int ReadFromPipe(char *data,int len)
+{
+ DWORD dwRead;
+
+ PeekNamedPipe(hChildStdoutRd,data,len,NULL,&dwRead,NULL);
+ if (dwRead == 0)
+ return 0;
+
+ // Read output from the child process, and write to parent's STDOUT.
+ if( !ReadFile( hChildStdoutRd, data, len, &dwRead,
+ NULL) || dwRead == 0)
+ return 0;
+ return dwRead;
+}
+
+static DWORD tid;
+/*------------------------------------------------------------------------
+ Procedure: StartOcaml ID:1
+ Purpose: Starts the thread that will call the ocaml.exe
+ program.
+ Input:
+ Output:
+ Errors:
+------------------------------------------------------------------------*/
+int StartOcaml(void)
+{
+ getcwd(ProgramParams.CurrentWorkingDir,sizeof(ProgramParams.CurrentWorkingDir));
+ CreateThread(NULL,0,DoStartOcaml,hwndMain,0,&tid);
+ return 1;
+}
+
+
+void *SafeMalloc(int size)
+{
+ void *result;
+
+ if (size < 0) {
+ char message[1024];
+
+error:
+ sprintf(message,"Can't allocate %d bytes",size);
+ MessageBox(NULL,message,"Ocaml",MB_OK);
+ exit(-1);
+ }
+ result = malloc(size);
+ if (result == NULL)
+ goto error;
+ return result;
+}