// dde_demo sample program
// Written by Kenneth Moore 6-19-1997
// Modified 10-17-1997 to eliminate need for memcpy of passed data block
// Modified 11-13-1998 to support path names with spaces

#include <windows.h>
#include <dde.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define WM_USER_INITIATE (WM_USER + 1)
#define DDE_TIMEOUT 5000 /* this is in milliseconds, make sure it is big enough! */
#define MAX_SURFS 200
#define MAX_DDE_RAYS 100

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
void WaitForData(HWND hwnd);
char * GetString(char *szBuffer, int n, char *szSubString);
void remove_quotes(char *s);
void PostRequestMessage(char *szItem, HWND hwndServer, HWND hwnd);
void GetFont(LOGFONT *lf, HDC hdc);

char szAppName[] = "ZEMAX Client Sample";
int GotData, text, showsettings, hidden;
char szOutputFile[260];
HINSTANCE globalhInstance;

typedef struct
	{
   double x, y, z, l, m, n, opd, intensity;
	double Exr, Exi, Eyr, Eyi, Ezr, Ezi;
	int wave, error, vigcode, want_opd;
	}DDERAYDATA;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
HWND       hwnd;
MSG        msg;
WNDCLASSEX wndclass;

wndclass.cbSize        = sizeof (wndclass);
wndclass.style         = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc   = WndProc;
wndclass.cbClsExtra    = 0;
wndclass.cbWndExtra    = 0;
wndclass.hInstance     = hInstance;
wndclass.hIcon         = LoadIcon (hInstance, szAppName);
wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
wndclass.lpszMenuName  = NULL;
wndclass.lpszClassName = szAppName;
wndclass.hIconSm       = LoadIcon (hInstance, szAppName);
RegisterClassEx (&wndclass);

globalhInstance = hPrevInstance;

if (szCmdLine[0])
	{
   char szSub[260];
   /*
   There are command line arguments!
   We are going to assume that ZEMAX is calling us.
   The syntax should be:
   type settings filename

	This feature always generates text, and has no options, so the 2 flags are ignored
   */

   GetString(szCmdLine, 0, szSub);
   text = atoi(szSub);

   GetString(szCmdLine, 1, szSub);
   showsettings = atoi(szSub);

   GetString(szCmdLine, 2, szSub);
   strcpy(szOutputFile,szSub);

   remove_quotes(szOutputFile);

   if (szOutputFile[0])
   	{
      hidden = 1;
      }
   }
else
	{
   text = 0;
   showsettings = 0;
   strcpy(szOutputFile,"");
   hidden = 0;
   }

hwnd = CreateWindow (szAppName, "ZEMAX Client Sample", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
if (!hidden) ShowWindow (hwnd, iCmdShow);
UpdateWindow (hwnd);
SendMessage (hwnd, WM_USER_INITIATE, 0, 0L);
while (GetMessage (&msg, NULL, 0, 0))
	{
   TranslateMessage (&msg);
   DispatchMessage (&msg);
   }
   return msg.wParam;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
LOGFONT lf;
HFONT hfontOld;
static HFONT   hFixedFont;
static int SystemIsValid;
static HWND   hwndServer = NULL;
static long   cxChar, cyChar;
ATOM          aApp, aTop, aItem;
DDEACK        DdeAck;
DDEDATA      *pDdeData;
GLOBALHANDLE  hDdeData;
HDC           hdc;
PAINTSTRUCT   ps;
int           i, s;
long          x, y;
TEXTMETRIC    tm;
WORD          wStatus;
UINT          uiLow, uiHi;
static double hx, hy, px, py;
static double xdata, ydata, zdata;
static int surf, mode, wave, initial = 1, error, numfield, numwaves, primwave, field_type, vignc;
static int numsurfs, units;
static char szBuffer[5000], szItem[256], szTest[256], lensname[100], filename[100];
static double xfield[15], yfield[15], wavelen[15];
static struct
	{
   char comment[20];
	char rtgs[1000];
   }surfdata[MAX_SURFS+2];

DDERAYDATA *RD;

static DDERAYDATA storeRD[MAX_DDE_RAYS+1];

HGLOBAL hPokeData;
DDEPOKE * lpPokeData;
long numbytes;
int numrays;

switch (iMsg)
	{
   case WM_CREATE :
		hdc = GetDC(hwnd);
      GetFont(&lf, hdc);
      hFixedFont = CreateFontIndirect(&lf);
      hfontOld = SelectObject(hdc, hFixedFont);

      GetTextMetrics (hdc, &tm);
      cxChar = tm.tmAveCharWidth;
      cyChar = tm.tmHeight + tm.tmExternalLeading;
      SelectObject(hdc, hfontOld);
      ReleaseDC(hwnd, hdc);

   	initial = 1;

	   if (showsettings) MessageBox (hwnd, "This window has no options.", "ZEMAX Client Window", MB_ICONEXCLAMATION | MB_OK | MB_SYSTEMMODAL);

      return 0;

	case WM_TIMER:
   	if (!initial)
      	{
         goto get_data_again;
         }
      return 0;

	case WM_USER_INITIATE :
   	/* find ZEMAX */
      aApp = GlobalAddAtom ("ZEMAX");
      aTop = GlobalAddAtom ("RayData");
		SendMessage (HWND_BROADCAST, WM_DDE_INITIATE, (WPARAM) hwnd, MAKELONG (aApp, aTop));

		/* delete the atoms */
      GlobalDeleteAtom (aApp);
      GlobalDeleteAtom (aTop);

      /* If no response, issue an error message */
      if (hwndServer == NULL)
      	{
         return 0;
         }
      else
      	{
			/* Update every second */
	      if (!hidden) SetTimer(hwnd, 1001, 10000, NULL);
         }

   	get_data_again:;

		/* set a flag which indicates the system is no good; it will be cleared if we get data */
		SystemIsValid = 0;

		/* first, update the lens */
      PostRequestMessage("GetRefresh", hwndServer, hwnd);

      /* now get the lens name */
      PostRequestMessage("GetName", hwndServer, hwnd);

      /* now get the file name */
      PostRequestMessage("GetFile", hwndServer, hwnd);

      /* now get the system data */
      PostRequestMessage("GetSystem", hwndServer, hwnd);

      /* now get the field data */
      PostRequestMessage("GetField,0", hwndServer, hwnd);

      for (i = 1; i <= numfield; i++)
      	{
         sprintf(szBuffer,"GetField,%i", i);
         PostRequestMessage(szBuffer, hwndServer, hwnd);
         }

      /* now get the wavelength data */
      PostRequestMessage("GetWave,0", hwndServer, hwnd);

      for (i = 1; i <= numwaves; i++)
      	{
         sprintf(szBuffer,"GetWave,%i", i);
         PostRequestMessage(szBuffer, hwndServer, hwnd);
         }

      /* get all the surface data */
		if (SystemIsValid)
      	{
	      for (s = 0; s <= min(numsurfs, MAX_SURFS); s++)
         	{
            sprintf(szBuffer,"GetComment,%i", s);
		      PostRequestMessage(szBuffer, hwndServer, hwnd);

            /* strip off the cr-lf */
            if (strlen(szBuffer) >= 2) szBuffer[strlen(szBuffer)-2] = '\0';
            strcpy(surfdata[s].comment, szBuffer);

            sprintf(szBuffer,"GetSurface,%i", s);
		      PostRequestMessage(szBuffer, hwndServer, hwnd);

            if (atof(GetString(szBuffer, 1, szTest)) == 0.0)
            	{
					sprintf(surfdata[s].rtgs,"%12s     Infinity %12.4E %12s %12.4E", GetString(szBuffer, 0, szTest), atof(GetString(szBuffer, 2, szTest)), GetString(szBuffer, 3, szItem), atof(GetString(szBuffer, 4, szTest)));
               }
            else
            	{
					sprintf(surfdata[s].rtgs,"%12s %12.4E %12.4E %12s %12.4E", GetString(szBuffer, 0, szTest), 1.0 / atof(GetString(szBuffer, 1, szTest)), atof(GetString(szBuffer, 2, szTest)), GetString(szBuffer, 3, szItem), atof(GetString(szBuffer, 4, szTest)));
               }
            }
         }


      /* sample ray trace using GetTrace to trace 1 ray */

      /* Define a ray to trace */
      surf = -1; /* a flag for "image surface" */
      mode =  0; /* a flag for "real ray trace" */
      wave =  0; /* primary wavelength is fine */
      hx = 0.0; /* these will define the chief ray */
      hy = 1.0;
      px = 0.0;
      py = 0.0;
      sprintf(szBuffer,"GetTrace,%i,%i,%i,%.8f,%.8f,%.8f,%.8f\r\n", wave, mode, surf, hx, hy, px, py);
      PostRequestMessage(szBuffer, hwndServer, hwnd);



      /* sample ray trace using WM_DDE_POKE in mode 0 to trace an "array" of 2 rays; marginal and chief */
      numrays = 2;

		/* allocate memory we can pass to ZEMAX and use for local storage of the rays */
      numbytes = (1+numrays)*sizeof(DDERAYDATA);
      hPokeData = GlobalAlloc(GMEM_DDESHARE, (LONG) sizeof(DDEPOKE) + numbytes);
      lpPokeData = (DDEPOKE *) GlobalLock(hPokeData);
      lpPokeData->fRelease = FALSE;
      lpPokeData->cfFormat = CF_TEXT;
      RD = (DDERAYDATA *) lpPokeData->Value;

      /* define an array of rays to be traced for an example */
      RD[0].x = 0.0; /* hx */
      RD[0].y = 0.0; /* hy */
      RD[0].z = 0.0; /* px */
      RD[0].l = 0.0; /* py */
      RD[0].m = 0.0; /* ignored */
      RD[0].n = 0.0; /* ignored */
      RD[0].opd = 0.0; /* this sets the "mode" to zero; which traces unpolarized rays using hx, hy, px, and py */
      RD[0].intensity = 0.0; /* ignored if not pol trace */

      RD[0].wave = 0; /* trace rays at primary wavelength */
      RD[0].error = 0; /* clear inital error flag */
      RD[0].vigcode = 0; /* clear inital vignetting flag */
      RD[0].want_opd = -1; /* let's get the OPD data as well; the -1 is required because we need to trace the chief ray each time */

		/* copy most of the data */
      RD[1] = RD[0];
      RD[2] = RD[0];

      /* put the mode, start, stop, and number of rays in position 0 */
      RD[0].wave  = 0; /* this sets the mode, 0 means real trace; 1 means paraxial */
      RD[0].error = numrays; /* the number of rays */
      RD[0].vigcode = 0; /* the starting surface */
      RD[0].want_opd = -1; /* the ending surface; -1 is a flag for image surface */

      /* make ray 2 and 1 different; 1 is the marginal, 2 is the chief */
      RD[1].l = 1.0; /* py */
      RD[2].y = 1.0; /* hy */

      /* poke the data; then trace the rays */
      GlobalUnlock(hPokeData);
		/* note we can choose any atom name we like; as long as we look for this atom name when we receive a WM_DDE_DATA */
		aItem = GlobalAddAtom("RayArrayData");
      PostMessage(hwndServer, WM_DDE_POKE, (WPARAM) hwnd, PackDDElParam(WM_DDE_POKE, (UINT) hPokeData, aItem));
      WaitForData(hwnd);

      /* ok, we have the data. It was stored in the handling of the RayArrayData WM_DDE_DATA message! */

		/* refresh the screen */
      InvalidateRect (hwnd, NULL, TRUE);

      /* finally, we can return... we have all the data safely in hand. */
   	initial = 0;


      if (hidden)
      	{
         /* we are running from within ZEMAX.... write data to the specified file and exit */
         FILE *output;
         char szModuleName[255];

			if ((output = fopen(szOutputFile, "wt")) == NULL)
         	{
            /* can't open the file */
            goto terminate_hidden;
            }
	      if (GotData == 0)
	      	{
		      sprintf(szBuffer, "Can't talk to ZEMAX...\n");
				fputs(szBuffer,output);
	         }
	      else
	      	{
	         if (!SystemIsValid)
	         	{
			      sprintf(szBuffer, "The current lens cannot be updated\n");
					fputs(szBuffer,output);
	            }
	         else
	         	{
			      sprintf(szBuffer, "Lens Name: %s\n", lensname);
					fputs(szBuffer,output);

			      sprintf(szBuffer, "File Name: %s\n", filename);
					fputs(szBuffer,output);

			      sprintf(szBuffer, "There are %i surfaces\n", numsurfs);
					fputs(szBuffer,output);

			      if (units == 0)sprintf(szBuffer, "The units are mm\n\n");
			      if (units == 1)sprintf(szBuffer, "The units are cm\n\n");
			      if (units == 2)sprintf(szBuffer, "The units are in\n\n");
			      if (units == 3)sprintf(szBuffer, "The units are Meters\n\n");
					fputs(szBuffer,output);

			      sprintf(szBuffer, "There are %i fields of type %i\n", numfield, field_type);
					fputs(szBuffer,output);
            	for (i = 1; i <= numfield; i++)
	            	{
				      sprintf(szBuffer, "Field %i : X = %.4E, Y = %.4E\n", i, xfield[i], yfield[i]);
						fputs(szBuffer,output);
            	   }
               fputs("\n",output);

			      sprintf(szBuffer, "There are %i wavelengths, the primary wavelength is %i\n", numwaves, primwave);
               fputs(szBuffer,output);
	            for (i = 1; i <= numwaves; i++)
   	         	{
				      sprintf(szBuffer, "Wave  %i : %.5f\n", i, wavelen[i]);
	               fputs(szBuffer,output);
	               }
               fputs("\n",output);

			      sprintf(szBuffer, "The error code is %i, vignette code is %i\n", error, vignc);
               fputs(szBuffer,output);

		   	   sprintf(szBuffer, "The Chief ray x coordinate is %.6E\n", xdata);
               fputs(szBuffer,output);

			      sprintf(szBuffer, "The Chief ray y coordinate is %.6E\n", ydata);
               fputs(szBuffer,output);

			      sprintf(szBuffer, "The Chief ray z coordinate is %.6E\n", zdata);
               fputs(szBuffer,output);

	            sprintf(szBuffer, "\n Srf                Comment       Type       Radius    Thickness        Glass    Semi-diam\n");
               fputs(szBuffer,output);
   	         for (i = 0; i <= min(numsurfs, MAX_SURFS); i++)
      	      	{
				      sprintf(szBuffer, "%4i %20s %s\n", i, surfdata[i].comment, surfdata[i].rtgs);
	               fputs(szBuffer,output);
	               }

               sprintf(szBuffer, "\n                      x            y            z            l            m            n          opd error   vig\n");
               fputs(szBuffer,output);
               sprintf(szBuffer, "Marginal : %12.4E %12.4E %12.4E %12.4E %12.4E %12.4E %12.4E %5i %5i\n", storeRD[1].x, storeRD[1].y, storeRD[1].z, storeRD[1].l, storeRD[1].m, storeRD[1].n, storeRD[1].opd, storeRD[1].error, storeRD[1].vigcode);
               fputs(szBuffer,output);
               sprintf(szBuffer, "Chief    : %12.4E %12.4E %12.4E %12.4E %12.4E %12.4E %12.4E %5i %5i\n", storeRD[2].x, storeRD[2].y, storeRD[2].z, storeRD[2].l, storeRD[2].m, storeRD[2].n, storeRD[2].opd, storeRD[2].error, storeRD[1].vigcode);
               fputs(szBuffer,output);

		         }
      	   }
			fclose(output);

         terminate_hidden:;

			/* this causes ZEMAX to create or redraw the window, whatever is required. */
         /* note the message passed back: the output file, module name, and window title are required! */
			GetModuleFileName(globalhInstance, szModuleName, 255);
			sprintf(szBuffer,"MakeTextWindow,\"%s\",\"%s\",\"ZEMAX Client Sample\",0",szOutputFile,szModuleName);
	      PostRequestMessage(szBuffer, hwndServer, hwnd);

         /* terminate the DDE connection */
	   	PostMessage(hwndServer, WM_DDE_TERMINATE, (WPARAM) hwnd, 0L);
	      hwndServer = NULL;

         /* now TERMINATE! */
         DestroyWindow(hwnd);
         }


      return 0;

   case WM_DDE_DATA :
   	/* here comes the data! */
      // wParam -- sending window handle
      // lParam -- DDEDATA memory handle & item atom
      UnpackDDElParam(WM_DDE_DATA, lParam, &uiLow, &uiHi);
      FreeDDElParam(WM_DDE_DATA, lParam);
		hDdeData  = (GLOBALHANDLE) uiLow;
      pDdeData = (DDEDATA *) GlobalLock (hDdeData);
      aItem     = (ATOM) uiHi;

      // Initialize DdeAck structure
      DdeAck.bAppReturnCode = 0;
      DdeAck.reserved       = 0;
      DdeAck.fBusy          = FALSE;
      DdeAck.fAck           = FALSE;

      // Check for matching format and data item
      if (pDdeData->cfFormat == CF_TEXT)
      	{
         GlobalGetAtomName (aItem, szItem, sizeof (szItem));
			GetString(szItem, 0, szTest);
         GotData = 1;
         strncpy (szBuffer, (char *) pDdeData->Value, sizeof(szBuffer));

         if (strcmp(szTest, "RayArrayData") == 0)
         	{
            int numrays;

            memcpy(storeRD, pDdeData->Value, sizeof(DDERAYDATA));
            numrays = storeRD[0].error;

            if (numrays <= MAX_DDE_RAYS)
            	{
	            memcpy(storeRD, pDdeData->Value, (numrays+1)*sizeof(DDERAYDATA));
               }
            DdeAck.fAck = TRUE;
            }

         if (strcmp(szTest, "GetName") == 0)
         	{
            strcpy(lensname, (char *) pDdeData->Value);
            /* strip off the cr-lf */
            if (strlen(lensname) >= 2) lensname[strlen(lensname)-2] = '\0';
            DdeAck.fAck = TRUE;
            }

         if (strcmp(szTest, "GetFile") == 0)
         	{
            strcpy(filename, (char *) pDdeData->Value);
            if (strlen(filename) >= 2) filename[strlen(filename)-2] = '\0';
            DdeAck.fAck = TRUE;
            }

         if (strcmp(szTest, "GetSystem") == 0)
         	{
            numsurfs = atoi(GetString(szBuffer, 0, szTest));
            units    = atoi(GetString(szBuffer, 1, szTest));
            /* ignore the rest of the data */
            DdeAck.fAck = TRUE;
            }

         if (strcmp(szTest, "GetSurface") == 0)
         	{
            /* we will process this in the main program */
            DdeAck.fAck = TRUE;
            }
         if (strcmp(szTest, "GetComment") == 0)
         	{
            /* we will process this in the main program */
            DdeAck.fAck = TRUE;
            }

         if (strcmp(szTest, "GetTrace") == 0)
         	{
            error = atoi(GetString(szBuffer, 0, szTest));
            vignc = atoi(GetString(szBuffer, 1, szTest));
            xdata = atof(GetString(szBuffer, 2, szTest));
            ydata = atof(GetString(szBuffer, 3, szTest));
            zdata = atof(GetString(szBuffer, 4, szTest));
            DdeAck.fAck = TRUE;
            }

         if (strcmp(szTest, "GetTraceDirect") == 0)
         	{
            error = atoi(GetString(szBuffer, 0, szTest));
            vignc = atoi(GetString(szBuffer, 1, szTest));
            xdata = atof(GetString(szBuffer, 2, szTest));
            ydata = atof(GetString(szBuffer, 3, szTest));
            zdata = atof(GetString(szBuffer, 4, szTest));
            DdeAck.fAck = TRUE;
            }

         if (strcmp(szTest, "GetUpdate") == 0)
         	{
            if (atoi((char *) pDdeData->Value)) SystemIsValid = 0;
            else SystemIsValid = 1;
            DdeAck.fAck = TRUE;
            }

         if (strcmp(szTest, "GetRefresh") == 0)
         	{
            if (atoi((char *) pDdeData->Value)) SystemIsValid = 0;
            else SystemIsValid = 1;
            DdeAck.fAck = TRUE;
            }

         if (strcmp(szTest, "GetField") == 0)
         	{
            int fn;
            GetString(szItem, 1, szTest);

            fn = atoi(szTest);
            if (fn == 0)
            	{
	            field_type = atoi(GetString(szBuffer, 0, szTest));
   	         numfield   = atoi(GetString(szBuffer, 1, szTest));
               }
            else
            	{
               xfield[fn] = atof(GetString(szBuffer, 0, szTest));
               yfield[fn] = atof(GetString(szBuffer, 1, szTest));
               }
            DdeAck.fAck = TRUE;
            }

         if (strcmp(szTest, "GetWave") == 0)
         	{
            int wn;
            GetString(szItem, 1, szTest);

            wn = atoi(szTest);
            if (wn == 0)
            	{
	            primwave = atoi(GetString(szBuffer, 0, szTest));
   	         numwaves = atoi(GetString(szBuffer, 1, szTest));
               }
            else
            	{
               wavelen[wn] = atof(GetString(szBuffer, 0, szTest));
               }
            DdeAck.fAck = TRUE;
            }
         }

      // Acknowledge if necessary
      if (pDdeData->fAckReq == TRUE)
      	{
         wStatus = *((WORD *) &DdeAck);
         if (!PostMessage ((HWND) wParam, WM_DDE_ACK, (WPARAM) hwnd, PackDDElParam (WM_DDE_ACK, wStatus, aItem)))
         	{
            GlobalDeleteAtom (aItem);
            GlobalUnlock (hDdeData);
            GlobalFree (hDdeData);
            return 0;
            }
         }
      else
      	{
         GlobalDeleteAtom (aItem);
         }

      // Clean up
      if (pDdeData->fRelease == TRUE || DdeAck.fAck == FALSE)
      	{
         GlobalUnlock (hDdeData);
         GlobalFree (hDdeData);
         }
      else
      	{
         GlobalUnlock (hDdeData);
         }

      return 0;

   case WM_DDE_ACK:
   	/* we are receiving an acknowledgement */
      /* the only one we care about is in response to the WM_DDE_INITIATE */
      if (hwndServer == NULL)
      	{
         UnpackDDElParam(WM_DDE_ACK, lParam, &uiLow, &uiHi);
         FreeDDElParam(WM_DDE_ACK, lParam);
         hwndServer = (HWND) wParam;
         GlobalDeleteAtom((ATOM) uiLow);
         GlobalDeleteAtom((ATOM) uiHi);
         }
		else
			{
         UnpackDDElParam(WM_DDE_ACK, lParam, &uiLow, &uiHi);
         FreeDDElParam(WM_DDE_ACK, lParam);
         GlobalDeleteAtom((ATOM) uiLow);
         GlobalDeleteAtom((ATOM) uiHi);
			}
   	return 0;

   case WM_DDE_TERMINATE :
   	PostMessage(hwndServer, WM_DDE_TERMINATE, (WPARAM) hwnd, 0L);
      hwndServer = NULL;
      return 0;

   case WM_PAINT :
   	hdc = BeginPaint(hwnd, &ps);

      if (hidden) goto done_paint;

      hfontOld = SelectObject(hdc, hFixedFont);
      SetTextAlign(hdc, TA_LEFT | TA_TOP);

      x = cxChar;
      y = 1;

      if (GotData == 0)
      	{
	      sprintf(szBuffer, "Can't talk to ZEMAX...");
   	   TextOut(hdc, x, y, szBuffer, strlen(szBuffer));
         }
      else
      	{
         if (!SystemIsValid)
         	{
		      sprintf(szBuffer, "The current lens cannot be updated");
		      TextOut(hdc, x, y, szBuffer, strlen(szBuffer));
            }
         else
         	{
		      sprintf(szBuffer, "Lens Name: %s", lensname);
		      TextOut(hdc, x, y, szBuffer, strlen(szBuffer));
		      y += cyChar;

		      sprintf(szBuffer, "File Name: %s", filename);
		      TextOut(hdc, x, y, szBuffer, strlen(szBuffer));
		      y += cyChar;

		      sprintf(szBuffer, "There are %i surfaces", numsurfs);
		      TextOut(hdc, x, y, szBuffer, strlen(szBuffer));
		      y += cyChar;

		      if (units == 0)sprintf(szBuffer, "The units are mm");
		      if (units == 1)sprintf(szBuffer, "The units are cm");
		      if (units == 2)sprintf(szBuffer, "The units are in");
		      if (units == 3)sprintf(szBuffer, "The units are Meters");
		      TextOut(hdc, x, y, szBuffer, strlen(szBuffer));
		      y += cyChar;
		      y += cyChar;

		      sprintf(szBuffer, "There are %i fields of type %i", numfield, field_type);
		      TextOut(hdc, x, y, szBuffer, strlen(szBuffer));
		      y += cyChar;
            for (i = 1; i <= numfield; i++)
            	{
			      sprintf(szBuffer, "Field %i : X = %.4E, Y = %.4E", i, xfield[i], yfield[i]);
			      TextOut(hdc, x, y, szBuffer, strlen(szBuffer));
			      y += cyChar;
               }
            y += cyChar;

		      sprintf(szBuffer, "There are %i wavelengths, the primary wavelength is %i", numwaves, primwave);
		      TextOut(hdc, x, y, szBuffer, strlen(szBuffer));
		      y += cyChar;
            for (i = 1; i <= numwaves; i++)
            	{
			      sprintf(szBuffer, "Wave  %i : %.5f", i, wavelen[i]);
			      TextOut(hdc, x, y, szBuffer, strlen(szBuffer));
			      y += cyChar;
               }
            y += cyChar;

		      sprintf(szBuffer, "The error code is %i, vignette code is %i", error, vignc);
		      TextOut(hdc, x, y, szBuffer, strlen(szBuffer));
		      y += cyChar;

		      sprintf(szBuffer, "The Chief ray x coordinate is %.6E", xdata);
		      TextOut(hdc, x, y, szBuffer, strlen(szBuffer));
		      y += cyChar;

		      sprintf(szBuffer, "The Chief ray y coordinate is %.6E", ydata);
		      TextOut(hdc, x, y, szBuffer, strlen(szBuffer));
		      y += cyChar;

		      sprintf(szBuffer, "The Chief ray z coordinate is %.6E", zdata);
		      TextOut(hdc, x, y, szBuffer, strlen(szBuffer));
            y += cyChar;

            y += cyChar;
            sprintf(szBuffer, " Srf             Comment          Type       Radius    Thickness        Glass    Semi-diam");
            TextOut(hdc, x, y, szBuffer, strlen(szBuffer));
            y += cyChar;
            for (i = 0; i <= min(numsurfs, MAX_SURFS); i++)
            	{
			      sprintf(szBuffer, "%4i %20s %s", i, surfdata[i].comment, surfdata[i].rtgs);
			      TextOut(hdc, x, y, szBuffer, strlen(szBuffer));
			      y += cyChar;
               }

            y += cyChar;
            sprintf(szBuffer, "                      x            y            z            l            m            n          opd error   vig");
            TextOut(hdc, x, y, szBuffer, strlen(szBuffer));

            y += cyChar;
            sprintf(szBuffer, "Marginal : %12.4E %12.4E %12.4E %12.4E %12.4E %12.4E %12.4E %5i %5i", storeRD[1].x, storeRD[1].y, storeRD[1].z, storeRD[1].l, storeRD[1].m, storeRD[1].n, storeRD[1].opd, storeRD[1].error, storeRD[1].vigcode);
            TextOut(hdc, x, y, szBuffer, strlen(szBuffer));

            y += cyChar;
            sprintf(szBuffer, "Chief    : %12.4E %12.4E %12.4E %12.4E %12.4E %12.4E %12.4E %5i %5i", storeRD[2].x, storeRD[2].y, storeRD[2].z, storeRD[2].l, storeRD[2].m, storeRD[2].n, storeRD[2].opd, storeRD[2].error, storeRD[1].vigcode);
            TextOut(hdc, x, y, szBuffer, strlen(szBuffer));

	         }
         }

      /* put the old font back */
      SelectObject(hdc, hfontOld);

      done_paint:;

      EndPaint(hwnd, &ps);
      return 0;

   case WM_CLOSE :
   	PostMessage(hwndServer, WM_DDE_TERMINATE, (WPARAM) hwnd, 0L);
      if (!hidden) KillTimer(hwnd, 1001);
   	break;             // for default processing

   case WM_DESTROY :
   	DeleteObject(hFixedFont);
   	PostQuitMessage(0);
      return 0;
   }
   return DefWindowProc(hwnd, iMsg, wParam, lParam);
}

void WaitForData(HWND hwnd)
{
MSG msg;
DWORD dwTime;
dwTime = GetCurrentTime();
GotData = 0;
while ( (GetCurrentTime() - dwTime < DDE_TIMEOUT) && !GotData)
	{
   while (PeekMessage (&msg, hwnd, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE))
   	{
      DispatchMessage (&msg);
      }
   }
}

char * GetString(char *szBuffer, int n, char *szSubString)
{
int i, j, k;
char szTest[1000];

szSubString[0] = '\0';
i = 0;
j = 0;
k = 0;
while (szBuffer[i] && (k <= n) )
	{
   szTest[j] = szBuffer[i];

   if (szBuffer[i] == '"')
   	{
      i++;
  	   j++;
	   szTest[j] = szBuffer[i];
      /* we have a double quote; keep reading until EOF or another double quote */
      while(szBuffer[i] != '"' && szBuffer[i])
      	{
	      i++;
   	   j++;
		   szTest[j] = szBuffer[i];
         }
      }

   if (szTest[j] == '\n' || szTest[j] == '\r' || szTest[j] == '\0' || szTest[j] == ',' || szTest[j] == ' ')
   	{
      szTest[j] = '\0';
      if (k == n)
      	{
         strcpy(szSubString, szTest);
			return szSubString;
         }
      k++;
      j = -1;
      }
   i++;
   j++;
   }

szTest[j] = szBuffer[i];
szTest[j] = '\0';
if (k == n) strcpy(szSubString, szTest);


return szSubString;
}

void PostRequestMessage(char *szItem, HWND hwndServer, HWND hwnd)
{
ATOM aItem;

aItem = GlobalAddAtom(szItem);

if (!PostMessage(hwndServer, WM_DDE_REQUEST, (WPARAM) hwnd, PackDDElParam(WM_DDE_REQUEST, CF_TEXT, aItem)))
	{
   MessageBox (hwnd, "Cannot communicate with ZEMAX!", "Hello?", MB_ICONEXCLAMATION | MB_OK);
   GlobalDeleteAtom(aItem);
   return;
   }
WaitForData(hwnd);
}

void GetFont(LOGFONT *lf, HDC hdc)
{
int nPtSize = 11;
lf->lfHeight = - MulDiv(nPtSize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
lf->lfWidth = 0;
lf->lfEscapement = 0;
lf->lfOrientation = 0;
lf->lfWeight = 0;
lf->lfItalic = 0;
lf->lfUnderline = 0;
lf->lfStrikeOut = 0;
lf->lfCharSet = ANSI_CHARSET;
lf->lfOutPrecision = OUT_CHARACTER_PRECIS;
lf->lfClipPrecision = CLIP_CHARACTER_PRECIS;
lf->lfQuality = PROOF_QUALITY;
lf->lfPitchAndFamily = FF_MODERN | FIXED_PITCH;
strcpy(lf->lfFaceName,"Courier New");
}

void remove_quotes(char *s)
{
int i=0;
/* remove the first quote if it exists */
if (s[0] == '"')
	{
	while (s[i])
		{
		s[i] = s[i+1];
		i++;
		}
	}
/* remove the last quote if it exists */
if (s[strlen(s)-1] == '"') s[strlen(s)-1] = '\0';
}

