1 /*******************************************************************************
2  * pvengine.cpp
3  *
4  * This file implements Windows specific routines, WinMain, and message loops.
5  *
6  * Primary author: Christopher J. Cason.
7  *
8  * ---------------------------------------------------------------------------
9  * Persistence of Vision Ray Tracer ('POV-Ray') version 3.7.
10  * Copyright 1991-2013 Persistence of Vision Raytracer Pty. Ltd.
11  *
12  * POV-Ray is free software: you can redistribute it and/or modify
13  * it under the terms of the GNU Affero General Public License as
14  * published by the Free Software Foundation, either version 3 of the
15  * License, or (at your option) any later version.
16  *
17  * POV-Ray is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU Affero General Public License for more details.
21  *
22  * You should have received a copy of the GNU Affero General Public License
23  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
24  * ---------------------------------------------------------------------------
25  * POV-Ray is based on the popular DKB raytracer version 2.12.
26  * DKBTrace was originally written by David K. Buck.
27  * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
28  * ---------------------------------------------------------------------------
29  * $File: //depot/public/povray/3.x/windows/pvengine.cpp $
30  * $Revision: #1 $
31  * $Change: 6069 $
32  * $DateTime: 2013/11/06 11:59:40 $
33  * $Author: chrisc $
34  *******************************************************************************/
35 
36 /*****************************************************************************/
37 /* NOTICE                                                                    */
38 /*                                                                           */
39 /* Much of this source code (all of pvengine.exe) should be considered on    */
40 /* its last legs. The base code was originally written back in early 1995    */
41 /* (with some of the code even predating that), and targeted at Win32s under */
42 /* Windows 3.1. An additional constraint was a desire for the code to  be    */
43 /* able to be compiled on a DEC Alpha under NT for the Alpha using only a    */
44 /* 'C' compiler, and for it to be able to run with or without the editor.    */
45 /*                                                                           */
46 /* With the introduction of VFE in version 3.7, creating a new UI for POVWIN */
47 /* should be a lot less painful as almost all of the bindings with the core  */
48 /* POV-Ray renderer have been abstracted into the above class library.       */
49 /*                                                                           */
50 /*****************************************************************************/
51 
52 #define POVWIN_FILE
53 #define _WIN32_IE COMMONCTRL_VERSION
54 
55 #if !defined( __BORLANDC__ ) && !defined( __DMC__ ) && !defined( __MINGW32__ )
56   #pragma comment(lib, "htmlhelp")
57   #pragma comment(lib, "winmm")
58 #endif
59 
60 #define _CRT_RAND_S
61 #define PSAPI_VERSION 1
62 #pragma comment(lib, "psapi")
63 
64 #include <windows.h>
65 #include <htmlhelp.h>
66 #include <shellapi.h>
67 #include <shlobj.h>
68 #include <shlwapi.h>
69 #include <mmsystem.h>
70 #include <commdlg.h>
71 #include <commctrl.h>
72 #include <crtdbg.h>
73 #include <psapi.h>
74 #include <dbghelp.h>
75 
76 // #define DEVELOPMENT
77 
78 #include <stdlib.h>
79 #include <stdio.h>
80 #include <tchar.h>
81 #include "pvengine.h"
82 #include "resource.h"
83 #include "pvdialog.h"
84 #include "pvguiext.h"
85 #include "pvedit.h"
86 #include "backend/control/benchmark.h"
87 #include "pvdisplay.h"
88 #include "syspovprotofrontend.h"
89 #include "povray.h"
90 
91 #ifdef RTR_SUPPORT
92   #include "rtrsupport.h"
93 #endif
94 
95 #if defined(USE_AVX_FMA4_FOR_NOISE)
96   #include "backend/texture/avxfma4check.h"
97 #endif
98 
99 // this must be the last file included
100 #include "syspovdebug.h"
101 
102 typedef HRESULT (CALLBACK* DLLGETVERSIONPROC) (DLLVERSIONINFO *);
103 typedef DWORD __stdcall shCopyType (HKEY, LPCTSTR, HKEY, DWORD) ;
104 
105 #ifndef SM_CMONITORS
106 #define SM_XVIRTUALSCREEN       76
107 #define SM_YVIRTUALSCREEN       77
108 #define SM_CXVIRTUALSCREEN      78
109 #define SM_CYVIRTUALSCREEN      79
110 #define SM_CMONITORS            80
111 #endif
112 
113 #ifndef PROCESS_MODE_BACKGROUND_BEGIN
114 #define PROCESS_MODE_BACKGROUND_BEGIN     0x00100000
115 #define PROCESS_MODE_BACKGROUND_END       0x00200000
116 #endif
117 
118 #define CONFIRM_STOP_THRESHOLD 900
119 
120 typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
121                                          CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
122                                          CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
123                                          CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
124                                          );
125 
126 char *WriteDump(struct _EXCEPTION_POINTERS *pExceptionInfo, bool full, long timestamp);
127 
128 namespace pov_frontend
129 {
130   extern shared_ptr<Display> gDisplay;
131 }
132 
133 namespace vfePlatform
134 {
135   extern bool GetCPUCount(unsigned int *TotAvailLogical, unsigned int *TotAvailCore, unsigned int *PhysicalNum);
136 }
137 
138 using namespace pov;
139 using namespace pov_frontend;
140 
141 void GenerateDumpMeta(bool brief);
142 
143 namespace povwin
144 {
145 
146 typedef struct
147 {
148   int         id ;
149   HWND        hwnd ;
150   SIZE        size ;
151 } StatusPanelItem ;
152 
153 bool                    rendering ;
154 bool                    stop_rendering ;
155 bool                    rendersleep ;
156 bool                    render_cooperate = false ;
157 bool                    InFrontend = false ;
158 bool                    ErrorNotified ;
159 bool                    ErrorOccurred ;
160 bool                    HideRenderWithMain ;
161 bool                    UseAlpha;
162 bool                    IsExpired;
163 bool                    BackendFailedFlag = false;
164 bool                    PreventSleep = true;
165 char                    DumpMeta[65536];
166 string                  ErrorMessage ;
167 string                  ErrorFilename ;
168 unsigned                ErrorLine ;
169 unsigned                ErrorCol ;
170 unsigned                render_priority = CM_RENDERPRIORITY_NORMAL ;
171 unsigned                Duty_Cycle = 9 ;
172 unsigned                renderwin_8bits ;
173 
174 extern int              renderwin_xoffset ;
175 extern int              renderwin_yoffset ;
176 extern int              renderwin_left ;
177 extern int              renderwin_top ;
178 extern char             PovLegacyRenderWinClass [] ;
179 extern unsigned         renderwin_max_width ;
180 extern unsigned         renderwin_max_height ;
181 extern unsigned         renderwin_flags ;
182 extern bool             MakeRenderwinActive ;
183 
184 int                     render_bitmap_depth ;
185 unsigned                render_width ;
186 unsigned                render_height ;
187 
188 int                     alert_sound ;
189 int                     run_count ;
190 int                     render_anim_count ;
191 int                     argc ;
192 int                     io_restrictions ;
193 int                     tb_combo_sel ;
194 int                     povray_return_code ;
195 int                     PerformanceScale = 1 ;
196 int                     seconds_for_last_line = -1 ;
197 int                     delay_next_status ;
198 int                     screen_origin_x ;
199 int                     screen_origin_y ;
200 int                     virtual_screen_width ;
201 int                     virtual_screen_height ;
202 int                     LastRenderPercentage ;
203 int                     renderwin_transparency ;
204 int                     cb_expect_selchange ;
205 char                    command_line [_MAX_PATH * 3] ;
206 char                    old_command_line [_MAX_PATH * 3] ;
207 char                    *argv [MAX_ARGV] ;
208 char                    source_file_name [_MAX_PATH] ;
209 char                    modulePath [_MAX_PATH] ;
210 char                    engineHelpPath [_MAX_PATH] ;
211 char                    lastRenderName [_MAX_PATH] ;
212 char                    lastBitmapName [_MAX_PATH] ;
213 char                    lastRenderPath [_MAX_PATH] ;
214 char                    lastBitmapPath [_MAX_PATH] ;
215 char                    lastQueuePath [_MAX_PATH] ;
216 char                    lastSecondaryIniFilePath [_MAX_PATH] ;
217 char                    DefaultRenderIniFileName [_MAX_PATH] ;
218 char                    SecondaryRenderIniFileName [_MAX_PATH] ;
219 char                    SecondaryRenderIniFileSection [64] ;
220 char                    background_file [_MAX_PATH] ;
221 char                    EngineIniFileName[_MAX_PATH] ;
222 char                    BinariesPath [_MAX_PATH] ;
223 char                    DocumentsPath [_MAX_PATH] ;
224 char                    LastInferredHome [_MAX_PATH] ;
225 char                    ToolIniFileName [_MAX_PATH] ;
226 char                    tool_commands [MAX_TOOLCMD] [MAX_TOOLCMDTEXT] ;
227 char                    tool_help [MAX_TOOLCMD] [MAX_TOOLHELPTEXT] ;
228 char                    requested_render_file [_MAX_PATH] ;
229 char                    RegionStr [128] ;
230 char                    TempRegionStr [128] ;
231 char                    demo_file_name [_MAX_PATH] ;
232 char                    demo_ini_name [_MAX_PATH] ;
233 char                    status_buffer [1024] ;
234 char                    render_complete_sound [_MAX_PATH] ;
235 char                    parse_error_sound [_MAX_PATH] ;
236 char                    render_error_sound [_MAX_PATH] ;
237 char                    FontPath [_MAX_PATH] ;
238 char                    *EditDLLPath ;
239 bool                    render_complete_sound_enabled ;
240 bool                    parse_error_sound_enabled  ;
241 bool                    render_error_sound_enabled ;
242 bool                    alert_on_completion ;
243 bool                    save_settings ;
244 bool                    IsW95UserInterface = true;
245 bool                    IsW98 ;
246 bool                    IsWNT ;
247 bool                    IsW2k ;
248 bool                    IsWXP ;
249 bool                    IsVista ;
250 bool                    running_demo ;
251 bool                    running_benchmark ;
252 bool                    benchmark_multithread ;
253 bool                    fast_scroll ;
254 bool                    no_shellout_wait ;
255 bool                    tile_background = false ;
256 bool                    debugging ;
257 bool                    no_palette_warn ;
258 bool                    render_lock_up ;
259 bool                    RenderwinIsChild = true ;
260 bool                    demo_mode ;
261 bool                    benchmark_mode;
262 bool                    ignore_auto_ini ;
263 bool                    newVersion ;
264 bool                    exit_after_render ;
265 bool                    system_noactive ;
266 bool                    one_instance = true ;
267 bool                    run_renderer ;
268 bool                    use_toolbar = true ;
269 bool                    use_tooltips = true ;
270 bool                    use_editors = true ;
271 bool                    editors_enabled = true;
272 bool                    resizing ;
273 bool                    drop_to_editor ;
274 bool                    restore_command_line ;
275 bool                    render_requested ;
276 bool                    render_auto_close ;
277 bool                    noexec ;
278 bool                    ExtensionsEnabled = true ;
279 bool                    use_taskbar = true ;
280 bool                    main_window_hidden ;
281 bool                    about_showing ;
282 bool                    NoRestore ;
283 bool                    IsComCtl5 = false ;
284 bool                    IsComCtl6 = false ;
285 bool                    allow_rw_source ;
286 bool                    no_shell_outs = true ;
287 bool                    hide_newuser_help ;
288 bool                    info_render_complete = false ;
289 bool                    no_status_output = false ;
290 bool                    temp_render_region = false ;
291 bool                    rendering_insert_menu = false ;
292 bool                    was_insert_render = false ;
293 bool                    rendering_animation = false ;
294 bool                    preserve_bitmap = false ;
295 bool                    first_frame = false ;
296 bool                    check_new_version ;
297 bool                    check_news ;
298 bool                    send_system_info ;
299 bool                    homeInferred = false ;
300 bool                    editSettingsCopied = false ;
301 bool                    FreshInstall = false;
302 bool                    output_to_file ;
303 bool                    UpdateCheckDone = false ;
304 bool                    AutoAppendPaths ;
305 HWND                    toolbar_window ;
306 HWND                    aux_toolbar_window ;
307 HWND                    window_list [MAX_WINDOWS] ;
308 HWND                    toolbar_combobox ;
309 HWND                    rebar_window ;
310 HWND                    StatusWindow ;
311 HWND                    StatusTooltip ;
312 HWND                    toolbar_cmdline ;
313 HWND                    tab_window ;
314 HICON                   ourIcon ;
315 HICON                   renderIcon ;
316 HFONT                   about_font ;
317 HANDLE                  hMainThread ;
318 string                  InputFileName ;
319 time_t                  SecondCountStart ;
320 time_t                  quit ;
321 HBITMAP                 hBmpBackground ;
322 HBITMAP                 hBmpRendering ;
323 HBITMAP                 hBmpIcon ;
324 HBITMAP                 hBmpAbout ;
325 __int64                 PerformanceFrequency ;
326 __int64                 PerformanceCounter1 ;
327 __int64                 PerformanceCounter2 ;
328 __int64                 KernelTimeStart ;
329 __int64                 KernelTimeEnd ;
330 __int64                 UserTimeStart ;
331 __int64                 UserTimeEnd ;
332 __int64                 KernelTimeTotal ;
333 __int64                 UserTimeTotal ;
334 __int64                 CPUTimeTotal ;
335 clock_t                 ClockTimeStart ;
336 clock_t                 ClockTimeEnd ;
337 clock_t                 ClockTimeTotal ;
338 clock_t                 SleepTimeStart ;
339 clock_t                 SleepTimeEnd ;
340 clock_t                 SleepTimeTotal ;
341 unsigned                class_registered = 0 ;
342 unsigned                currentX = 0 ;
343 unsigned                currentY = 0 ;
344 unsigned                screen_width ;
345 unsigned                screen_height ;
346 unsigned                screen_depth ;
347 unsigned                background_width ;
348 unsigned                background_height ;
349 unsigned                seconds = 0 ;
350 unsigned                toolheight = 0 ;
351 unsigned                statusheight = 0 ;
352 unsigned                on_completion = CM_COMPLETION_NOTHING ;
353 unsigned                window_count = 0 ;
354 unsigned                ThreadCount = 2 ;
355 unsigned                NumberOfCPUs ;
356 unsigned                NumLogicalCPUs ;
357 unsigned                NumCPUCores ;
358 unsigned                NumPhysicalCPUs ;
359 HPALETTE                hPalApp ;
360 HPALETTE                hPalBitmap ;
361 COLORREF                background_colour ;
362 COLORREF                text_colours [3] ;
363 COLORREF                custom_colours [16] ;
364 COLORREF                background_shade = RGB (1, 1, 1) ;
365 HINSTANCE               hInstance ;
366 HH_AKLINK               hh_aklink ;
367 OSVERSIONINFO           version_info ;
368 StatusPanelItem         StatusPanelItems [IDC_STATUS_ID_LAST + 1] ;
369 CRITICAL_SECTION        critical_section ;
370 
371 // key is the name of an included file (all lower case).
372 // content is the name of the most recent rendered file that caused it to be included.
373 std::map<string, string> IncludeToSourceMap;
374 std::map<string, bool>  IncludeAlternateDecisionMap;
375 
376 char                    queued_files [MAX_QUEUE] [_MAX_PATH] ;
377 char                    dir [_MAX_PATH] ;
378 unsigned                queued_file_count = 0 ;
379 unsigned                auto_render = true ;
380 unsigned                timer_id ;
381 unsigned                about_timer_id ;
382 unsigned                timer_ticks;
383 
384 unsigned                panel_size ;
385 
386 char                    PovMainWinClass [] = CLASSNAMEPREFIX "MainWinClass" ;
387 unsigned                mainwin_xpos ;
388 unsigned                mainwin_ypos ;
389 HWND                    main_window ;
390 HWND                    message_window ;
391 WINDOWPLACEMENT         mainwin_placement ;
392 
393 char                    PovAboutWinClass [] = CLASSNAMEPREFIX "AboutWinClass" ;
394 HWND                    about_window ;
395 HWND                    about_buttons [3] ;
396 WNDPROC                 about_button_wndproc ;
397 unsigned                about_width ;
398 unsigned                about_height ;
399 HPALETTE                about_palette ;
400 
401 HWND                    statuspanel ;
402 
403 char                    PovMessageWinClass [] = CLASSNAMEPREFIX "MessageWinClass" ;
404 
405 #define NUM_ABOUT_LINKS 7
406 RECT                    AboutLinks[NUM_ABOUT_LINKS] =
407                         {
408                           {  23,  14, 188,  87 },
409                           { 104, 397, 184, 409 },
410                           { 185, 397, 262, 409 },
411                           { 263, 397, 370, 409 },
412                           { 371, 397, 480, 409 },
413                           { 481, 397, 560, 409 },
414                           {  32, 411, 154, 423 }
415                         };
416 char                    *AboutURLs[NUM_ABOUT_LINKS] =
417                         {
418                           "http://www.povray.org/",
419                           "http://www.digicert.com/",
420                           "http://ntplx.net/",
421                           "http://opensourcelaw.biz/",
422                           "http://www.perforce.com/",
423                           "http://softwarefreedom.org/",
424                           "http://softwarefreedom.org/"
425                         };
426 
427 bool handle_main_command (WPARAM wParam, LPARAM lParam) ;
428 void SetStatusPanelItemText (int id, LPCSTR format, ...) ;
429 void ShowAboutBox (void);
430 
431 extern int              message_xchar ;
432 extern int              message_ychar ;
433 extern int              message_scroll_pos_x ;
434 extern int              message_scroll_pos_y ;
435 extern int              top_message_row ;
436 extern int              message_count ;
437 extern int              message_cols ;
438 extern int              message_rows ;
439 extern int              listbox_xchar ;
440 extern int              listbox_ychar ;
441 extern int              EditFileCount ;
442 extern int              message_output_x ;
443 extern char             message_font_name [256] ;
444 extern char             *EditFiles [] ;
445 extern bool             ListenMode ;
446 extern bool             keep_messages ;
447 extern bool             MenuBarDraw ;
448 extern bool             TrackMem;
449 extern __int64          PeakMem;
450 extern unsigned         message_font_size ;
451 extern unsigned         message_font_weight ;
452 extern HFONT            message_font ;
453 extern HFONT            tab_font ;
454 extern HMENU            hMenuBar ;
455 extern HMENU            hMainMenu ;
456 extern HMENU            hPopupMenus ;
457 extern HMENU            hVidcapMenu ;
458 extern HACCEL           hAccelerators ;
459 extern HINSTANCE        hLibPovEdit ;
460 
461 #define MAX_INSERT_MENU_SECTIONS  8192
462 
463 typedef std::vector<int> InsMenuSecList;
464 
465 int                     InsertMenuSection;
466 bool                    StartInsertRender;
467 InsMenuSecList          InsertMenuSections;
468 
469 typedef struct
470 {
471   WORD        wVirtkey ;
472   int         iMessage ;
473   WORD        wRequest ;
474 } SCROLLKEYS ;
475 
476 SCROLLKEYS key2scroll [] =
477 {
478   { VK_END,   WM_VSCROLL, SB_BOTTOM   },
479   { VK_PRIOR, WM_VSCROLL, SB_PAGEUP   },
480   { VK_NEXT,  WM_VSCROLL, SB_PAGEDOWN },
481   { VK_UP,    WM_VSCROLL, SB_LINEUP   },
482   { VK_DOWN,  WM_VSCROLL, SB_LINEDOWN },
483   { VK_LEFT,  WM_HSCROLL, SB_PAGEUP   },
484   { VK_RIGHT, WM_HSCROLL, SB_PAGEDOWN },
485   { -1,       -1,         -1          }
486 } ;
487 
StripFilePath(const string & str)488 string StripFilePath (const string& str)
489 {
490   string::size_type pos  = str.find_last_of ("\\/") ;
491   if (pos == string::npos)
492     return (str) ;
493   return string (str, pos + 1) ;
494 }
495 
StripPathComponent(char * path,int number)496 bool StripPathComponent (char *path, int number)
497 {
498   if (number > 1)
499     if (!StripPathComponent (path, number - 1))
500       return (false) ;
501   char *s = path + strlen (path) - 1 ;
502   if (isPathSeparator(*s))
503     *s-- = '\0' ;
504   while (s > path && !isPathSeparator(*s))
505     s-- ;
506   *s = '\0' ;
507   return (path [0] != '\0') ;
508 }
509 
debug_output(const char * format,...)510 void debug_output (const char *format, ...)
511 {
512   char                  str [2048] ;
513   va_list               arg_ptr ;
514   FILE                  *f ;
515 
516   if (format == NULL)
517   {
518     _unlink ("c:\\temp\\povdebug.txt") ;
519     return ;
520   }
521 
522   va_start (arg_ptr, format) ;
523   vsprintf (str, format, arg_ptr) ;
524   va_end (arg_ptr) ;
525   OutputDebugString (str) ;
526 
527   if ((f = fopen ("c:\\temp\\povdebug.txt", "a+t")) != NULL)
528   {
529     fprintf (f, sizeof(time_t) == 4 ? "%u: %s" : "%I64u: %s", time (NULL), str) ;
530 
531     fclose (f) ;
532   }
533 }
534 
535 // this function is declared in syspovconfig.h ... use pov::WIN32_DEBUG_OUTPUT() from
536 // anywhere in the POV-Ray source, core or otherwise
WIN32_DEBUG_OUTPUT(const char * format,...)537 void WIN32_DEBUG_OUTPUT (const char *format,...)
538 {
539   char                  str [2048] ;
540   va_list               arg_ptr ;
541 
542   sprintf (str, "%5d ", GetCurrentThreadId());
543   va_start (arg_ptr, format) ;
544   vsprintf (str + 6, format, arg_ptr) ;
545   va_end (arg_ptr) ;
546   OutputDebugString (str) ;
547 }
548 
549 // this function is declared in syspovconfig.h ... use pov::WIN32_DEBUG_FILE_OUTPUT() from
550 // anywhere in the POV-Ray source, core or otherwise. it's also thread-safe.
WIN32_DEBUG_FILE_OUTPUT(const char * format,...)551 void WIN32_DEBUG_FILE_OUTPUT (const char *format,...)
552 {
553   va_list               arg_ptr ;
554   static FILE           *f ;
555   static boost::mutex   mtx;
556 
557   if (format == NULL)
558   {
559     if (f != NULL)
560     {
561       fclose (f) ;
562       f = NULL ;
563     }
564     return ;
565   }
566 
567   if (f == NULL)
568   {
569     f = fopen ("c:\\temp\\povdebug.txt", "at") ;
570     if (f == NULL)
571       return ;
572   }
573 
574   boost::mutex::scoped_lock l(mtx);
575   fprintf (f, "%u [%d]: ", GetTickCount (), GetCurrentThreadId ()) ;
576   va_start (arg_ptr, format) ;
577   vfprintf (f, format, arg_ptr) ;
578   va_end (arg_ptr) ;
579   fflush (f);
580 }
581 
SetCaption(LPCSTR str)582 void SetCaption (LPCSTR str)
583 {
584   char        buffer [1024] ;
585   static char lastStr [1024] ;
586   vfeSession& Session (GetSession());
587 
588   if (str != NULL)
589     strcpy (lastStr, str) ;
590   else
591     str = lastStr ;
592 
593   if (Session.BackendFailed())
594   {
595     SetWindowText (main_window, "Backend Failed") ;
596     return;
597   }
598 
599 #ifndef DEVELOPMENT
600   if (Session.GetBackendState() == kRendering && InputFileName.size () > 0)
601   {
602     string filename = StripFilePath (InputFileName) ;
603     if (strstr (str, filename.c_str ()) != NULL)
604     {
605       // if the filename is in the caption already, we're probably rendering
606       // the current editor file (exception: if a file with the same name but
607       // a different path is being viewed).
608       sprintf (buffer, "%s [%s %d%%]", str, Session.GetBackendStateName(), Session.GetPercentComplete()) ;
609     }
610     else
611     {
612       // the render file name is not in the caption: in that case we are
613       // probably viewing another file or the message window.
614       sprintf (buffer, "%s [Rendering %s: %d%%]", str, filename.c_str (), Session.GetPercentComplete()) ;
615     }
616   }
617   else
618     sprintf (buffer, "%s [%s]", str, Session.GetBackendStateName ()) ;
619   SetWindowText (main_window, buffer) ;
620 #else
621   if (Session.GetBackendState() == kRendering && InputFileName.size () > 0)
622   {
623     string filename = StripFilePath (InputFileName) ;
624     if (strstr (str, filename.c_str ()) != NULL)
625     {
626       // if the filename is in the caption already, we're probably rendering
627       // the current editor file (exception: if a file with the same name but
628       // a different path is being viewed).
629       sprintf (buffer, CAPTIONPREFIX " %s [%s %d%%]", str, Session.GetBackendStateName(), Session.GetPercentComplete()) ;
630     }
631     else
632     {
633       // the render file name is not in the caption: in that case we are
634       // probably viewing another file or the message window.
635       sprintf (buffer, CAPTIONPREFIX " %s [Rendering %s:%d%%]", str, filename.c_str (), Session.GetPercentComplete()) ;
636     }
637   }
638   else
639     sprintf (buffer, CAPTIONPREFIX " %s [%s]", str, Session.GetBackendStateName()) ;
640   SetWindowText (main_window, buffer) ;
641 #endif
642 }
643 
644 // returned value is in microseconds
GetCPUTime(bool Kernel=true,bool User=true)645 __int64 GetCPUTime (bool Kernel = true, bool User = true)
646 {
647   __int64     kt ;
648   __int64     ut ;
649   __int64     total = 0 ;
650   FILETIME    ct ;
651   FILETIME    et ;
652 
653   if (IsWNT)
654   {
655     if (!GetProcessTimes (GetCurrentProcess (), &ct, &et, (FILETIME *) &kt, (FILETIME *) &ut))
656     {
657       assert (false) ;
658       return (0) ;
659     }
660     if (Kernel)
661       total += kt ;
662     if (User)
663       total += ut ;
664     return (total / 10) ;
665   }
666   else
667   {
668     // have to simulate the results for now
669     // TODO: handle pause time
670     ut = clock () ;
671     if (User)
672       total += ut * 1000 ;
673     return (total) ;
674   }
675 }
676 
PPS_String(unsigned pixels,unsigned renderseconds)677 char *PPS_String (unsigned pixels, unsigned renderseconds)
678 {
679   static char str [128] ;
680 
681   if (rendersleep)
682     return ("PAUSED") ;
683 
684   if (renderseconds == 0)
685     return ("??? PPS") ;
686 
687   if (pixels / renderseconds < 5)
688   {
689     if (pixels * 60 / renderseconds < 5)
690       sprintf (str, "%u PPH", pixels * 3600 / renderseconds) ;
691     else
692       sprintf (str, "%u PPM", pixels * 60 / renderseconds) ;
693   }
694   else
695     sprintf (str, "%u PPS", pixels / renderseconds) ;
696   return (str) ;
697 }
698 
PrintRenderTimes(int Finished,int NormalCompletion)699 void PrintRenderTimes (int Finished, int NormalCompletion)
700 {
701   int         PixelsRendered = GetSession().GetPixelsRendered();
702   unsigned    STT = SleepTimeTotal ;
703 
704   if (rendersleep)
705   {
706     SleepTimeEnd = clock () ;
707     if (Finished)
708     {
709       SleepTimeTotal += SleepTimeEnd - SleepTimeStart ;
710       STT = SleepTimeTotal ;
711       rendersleep = false ;
712     }
713     else
714       STT += SleepTimeEnd - SleepTimeStart ;
715   }
716   KernelTimeEnd = GetCPUTime (true, false) ;
717   UserTimeEnd = GetCPUTime (false, true) ;
718   KernelTimeTotal = KernelTimeEnd - KernelTimeStart ;
719   UserTimeTotal = UserTimeEnd - UserTimeStart ;
720   CPUTimeTotal = UserTimeTotal + KernelTimeTotal ;
721   ClockTimeEnd = clock () ;
722   ClockTimeTotal = ClockTimeEnd - ClockTimeStart - STT ;
723   if (ClockTimeTotal >= CLOCKS_PER_SEC)
724     status_printf (StatusPPS, PPS_String (PixelsRendered, ClockTimeTotal / CLOCKS_PER_SEC)) ;
725   say_status_message (StatusRendertime, get_elapsed_time (ClockTimeTotal / CLOCKS_PER_SEC)) ;
726   if (IsWNT != 0 && Finished != 0)
727   {
728     message_printf ("CPU time used: kernel %.02f seconds, user %.02f seconds, total %.02f seconds.\n",
729                      KernelTimeTotal / 1000000.0, UserTimeTotal / 1000000.0, CPUTimeTotal / 1000000.0) ;
730     message_printf ("Elapsed time %.02f seconds", (double) ClockTimeTotal / CLOCKS_PER_SEC) ;
731     if (NumberOfCPUs > 1 && ThreadCount > 1)
732     {
733       POV_ULONG cputotal = CPUTimeTotal * CLOCKS_PER_SEC / 1000000 ;
734       if (cputotal > ClockTimeTotal * 10 / 9)
735         message_printf (", CPU vs elapsed time ratio %.02f", (double) cputotal / ClockTimeTotal) ;
736     }
737     message_printf (".\n") ;
738     if (PixelsRendered > 0 && CPUTimeTotal > 0 && NormalCompletion)
739     {
740       message_printf ("Render averaged %.02f PPS (%.02f PPS CPU time) over %u pixels.\n",
741         (double) PixelsRendered * CLOCKS_PER_SEC / ClockTimeTotal, (double) PixelsRendered * 1000000 / CPUTimeTotal, PixelsRendered) ;
742       message_printf ("----------------------------------------------------------------------------\n") ;
743 #ifndef _DEBUG
744       char str [2048] ;
745       if (running_benchmark)
746       {
747         char *s = str;
748         s += sprintf(str, "CPU time used: kernel %.02f seconds, user %.02f seconds, total %.02f seconds.\n",
749           KernelTimeTotal / 1000000.0, UserTimeTotal / 1000000.0, CPUTimeTotal / 1000000.0) ;
750         s += sprintf(s, "Elapsed time %.02f seconds", (double) ClockTimeTotal / CLOCKS_PER_SEC) ;
751         if (NumberOfCPUs > 1 && ThreadCount > 1)
752         {
753           POV_ULONG cputotal = CPUTimeTotal * CLOCKS_PER_SEC / 1000000 ;
754           if (cputotal > ClockTimeTotal * 10 / 9)
755             s += sprintf(s, ", CPU vs elapsed time ratio %.02f", (double) cputotal / ClockTimeTotal) ;
756         }
757         s += sprintf(s, ".\n") ;
758         s += sprintf (s, "Render averaged %.02f PPS (%.02f PPS CPU time) over %u pixels using %u thread(s).\n",
759           (double) PixelsRendered * CLOCKS_PER_SEC / ClockTimeTotal, (double) PixelsRendered * 1000000 / CPUTimeTotal, PixelsRendered, ThreadCount) ;
760         copy_text_to_clipboard(str);
761         if (benchmark_mode)
762         {
763           // special case: we are running the benchmark because of a command-line request.
764           char fn[_MAX_PATH];
765           char ts[256];
766           time_t t = time(NULL);
767 
768           strftime(ts, sizeof(ts), "%Y%m%d.%H%M%S", gmtime(&t));
769           sprintf(fn, "%sbenchmark-%s.txt", DocumentsPath, ts);
770           FILE *f = fopen(fn, "wt");
771           if (f != NULL)
772           {
773             int n = Get_Benchmark_Version();
774 
775             fprintf(f, "%s", str);
776             strftime(str, sizeof(str), "%#c", gmtime(&t));
777             fprintf(f, "\nRender of benchmark version %x.%02x completed at %s UTC.\n", n / 256, n % 256, str);
778             fprintf(f, "----------------------------------------------------------------------------\n");
779             GenerateDumpMeta(true);
780             fwrite(DumpMeta, strlen(DumpMeta), 1, f);
781             fprintf(f, "povversion=%s\n", POV_RAY_VERSION) ;
782             fprintf(f, "compilerversion=%s\n", COMPILER_VER) ;
783             fprintf(f, "platformversion=%s\n", PVENGINE_VER) ;
784             fclose(f);
785           }
786         }
787         else
788         {
789           strcat(str, "\nThese results have been placed in the clipboard.\n");
790           MessageBox (main_window, str, "Benchmark Complete.", MB_OK) ;
791         }
792       }
793 #endif
794     }
795     else
796       message_printf ("----------------------------------------------------------------------------\n") ;
797   }
798 }
799 
OkToStopRendering(void)800 bool OkToStopRendering (void)
801 {
802   if (GetSession().BackendFailed())
803     return (true);
804   if (time (NULL) - SecondCountStart < CONFIRM_STOP_THRESHOLD)
805     return (true) ;
806   if (GetSession().GetRealTimeRaytracing() == true)
807     return (true);
808   if (MessageBox (main_window, "You've been running this render for quite a while - really cancel ?", "Stop rendering ?", MB_ICONQUESTION | MB_YESNO) == IDYES)
809     return (true) ;
810   return (false) ;
811 }
812 
menuhelp(UINT idCommand)813 void menuhelp (UINT idCommand)
814 {
815   switch (idCommand)
816   {
817     case CM_FILEMENUHELP :
818          hh_aklink.pszKeywords = "File Menu" ;
819          break ;
820 
821     case CM_EDITMENUHELP :
822          hh_aklink.pszKeywords = "Edit Menu" ;
823          break ;
824 
825     case CM_SEARCHMENUHELP :
826          hh_aklink.pszKeywords = "Search Menu" ;
827          break ;
828 
829     case CM_TEXTMENUHELP :
830          hh_aklink.pszKeywords = "Text Menu" ;
831          break ;
832 
833     case CM_EDITORMENUHELP :
834          hh_aklink.pszKeywords = "Editor Menu" ;
835          break ;
836 
837     case CM_RENDERMENUHELP :
838          hh_aklink.pszKeywords = "Render Menu" ;
839          break ;
840 
841     case CM_OPTIONSMENUHELP :
842          hh_aklink.pszKeywords = "Options Menu" ;
843          break ;
844 
845     case CM_TOOLSMENUHELP :
846          hh_aklink.pszKeywords = "Tools Menu" ;
847          break ;
848 
849     case CM_WINDOWMENUHELP :
850          hh_aklink.pszKeywords = "Window Menu" ;
851          break ;
852 
853     case CM_RENDERWINMENUHELP :
854          hh_aklink.pszKeywords = "Render Window Menu" ;
855          break ;
856 
857     case CM_MESSAGEWINMENUHELP :
858          hh_aklink.pszKeywords = "Message Window Menu" ;
859          break ;
860 
861     default :
862          hh_aklink.pszKeywords = NULL ;
863          break ;
864   }
865   if (hh_aklink.pszKeywords != NULL)
866     HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ;
867 }
868 
869 // example taken from MSDN documentation
GetDllVersion(LPCTSTR lpszDllName)870 DWORD GetDllVersion (LPCTSTR lpszDllName)
871 {
872   HINSTANCE hinstDll;
873   DWORD dwVersion = 0;
874 
875   hinstDll = LoadLibrary(lpszDllName) ;
876 
877   if (hinstDll)
878   {
879     DLLGETVERSIONPROC pDllGetVersion;
880 
881     pDllGetVersion = (DLLGETVERSIONPROC) GetProcAddress (hinstDll, "DllGetVersion");
882 
883     if (pDllGetVersion)
884     {
885       DLLVERSIONINFO dvi;
886       HRESULT hr;
887 
888       ZeroMemory(&dvi, sizeof (dvi));
889       dvi.cbSize = sizeof (dvi);
890 
891       hr = (*pDllGetVersion) (&dvi);
892 
893       if (SUCCEEDED (hr))
894         dwVersion = MAKELONG (dvi.dwMajorVersion, dvi.dwMinorVersion);
895     }
896 
897     FreeLibrary (hinstDll);
898   }
899   return dwVersion;
900 }
901 
getvars(ExternalVarStruct * v)902 void getvars (ExternalVarStruct *v)
903 {
904   strcpy (v->command_line, command_line) ;
905   strcpy (v->source_file_name, source_file_name) ;
906   strcpy (v->lastRenderName, lastRenderName) ;
907   strcpy (v->lastRenderPath, lastRenderPath) ;
908   strcpy (v->lastQueuePath, lastQueuePath) ;
909   strcpy (v->lastSecondaryIniFilePath, lastSecondaryIniFilePath) ;
910   strcpy (v->DefaultRenderIniFileName, DefaultRenderIniFileName) ;
911   strcpy (v->SecondaryRenderIniFileName, SecondaryRenderIniFileName) ;
912   strcpy (v->SecondaryRenderIniFileSection, SecondaryRenderIniFileSection) ;
913   strcpy (v->ourPath, modulePath) ;
914   strcpy (v->engineHelpPath, engineHelpPath) ;
915   strcpy (v->rendererHelpPath, "") ;
916   strcpy (v->BinariesPath, BinariesPath) ;
917   strcpy (v->EngineIniFileName, EngineIniFileName) ;
918   strcpy (v->ToolIniFileName, ToolIniFileName) ;
919   memcpy (v->queued_files, queued_files, sizeof (v->queued_files)) ;
920   v->loadRerun = false ;
921   v->continueRerun = false ;
922   v->povray_return_code = povray_return_code ;
923   v->rendering = rendering ;
924   v->IsWin32 = true ;
925   v->IsW95UserInterface = IsW95UserInterface ;
926   v->running_demo = running_demo ;
927   v->debugging = debugging ;
928   v->isMaxiMinimized = false ;
929   v->newVersion = newVersion ;
930   v->use_threads = true ;
931   v->use_toolbar = use_toolbar ;
932   v->use_tooltips = use_tooltips ;
933   v->use_editors = use_editors ;
934   v->drop_to_editor = drop_to_editor ;
935   v->rendersleep = rendersleep ;
936   v->ExtensionsEnabled = ExtensionsEnabled ;
937   v->queued_file_count = queued_file_count > OLD_MAX_QUEUE ? OLD_MAX_QUEUE : queued_file_count ;
938   v->auto_render = auto_render ;
939 }
940 
setvars(ExternalVarStruct * v)941 void setvars (ExternalVarStruct *v)
942 {
943   strncpy (command_line, v->command_line, sizeof (command_line) - 1) ;
944   SendMessage (toolbar_cmdline, WM_SETTEXT, 0, (LPARAM) command_line) ;
945   strncpy (source_file_name, v->source_file_name, sizeof (source_file_name) - 1) ;
946   strncpy (lastRenderName, v->lastRenderName, sizeof (lastRenderName) - 1) ;
947   strncpy (lastRenderPath, v->lastRenderPath, sizeof (lastRenderPath) - 1) ;
948   strncpy (lastQueuePath, v->lastQueuePath, sizeof (lastQueuePath) - 1) ;
949   strncpy (lastSecondaryIniFilePath, v->lastSecondaryIniFilePath, sizeof (lastSecondaryIniFilePath) - 1) ;
950   strncpy (DefaultRenderIniFileName, v->DefaultRenderIniFileName, sizeof (DefaultRenderIniFileName) - 1) ;
951   strncpy (SecondaryRenderIniFileName, v->SecondaryRenderIniFileName, sizeof (SecondaryRenderIniFileName) - 1) ;
952   strncpy (SecondaryRenderIniFileSection, v->SecondaryRenderIniFileSection, sizeof (SecondaryRenderIniFileSection) - 1) ;
953 }
954 
HaveWin95OrLater(void)955 bool HaveWin95OrLater (void)
956 {
957   return (version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) ;
958 }
959 
HaveWin98OrLater(void)960 bool HaveWin98OrLater (void)
961 {
962   if (version_info.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)
963     return (false) ;
964   if (version_info.dwMajorVersion < 4)
965     return (false) ;
966   if (version_info.dwMajorVersion > 4)
967     return (true) ;
968   return (version_info.dwMinorVersion > 0) ;
969 }
970 
HaveNT4OrLater(void)971 bool HaveNT4OrLater (void)
972 {
973   return (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT && version_info.dwMajorVersion >= 4) ;
974 }
975 
HaveWin2kOrLater(void)976 bool HaveWin2kOrLater (void)
977 {
978   return (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT && version_info.dwMajorVersion >= 5) ;
979 }
980 
HaveWinXPOrLater(void)981 bool HaveWinXPOrLater (void)
982 {
983   if (version_info.dwPlatformId != VER_PLATFORM_WIN32_NT || version_info.dwMajorVersion < 5)
984     return (false) ;
985   return (version_info.dwMajorVersion > 5 || (version_info.dwMajorVersion == 5 && version_info.dwMinorVersion > 0)) ;
986 }
987 
HaveVistaOrLater(void)988 bool HaveVistaOrLater (void)
989 {
990   return version_info.dwPlatformId == VER_PLATFORM_WIN32_NT && version_info.dwMajorVersion > 5;
991 }
992 
set_render_priority(unsigned priority)993 void set_render_priority (unsigned priority)
994 {
995   switch (priority)
996   {
997     case CM_RENDERPRIORITY_BACKGROUND :
998          SetPriorityClass (GetCurrentProcess(), PROCESS_MODE_BACKGROUND_BEGIN) ;
999          break ;
1000 
1001     case CM_RENDERPRIORITY_LOW :
1002          if (IsVista)
1003            SetPriorityClass (GetCurrentProcess(), PROCESS_MODE_BACKGROUND_END);
1004          SetPriorityClass (GetCurrentProcess(), IDLE_PRIORITY_CLASS) ;
1005          break ;
1006 
1007     case CM_RENDERPRIORITY_NORMAL :
1008          if (IsVista)
1009            SetPriorityClass (GetCurrentProcess(), PROCESS_MODE_BACKGROUND_END);
1010          SetPriorityClass (GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS) ;
1011          break ;
1012 
1013     case CM_RENDERPRIORITY_HIGH :
1014          if (IsVista)
1015            SetPriorityClass (GetCurrentProcess(), PROCESS_MODE_BACKGROUND_END);
1016          SetPriorityClass (GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS) ;
1017          break ;
1018   }
1019 }
1020 
1021 // we can't allow LoadBitmap to load our background bitmaps 'cause if we're running
1022 // a 256-colour mode, it will map the incoming resource to 16 colours ...
1023 // LoadImage () doesn't exist under Win32s, either. sigh.
NonBogusLoadBitmap(HINSTANCE hInst,LPSTR lpszBitmap)1024 HBITMAP NonBogusLoadBitmap (HINSTANCE hInst, LPSTR lpszBitmap)
1025 {
1026   void        *p ;
1027   HRSRC       hres ;
1028   HGLOBAL     hg ;
1029   HBITMAP     hBitmap ;
1030 
1031   if ((hres = FindResource (hInst, lpszBitmap, RT_BITMAP)) == NULL)
1032     return (NULL) ;
1033   if ((hg = LoadResource (hInst, hres)) == NULL)
1034     return (NULL) ;
1035   if ((p = LockResource (hg)) == NULL)
1036   {
1037     FreeResource (hg) ;
1038     return (NULL) ;
1039   }
1040   hBitmap = lpDIBToBitmap (p, hPalApp) ;
1041   FreeResource (hg) ;
1042   return (hBitmap) ;
1043 }
1044 
NonBogusLoadBitmapAndPalette(HINSTANCE hInst,LPSTR lpszBitmap)1045 HBITMAP NonBogusLoadBitmapAndPalette (HINSTANCE hInst, LPSTR lpszBitmap)
1046 {
1047   void        *p ;
1048   HRSRC       hres ;
1049   HGLOBAL     hg ;
1050   HBITMAP     hBitmap ;
1051 
1052   if ((hres = FindResource (hInst, lpszBitmap, RT_BITMAP)) == NULL)
1053     return (NULL) ;
1054   if ((hg = LoadResource (hInst, hres)) == NULL)
1055     return (NULL) ;
1056   if ((p = LockResource (hg)) == NULL)
1057   {
1058     FreeResource (hg) ;
1059     return (NULL) ;
1060   }
1061   hBitmap = lpDIBToBitmapAndPalette (p) ;
1062   FreeResource (hg) ;
1063   return (hBitmap) ;
1064 }
1065 
1066 // finds fist separator character in a path
findFirstPathSeparator(char * s)1067 char *findFirstPathSeparator (char *s)
1068 {
1069   size_t  pos = strcspn(s, "\\/");
1070 
1071   return pos >= strlen(s) ? NULL : s + pos;
1072 }
1073 
1074 // finds last separator character in a path
findLastPathSeparator(char * s)1075 char *findLastPathSeparator (char *s)
1076 {
1077   char    *s1 = strrchr (s, '\\');
1078   char    *s2 = strrchr (s1 ? s1 : s, '/');
1079 
1080   return s2 ? s2 : s1;
1081 }
1082 
1083 // append separator character to a path, if not present already
1084 // does not append to empty strings.
1085 // does append to solitary drive letters; this isn't quite legit but as we don't
1086 // support the use of drive references without a path (i.e. references that rely
1087 // on the uniquely-DOS/Windows concept of a CWD for *each* mounted device), it
1088 // doesn't really matter.
appendPathSeparator(char * str)1089 void appendPathSeparator (char *str)
1090 {
1091   if (str[0] != '\0') // only append to non-empty strings
1092     if (!hasTrailingPathSeparator(str))
1093       strcat(str, "\\");
1094 }
1095 
1096 // tests if path has trailing separator character
1097 // does not return true if path is a solitary drive letter (e.g. "C:").
1098 // the same consideration applies regarding relative drive references as
1099 // mentioned in appendPathSeparator.
hasTrailingPathSeparator(const char * str)1100 bool hasTrailingPathSeparator (const char *str)
1101 {
1102   return isPathSeparator(str[strlen (str) - 1]);
1103 }
1104 
1105 // strips trailing separator character from path
1106 // will strip a trailing separator right after drive letter (e.g. "C:\").
1107 // calling functions must be careful not to let this trip them up if they
1108 // are passed any user-specified input.
trimTrailingPathSeparator(char * str)1109 void trimTrailingPathSeparator (char *str)
1110 {
1111   char *s = str + strlen (str) - 1 ;
1112   if (isPathSeparator(*s))
1113     *s = '\0' ;
1114 }
1115 
1116 // strips leading and trailing double-quotes from a string.
1117 // does not check that both are present, just removes them
1118 // if they are there. returns new start of string.
trimDoubleQuotes(char * str)1119 char *trimDoubleQuotes (char *str)
1120 {
1121   if (str[0] == '"')
1122     str++;
1123   char *s = str + strlen (str) - 1 ;
1124   if (*s == '"')
1125     *s = '\0' ;
1126   return str;
1127 }
1128 
1129 // strips trailing separator character from path
validatePath(char * s)1130 void validatePath (char *s)
1131 {
1132   if (s [1] == ':' && strlen (s) < 4)
1133     return ; // make sure we don't trim a trailing separator right after a drive letter (e.g. "C:\")
1134   trimTrailingPathSeparator (s);
1135 }
1136 
joinPath(char * out,const char * path,const char * name)1137 int joinPath (char *out, const char *path, const char *name)
1138 {
1139   strcpy (out, path) ;
1140   appendPathSeparator (out);
1141   strcat (out, name) ;
1142   return ((int) strlen (out)) ;
1143 }
1144 
reg_printf(bool useHKCU,char * keyName,char * valName,char * format,...)1145 bool reg_printf (bool useHKCU, char *keyName, char *valName, char *format, ...)
1146 {
1147   char                  str [2048] ;
1148   HKEY                  hKey ;
1149   va_list               arg_ptr ;
1150 
1151   if (strlen (format) > sizeof (str) - 256)
1152     return (false) ;
1153   if (RegCreateKeyEx (useHKCU ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, keyName, 0, "", REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS)
1154   {
1155     va_start (arg_ptr, format) ;
1156     vsprintf (str, format, arg_ptr) ;
1157     va_end (arg_ptr) ;
1158     RegSetValueEx (hKey, valName, 0, REG_SZ, (BYTE *) str, (int) strlen (str) + 1) ;
1159     RegCloseKey (hKey) ;
1160     return (true) ;
1161   }
1162   return (false) ;
1163 }
1164 
1165 // conditional version of reg_printf
cond_reg_printf(char * keyName,char * valName,char * format,...)1166 bool cond_reg_printf (char *keyName, char *valName, char *format, ...)
1167 {
1168   char                  str [2048] ;
1169   DWORD                 len = sizeof (str) ;
1170   HKEY                  hKey ;
1171   va_list               arg_ptr ;
1172 
1173   if (strlen (format) > sizeof (str) - 256)
1174     return (false) ;
1175   if (RegOpenKeyEx (HKEY_CURRENT_USER, keyName, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
1176   {
1177     if (RegQueryValueEx (hKey, valName, 0, NULL, (BYTE *) str, &len) == ERROR_SUCCESS)
1178     {
1179       RegCloseKey (hKey) ;
1180       // it already exists - if it doesn't have zero length we don't update it
1181       if (str [0])
1182         return (true) ;
1183     }
1184     else
1185       RegCloseKey (hKey) ;
1186   }
1187   if (RegCreateKeyEx (HKEY_CURRENT_USER, keyName, 0, "", REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS)
1188   {
1189     va_start (arg_ptr, format) ;
1190     vsprintf (str, format, arg_ptr) ;
1191     va_end (arg_ptr) ;
1192     RegSetValueEx (hKey, valName, 0, REG_SZ, (BYTE *) str, (int) strlen (str) + 1) ;
1193     RegCloseKey (hKey) ;
1194     return (true) ;
1195   }
1196   return (false) ;
1197 }
1198 
reg_dword(char * keyName,char * valName,DWORD value)1199 static bool reg_dword (char *keyName, char *valName, DWORD value)
1200 {
1201   HKEY                  hKey ;
1202 
1203   if (RegCreateKeyEx (HKEY_CURRENT_USER, keyName, 0, "", REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS)
1204   {
1205     RegSetValueEx (hKey, valName, 0, REG_DWORD, (BYTE *) &value, 4) ;
1206     RegCloseKey (hKey) ;
1207     return (true) ;
1208   }
1209   return (false) ;
1210 }
1211 
GetInstallTime(void)1212 char *GetInstallTime (void)
1213 {
1214   HKEY        key ;
1215   DWORD       len ;
1216   static char str [64] ;
1217 
1218   len = sizeof (str) ;
1219   if (RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY, 0, KEY_READ, &key) == ERROR_SUCCESS)
1220   {
1221     if (RegQueryValueEx (key, INSTALLTIMEKEY, 0, NULL, (BYTE *) str, &len) == ERROR_SUCCESS)
1222     {
1223       RegCloseKey (key) ;
1224       return (str) ;
1225     }
1226     RegCloseKey (key) ;
1227   }
1228   return (NULL) ;
1229 }
1230 
checkRegKey(void)1231 bool checkRegKey (void)
1232 {
1233   char        str [_MAX_PATH] ;
1234   HKEY        key ;
1235   DWORD       val;
1236   DWORD       len = sizeof (str) ;
1237   FILETIME    file_time ;
1238   SYSTEMTIME  system_time ;
1239 
1240   if (GetInstallTime () == NULL)
1241   {
1242     GetSystemTime (&system_time) ;
1243     if (SystemTimeToFileTime (&system_time, &file_time))
1244       reg_printf (true, "Software\\" REGKEY, INSTALLTIMEKEY, "%I64u", ((__int64) file_time.dwHighDateTime << 32) | file_time.dwLowDateTime) ;
1245   }
1246 
1247   if (RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", 0, KEY_READ, &key) == ERROR_SUCCESS)
1248   {
1249     if (RegQueryValueEx (key, "Home", 0, NULL, (BYTE *) str, &len) != 0)
1250       str[0] = '\0';
1251     if (str [0] == '\0')
1252     {
1253       RegCloseKey (key) ;
1254       return (false) ;
1255     }
1256     len = sizeof(val);
1257     if (RegQueryValueEx (key, "FreshInstall", 0, NULL, (BYTE *) &val, &len) == 0)
1258     {
1259       FreshInstall = val != 0;
1260       RegCloseKey (key) ;
1261       if (FreshInstall && RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", 0, KEY_READ | KEY_SET_VALUE, &key) == ERROR_SUCCESS)
1262       {
1263         RegDeleteValue(key, "FreshInstall");
1264         RegCloseKey (key) ;
1265       }
1266     }
1267     else
1268       RegCloseKey (key) ;
1269   }
1270   else
1271     return (false) ;
1272 
1273   if (RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\CurrentVersion\\Windows", 0, KEY_READ | KEY_WRITE, &key) == ERROR_SUCCESS)
1274   {
1275     len = sizeof (str) ;
1276     if (RegQueryValueEx (key, VERSIONVAL, 0, NULL, (BYTE *) str, &len) != 0 || strcmp (str, POV_RAY_VERSION) != 0)
1277         RegSetValueEx (key, VERSIONVAL, 0, REG_SZ, (BYTE *) POV_RAY_VERSION, (int) strlen (POV_RAY_VERSION) + 1) ;
1278     RegCloseKey (key) ;
1279   }
1280 
1281   return true;
1282 }
1283 
getHome(void)1284 bool getHome (void)
1285 {
1286   HKEY        key ;
1287   DWORD       len ;
1288 
1289   if (debugging)
1290     debug_output ("querying registry\n") ;
1291   DocumentsPath [0] = BinariesPath [0] = '\0' ;
1292   if (RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", 0, KEY_READ, &key) == ERROR_SUCCESS)
1293   {
1294     len = sizeof (LastInferredHome) ;
1295     RegQueryValueEx (key, "LastInferredHome", 0, NULL, (BYTE *) LastInferredHome, &len) ;
1296 
1297     len = sizeof (BinariesPath) ;
1298     RegQueryValueEx (key, "Home", 0, NULL, (BYTE *) BinariesPath, &len) ;
1299     if (debugging && BinariesPath[0] != '\0')
1300       debug_output("Win32 getHome() succeeded (HKCU::Home), BinariesPath is '%s'\n", BinariesPath) ;
1301 
1302     len = sizeof (DocumentsPath) ;
1303     RegQueryValueEx (key, "DocPath", 0, NULL, (BYTE *) DocumentsPath, &len) ;
1304     if (debugging && DocumentsPath[0] != '\0')
1305       debug_output("Win32 getHome() succeeded (HKCU::DocPath), DocumentsPath is '%s'\n", DocumentsPath) ;
1306 
1307     RegCloseKey (key) ;
1308     return (BinariesPath[0] != '\0') ;
1309   }
1310   if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", 0, KEY_READ, &key) == ERROR_SUCCESS)
1311   {
1312     len = sizeof (BinariesPath) ;
1313     RegQueryValueEx (key, "Home", 0, NULL, (BYTE *) BinariesPath, &len) ;
1314     RegCloseKey (key) ;
1315     if (debugging && BinariesPath[0] != '\0')
1316       debug_output("Win32 getHome() succeeded (HKLM::Home), BinariesPath is '%s'\n", BinariesPath) ;
1317     return (BinariesPath[0] != '\0') ;
1318   }
1319   return (false) ;
1320 }
1321 
inferHome(void)1322 bool inferHome (void)
1323 {
1324   char        exePath [_MAX_PATH] ;
1325   char        *s ;
1326 
1327   if (GetModuleFileName (NULL, exePath, _MAX_PATH) == 0)
1328     return (false) ;
1329 
1330   // find path component
1331   if ((s = findLastPathSeparator (exePath)) == NULL)
1332     return (false) ;
1333   *s = '\0' ;
1334 
1335   // now step up one directory
1336   if ((s = findLastPathSeparator (exePath)) == NULL)
1337     return (false) ;
1338   *++s = '\0' ;
1339 
1340   // now look for some standard directories
1341   strcpy (s, "help") ;
1342   if (!dirExists (exePath))
1343   {
1344     strcpy (s, "sounds") ;
1345     if (!dirExists (exePath))
1346     {
1347       strcpy (s, "tiles") ;
1348       if (!dirExists (exePath))
1349         return (false) ;
1350     }
1351   }
1352 
1353   *s = '\0' ;
1354   strcpy (BinariesPath, exePath) ;
1355   homeInferred = true ;
1356   return (true) ;
1357 }
1358 
get36Home(void)1359 string get36Home(void)
1360 {
1361   char        str[_MAX_PATH];
1362   HKEY        key ;
1363   DWORD       len = sizeof(str);
1364 
1365   if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\" REGKEY "\\v3.6\\Windows", 0, KEY_READ, &key) == ERROR_SUCCESS)
1366   {
1367     if (RegQueryValueEx (key, "Home", 0, NULL, (BYTE *) str, &len) == 0)
1368     {
1369       RegCloseKey (key) ;
1370       appendPathSeparator(str);
1371       return string(str);
1372     }
1373     RegCloseKey (key) ;
1374   }
1375   if (RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\v3.6\\Windows", 0, KEY_READ, &key) == ERROR_SUCCESS)
1376   {
1377     if (RegQueryValueEx (key, "Home", 0, NULL, (BYTE *) str, &len) == 0)
1378     {
1379       RegCloseKey (key) ;
1380       appendPathSeparator(str);
1381       return string(str);
1382     }
1383     RegCloseKey (key) ;
1384   }
1385   return string();
1386 }
1387 
copy36EditSettings(void)1388 bool copy36EditSettings(void)
1389 {
1390   HKEY        hKeySrc ;
1391   HKEY        hKeyDst ;
1392   DWORD       result ;
1393   HINSTANCE   hLib ;
1394   shCopyType  *shCopyKey ;
1395 
1396   if ((hLib = LoadLibrary ("shlwapi.dll")) == NULL)
1397     return (false) ;
1398   shCopyKey = (shCopyType *) GetProcAddress (hLib, "SHCopyKeyA") ;
1399   if (shCopyKey == NULL)
1400   {
1401     FreeLibrary (hLib) ;
1402     return (false) ;
1403   }
1404 
1405   if (RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\v3.6", 0, KEY_READ, &hKeySrc) != ERROR_SUCCESS)
1406   {
1407     FreeLibrary (hLib) ;
1408     return (false) ;
1409   }
1410 
1411   if (RegCreateKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit", 0, "", REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKeyDst, NULL) != ERROR_SUCCESS)
1412   {
1413     RegCloseKey (hKeySrc) ;
1414     FreeLibrary (hLib) ;
1415     return (false) ;
1416   }
1417 
1418   result = shCopyKey (hKeySrc, "POV-Edit", hKeyDst, NULL) ;
1419   RegCloseKey (hKeySrc) ;
1420   RegCloseKey (hKeyDst) ;
1421   FreeLibrary (hLib) ;
1422 
1423   return (result == ERROR_SUCCESS) ;
1424 }
1425 
checkEditKey36(void)1426 bool checkEditKey36 (void)
1427 {
1428   HKEY        key ;
1429 
1430   if (RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\v3.6\\POV-Edit", 0, KEY_READ, &key) == ERROR_SUCCESS)
1431   {
1432     RegCloseKey (key) ;
1433     return (true) ;
1434   }
1435   return (false) ;
1436 }
1437 
checkEditKey37(void)1438 bool checkEditKey37 (void)
1439 {
1440   HKEY        key ;
1441 
1442   if (RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit", 0, KEY_READ, &key) == ERROR_SUCCESS)
1443   {
1444     RegCloseKey (key) ;
1445     return (true) ;
1446   }
1447   return (false) ;
1448 }
1449 
1450 // called if either our registry entries don't seem to be set up, or if they do exist and
1451 // the FreshInstall option is set in the registry.
CloneOptions(void)1452 bool CloneOptions (void)
1453 {
1454   if (debugging)
1455     debug_output("attempting to create registry entries\n") ;
1456 
1457   // don't do this if we're being called as a result of the FreshInstall registry setting
1458   if (!FreshInstall)
1459   {
1460     if (!reg_printf (true, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", "Home", "%s", BinariesPath))
1461       return (false) ;
1462     if (!homeInferred)
1463       reg_printf (true, "Software\\" REGKEY "\\CurrentVersion\\Windows", "Home", "%s", BinariesPath) ;
1464   }
1465 
1466   reg_printf (true, "Software\\" REGKEY "\\CurrentVersion\\Windows", VERSIONVAL, "%s", POV_RAY_VERSION) ;
1467 
1468   cond_reg_printf ("Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit\\Open",   "Open0",   "%sChanges.txt,1,1,0,0,8,2",                   DocumentsPath) ;
1469   cond_reg_printf ("Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit\\Recent", "Recent0", "%sChanges.txt,1,1,0,0,8,2",                   DocumentsPath) ;
1470   cond_reg_printf ("Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit\\Open",   "Open1",   "%sRevision.txt,1,1,0,0,8,2",                  DocumentsPath) ;
1471   cond_reg_printf ("Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit\\Recent", "Recent1", "%sRevision.txt,1,1,0,0,8,2",                  DocumentsPath) ;
1472   cond_reg_printf ("Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit\\Open",   "Open2",   "%sscenes\\advanced\\biscuit.pov,1,1,0,6,8,2", DocumentsPath) ;
1473   cond_reg_printf ("Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit\\Recent", "Recent2", "%sscenes\\advanced\\biscuit.pov,1,1,0,6,8,2", DocumentsPath) ;
1474   cond_reg_printf ("Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit\\Open",   "Open3",   "%sscenes\\advanced\\woodbox.pov,1,1,0,6,8,2", DocumentsPath) ;
1475   cond_reg_printf ("Software\\" REGKEY "\\" REGVERKEY "\\POV-Edit\\Recent", "Recent3", "%sscenes\\advanced\\woodbox.pov,1,1,0,6,8,2", DocumentsPath) ;
1476 
1477   return (true) ;
1478 }
1479 
parse_commandline(char * s)1480 int parse_commandline (char *s)
1481 {
1482   char        *prevWord = NULL ;
1483   char        inQuote = '\0' ;
1484   static char str [_MAX_PATH * 3] ;
1485   static char filename [_MAX_PATH] ;
1486 
1487   argc = 0 ;
1488   GetModuleFileName (hInstance, filename, sizeof (filename) - 1) ;
1489   argv [argc++] = filename ;
1490   s = strncpy (str, s, sizeof (str) - 1) ;
1491   while (*s)
1492   {
1493     switch (*s)
1494     {
1495       case '"' :
1496       case '\'' :
1497            if (inQuote)
1498            {
1499              if (*s == inQuote)
1500                inQuote = 0 ;
1501            }
1502            else
1503            {
1504              inQuote = *s ;
1505              if (prevWord == NULL)
1506                prevWord = s ;
1507            }
1508            break ;
1509 
1510       case ' ' :
1511       case '\t' :
1512            if (!inQuote)
1513            {
1514              if (prevWord != NULL)
1515              {
1516                *s = '\0' ;
1517                argv [argc++] = prevWord ;
1518                prevWord = NULL ;
1519              }
1520            }
1521            break ;
1522 
1523       default :
1524            if (prevWord == NULL)
1525              prevWord = s ;
1526            break ;
1527     }
1528     if (argc >= MAX_ARGV - 1)
1529       break ;
1530     s++ ;
1531   }
1532   if (prevWord != NULL && argc < MAX_ARGV - 1)
1533     argv [argc++] = prevWord ;
1534   argv [argc] = NULL ;
1535   return (argc) ;
1536 }
1537 
InstallSettings(char * binpath,char * docpath,bool quiet)1538 int InstallSettings (char *binpath, char *docpath, bool quiet)
1539 {
1540   char        base [_MAX_PATH] ;
1541   char        str [_MAX_PATH] ;
1542   char        *s ;
1543 
1544   // we attempt to infer the install dir if it's not supplied
1545   if (binpath == NULL)
1546   {
1547     if (_getcwd (base, sizeof (base) - 1) == NULL)
1548     {
1549       if (!quiet)
1550         MessageBox (NULL, "Could not get current directory - cannot infer home path. Please supply it on the command-line",
1551                           "POV-Ray for Windows - running INSTALL option", MB_OK | MB_ICONSTOP) ;
1552       return 5 ;
1553     }
1554     if (strlen (base) < 3 || (strlen (base) == 3 && base [1] == ':' && isPathSeparator(base [2])))
1555     {
1556       if (!quiet)
1557       {
1558         sprintf (str, "Current dir '%s' is root - cannot infer home path. Please supply it on the command-line.", base) ;
1559         MessageBox (NULL, str, "POV-Ray for Windows - running INSTALL option", MB_OK | MB_ICONSTOP) ;
1560       }
1561       return 10 ;
1562     }
1563     // the strlen test covers the case where base is "\\" (i.e. a network path) or a bare drive (e.g. "c:").
1564     if (!StripPathComponent (base, 1) || strlen(base) < 3)
1565     {
1566       if (!quiet)
1567         MessageBox (NULL, "Cannot infer home path. Please supply it on the command-line.",
1568                           "POV-Ray for Windows - running INSTALL option", MB_OK | MB_ICONSTOP) ;
1569       return 15 ;
1570     }
1571   }
1572   else
1573   {
1574     strcpy (str, binpath) ;
1575     s = trimDoubleQuotes(str);
1576     validatePath (s) ;
1577     if (GetFullPathName (s, sizeof (base), base, NULL) == 0)
1578     {
1579       sprintf (str, "GetFullPathName() for '%s' failed [0x%08x]", s, GetLastError ()) ;
1580       MessageBox (NULL, str, "POV-Ray for Windows - running INSTALL option", MB_OK | MB_ICONSTOP) ;
1581     }
1582   }
1583   if (!dirExists (base))
1584   {
1585     if (!quiet)
1586     {
1587       sprintf (str, "Could not stat directory '%s'", base) ;
1588       MessageBox (NULL, str, "POV-Ray for Windows - running INSTALL option", MB_OK | MB_ICONSTOP) ;
1589     }
1590     return 20 ;
1591   }
1592 
1593   if (docpath != NULL)
1594   {
1595     if (!dirExists(docpath))
1596     {
1597       // if the path doesn't exist and quiet is selected, we continue, assuming that
1598       // by the time povray is ready to be used, it will either exist or be able to be
1599       // created. note that we do auto-create the path if possible (i.e. the parent
1600       // directory exists and is writable by the user who launches POV-Ray).
1601       if (!quiet)
1602         if (MessageBox (NULL, "Could not verify supplied user files path: use it anyway?\n(Selecting NO will exit.)", "POV-Ray for Windows - running INSTALL option", MB_YESNO | MB_ICONEXCLAMATION) == IDNO)
1603           return 30;
1604     }
1605     reg_printf (true, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", "DocPath", "%s\\", docpath);
1606   }
1607 
1608   if (!reg_printf (true, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", "Home", "%s\\", base))
1609   {
1610     if (!quiet)
1611       MessageBox (NULL, "Failed to write to HKCU in registry", "POV-Ray for Windows - running INSTALL option", MB_OK | MB_ICONSTOP) ;
1612     return 35 ;
1613   }
1614 
1615   // it's ok for this to fail as they may not have administrative rights
1616   reg_printf (false, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", "Home", "%s\\", base) ;
1617 
1618   if (!quiet)
1619   {
1620     sprintf (str, "[Home path is %s]\n\nSuccess!", base) ;
1621     MessageBox (NULL, str, "POV-Ray for Windows - running INSTALL option", MB_OK | MB_ICONINFORMATION) ;
1622   }
1623   return (0) ;
1624 }
1625 
GetExceptionDescription(DWORD code)1626 char *GetExceptionDescription (DWORD code)
1627 {
1628   switch (code)
1629   {
1630     case EXCEPTION_ACCESS_VIOLATION :
1631          return ("a memory access violation") ;
1632 
1633     case EXCEPTION_DATATYPE_MISALIGNMENT :
1634          return ("a datatype misalignment") ;
1635 
1636     case EXCEPTION_FLT_DENORMAL_OPERAND :
1637          return ("a denormal floating point operand") ;
1638 
1639     case EXCEPTION_FLT_DIVIDE_BY_ZERO :
1640          return ("a floating point divide by zero") ;
1641 
1642     case EXCEPTION_FLT_INEXACT_RESULT :
1643          return ("an inexact floating-point result") ;
1644 
1645     case EXCEPTION_FLT_INVALID_OPERATION :
1646          return ("an invalid floating-point operation") ;
1647 
1648     case EXCEPTION_FLT_OVERFLOW :
1649          return ("a floating-point overflow") ;
1650 
1651     case EXCEPTION_FLT_STACK_CHECK :
1652          return ("a floating-point stack over/underflow") ;
1653 
1654     case EXCEPTION_FLT_UNDERFLOW :
1655          return ("a floating-point underflow") ;
1656 
1657     case EXCEPTION_INT_DIVIDE_BY_ZERO :
1658          return ("an integer divide by zero") ;
1659 
1660     case EXCEPTION_INT_OVERFLOW :
1661          return ("an integer overflow") ;
1662 
1663     case EXCEPTION_PRIV_INSTRUCTION :
1664          return ("the execution of a privileged instruction") ;
1665 
1666     case EXCEPTION_IN_PAGE_ERROR :
1667          return ("a page error") ;
1668 
1669     case EXCEPTION_ILLEGAL_INSTRUCTION :
1670          return ("the execution of an illegal instruction") ;
1671 
1672     case EXCEPTION_NONCONTINUABLE_EXCEPTION :
1673          return ("a continuation after a noncontinuable exception") ;
1674 
1675     case EXCEPTION_STACK_OVERFLOW :
1676          return ("a stack overflow") ;
1677 
1678     case EXCEPTION_INVALID_DISPOSITION :
1679          return ("an invalid disposition") ;
1680 
1681     case EXCEPTION_GUARD_PAGE :
1682          return ("a guard page exception") ;
1683 
1684     case EXCEPTION_INVALID_HANDLE :
1685          return ("an invalid handle exception") ;
1686 
1687     default :
1688          return NULL ;
1689   }
1690 }
1691 
1692 #if POV_RAY_IS_OFFICIAL == 1
1693 // this pulls in the code for update checks and crash dump submission.
1694 // it is only used in official releases made by the POV-Ray developers,
1695 // so the source is not included in the public distribution.
1696 #include "official.h"
1697 #else
ExceptionHandler(struct _EXCEPTION_POINTERS * ExceptionInfo)1698 LONG WINAPI ExceptionHandler(struct _EXCEPTION_POINTERS* ExceptionInfo)
1699 {
1700   char                        *s;
1701   long                        timestamp = _time32(NULL);
1702   PCONTEXT                    c ;
1703   static char                 str[2048] ;
1704   static boost::mutex         mtx;
1705   boost::mutex::scoped_lock   l(mtx);
1706 
1707   c = ExceptionInfo->ContextRecord ;
1708   const char *desc = GetExceptionDescription(ExceptionInfo->ExceptionRecord->ExceptionCode);
1709   if (desc == NULL)
1710     desc = "an" ;
1711   sprintf (str,
1712            "Unfortunately, it appears that %s at address 0x%p has caused this unofficial POV-Ray build to crash. "
1713            "This dialog will allow you to choose whether or not a dump file (useful for diagnostics) is written.\n\n"
1714            "NOTE: If you were running a render, you should be able to recover the part that had already been generated. "
1715            "See the 'Continue' (+c) option in the documentation for more information about this.\n\n"
1716            "Would you like to write a dump file?",
1717            desc,
1718 #ifdef _WIN64
1719            c->Rip);
1720 #else
1721            c->Eip);
1722 #endif
1723   DWORD result = MessageBox (NULL, str, "POV-Ray for Windows", MB_ICONSTOP | MB_TOPMOST | MB_TASKMODAL | MB_YESNO | MB_DEFBUTTON1 | MB_SETFOREGROUND) ;
1724   if (result == IDYES)
1725   {
1726     // write a full dump first, then a minidump. it's no big deal if the full dump write fails.
1727     WriteDump(ExceptionInfo, true, timestamp);
1728     if ((s = WriteDump(ExceptionInfo, false, timestamp)) != NULL)
1729     {
1730       MessageBox (main_window, "The dump was successfully saved.", "POV-Ray for Windows", MB_OK) ;
1731       sprintf(str, "/select,%s", s);
1732       ShellExecute (NULL, NULL, "explorer.exe", str, NULL, SW_SHOWNORMAL) ;
1733       ExitProcess (1) ;
1734     }
1735   }
1736   else
1737     MessageBox (main_window, "POV-Ray will now exit.", "POV-Ray for Windows", MB_OK) ;
1738   ExitProcess (1) ;
1739   return (EXCEPTION_CONTINUE_SEARCH) ; // make compiler happy
1740 }
1741 #endif // POV_RAY_IS_OFFICIAL
1742 
execute_tool(char * s)1743 int execute_tool (char *s)
1744 {
1745   int                   error ;
1746   STARTUPINFO           startupInfo ;
1747   PROCESS_INFORMATION   procInfo ;
1748 
1749   if (strlen (s) == 0)
1750   {
1751     PovMessageBox ("No command to run!", "Tool Error") ;
1752     return (0) ;
1753   }
1754 
1755   if (*s == '$')
1756   {
1757     switch (toupper (s[1]))
1758     {
1759       case 'S' :
1760            s += 2 ;
1761            while (*s == ' ')
1762              s++ ;
1763            if (strlen (s) == 0)
1764            {
1765              PovMessageBox ("No file to open!", "Tool Error") ;
1766              return (0) ;
1767            }
1768            if ((error = PtrToInt (ShellExecute (main_window, "open", s, NULL, NULL, SW_SHOWNORMAL))) <= 32)
1769              PovMessageBox ("ShellExecute failed", "Tool Error") ;
1770            return (error) ;
1771 
1772       case 'E' :
1773            s += 2 ;
1774            while (*s == ' ')
1775              s++ ;
1776            if (strlen (s) == 0)
1777            {
1778              PovMessageBox ("No file to open!", "Tool Error") ;
1779              return (0) ;
1780            }
1781            return EditOpenFile(s) ? 0 : 1;
1782     }
1783   }
1784 
1785   startupInfo.cb               = sizeof (STARTUPINFO) ;
1786   startupInfo.lpReserved       = 0 ;
1787   startupInfo.lpDesktop        = NULL ;
1788   startupInfo.lpTitle          = NULL ;
1789   startupInfo.dwX              = 0 ;
1790   startupInfo.dwY              = 0 ;
1791   startupInfo.dwXSize          = 0 ;
1792   startupInfo.dwYSize          = 0 ;
1793   startupInfo.dwXCountChars    = 0 ;
1794   startupInfo.dwYCountChars    = 0 ;
1795   startupInfo.dwFillAttribute  = 0 ;
1796   startupInfo.dwFlags          = STARTF_USESHOWWINDOW ;
1797   startupInfo.wShowWindow      = SW_SHOW ;
1798   startupInfo.cbReserved2      = 0 ;
1799   startupInfo.lpReserved2      = 0 ;
1800 
1801   if (CreateProcess (NULL, s, NULL, NULL, false, 0, NULL, NULL, &startupInfo, &procInfo) == false)
1802   {
1803     error = GetLastError () ;
1804     PovMessageBox ("Could not run program", "Tool Error") ;
1805     return (error) ;
1806   }
1807 
1808   // clean up
1809   CloseHandle (procInfo.hProcess) ;
1810   CloseHandle (procInfo.hThread) ;
1811 
1812   return (0) ;
1813 }
1814 
RenderInsertMenu(void)1815 void RenderInsertMenu (void)
1816 {
1817   int         val ;
1818   char        str [_MAX_PATH] ;
1819   char        *s1 ;
1820   char        *s2 ;
1821   FILE        *f ;
1822 
1823   stop_rendering = false ;
1824   sprintf (str, "%sInsert Menu\\Images.ini", DocumentsPath) ;
1825   if ((f = fopen (str, "rt")) == NULL)
1826   {
1827     MessageBox (main_window, "Cannot open 'Images.ini' in Insert Menu directory", "Insert Menu Images", MB_OK | MB_ICONEXCLAMATION) ;
1828     return ;
1829   }
1830   InsertMenuSection = 0 ;
1831   InsertMenuSections.clear();
1832   while (fgets (str, sizeof (str), f) != NULL)
1833   {
1834     s1 = clean (str) ;
1835     if (*s1 == '[')
1836     {
1837       if ((s2 = strchr (s1, ']')) != NULL)
1838       {
1839         *s2  = '\0' ;
1840         val = atoi (++s1) ;
1841         if (val == 0)
1842           continue ;
1843         InsertMenuSections.push_back(val);
1844         if (InsertMenuSections.size() == MAX_INSERT_MENU_SECTIONS)
1845           break ;
1846       }
1847     }
1848   }
1849   fclose (f) ;
1850   if (InsertMenuSections.empty())
1851   {
1852     MessageBox (main_window, "No insert menu sections found in 'Images.ini'", "Insert Menu Images", MB_OK | MB_ICONSTOP) ;
1853     return ;
1854   }
1855   sprintf (str, "There are %u insert menu images to render. Press OK to start rendering these now.\n\n"
1856                 "Once the render has started you can press the 'Stop Rendering' button to cancel the render job.", (unsigned int) InsertMenuSections.size()) ;
1857   if (MessageBox (main_window, str, "Insert Menu Images", MB_OKCANCEL | MB_ICONINFORMATION) == IDCANCEL)
1858     return ;
1859   PVEnableMenuItem (CM_RENDERSHOW, MF_GRAYED) ;
1860   update_menu_for_render (true) ;
1861   rendering_insert_menu = was_insert_render = no_status_output = true ;
1862   EditShowMessages (true) ;
1863   CalculateClientWindows (true) ;
1864   ShowWindow (message_window, SW_SHOW) ;
1865   sprintf (str, "%sInsert Menu", DocumentsPath) ;
1866   SetCurrentDirectory (str) ;
1867   StartInsertRender = true ;
1868 }
1869 
GetUCS2String(POVMSObjectPtr object,POVMSType key,char * result,int * maxlen)1870 int GetUCS2String(POVMSObjectPtr object, POVMSType key, char *result, int *maxlen)
1871 {
1872   UCS2 *str = new UCS2 [*maxlen] ;
1873   int err = POVMSUtil_GetUCS2String (object, key, str, maxlen) ;
1874   if (err == kNoErr)
1875   {
1876     string abc = UCS2toASCIIString (str) ;
1877     strcpy (result, abc.c_str ()) ;
1878   }
1879   delete str ;
1880   return err ;
1881 }
1882 
ShowIsPaused(void)1883 void ShowIsPaused(void)
1884 {
1885   if (GetSession().BackendFailed() == false && rendersleep == false)
1886   {
1887     SleepTimeStart = clock () ;
1888     status_printf (StatusPPS, PPS_String (GetSession().GetPixelsRendered(), ClockTimeTotal / CLOCKS_PER_SEC)) ;
1889     say_status_message (StatusPPS, "PAUSED") ;
1890     rendersleep = true ;
1891     SendMessage (toolbar_window, TB_CHECKBUTTON, (WPARAM) CM_RENDERSLEEP, MAKELONG (1, 0)) ;
1892   }
1893 }
1894 
getCommandLine(void)1895 char *getCommandLine (void)
1896 {
1897   HKEY        key ;
1898   static char str [2048] ;
1899   DWORD       len = sizeof (str) ;
1900 
1901   str [0] = '\0' ;
1902   if (RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", 0, KEY_READ, &key) == ERROR_SUCCESS)
1903   {
1904     RegQueryValueEx (key, "Command Line", 0, NULL, (BYTE *) str, &len) ;
1905     RegCloseKey (key) ;
1906   }
1907   return (str) ;
1908 }
1909 
setRunOnce(void)1910 void setRunOnce (void)
1911 {
1912 #ifndef NOSETRUNONCE
1913   char        str [_MAX_PATH] ;
1914   HKEY        key ;
1915   DWORD       result ;
1916 
1917   if (RegCreateKeyEx (HKEY_CURRENT_USER,
1918                       "Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce",
1919                       0,
1920                       "",
1921                       REG_OPTION_NON_VOLATILE,
1922                       KEY_WRITE,
1923                       NULL,
1924                       &key,
1925                       &result) == ERROR_SUCCESS)
1926   {
1927     GetModuleFileName (hInstance, str, sizeof (str)) ;
1928     RegSetValueEx (key, "POV-Ray for Windows", 0, REG_SZ, (BYTE *) str, (int) strlen (str) + 1) ;
1929     RegCloseKey (key) ;
1930   }
1931 #endif
1932 }
1933 
display_cleanup(bool unconditional)1934 void display_cleanup (bool unconditional)
1935 {
1936   if (unconditional)
1937   {
1938     gDisplay.reset();
1939     return;
1940   }
1941   Display *d = gDisplay.get();
1942   if (d == NULL)
1943     return;
1944   WinDisplay *wd = dynamic_cast<WinDisplay *>(d);
1945   if (wd == NULL)
1946     return;
1947   if (wd->GetWidth() != render_width || wd->GetHeight() != render_height)
1948   {
1949     gDisplay.reset();
1950     return;
1951   }
1952   wd->Clear();
1953 }
1954 
cancel_render(void)1955 void cancel_render (void)
1956 {
1957   stop_rendering = true ;
1958   if (GetSession().BackendFailed())
1959   {
1960     render_stopped() ;
1961     return;
1962   }
1963   if (GetSession().CancelRender() == vfeNotRunning)
1964   {
1965     // we possibly have an anamolous situation
1966     MessageBox (NULL, "Warning: had to force state to stopped", "Cancel Render", MB_OK | MB_ICONEXCLAMATION) ;
1967     render_stopped() ;
1968   }
1969 }
1970 
1971 // TODO: we have a problem here - if the parse completes very quickly, it's
1972 // possible for the VFE code to process the change to rendering mode before
1973 // we exit start_rendering() [note that the VFE worker thread runs at a higher
1974 // priority than the main UI thread]. as a result, on occasion, the VFE code
1975 // will call the display's Show() method at the same time as we are executing
1976 // display_cleanup(). display_cleanup() can cause the value of the pointer in
1977 // gDisplay to change, and potentially destroy the old one ...
start_rendering(bool ignore_source_file)1978 bool start_rendering (bool ignore_source_file)
1979 {
1980   int                   threadCount = ThreadCount ;
1981   char                  str [sizeof (command_line)] ;
1982   char                  path [_MAX_PATH] ;
1983   char                  file [_MAX_PATH] ;
1984   vfeSession&           Session (GetSession());
1985 
1986   if (Session.BackendFailed())
1987   {
1988     MessageBox (main_window, "The render backend has shut down due to an error: please re-start POV-Ray", "Error", MB_OK | MB_ICONSTOP) ;
1989     return false;
1990   }
1991 
1992   Session.Clear();
1993   Session.ClearOptions();
1994   if (!keep_messages)
1995     clear_messages(false);
1996 
1997   if (running_benchmark)
1998     threadCount = benchmark_mode || benchmark_multithread ? ThreadCount : 1 ;
1999 
2000   ErrorOccurred = ErrorNotified = false ;
2001   ErrorMessage.clear() ;
2002   ErrorFilename.clear() ;
2003   status_buffer [0] = '\0' ;
2004   povray_return_code = 0 ;
2005   rendersleep = false ;
2006   SleepTimeTotal = 0 ;
2007   render_anim_count = 0 ;
2008   rendering_animation = false ;
2009   stop_rendering = false ;
2010   was_insert_render = false ;
2011   first_frame = true ;
2012   render_width = render_height = 0 ;
2013   KernelTimeStart = GetCPUTime (true, false) ;
2014   UserTimeStart = GetCPUTime (false, true) ;
2015   CPUTimeTotal = KernelTimeTotal = UserTimeTotal = 0 ;
2016   ClockTimeStart = clock () ;
2017   SecondCountStart = time (NULL) ;
2018   SleepTimeTotal = ClockTimeTotal = 0 ;
2019   status_printf (StatusPPS, "") ;
2020   say_status_message (StatusRendertime, "") ;
2021   output_to_file = false ;
2022   InputFileName.clear();
2023   LastRenderPercentage = 0;
2024 
2025   SendMessage (StatusPanelItems [IDC_STATUS_PROGRESS].hwnd, PBM_SETPOS, 0, 0) ;
2026 
2027   say_status_message (StatusMessage, "") ;
2028 
2029   PVEnableMenuItem (CM_RENDERSHOW, MF_GRAYED) ;
2030   update_menu_for_render (true) ;
2031   SendMessage (toolbar_combobox, CB_GETLBTEXT, SendMessage (toolbar_combobox, CB_GETCURSEL, 0, 0), (LPARAM) SecondaryRenderIniFileSection) ;
2032 
2033   if (!StartInsertRender)
2034   {
2035     if (!temp_render_region)
2036       if (RegionStr [0] != '\0' && strstr (command_line, RegionStr + 1) == NULL)
2037         RegionStr [0] = '\0' ;
2038   }
2039 
2040   if (save_settings)
2041   {
2042     if (restore_command_line)
2043     {
2044       strcpy (str, command_line) ;
2045       strcpy (command_line, old_command_line) ;
2046     }
2047     write_INI_settings (true) ;
2048     if (restore_command_line)
2049       strcpy (command_line, str) ;
2050     EditSaveState () ;
2051   }
2052 
2053   try
2054   {
2055     // set up render options
2056     vfeRenderOptions opts ;
2057 
2058     opts.SetThreadCount (threadCount);
2059     opts.AddINI (DefaultRenderIniFileName) ;
2060 
2061     if (AutoAppendPaths || homeInferred)
2062     {
2063       sprintf (str, "%sinclude", DocumentsPath) ;
2064       opts.AddLibraryPath (str);
2065       opts.AddLibraryPath (FontPath);
2066     }
2067 
2068     if (!StartInsertRender)
2069     {
2070       if (running_demo == 0)
2071       {
2072         if (SecondaryRenderIniFileName [0] != '\0')
2073         {
2074           if (!hasTrailingPathSeparator(SecondaryRenderIniFileName))
2075           {
2076             splitpath (SecondaryRenderIniFileName, NULL, str) ;
2077             if (str [0] != '\0')
2078             {
2079               if (SecondaryRenderIniFileSection [0] == '\0')
2080                 wrapped_printf ("Preset INI file is '%s'.", SecondaryRenderIniFileName) ;
2081               else
2082                 wrapped_printf ("Preset INI file is '%s', section is '%s'.", SecondaryRenderIniFileName, SecondaryRenderIniFileSection) ;
2083               sprintf (str, "%s%s", SecondaryRenderIniFileName, SecondaryRenderIniFileSection) ;
2084               opts.AddINI (str);
2085             }
2086           }
2087         }
2088 
2089         if (!ignore_source_file && strlen (source_file_name) != 0)
2090         {
2091           wrapped_printf ("Preset source file is '%s'.", source_file_name) ;
2092           splitpath (source_file_name, dir, NULL) ;
2093           SetCurrentDirectory (dir) ;
2094           sprintf (str, "%s\\povray.ini", dir) ;
2095           if (fileExists (str))
2096           {
2097             wrapped_printf ("File '%s' exists - merging it.", str) ;
2098             opts.AddINI (str);
2099           }
2100           switch (get_file_type (source_file_name))
2101           {
2102             case filePOV :
2103             case fileINC :
2104                 opts.SetSourceFile (source_file_name);
2105                 break ;
2106 
2107             case fileINI :
2108                 opts.AddINI (source_file_name);
2109                 break ;
2110 
2111             default :
2112                 message_printf ("POV-Ray for Windows doesn't recognize this file type ; assuming POV source.\n") ;
2113                 opts.SetSourceFile (source_file_name);
2114                 break ;
2115           }
2116         }
2117       }
2118 
2119       if (running_benchmark)
2120       {
2121         opts.AddINI (demo_ini_name) ;
2122         opts.SetSourceFile (demo_file_name) ;
2123         if (strlen (demo_file_name) != 0)
2124         {
2125           splitpath (demo_file_name, dir, NULL) ;
2126           SetCurrentDirectory (dir) ;
2127         }
2128       }
2129       else
2130       {
2131         if (RegionStr [0] != 0)
2132         {
2133           if (strstr (command_line, RegionStr) == NULL && strstr (command_line, RegionStr + 1) == NULL)
2134           {
2135             if (!running_demo)
2136               message_printf ("Selected render region is '%s'.\n", RegionStr + 1) ;
2137             opts.AddCommand (RegionStr);
2138           }
2139         }
2140 
2141         if (strlen (command_line))
2142         {
2143           if (!running_demo)
2144             wrapped_printf ("Rendering using command line '%s'.", command_line) ;
2145           opts.AddCommand (command_line);
2146         }
2147       }
2148     }
2149     else
2150     {
2151       // we are rendering the insert menu
2152       if (InsertMenuSection >= InsertMenuSections.size())
2153         throw POV_EXCEPTION_STRING("Insert menu render error - we should be stopped already!");
2154       int section = InsertMenuSections [InsertMenuSection] ;
2155       sprintf (str, "Images.ini[%d]", section) ;
2156       opts.AddINI (str);
2157     }
2158 
2159     int result = Session.SetOptions (opts) ;
2160     if (result == vfeNoInputFile)
2161       throw POV_EXCEPTION_STRING("No source file specified, either directly or via an INI file.");
2162     else if (result != vfeNoError)
2163       throw POV_EXCEPTION_STRING (Session.GetErrorString());
2164 
2165     // TODO FIXME - magic values
2166     if (opts.GetOptions().TryGetInt(kPOVAttrib_RenderBlockSize, 32) < 4)
2167       throw POV_EXCEPTION (kParseErr, "Minimum permitted render block size is 4 (+BS4 or Render_Block_Size=4)") ;
2168 
2169     InputFileName = UCS2toASCIIString (Session.GetInputFilename());
2170     output_to_file = opts.GetOptions().TryGetBool(kPOVAttrib_OutputToFile, true) ;
2171     render_width = Session.GetRenderWidth();
2172     render_height = Session.GetRenderHeight();
2173     PutHKCU("LastRender", "SceneFile", "") ;
2174     PutHKCU("LastRender", "OutputFile", "") ;
2175     PutHKCU("LastRender", "IniOutputFile", "") ;
2176     PutHKCU("LastRender", "IniOutputFile", "") ;
2177 
2178     UseAlpha = Session.GetBoolOption("Output_Alpha", false);
2179     if (Session.GetBoolOption("Display", true) == false)
2180       display_cleanup(true);
2181 
2182     if (StartInsertRender)
2183       status_printf (StatusMessage, "Rendering Insert Menu entry %d of %d", InsertMenuSection + 1, (unsigned int) InsertMenuSections.size()) ;
2184     else
2185       status_printf (StatusMessage, "Parsing %s", InputFileName.c_str()) ;
2186 
2187     if (!running_demo && !demo_mode && !benchmark_mode)
2188     {
2189       GetCurrentDirectory (sizeof (dir), dir) ;
2190       PutHKCU("LastRender", "CurrentDirectory", dir) ;
2191       splitpath ((char *) InputFileName.c_str (), path, file) ;
2192       PutHKCU("LastRender", "SourceFile", get_full_name (file)) ;
2193       splitfn (str, NULL, file, NULL) ;
2194       PutHKCU("LastRender", "SceneFile", file) ;
2195     }
2196 
2197     result = Session.StartRender();
2198     if (result < 0)
2199       throw POV_EXCEPTION_CODE (result);
2200     else if (result > 0)
2201       throw POV_EXCEPTION_STRING (Session.GetErrorString());
2202   }
2203   catch (std::exception& e)
2204   {
2205     int errorCode = 0 ;
2206     if (dynamic_cast<pov_base::Exception *> (&e) != NULL)
2207     {
2208       errorCode = dynamic_cast<pov_base::Exception *> (&e)->code() ;
2209       povray_return_code = errorCode ;
2210     }
2211     if (povray_return_code == 0)
2212       povray_return_code = -1 ;
2213     ErrorOccurred = true ;
2214     PVEnableMenuItem (CM_RENDERSHOW, MF_ENABLED) ;
2215     update_menu_for_render (false) ;
2216     if (restore_command_line)
2217     {
2218       strcpy (command_line, old_command_line) ;
2219       SendMessage (toolbar_cmdline, WM_SETTEXT, 0, (UINT_PTR) command_line) ;
2220       restore_command_line = false ;
2221     }
2222 
2223     // make sure any outstanding messages are processed
2224     ProcessSession();
2225 
2226     EditShowMessages (true) ;
2227 
2228     if (ErrorNotified == false)
2229     {
2230       sprintf (str, "Failed to start render: %s", e.what()) ;
2231       say_status_message (StatusMessage, str) ;
2232       message_printf ("%s\n", str) ;
2233     }
2234     if (errorCode != kCannotOpenFileErr && errorCode != kParseErr && errorCode != kOutOfMemoryErr)
2235     {
2236       sprintf (str, "Failed to set render options (%s).\nSee message pane for more details.", e.what()) ;
2237       MessageBox (main_window, str, "Error", MB_OK | MB_ICONSTOP) ;
2238     }
2239 
2240     if (ErrorFilename.empty() == false)
2241       EditShowParseError (ErrorFilename.c_str(), ErrorMessage.c_str(), ErrorLine, ErrorCol) ;
2242     if (parse_error_sound_enabled)
2243     {
2244       PlaySound (parse_error_sound, NULL, SND_NOWAIT | SND_ASYNC | SND_NODEFAULT) ;
2245       if (!running_demo && !demo_mode && !benchmark_mode)
2246         FeatureNotify ("ParserErrorSound",
2247                         "POV-Ray - Parse Error Sound",
2248                         "You can change the sound played upon parse errors "
2249                         "from the Render Menu.\n\n"
2250                         "Click Help for more information.",
2251                         "sounds", false) ;
2252     }
2253     buffer_message (mDivider, "\n") ;
2254     EditShowMessages (true) ;
2255 
2256     return (false) ;
2257   }
2258 
2259   if (!StartInsertRender)
2260   {
2261     if (MenuBarDraw)
2262     {
2263       DrawMenuBar (main_window) ;
2264       MenuBarDraw = false ;
2265     }
2266     bool show = EditShowMessages (true) ;
2267     CalculateClientWindows (true) ;
2268     if (show)
2269       ShowWindow (message_window, SW_SHOW) ;
2270     PutHKCU ("Info", "Rendering", 1) ;
2271     display_cleanup (false) ;
2272   }
2273 
2274   currentX = seconds_for_last_line = -1 ;
2275   message_printf ("Rendering with %d thread%s.\n", threadCount, threadCount > 1 ? "s" : "") ;
2276 
2277   if (GetRenderWindow())
2278     GetRenderWindow()->SetRenderState (true);
2279 
2280   ExternalEvent (EventStartRendering, 0) ;
2281 
2282   set_render_priority (render_priority) ;
2283 
2284   // FIXME - ought to wait for the render to start here
2285   rendering = true ;
2286   // StartProfile () ;
2287 
2288   return (true) ;
2289 }
2290 
render_stopped(void)2291 void render_stopped (void)
2292 {
2293   char            *s ;
2294   char            str [4096] ;
2295   vfeWinSession&  Session (GetSession());
2296 
2297   run_renderer = false ;
2298   rendering = false ;
2299   status_buffer[0] = '\0' ;
2300   delay_next_status = 0 ;
2301   SetStatusPanelItemText (IDC_STATUS_DATA_FRAME, "N/A") ;
2302   SendMessage (StatusPanelItems [IDC_STATUS_PROGRESS].hwnd, PBM_SETPOS, 0, 0) ;
2303   bool success = Session.Succeeded();
2304 
2305   if (message_output_x > 0)
2306     buffer_message (mIDE, "\n") ;
2307 
2308   s = EditGetFilename(true) ;
2309   if (s != NULL && *s != '\0')
2310   {
2311     sprintf (str, "POV-Ray - %s", s) ;
2312     SetCaption (str) ;
2313   }
2314   else
2315     SetCaption ("POV-Ray for Windows") ;
2316 
2317   if ((!success || ErrorOccurred) && povray_return_code == 0)
2318     povray_return_code = -1 ;
2319   PrintRenderTimes (true, !ErrorOccurred && !stop_rendering) ;
2320   ExternalEvent (EventStopRendering, povray_return_code) ;
2321 
2322   // EndProfile () ;
2323 
2324   if (restore_command_line && !rendering_insert_menu)
2325   {
2326     strcpy (command_line, old_command_line) ;
2327     SendMessage (toolbar_cmdline, WM_SETTEXT, 0, (LPARAM) command_line) ;
2328     restore_command_line = false ;
2329   }
2330 
2331   if (rendering_insert_menu)
2332   {
2333     if (InsertMenuSection < InsertMenuSections.size() - 1 && !(stop_rendering || quit))
2334     {
2335       wrapped_printf ("Completed rendering Insert Menu section %d. result = %d", InsertMenuSections [InsertMenuSection++], povray_return_code) ;
2336       StartInsertRender = true ;
2337       return ;
2338     }
2339     StartInsertRender = rendering_insert_menu = no_status_output = false ;
2340     was_insert_render = true ;
2341   }
2342   else if (running_benchmark || running_demo)
2343   {
2344     if (running_benchmark == false)
2345     {
2346       strcpy (command_line, old_command_line) ;
2347       restore_command_line = false ;
2348     }
2349     _unlink (demo_file_name) ;
2350     _unlink (demo_ini_name) ;
2351     running_benchmark = running_demo = false ;
2352     if (benchmark_mode) // only applies to benchmarks started from the command-line
2353       PostQuitMessage (0) ;
2354     if (demo_mode)
2355     {
2356       PovMessageBox ("Demonstration completed. POV-Ray will now exit.", "Finished test run") ;
2357       PostQuitMessage (0) ;
2358     }
2359   }
2360 
2361   PutHKCU("Info", "Rendering", 0U) ;
2362   set_render_priority (CM_RENDERPRIORITY_NORMAL) ;
2363 
2364   if (quit != 0 || exit_after_render)
2365   {
2366     DestroyWindow (main_window) ;
2367     return ;
2368   }
2369 
2370   WinDisplay *rw = GetRenderWindow();
2371   if (rw != NULL)
2372   {
2373     rw->SetCaption ("POV-Ray Render Window");
2374     rw->SetRenderState (false);
2375     if (render_auto_close)
2376       rw->Hide();
2377   }
2378   if (main_window_hidden)
2379     TaskBarModifyIcon (main_window, 0, "POV-Ray (Restore: DblClk ; Menu: Mouse2)") ;
2380   InvalidateRect (statuspanel, NULL, false) ;
2381 
2382   if (success == true && ErrorOccurred == false)
2383   {
2384     if (render_complete_sound_enabled)
2385     {
2386       PlaySound (render_complete_sound, NULL, SND_ASYNC | SND_NODEFAULT) ;
2387       if (!running_demo && !demo_mode && !benchmark_mode)
2388         FeatureNotify ("RenderCompleteSound",
2389                       "POV-Ray - Render Complete Sound",
2390                       "You can change the sound played upon completion of rendering "
2391                       "from the Render Menu.\n\nIt is also possible to tell POV-Ray "
2392                       "for Windows to do other things when a render stops (such as "
2393                       "display a message or exit.)",
2394                       "sounds", false) ;
2395     }
2396     say_status_message (StatusMessage, "") ;
2397     EditShowMessages (false) ;
2398     CalculateClientWindows (false) ;
2399     switch (on_completion)
2400     {
2401       case CM_COMPLETION_EXIT :
2402            DestroyWindow (main_window) ;
2403            break ;
2404 
2405       case CM_COMPLETION_MESSAGE :
2406            PovMessageBox ("Render completed", "Message from POV-Ray for Windows") ;
2407            break ;
2408     }
2409     if (!running_demo && !demo_mode && !benchmark_mode && !rendering_insert_menu && !running_benchmark && !was_insert_render)
2410     {
2411       string ofn = UCS2toASCIIString (Session.GetOutputFilename());
2412       if (output_to_file && ofn.size () != 0)
2413       {
2414         sprintf (str, "Output -> '%s'", ofn.c_str ()) ;
2415         say_status_message (StatusMessage, str) ;
2416         //buffer_stream_message (mIDE, str) ;
2417         sprintf (str, "Your output file has been written to the following location:\n\n"
2418                       "  %s\n\n"
2419                       "Press F1 to learn more about how to control where files are written.",
2420                       ofn.c_str ()) ;
2421         FeatureNotify ("OutputFileLocation", "POV-Ray - Output File Notification", str, "Output_File_Name", false) ;
2422         PutHKCU("LastRender", "OutputFile", ofn.c_str ()) ;
2423       }
2424       else
2425       {
2426         if (!running_benchmark)
2427         {
2428             FeatureNotify ("OutputFileOff",
2429                            "POV-Ray - No Output File",
2430                            "A render has completed but file output was turned off. No file "
2431                            "was written.\n\nPress F1 for help on output file control.",
2432                            "Output_To_File",
2433                            false) ;
2434         }
2435       }
2436     }
2437   }
2438   else
2439   {
2440     if (ErrorNotified == false && ErrorMessage.empty() == false)
2441       say_status_message (StatusMessage, ErrorMessage.c_str()) ;
2442     else if (stop_rendering)
2443       say_status_message (StatusMessage, "Render cancelled by user") ;
2444     else
2445       say_status_message (StatusMessage, "Render failed") ;
2446     if (ErrorFilename.empty() == false)
2447       EditShowParseError (ErrorFilename.c_str(), ErrorMessage.c_str(), ErrorLine, ErrorCol) ;
2448     if (stop_rendering)
2449     {
2450       if (render_error_sound_enabled)
2451       {
2452         PlaySound (render_error_sound, NULL, SND_ASYNC | SND_NODEFAULT) ;
2453         if (!running_demo && !demo_mode && !benchmark_mode)
2454           FeatureNotify ("RenderErrorSound",
2455                         "POV-Ray - Render Stopped Sound",
2456                         "You can change the sound played upon render errors/cancellation "
2457                         "from the Render Menu.",
2458                         "sounds", false) ;
2459       }
2460     }
2461     else
2462     {
2463       if (parse_error_sound_enabled)
2464       {
2465         PlaySound (parse_error_sound, NULL, SND_NOWAIT | SND_ASYNC | SND_NODEFAULT) ;
2466         if (!running_demo && !demo_mode && !benchmark_mode)
2467           FeatureNotify ("ParserErrorSound",
2468                         "POV-Ray - Parse Error Sound",
2469                         "You can change the sound played upon parse errors "
2470                         "from the Render Menu.\n\n"
2471                         "Click Help for more information.",
2472                         "sounds", false) ;
2473       }
2474     }
2475   }
2476 
2477   // update the mapping of included files to source files
2478   const std::set<string>& rf = Session.GetReadFiles();
2479   for (std::set<string>::const_iterator it = rf.begin(); it != rf.end(); it++)
2480   {
2481     if (_stricmp(it->c_str(), InputFileName.c_str()) == 0)
2482       continue;
2483     if (is_non_primary_file(it->c_str()))
2484     {
2485       FileType ft = get_file_type(it->c_str());
2486       if (ft < fileFirstImageType || ft > fileLastImageType)
2487       {
2488         std::pair<std::map<string, string>::iterator, bool> result = IncludeToSourceMap.insert(std::pair<string, string> (*it, InputFileName));
2489         if (result.second == false)
2490           result.first->second = InputFileName;
2491       }
2492     }
2493   }
2494 }
2495 
ofn_hook_fn(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)2496 UINT WINAPI ofn_hook_fn (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2497 {
2498   switch (message)
2499   {
2500     case WM_INITDIALOG :
2501          SetupExplorerDialog (hwnd) ;
2502          break ;
2503   }
2504   return (false) ;
2505 }
2506 
init_ofn(OPENFILENAME * ofn,HWND hWnd,char * title,char * name,int maxlen,char * lastPath,char * defaultExt)2507 void init_ofn (OPENFILENAME *ofn, HWND hWnd, char *title, char *name, int maxlen, char *lastPath, char *defaultExt)
2508 {
2509   ofn->lStructSize = sizeof (OPENFILENAME) ;
2510   ofn->hwndOwner = hWnd ;
2511   ofn->hInstance = hInstance ;
2512   ofn->lpstrCustomFilter = NULL ;
2513   ofn->nMaxCustFilter = 0 ;
2514   ofn->nFilterIndex = 1 ;
2515   ofn->lpstrTitle = title ;
2516   ofn->lpstrFile = name ;
2517   ofn->nMaxFile = maxlen ;
2518   ofn->lpstrFileTitle = NULL ;
2519   ofn->nMaxFileTitle = 0 ;
2520   ofn->lpstrInitialDir = lastPath ;
2521   ofn->Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR ;
2522   if (IsW95UserInterface)
2523     ofn->Flags |= OFN_EXPLORER ;
2524   ofn->nFileOffset = 0 ;
2525   ofn->nFileExtension = 0 ;
2526   ofn->lpstrDefExt = defaultExt ;
2527   ofn->lCustData = 0L ;
2528   ofn->lpfnHook = NULL ;
2529   ofn->lpTemplateName = NULL ;
2530 }
2531 
file_open(HWND hWnd)2532 char *file_open (HWND hWnd)
2533 {
2534   int           result ;
2535   OPENFILENAME  ofnTemp ;
2536   static char   name [_MAX_PATH] ;
2537 
2538   strcpy (name, lastRenderName) ;
2539   validatePath (lastRenderPath) ;
2540   init_ofn (&ofnTemp, hWnd, "Render File", name, sizeof (name), lastRenderPath, "pov") ;
2541   ofnTemp.lpstrFilter = "POV source and INI (*.pov;*.ini)\0*.pov;*.ini\0POV files (*.pov)\0*.pov\0INI files (*.ini)\0*.ini\0Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0" ;
2542   if ((result = GetOpenFileName (&ofnTemp)) != 0)
2543   {
2544     strcpy (lastRenderPath, name) ;
2545     // this removes the name AND the trailing '\' [which is what we want]
2546     lastRenderPath [ofnTemp.nFileOffset - 1] = '\0' ;
2547     validatePath (lastRenderPath) ;
2548     strcpy (lastRenderName, name + ofnTemp.nFileOffset) ;
2549   }
2550   return (result ? name : NULL) ;
2551 }
2552 
get_background_file(HWND hWnd)2553 char *get_background_file (HWND hWnd)
2554 {
2555   int           result ;
2556   OPENFILENAME  ofnTemp ;
2557   static char   name [_MAX_PATH] ;
2558 
2559   strcpy (name, lastBitmapName) ;
2560   validatePath (lastBitmapPath) ;
2561   init_ofn (&ofnTemp, hWnd, "Tile Bitmap File", name, sizeof (name), lastBitmapPath, "bmp") ;
2562   ofnTemp.lpstrFilter = "BMP files (*.bmp)\0*.bmp\0" ;
2563   if ((result = GetOpenFileName (&ofnTemp)) != 0)
2564   {
2565     strcpy (lastBitmapPath, name) ;
2566     lastBitmapPath [ofnTemp.nFileOffset - 1] = '\0' ;
2567     strcpy (lastBitmapName, name + ofnTemp.nFileOffset) ;
2568   }
2569   return (result ? name : NULL) ;
2570 }
2571 
get_font(void)2572 void get_font (void)
2573 {
2574   HDC         hdc ;
2575   HFONT       hfont ;
2576   HFONT       hfontOld ;
2577   LOGFONT     lf ;
2578   CHOOSEFONT  cf ;
2579   TEXTMETRIC  tm ;
2580 
2581   hdc = GetDC (message_window) ;
2582   memset(&cf, 0, sizeof (CHOOSEFONT)) ;
2583   cf.lStructSize = sizeof (CHOOSEFONT) ;
2584   cf.hwndOwner = main_window ;
2585   cf.lpLogFont = &lf ;
2586   cf.Flags = CF_SCREENFONTS | CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT ;
2587   cf.nFontType = SCREEN_FONTTYPE ;
2588   get_logfont (hdc, &lf) ;
2589   if (ChooseFont (&cf))
2590   {
2591     if ((hfont = CreateFontIndirect (&lf)) == NULL)
2592     {
2593       PovMessageBox ("Failed to create message font", "Cannot change to selected font") ;
2594       ReleaseDC (message_window, hdc) ;
2595       return ;
2596     }
2597     hfontOld = (HFONT)SelectObject (hdc, hfont) ;
2598     GetTextMetrics (hdc, &tm) ;
2599     message_xchar = tm.tmAveCharWidth ;
2600     message_ychar = tm.tmHeight + tm.tmExternalLeading ;
2601     SelectObject (hdc, hfontOld) ;
2602     DeleteObject (message_font) ;
2603     message_font = hfont ;
2604     PovInvalidateRect (message_window, NULL, true) ;
2605     message_font_size = -MulDiv (lf.lfHeight, 72, GetDeviceCaps (hdc, LOGPIXELSY)) ;
2606     message_font_weight = lf.lfWeight ;
2607     strncpy (message_font_name, lf.lfFaceName, sizeof (message_font_name) - 1) ;
2608   }
2609   ReleaseDC (message_window, hdc) ;
2610 }
2611 
DragFunction(HDROP handle)2612 void DragFunction (HDROP handle)
2613 {
2614   int         cFiles ;
2615   int         i ;
2616   char        szFile [_MAX_PATH] ;
2617   HDIB        hDIB ;
2618   bool        calc = 0 ;
2619   BITMAP      bm ;
2620 
2621   cFiles = DragQueryFile (handle, -1, NULL, 0) ;
2622   if (rendering)
2623     message_printf ("\n") ;
2624   for (i = 0 ; i < cFiles ; i++)
2625   {
2626     DragQueryFile (handle, i, szFile, sizeof (szFile)) ;
2627     switch (get_file_type (szFile))
2628     {
2629       case filePOV :
2630       case fileINI :
2631       case fileINC :
2632            if (!use_editors || !drop_to_editor)
2633              break ;
2634            if ((EditGetFlags () & EDIT_CAN_OPEN) == 0)
2635            {
2636              say_status_message (StatusMessage, "Cannot open dropped file - max editor count reached") ;
2637              message_printf ("Cannot open dropped file - max editor count reached\n") ;
2638            }
2639            else
2640              EditOpenFile (szFile) ;
2641            continue ;
2642 
2643       case fileBMP :
2644            if (screen_depth < 8)
2645            {
2646              PovMessageBox ("Tiled bitmaps not supported in this color depth", "File ignored") ;
2647              continue ;
2648            }
2649            if ((hDIB = LoadDIB (szFile)) != NULL)
2650            {
2651              strcpy (background_file, szFile) ;
2652              DeleteObject (hBmpBackground) ;
2653              hBmpBackground = DIBToBitmap (hDIB, hPalApp) ;
2654              DeleteObject (hDIB) ;
2655              GetObject (hBmpBackground, sizeof (BITMAP), (LPSTR) &bm) ;
2656              background_width = bm.bmWidth ;
2657              background_height = bm.bmHeight ;
2658              tile_background = true ;
2659              PovInvalidateRect (message_window, NULL, true) ;
2660            }
2661            else
2662              PovMessageBox ("Failed to load bitmap file", "Error") ;
2663            continue ;
2664 
2665       default :
2666            if (!ExternalDragFunction (szFile, dfRealDrop))
2667            {
2668              if (!use_editors || !drop_to_editor)
2669              {
2670                say_status_message (StatusMessage, "Dropped file ignored (must be .POV, .INC, or .INI if destination is renderer)") ;
2671                wrapped_printf ("Dropped file '%s' ignored (must be .POV, .INC, or .INI if destination is renderer).", szFile) ;
2672              }
2673              else
2674              {
2675                if ((EditGetFlags () & EDIT_CAN_OPEN) == 0)
2676                {
2677                  say_status_message (StatusMessage, "Cannot open dropped file - max editor count reached") ;
2678                  message_printf ("Cannot open dropped file - max editor count reached\n") ;
2679                }
2680                else
2681                  EditOpenFile (szFile) ;
2682              }
2683            }
2684            continue ;
2685     }
2686     if (queued_file_count < MAX_QUEUE)
2687     {
2688       strcpy (queued_files [queued_file_count++], szFile) ;
2689       wrapped_printf ("File '%s' dropped as queue entry %d.", szFile, queued_file_count) ;
2690     }
2691     else
2692       wrapped_printf ("render queue full ; file '%s' ignored.", szFile) ;
2693   }
2694   if (rendering)
2695     message_printf ("\n") ;
2696   DragFinish (handle) ;
2697   update_queue_status (true) ;
2698   if (calc)
2699     CalculateClientWindows (true) ;
2700   FeatureNotify ("DropFiles",
2701                  "POV-Ray - Drag and Drop",
2702                  "POV-Ray can do one of several things when you drop files onto it, "
2703                  "depending on the state of the 'Drop to Editor' option and the type "
2704                  "of file dropped. For example if the file is a .POV or .INI you can "
2705                  "chose whether POV-Ray opens it or renders it.\n\nPress F1 for more "
2706                  "information.",
2707                  "drag and drop",
2708                  true) ;
2709 }
2710 
WIN_Debug_Log(unsigned int from,const char * msg)2711 void WIN_Debug_Log (unsigned int from, const char *msg)
2712 {
2713   if (debugging)
2714     OutputDebugString (msg) ;
2715 }
2716 
2717 #if POV_RAY_IS_OFFICIAL != 1
WIN_PrintOtherCredits(void)2718 void WIN_PrintOtherCredits (void)
2719 {
2720   char        *s = DISTRIBUTION_MESSAGE_2 ;
2721 
2722   while (*s == ' ' || *s == '\t')
2723     s++ ;
2724   message_printf ("This is an UNSUPPORTED UNOFFICIAL COMPILE by %s.\n", s) ;
2725 }
2726 #endif
2727 
PovMessageBox(const char * message,char * title)2728 void PovMessageBox (const char *message, char *title)
2729 {
2730   MessageBox (main_window, message, title, MB_ICONEXCLAMATION) ;
2731 }
2732 
detect_graphics_config(void)2733 void detect_graphics_config (void)
2734 {
2735   HDC   hdc ;
2736 
2737   hdc = GetDC (NULL) ;
2738   screen_depth = GetDeviceCaps (hdc, BITSPIXEL) ;
2739   render_bitmap_depth = (GetDeviceCaps (hdc, BITSPIXEL) > 8 && renderwin_8bits == 0) ? 24 : 8 ;
2740   screen_width = GetDeviceCaps (hdc, HORZRES) ;
2741   screen_height = GetDeviceCaps (hdc, VERTRES) ;
2742   if (GetSystemMetrics (SM_CMONITORS) > 1)
2743   {
2744     screen_origin_x = GetSystemMetrics (SM_XVIRTUALSCREEN) ;
2745     screen_origin_y = GetSystemMetrics (SM_YVIRTUALSCREEN) ;
2746     virtual_screen_width = GetSystemMetrics (SM_CXVIRTUALSCREEN) ;
2747     virtual_screen_height = GetSystemMetrics (SM_CYVIRTUALSCREEN) ;
2748   }
2749   else
2750   {
2751     screen_origin_x = screen_origin_y = 0 ;
2752     virtual_screen_width = screen_width ;
2753     virtual_screen_height = screen_height ;
2754   }
2755   ReleaseDC (NULL, hdc) ;
2756 }
2757 
2758 // Clear the system palette when we start to ensure an identity palette mapping
clear_system_palette(void)2759 void clear_system_palette (void)
2760 {
2761   int         Counter ;
2762   HDC         ScreenDC ;
2763   LogPal      Palette = { 0x300, 256 } ;
2764   HPALETTE    ScreenPalette ;
2765 
2766   // Reset everything in the system palette to black
2767   for (Counter = 0 ; Counter < 256 ; Counter++)
2768   {
2769     Palette.pe [Counter].peRed = 0 ;
2770     Palette.pe [Counter].peGreen = 0 ;
2771     Palette.pe [Counter].peBlue = 0 ;
2772     Palette.pe [Counter].peFlags = PC_NOCOLLAPSE ;
2773   }
2774 
2775   // Create, select, realize, deselect, and delete the palette
2776   ScreenDC = GetDC (NULL) ;
2777   ScreenPalette = CreatePalette ((LOGPALETTE *) &Palette) ;
2778   if (ScreenPalette)
2779   {
2780     ScreenPalette = SelectPalette (ScreenDC, ScreenPalette, false) ;
2781     RealizePalette (ScreenDC) ;
2782     ScreenPalette = SelectPalette (ScreenDC, ScreenPalette, false) ;
2783     DeleteObject (ScreenPalette) ;
2784   }
2785   ReleaseDC (NULL, ScreenDC) ;
2786 }
2787 
create_about_font(void)2788 void create_about_font (void)
2789 {
2790   LOGFONT     lf ;
2791 
2792   HDC hdc = GetDC (NULL) ;
2793   memset (&lf, 0, sizeof (LOGFONT)) ;
2794   lf.lfHeight = -12 ;
2795   lf.lfWeight = FW_REGULAR ;
2796   lf.lfPitchAndFamily = VARIABLE_PITCH ;
2797   lf.lfCharSet = DEFAULT_CHARSET ;
2798   lf.lfQuality = PROOF_QUALITY ;
2799   strcpy (lf.lfFaceName, "Trebuchet MS") ;
2800   if ((about_font = CreateFontIndirect (&lf)) == NULL)
2801   {
2802     strcpy (lf.lfFaceName, "Arial") ;
2803     about_font = CreateFontIndirect (&lf) ;
2804   }
2805   ReleaseDC (NULL, hdc) ;
2806 }
2807 
CalculateClientWindows(bool redraw)2808 void CalculateClientWindows (bool redraw)
2809 {
2810   RECT        rect ;
2811 
2812   GetClientRect (main_window, &rect) ;
2813   rect.bottom -= toolheight + statusheight ;
2814   if (!use_editors)
2815     MoveWindow (message_window, 0, toolheight, rect.right, rect.bottom, redraw) ;
2816   else
2817     SetEditorPosition (0, toolheight, rect.right, rect.bottom) ;
2818 }
2819 
2820 // handle a WM_CHAR message destined for the toolbar commandline edit control.
2821 // return true if the message is to be discarded.
handle_toolbar_cmdline(UINT wParam,UINT lParam)2822 bool handle_toolbar_cmdline (UINT wParam, UINT lParam)
2823 {
2824   if (wParam == VK_RETURN)
2825   {
2826     SendMessage (main_window, WM_COMMAND, CM_FILERENDER, 0) ;
2827     return (true) ;
2828   }
2829   if (wParam == VK_ESCAPE)
2830   {
2831     EditSetFocus () ;
2832     return (true) ;
2833   }
2834   if (wParam == 0x01) // ctrl-a
2835   {
2836     SendMessage(toolbar_cmdline, EM_SETSEL, 0, -1);
2837     return (true) ;
2838   }
2839   return (false) ;
2840 }
2841 
SetupStatusPanel(HWND hDlg)2842 void SetupStatusPanel (HWND hDlg)
2843 {
2844   int                   max = 0 ;
2845   int                   ypos = 0;
2846   char                  str [256] ;
2847   RECT                  rect ;
2848   StatusPanelItem       item ;
2849 
2850   GetWindowRect (hDlg, &rect) ;
2851   int x = rect.left ;
2852   int y = rect.top ;
2853   int width = rect.right - rect.left + 1 ;
2854   int height = rect.bottom - rect.top + 1 ;
2855   for (int id = IDC_STATUS_LABEL_FIRST ; id <= IDC_STATUS_ID_LAST ; id++)
2856   {
2857     item.id = id ;
2858     item.hwnd = GetDlgItem (hDlg, id) ;
2859     if (item.hwnd == NULL)
2860       continue ;
2861     if (id <= IDC_STATUS_DATA_LAST)
2862     {
2863       GetWindowText (item.hwnd, str, sizeof (str)) ;
2864       HDC hdc = GetDC (item.hwnd) ;
2865       HFONT hFont = (HFONT) SendMessage (item.hwnd, WM_GETFONT, 0, 0) ;
2866       HFONT oldFont = (HFONT) SelectObject (hdc, hFont) ;
2867       GetTextExtentPoint32 (hdc, str, (int) strlen (str), &item.size) ;
2868       SelectObject (hdc, oldFont) ;
2869       ReleaseDC (GetDlgItem (hDlg, id), hdc) ;
2870       if (id <= IDC_STATUS_LABEL_LAST)
2871         if (item.size.cx > max)
2872           max = item.size.cx ;
2873     }
2874     else
2875     {
2876       GetClientRect (item.hwnd, &rect) ;
2877       item.size.cx = rect.right ;
2878       item.size.cy = rect.bottom ;
2879     }
2880     StatusPanelItems [id] = item ;
2881   }
2882   for (int id = IDC_STATUS_LABEL_FIRST; id <= IDC_STATUS_LABEL_LAST ; id++)
2883   {
2884     item = StatusPanelItems [id] ;
2885     if (item.hwnd == NULL)
2886       continue ;
2887     MoveWindow (item.hwnd, 2, ypos, max + 2, item.size.cy, false) ;
2888     item = StatusPanelItems [id + IDC_STATUS_DATA_FIRST] ;
2889     MoveWindow (item.hwnd, max + 7, ypos, width - max - 8, item.size.cy, false) ;
2890     if (id >= IDC_STATUS_DATA_FIRST)
2891       SetWindowText (item.hwnd, "") ;
2892     ypos += item.size.cy ;
2893   }
2894   item = StatusPanelItems [IDC_STATUS_PROGRESS] ;
2895 
2896   if (height - ypos > 6)
2897   {
2898       // there's at least six rows available, so we show the progress bar
2899       item.size.cy = height - ypos - 1;
2900       MoveWindow (item.hwnd, 2, ypos + 1, width - 2, item.size.cy, false) ;
2901   }
2902   else
2903   {
2904       // not enough room for progress bar: hide it
2905       ShowWindow(item.hwnd, SW_HIDE);
2906   }
2907 }
2908 
SetStatusPanelItemText(int id,LPCSTR format,...)2909 void SetStatusPanelItemText (int id, LPCSTR format, ...)
2910 {
2911   char                  str [2048] ;
2912   va_list               arg_ptr ;
2913 
2914   va_start (arg_ptr, format) ;
2915   vsprintf (str, format, arg_ptr) ;
2916   va_end (arg_ptr) ;
2917   SetWindowText (StatusPanelItems [id].hwnd, str) ;
2918 }
2919 
2920 /**************************************************************************************/
2921 /*                                  WINDOW PROCEDURES                                 */
2922 /**************************************************************************************/
2923 
2924 /*
2925  * Return true if we are to return 0 to Windows, false if we are to continue.
2926  */
handle_main_command(WPARAM wParam,LPARAM lParam)2927 bool handle_main_command (WPARAM wParam, LPARAM lParam)
2928 {
2929   int         n ;
2930   char        *s ;
2931   char        filename [_MAX_PATH] ;
2932   HDIB        hDIB ;
2933   RECT        rect ;
2934   BITMAP      bm ;
2935   HBITMAP     hBMP ;
2936   CHOOSECOLOR cc ;
2937   struct stat st ;
2938   static char str [8192] ;
2939   vfeWinSession& Session(GetSession());
2940 
2941   if (process_toggles (wParam))
2942     return (true) ;
2943 
2944   if (LOWORD (wParam) >= CM_FIRSTTOOL && LOWORD (wParam) <= CM_LASTTOOL)
2945   {
2946     s = parse_tool_command (tool_commands [LOWORD (wParam) - CM_FIRSTTOOL]) ;
2947     if (GetHKCU("General", "Debug", 0))
2948       message_printf ("Tool request - in '%s', out '%s'\n", tool_commands [LOWORD (wParam) - CM_FIRSTTOOL], s) ;
2949     else
2950       execute_tool (s) ;
2951     return (true) ;
2952   }
2953 
2954   if (LOWORD (wParam) >= CM_FIRSTMENUHELP && LOWORD (wParam) <= CM_LASTMENUHELP)
2955   {
2956     menuhelp (LOWORD (wParam)) ;
2957     return (true) ;
2958   }
2959 
2960   if (LOWORD (wParam) >= CM_DUTYCYCLE_10 && LOWORD (wParam) <= CM_DUTYCYCLE_100)
2961   {
2962     PVCheckMenuRadioItem (CM_DUTYCYCLE_10, CM_DUTYCYCLE_100, LOWORD (wParam)) ;
2963     Duty_Cycle = LOWORD (wParam) - CM_DUTYCYCLE_10 ;
2964     return (true) ;
2965   }
2966 
2967 #ifdef RTR_SUPPORT
2968   if (LOWORD (wParam) >= CM_FIRSTVIDEOSOURCE && LOWORD (wParam) <= CM_LASTVIDEOSOURCE)
2969   {
2970     char          str [256] ;
2971     MENUITEMINFO  mi ;
2972 
2973     mi.cbSize = sizeof (MENUITEMINFO) ;
2974     mi.fMask = MIIM_TYPE ;
2975     mi.dwTypeData = str ;
2976     mi.cch = sizeof (str) ;
2977     if (GetMenuItemInfo(hVidcapMenu, LOWORD (wParam), false, &mi))
2978     {
2979       PVCheckMenuRadioItem (CM_FIRSTVIDEOSOURCE, CM_LASTVIDEOSOURCE, LOWORD (wParam)) ;
2980       status_printf (StatusMessage, "Selected video source '%s'", str) ;
2981       SetVideoSourceName(str);
2982     }
2983     return (true) ;
2984   }
2985 #endif
2986 
2987   if (LOWORD (wParam) >= CM_FIRSTEDITNOTIFY && LOWORD (wParam) <= CM_LASTEDITNOTIFY)
2988   {
2989     switch (LOWORD (wParam) - CM_FIRSTEDITNOTIFY)
2990     {
2991       case NotifyTabChange :
2992            if ((lParam & EDIT_MSG_SELECTED) == 0)
2993            {
2994              build_editor_menu (hMainMenu) ;
2995              PVEnableMenuItem (CM_FILESAVE, (lParam & EDIT_CURRENT_MODIFIED) ? MF_ENABLED : MF_GRAYED) ;
2996              PVEnableMenuItem (CM_FILECLOSE, MF_ENABLED) ;
2997              s = EditGetFilename(true) ;
2998              if (s != NULL && *s != '\0')
2999              {
3000                sprintf (str, rendersleep ? "POV-Ray (paused) - %s" : "POV-Ray - %s", s) ;
3001                SetCaption (str) ;
3002              }
3003              else
3004                SetCaption (rendersleep ? "POV-Ray for Windows (paused)" : "POV-Ray for Windows") ;
3005            }
3006            else
3007            {
3008              build_main_menu (hMainMenu, true) ;
3009              PVEnableMenuItem (CM_FILESAVE, MF_GRAYED) ;
3010              PVEnableMenuItem (CM_FILECLOSE, MF_GRAYED) ;
3011              SetCaption (rendersleep ? "POV-Ray for Windows (paused)" : "POV-Ray for Windows") ;
3012            }
3013            break ;
3014 
3015       case NotifyModifiedChange :
3016            PVEnableMenuItem (CM_FILESAVE, lParam ? MF_ENABLED : MF_GRAYED) ;
3017            s = EditGetFilename(true) ;
3018            if (s != NULL && *s != '\0')
3019            {
3020              sprintf (str, rendersleep ? "POV-Ray (paused) - %s" : "POV-Ray - %s", s) ;
3021              SetCaption (str) ;
3022            }
3023            else
3024              SetCaption (rendersleep ? "POV-Ray for Windows (paused)" : "POV-Ray for Windows") ;
3025            break ;
3026 
3027       case NotifyFocusSaveModified :
3028            FeatureNotify ("FocusSaveModified",
3029                           "POV-Ray - Modified Files Auto-Saved",
3030                           "Your modified files were automatically saved when you switched to another "
3031                           "application. This is necessary for the Auto-Reload feature to work. If you "
3032                           "do not want this to happen, turn auto-reload off via the Editor menu.\n\n"
3033                           "Click Help for more information.",
3034                           "auto-reload", false) ;
3035            break ;
3036 
3037       case NotifyExitRequest :
3038            handle_main_command (CM_FILEEXIT, 0) ;
3039            break ;
3040     }
3041     return (true) ;
3042   }
3043 
3044   switch (LOWORD (wParam))
3045   {
3046     case CM_HIDENEWUSERHELP :
3047          set_newuser_menus (hide_newuser_help) ;
3048          return (0) ;
3049 
3050     case CM_IO_NO_RESTRICTIONS :
3051     case CM_IO_RESTRICT_WRITE :
3052     case CM_IO_RESTRICT_READWRITE :
3053          io_restrictions = LOWORD (wParam) - CM_IO_NO_RESTRICTIONS ;
3054          PVCheckMenuRadioItem (CM_IO_NO_RESTRICTIONS, CM_IO_RESTRICT_READWRITE, LOWORD (wParam)) ;
3055          PutHKCU ("Scripting", "IO Restrictions", io_restrictions) ;
3056          SetupFrontend();
3057          return (0) ;
3058 
3059     case CM_SHOWMAINWINDOW :
3060          if (main_window_hidden)
3061          {
3062            if (ListenMode)
3063            {
3064              char *s = "POV-Ray is in network listen mode. Press OK to continue listening or "
3065                        "CANCEL to shut down and exit." ;
3066              if (MessageBox (main_window, s, "POV-Ray - Network Listen Mode", MB_OKCANCEL) == IDOK)
3067                return (0) ;
3068              TaskBarDeleteIcon (main_window, 0) ;
3069              DestroyWindow (main_window) ;
3070              return (0) ;
3071            }
3072            ShowWindow (main_window, SW_SHOW) ;
3073            ShowWindow (main_window, SW_RESTORE) ;
3074            if (RenderwinIsChild == false && HideRenderWithMain == true)
3075              if (GetRenderWindow() != NULL)
3076                GetRenderWindow()->Show();
3077            PVModifyMenu (CM_SHOWMAINWINDOW, MF_STRING, CM_SHOWMAINWINDOW, "Minimize to System &Tray\tAlt+W") ;
3078            main_window_hidden = 0 ;
3079            TaskBarDeleteIcon (main_window, 0) ;
3080          }
3081          else
3082          {
3083            if (use_taskbar)
3084            {
3085              char *s = "POV-Ray (Restore: DblClk ; Menu: Mouse Btn 2)" ;
3086              if (ListenMode)
3087                s = "POV-Ray: Network Listen Mode - DblClick for Options" ;
3088              if (TaskBarAddIcon (main_window, 0, ourIcon, s))
3089              {
3090                ShowWindow (main_window, SW_MINIMIZE) ;
3091                ShowWindow (main_window, SW_HIDE) ;
3092                if (RenderwinIsChild == false && HideRenderWithMain == true)
3093                  if (GetRenderWindow() != NULL)
3094                    GetRenderWindow()->Hide();
3095                PVModifyMenu (CM_SHOWMAINWINDOW, MF_STRING, CM_SHOWMAINWINDOW, "Restore &Main Window from System Tray") ;
3096                main_window_hidden = true ;
3097              }
3098            }
3099          }
3100          return (0) ;
3101 
3102     case CM_FILENEW :
3103          EditOpenFile (NULL) ;
3104          return (0) ;
3105 
3106     case CM_FILEOPEN :
3107          EditBrowseFile (true) ;
3108          return (0) ;
3109 
3110     case CM_FILESAVE :
3111          EditSaveFile (NULL) ;
3112          return (0) ;
3113 
3114     case CM_FILECLOSE :
3115          EditCloseFile (NULL) ;
3116          return (0) ;
3117 
3118     case CM_RENDERSLEEP :
3119          if (Session.BackendFailed())
3120            break ;
3121          if (!Session.IsPausable())
3122            break ;
3123          if (Session.Paused())
3124          {
3125            if (Session.Resume())
3126            {
3127              SetCaption ("POV-Ray for Windows") ;
3128              FlashWindow (main_window, 0) ;
3129              SleepTimeEnd = clock () ;
3130              SleepTimeTotal += SleepTimeEnd - SleepTimeStart ;
3131              say_status_message (StatusPPS, "") ;
3132              rendersleep = false ;
3133              SendMessage (toolbar_window, TB_CHECKBUTTON, (WPARAM) CM_RENDERSLEEP, 0) ;
3134            }
3135            else
3136              SendMessage (toolbar_window, TB_CHECKBUTTON, (WPARAM) CM_RENDERSLEEP, MAKELONG (1, 0)) ;
3137          }
3138          else
3139            if (Session.Pause () == false)
3140              SendMessage (toolbar_window, TB_CHECKBUTTON, (WPARAM) CM_RENDERSLEEP, 0) ;
3141          break ;
3142 
3143     case CM_DROPEDITOR :
3144     case CM_DROPRENDERER :
3145          PVCheckMenuItem (CM_DROPEDITOR, LOWORD (wParam) == CM_DROPEDITOR ? MF_CHECKED : MF_UNCHECKED) ;
3146          PVCheckMenuItem (CM_DROPRENDERER, LOWORD (wParam) == CM_DROPRENDERER ? MF_CHECKED : MF_UNCHECKED) ;
3147          drop_to_editor = LOWORD (wParam) == CM_DROPEDITOR ;
3148          break ;
3149 
3150     case CM_RENDERPRIORITY_BACKGROUND :
3151     case CM_RENDERPRIORITY_LOW :
3152     case CM_RENDERPRIORITY_NORMAL :
3153     case CM_RENDERPRIORITY_HIGH :
3154          render_priority = LOWORD (wParam) ;
3155          PVCheckMenuRadioItem (CM_RENDERPRIORITY_BACKGROUND, CM_RENDERPRIORITY_HIGH, render_priority) ;
3156          // only change process priority when the renderer is running
3157          if (rendering)
3158            set_render_priority (render_priority) ;
3159          return (true) ;
3160 
3161     case CM_COMPLETION_EXIT :
3162     case CM_COMPLETION_NOTHING :
3163     case CM_COMPLETION_MESSAGE :
3164          PVCheckMenuItem (on_completion, MF_UNCHECKED) ;
3165          on_completion = LOWORD (wParam) ;
3166          PVCheckMenuItem (on_completion, MF_CHECKED) ;
3167          return (true) ;
3168 
3169     case CM_PREVWINDOW :
3170          EditNextTab (false) ;
3171          return (true) ;
3172 
3173     case CM_NEXTWINDOW :
3174          EditNextTab (true) ;
3175          return (true) ;
3176 
3177     case CM_USETOOLBAR :
3178          if (rebar_window == NULL)
3179            return (true) ;
3180          ShowWindow (rebar_window, use_toolbar ? SW_SHOW : SW_HIDE) ;
3181          // this seems to be needed to get the rebar to redraw properly with v4.72 of comctrl32.dll.
3182          InvalidateRect (main_window, NULL, true) ;
3183          toolheight = 0 ;
3184          GetClientRect (main_window, &rect) ;
3185          SendMessage (main_window, WM_SIZE, SIZE_RESTORED, MAKELPARAM (rect.right, rect.bottom)) ;
3186          return (true) ;
3187 
3188     case CM_SINGLEINSTANCE :
3189          PutHKCU ("General", "OneInstance", one_instance) ;
3190          return (true) ;
3191 
3192     case CM_FILEEXIT :
3193          if (rendering)
3194          {
3195            if (MessageBox (main_window,
3196                            "POV-Ray is currently rendering - do you want to stop ?",
3197                            "Stop rendering ?",
3198                            MB_ICONQUESTION | MB_YESNO) == IDYES)
3199            {
3200              if (!EditCanClose (true))
3201                return (true) ;
3202              if (!quit)
3203                quit = time (NULL) ;
3204              cancel_render () ;
3205            }
3206          }
3207          else
3208          {
3209            if (!EditCanClose (true))
3210              return (true) ;
3211            DestroyWindow (main_window) ;
3212          }
3213          return (true) ;
3214 
3215     case CM_FILERENDER :
3216     case CM_STOPRENDER :
3217          if (Session.BackendFailed())
3218            return (true) ;
3219          if (!rendering)
3220          {
3221            if (EditSaveModified (NULL) == 0)
3222              return (true) ;
3223            // EDIT_MSG_SELECTED is only ever set if use_editors == true
3224            if ((EditGetFlags () & EDIT_MSG_SELECTED) == 0)
3225            {
3226              if ((s = EditGetFilename(false)) == NULL)
3227              {
3228                PovMessageBox ("No file to render in current editor tab!", "Cannot render") ;
3229                return (true) ;
3230              }
3231              n = get_file_type (s) ;
3232              if (n == filePOV || n == fileINI || !ExternalDragFunction (s, dfRenderEditor))
3233                PostMessage (main_window, EDITOR_RENDER_MESSAGE, 0, (LPARAM) s) ;
3234              return (true) ;
3235            }
3236            SetForegroundWindow (main_window) ;
3237            if (!ExternalDragFunction (source_file_name, dfRenderMessage))
3238              start_rendering (false) ;
3239          }
3240          else
3241          {
3242            if (Session.GetBackendState () >= kStopping)
3243              return (true) ;
3244            if (OkToStopRendering ())
3245            {
3246              if (rendersleep)
3247              {
3248                SleepTimeEnd = clock () ;
3249                SleepTimeTotal += SleepTimeEnd - SleepTimeStart ;
3250                rendersleep = false ;
3251              }
3252              stop_rendering = true ;
3253              cancel_render () ;
3254            }
3255          }
3256          return (true) ;
3257 
3258     case CM_SAVE_SETTINGS :
3259          PutHKCU ("General", "SaveSettingsOnExit", save_settings) ;
3260          return (true) ;
3261 
3262     case CM_DUMPPANE :
3263          dump_pane_to_clipboard () ;
3264          return (true) ;
3265 
3266     case CM_CLEARMESSAGES :
3267          clear_messages () ;
3268          PovInvalidateRect (message_window, NULL, false) ;
3269          UpdateWindow (message_window) ;
3270          return (true) ;
3271 
3272     case CM_FORCE8BITS :
3273          detect_graphics_config () ;
3274          if (hPalApp)
3275            DeleteObject (hPalApp) ;
3276          hPalApp = WinLegacyDisplay::CreatePalette (NULL, 0, render_bitmap_depth != 24) ;
3277          buffer_message (mIDE, render_bitmap_depth == 24 ? "Using 24-bit internal bitmap\n" :
3278                                                            renderwin_8bits ? "Using 8-bit dithered internal bitmap (menu setting)\n" :
3279                                                                              "Using 8-bit dithered internal bitmap (4 or 8-bit video mode)\n") ;
3280          return (true) ;
3281 
3282     case CM_RENDERABOVEMAIN :
3283          // TODO FIXME CJC
3284 #if 0
3285          // simply re-parenting doesn't seem to have the desired effect. sigh.
3286          WinDisplay *rw = GetRenderWindow();
3287          if (rw != NULL)
3288          {
3289            oldHwnd = render_window ;
3290            render_window = NULL ;
3291            ShowWindow (oldHwnd, SW_HIDE) ;
3292            SetForegroundWindow (main_window) ;
3293            DestroyWindow (oldHwnd) ;
3294            renderwin_manually_closed = false ;
3295            create_render_window (true) ;
3296            ShowWindow (render_window, SW_SHOW) ;
3297          }
3298 #endif
3299          PVEnableMenuItem (CM_RENDERHIDE, RenderwinIsChild ? MF_GRAYED : MF_ENABLED) ;
3300          PVEnableMenuItem (CM_RENDERACTIVE, RenderwinIsChild ? MF_GRAYED : MF_ENABLED) ;
3301          return (true) ;
3302 
3303     case CM_USEEDITOR :
3304          editors_enabled = !editors_enabled;
3305          PutHKCU ("General", "UseEditors", editors_enabled) ;
3306          PVCheckMenuItem (CM_USEEDITOR, editors_enabled ? MF_CHECKED : MF_UNCHECKED) ;
3307          if (editors_enabled == use_editors)
3308            return true;
3309          if (MessageBox (main_window,
3310                         "POV-Ray for Windows needs to re-start for this to take effect immediately.\n\n"
3311                         "Re-start POV-Ray ?",
3312                         "Re-start POV-Ray for Windows ?",
3313                         MB_ICONEXCLAMATION | MB_YESNO) == IDYES)
3314          {
3315            GetModuleFileName (hInstance, filename, sizeof (filename) - 1) ;
3316            if (save_settings)
3317            {
3318              SendMessage (toolbar_combobox,
3319                           CB_GETLBTEXT,
3320                           SendMessage (toolbar_combobox, CB_GETCURSEL, 0, 0),
3321                           (LPARAM) SecondaryRenderIniFileSection) ;
3322              if (restore_command_line)
3323              {
3324                strcpy (command_line, old_command_line) ;
3325                SendMessage (toolbar_cmdline, WM_SETTEXT, 0, (LPARAM) command_line) ;
3326                restore_command_line = false ;
3327              }
3328              write_INI_settings () ;
3329              EditSaveState () ;
3330            }
3331            DestroyWindow (main_window) ;
3332            execute_tool (filename) ;
3333          }
3334          return (true) ;
3335 
3336     case CM_HELPABOUT :
3337          ShowAboutBox () ;
3338          return (true) ;
3339 
3340     case CM_TOOLBARCMDLINE :
3341          if (!rendering)
3342          {
3343            SetFocus (toolbar_cmdline) ;
3344            SendMessage (toolbar_cmdline, EM_SETSEL, 0, -1) ;
3345          }
3346          return (true) ;
3347 
3348     case CM_RENDERINSERT :
3349          if (!rendering)
3350            RenderInsertMenu () ;
3351          return (true) ;
3352 
3353     case CM_COMMANDLINE :
3354          if (!rendering)
3355          {
3356            if (DialogBoxParam (hInstance,
3357                                MAKEINTRESOURCE (IDD_COMMANDLINE),
3358                                main_window,
3359                                (DLGPROC) PovCommandLineDialogProc,
3360                                (LPARAM) main_window))
3361            {
3362              if (!ExternalDragFunction (source_file_name, dfRenderCommandLine))
3363                start_rendering (false) ;
3364            }
3365          }
3366          return (true) ;
3367 
3368     case CM_TILEDBACKGROUND :
3369          PVModifyMenu (CM_TILEDBACKGROUND, MF_STRING, CM_TILEDBACKGROUND, tile_background ? "&Use Plain Background" : "&Use Tiled Background") ;
3370          if (tile_background && hBmpBackground == NULL)
3371          {
3372            if ((hBmpBackground = NonBogusLoadBitmap (hInstance, MAKEINTRESOURCE (BMP_BACKGROUND00))) != NULL)
3373            {
3374              GetObject (hBmpBackground, sizeof (BITMAP), (LPSTR) &bm) ;
3375              background_width = bm.bmWidth ;
3376              background_height = bm.bmHeight ;
3377              tile_background = true ;
3378              PovInvalidateRect (message_window, NULL, true) ;
3379            }
3380            else
3381            {
3382              tile_background = false ;
3383              // make sure this messagebox is AFTER we set tile_background to false !
3384              PovMessageBox ("Failed to load internal bitmap", "Error") ;
3385              PVModifyMenu (CM_TILEDBACKGROUND, MF_STRING, CM_TILEDBACKGROUND, "&Select Tiled Background") ;
3386              background_file [0] = '\0' ;
3387            }
3388            return (true) ;
3389          }
3390          else
3391            PovInvalidateRect (message_window, NULL, true) ;
3392          return (true) ;
3393 
3394     case CM_BACKGROUNDCOLOUR :
3395          memset (&cc, 0, sizeof (CHOOSECOLOR)) ;
3396          cc.lStructSize = sizeof (CHOOSECOLOR) ;
3397          cc.hwndOwner = main_window ;
3398          cc.rgbResult = background_colour ;
3399          cc.Flags = CC_RGBINIT | CC_FULLOPEN ;
3400          cc.lpCustColors = custom_colours ;
3401          if (ChooseColor (&cc))
3402          {
3403            background_colour = cc.rgbResult ;
3404            PovInvalidateRect (message_window, NULL, true) ;
3405          }
3406          return (true) ;
3407 
3408     case CM_BACKGROUNDBITMAP :
3409          if ((s = get_background_file (main_window)) != NULL)
3410          {
3411            if ((hDIB = LoadDIB (s)) != NULL)
3412            {
3413              strcpy (background_file, s) ;
3414              DeleteObject (hBmpBackground) ;
3415              hBmpBackground = DIBToBitmap (hDIB, hPalApp) ;
3416              DeleteObject (hDIB) ;
3417              GetObject (hBmpBackground, sizeof (BITMAP), (LPSTR) &bm) ;
3418              background_width = bm.bmWidth ;
3419              background_height = bm.bmHeight ;
3420              tile_background = true ;
3421              PVModifyMenu (CM_TILEDBACKGROUND, MF_STRING, CM_TILEDBACKGROUND, "&Select Plain Background") ;
3422              background_shade = RGB (1, 1, 1) ;
3423              PovInvalidateRect (message_window, NULL, true) ;
3424            }
3425            else
3426              PovMessageBox ("Failed to load bitmap file", "Error") ;
3427          }
3428          return (true) ;
3429 
3430     case CM_BACKGROUNDSTD + 0 :
3431     case CM_BACKGROUNDSTD + 1 :
3432     case CM_BACKGROUNDSTD + 2 :
3433     case CM_BACKGROUNDSTD + 3 :
3434     case CM_BACKGROUNDSTD + 4 :
3435     case CM_BACKGROUNDSTD + 5 :
3436     case CM_BACKGROUNDSTD + 6 :
3437     case CM_BACKGROUNDSTD + 7 :
3438     case CM_BACKGROUNDSTD + 8 :
3439     case CM_BACKGROUNDSTD + 9 :
3440          if ((hBMP = NonBogusLoadBitmap (hInstance, MAKEINTRESOURCE (BMP_BACKGROUND00 + (LOWORD (wParam) - CM_BACKGROUNDSTD)))) != NULL)
3441          {
3442            DeleteObject (hBmpBackground) ;
3443            hBmpBackground = hBMP ;
3444            if (GetObject (hBmpBackground, sizeof (BITMAP), (LPVOID) &bm) == 0)
3445            {
3446              PovMessageBox ("Failed to load internal bitmap", "Error") ;
3447              tile_background = false ;
3448              return (true) ;
3449            }
3450            background_width = bm.bmWidth ;
3451            background_height = bm.bmHeight ;
3452            background_file [0] = '0' + (char) (LOWORD (wParam) - CM_BACKGROUNDSTD) ;
3453            background_file [1] = '\0' ;
3454            switch (LOWORD (wParam))
3455            {
3456              case CM_BACKGROUNDSTD + 0 :
3457                   background_shade = RGB (1, 1, 1) ;
3458                   if (lParam != 1)
3459                     text_colours[0] = RGB (255, 255, 255) ;
3460                   break ;
3461 
3462              case CM_BACKGROUNDSTD + 1 :
3463                   background_shade = RGB (0, 0, 0) ;
3464                   if (lParam != 1)
3465                     text_colours[0] = RGB (255, 255, 255) ;
3466                   break ;
3467 
3468              case CM_BACKGROUNDSTD + 2 :
3469                   background_shade = RGB (1, 1, 1) ;
3470                   if (lParam != 1)
3471                     text_colours[0] = RGB (255, 255, 255) ;
3472                   break ;
3473 
3474              case CM_BACKGROUNDSTD + 3 :
3475                   background_shade = RGB (1, 1, 1) ;
3476                   if (lParam != 1)
3477                     text_colours[0] = RGB (255, 255, 255) ;
3478                   break ;
3479 
3480              case CM_BACKGROUNDSTD + 4 :
3481                   background_shade = RGB (1, 1, 1) ;
3482                   if (lParam != 1)
3483                     text_colours[0] = RGB (255, 255, 255) ;
3484                   break ;
3485 
3486              case CM_BACKGROUNDSTD + 5 :
3487                   background_shade = RGB (1, 1, 1) ;
3488                   if (lParam != 1)
3489                     text_colours[0] = RGB (0, 0, 0) ;
3490                   break ;
3491            }
3492            tile_background = true ;
3493            PVModifyMenu (CM_TILEDBACKGROUND, MF_STRING, CM_TILEDBACKGROUND, "&Select Plain Background") ;
3494            PovInvalidateRect (message_window, NULL, true) ;
3495          }
3496          else
3497            PovMessageBox ("Failed to load internal bitmap", "Error") ;
3498          return (true) ;
3499 
3500     case CM_TEXTCOLOUR_NORMAL :
3501     case CM_TEXTCOLOUR_WARNING :
3502     case CM_TEXTCOLOUR_ERROR :
3503          memset (&cc, 0, sizeof (CHOOSECOLOR)) ;
3504          cc.lStructSize = sizeof (CHOOSECOLOR) ;
3505          cc.hwndOwner = main_window ;
3506          cc.rgbResult = text_colours[LOWORD (wParam) - CM_TEXTCOLOUR_FIRST] ;
3507          cc.Flags = CC_RGBINIT | CC_FULLOPEN ;
3508          cc.lpCustColors = custom_colours ;
3509          if (ChooseColor (&cc))
3510          {
3511            text_colours[LOWORD (wParam) - CM_TEXTCOLOUR_FIRST] = cc.rgbResult ;
3512            PovInvalidateRect (message_window, NULL, true) ;
3513          }
3514          return (true) ;
3515 
3516     case CM_FONT :
3517          get_font () ;
3518          return (true) ;
3519 
3520     case CM_RENDERSHOW :
3521          if (GetRenderWindow() != NULL)
3522          {
3523            GetRenderWindow()->Show();
3524            PVEnableMenuItem (CM_RENDERSHOW, MF_GRAYED) ;
3525            PVEnableMenuItem (CM_RENDERCLOSE, MF_ENABLED) ;
3526          }
3527          return (true) ;
3528 
3529     case CM_RENDERCLOSE :
3530          if (GetRenderWindow() != NULL)
3531          {
3532            if (GetForegroundWindow () == GetRenderwinHandle())
3533              if (RenderwinIsChild)
3534                SetForegroundWindow (main_window) ;
3535            GetRenderWindow()->Hide();
3536            PVEnableMenuItem (CM_RENDERSHOW, MF_ENABLED) ;
3537            PVEnableMenuItem (CM_RENDERCLOSE, MF_GRAYED) ;
3538          }
3539          return (true) ;
3540 
3541     case CM_RENDERDESTROY :
3542          if (GetForegroundWindow () == (HWND) lParam)
3543            SetForegroundWindow (main_window) ;
3544          DestroyWindow ((HWND) lParam) ;
3545          return (true) ;
3546 
3547     case CM_CLEARQUEUE :
3548          queued_file_count = 0 ;
3549          update_queue_status (true) ;
3550          return (true) ;
3551 
3552     case CM_FILEQUEUE :
3553          DialogBoxParam (hInstance, MAKEINTRESOURCE (IDD_FILEQUEUE), main_window, (DLGPROC) PovFileQueueDialogProc, (LPARAM) main_window) ;
3554          return (true) ;
3555 
3556     case CM_SOURCEFILE :
3557          if (!rendering)
3558          {
3559            if ((s = file_open (main_window)) != NULL)
3560            {
3561              strcpy (source_file_name, s) ;
3562              splitpath (source_file_name, lastRenderPath, lastRenderName) ;
3563              validatePath (lastRenderPath) ;
3564              if (!ExternalDragFunction (source_file_name, dfRenderSourceFile))
3565                start_rendering (false) ;
3566            }
3567          }
3568          return (true) ;
3569 
3570     case CM_RENDERSOUNDS :
3571          hh_aklink.pszKeywords = "sounds" ;
3572          DialogBoxParam (hInstance, MAKEINTRESOURCE (IDD_SOUNDS), main_window, (DLGPROC) PovSoundsDialogProc, (LPARAM) main_window) ;
3573          return (true) ;
3574 
3575     case CM_RENDERTHREADCOUNT :
3576          hh_aklink.pszKeywords = "thread count" ; // TODO
3577          DialogBoxParam (hInstance, MAKEINTRESOURCE (IDD_THREADS), main_window, (DLGPROC) PovThreadCountDialogProc, (LPARAM) main_window) ;
3578          return (true) ;
3579 
3580     case CM_DEMO :
3581          if (!rendering && !running_demo)
3582          {
3583            if (save_demo_file (demo_file_name, demo_ini_name) != NULL)
3584            {
3585              if (!demo_mode)
3586              {
3587                running_demo = true ;
3588                if (DialogBoxParam (hInstance, MAKEINTRESOURCE (IDD_SHORTCOMMANDLINE), main_window, (DLGPROC) PovShortCommandLineDialogProc, (LPARAM) main_window))
3589                {
3590                  if (!restore_command_line)
3591                    strcpy (old_command_line, command_line) ;
3592                  restore_command_line = true ;
3593                  sprintf (command_line, "Include_Ini='%s' Input_File_Name='%s' ", demo_ini_name, demo_file_name) ;
3594                  _strupr (command_line) ;
3595                  strcat (command_line, old_command_line) ;
3596                  ignore_auto_ini = true ;
3597                  start_rendering (true) ;
3598                }
3599              }
3600              else
3601              {
3602                if (!restore_command_line)
3603                  strcpy (old_command_line, command_line) ;
3604                restore_command_line = true ;
3605                sprintf (command_line, "Include_Ini='%s' Input_File_Name='%s' ", demo_ini_name, demo_file_name) ;
3606                running_demo = true ;
3607                start_rendering (true) ;
3608              }
3609            }
3610          }
3611          return (true) ;
3612 
3613     case CM_BENCHMARK :
3614     case CM_BENCHMARKONETHREAD :
3615          if (rendering)
3616            return (0) ;
3617          if (!benchmark_mode)
3618          {
3619            n = Get_Benchmark_Version () ;
3620            hh_aklink.pszKeywords = "Run Benchmark" ;
3621            sprintf (str, "This command will run the standard POV-Ray benchmark version %x.%02x.\n", n / 256, n % 256) ;
3622            strcat (str, "This will take some time, and there will be no display or file output.\n\n") ;
3623            strcat (str, "Note that the benchmark has changed since v3.6 and cannot be compared with it.\n\n") ;
3624            if (LOWORD (wParam) == CM_BENCHMARK)
3625            {
3626              sprintf(str + strlen(str), "The benchmark will be rendered using %d threads. Continue?", ThreadCount) ;
3627              benchmark_multithread = true ;
3628            }
3629            else
3630            {
3631              strcat (str, "The benchmark will be rendered using a single thread. Continue?") ;
3632              benchmark_multithread = false ;
3633            }
3634            if (MessageBox (main_window, str, "Standard Benchmark", MB_YESNO | MB_ICONINFORMATION | MB_HELP) == IDNO)
3635              return (0) ;
3636          }
3637          GetTempPath (_MAX_PATH - 16, demo_file_name) ;
3638          appendPathSeparator(demo_file_name) ;
3639          strcpy (demo_ini_name, demo_file_name) ;
3640          strcat (demo_file_name, "POVBENCH.$$1") ;
3641          strcat (demo_ini_name, "POVBENCH.$$2") ;
3642          if (Write_Benchmark_File (demo_file_name, demo_ini_name))
3643          {
3644            running_benchmark = running_demo = true ;
3645            int threadCount = benchmark_mode || benchmark_multithread ? ThreadCount : 1 ;
3646            message_printf ("Running standard POV-Ray benchmark version %x.%02x using %d thread%s\n", n / 256, n % 256, threadCount, threadCount > 1 ? "s" : "") ;
3647            buffer_message (mDivider, "\n") ;
3648            status_printf (0, "Running standard POV-Ray benchmark version %x.%02x\n", n / 256, n % 256) ;
3649            start_rendering (true) ;
3650          }
3651          else
3652            PovMessageBox ("Failed to write temporary files", "Benchmark Failed") ;
3653          return (true) ;
3654 
3655     case CM_LOADTOOLMENU :
3656          ExternalEvent (EventLoadToolMenu, 0) ;
3657          load_tool_menu (ToolIniFileName) ;
3658          break ;
3659 
3660     case CM_HELPLOOKUP :
3661          if (GetFocus () == GetRenderwinHandle ())
3662          {
3663            hh_aklink.pszKeywords = "Render Window" ;
3664            HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ;
3665            return (true) ;
3666          }
3667          if (GetFocus () == toolbar_cmdline)
3668          {
3669            hh_aklink.pszKeywords = "Toolbar Command Line" ;
3670            HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ;
3671            return (true) ;
3672          }
3673          if (GetFocus () == toolbar_combobox)
3674          {
3675            hh_aklink.pszKeywords = "Preset Rendering Options" ;
3676            HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ;
3677            return (true) ;
3678          }
3679          if ((EditGetFlags () & EDIT_MSG_SELECTED) != 0)
3680            HtmlHelp (NULL, engineHelpPath, HH_DISPLAY_TOC, 0) ;
3681          else
3682            EditContextHelp () ;
3683          return (true) ;
3684 
3685     case CM_HELPPOVWIN :
3686          hh_aklink.pszKeywords = "welcome" ;
3687          HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ;
3688          return (true) ;
3689 
3690     case CM_HELPSCENE :
3691          hh_aklink.pszKeywords = "Scene Description Language" ;
3692          HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ;
3693          return (true) ;
3694 
3695     case CM_GOPOVRAYORG :
3696          ShellExecute (NULL, NULL, "http://www.povray.org/", NULL, NULL, SW_SHOWNORMAL) ;
3697          return (true) ;
3698 
3699     case CM_HELPBUGS :
3700          hh_aklink.pszKeywords = "Bug Reports" ;
3701          HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ;
3702          return (true) ;
3703 
3704     case CM_POVLEGAL :
3705          if (stat (engineHelpPath, &st) == 0)
3706          {
3707            hh_aklink.pszKeywords = "POV-Ray License" ;
3708            if (HtmlHelp (main_window, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink))
3709              return (true) ;
3710          }
3711          DialogBoxParam (hInstance, MAKEINTRESOURCE (IDD_VIEW), main_window, (DLGPROC) PovLegalDialogProc, (LPARAM) main_window) ;
3712          return (true) ;
3713 
3714     case CM_CHECKUPDATENOW:
3715 #if POV_RAY_IS_OFFICIAL == 1
3716          ManualUpdateCheck();
3717 #endif
3718          return true;
3719    }
3720    return (false) ;
3721 }
3722 
PovMainWndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)3723 LRESULT CALLBACK PovMainWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3724 {
3725   int                   i ;
3726   char                  *s ;
3727   char                  str [4096] ;
3728   bool                  f ;
3729   HDC                   hdc ;
3730   RECT                  rect ;
3731   POINT                 pt ;
3732   NMHDR                 *nmh ;
3733   DWORD                 result = 0 ;
3734   HPALETTE              oldPalette ;
3735   TOOLTIPTEXT           *t  ;
3736   COPYDATASTRUCT        *cd ;
3737   vfeSession&           Session (GetSession());
3738 
3739   PROCESS_MEMORY_COUNTERS memInfo;
3740 
3741   switch (message)
3742   {
3743     case WM_COPYDATA :
3744          cd = (COPYDATASTRUCT *) lParam ;
3745          if (cd->dwData == EDIT_FILE)
3746          {
3747            strncpy (str, (char *) cd->lpData, sizeof (str) - 1) ;
3748            str [sizeof (str) - 1] = '\0' ;
3749            if (EditGetFlags () & EDIT_CAN_OPEN)
3750              EditOpenFile (str) ;
3751            return (0) ;
3752          }
3753          if (cd->dwData == RENDER_FILE)
3754          {
3755            strncpy (str, (char *) cd->lpData, sizeof (str) - 1) ;
3756            str [sizeof (str) - 1] = '\0' ;
3757            if (rendering)
3758              return (0) ;
3759            strcpy (source_file_name, str) ;
3760            start_rendering (false) ;
3761            return (0) ;
3762          }
3763          return (1) ;
3764 
3765     case COPY_COMMANDLINE_MESSAGE :
3766          command_line [sizeof (command_line) - 1] = '\0' ;
3767          strncpy (command_line, (LPCSTR) lParam, sizeof (command_line) - 1) ;
3768          SendMessage (toolbar_cmdline, WM_SETTEXT, 0, (LPARAM) command_line) ;
3769          SendMessage (toolbar_cmdline, EM_SETSEL, 0, strlen (command_line)) ;
3770          SetFocus (toolbar_cmdline) ;
3771          return (true) ;
3772 
3773     case WM_HELP :
3774          // we expect that whatever routine caused the WM_HELP would have set up the keyword
3775          HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ;
3776          return (true) ;
3777 
3778     case KEYWORD_LOOKUP_MESSAGE :
3779          hh_aklink.pszKeywords = (LPCSTR) lParam ;
3780          if (strncmp (hh_aklink.pszKeywords, "oooo", 4) == 0)
3781            hh_aklink.pszKeywords = ""  ;
3782          if (strncmp (hh_aklink.pszKeywords, "//", 2) == 0)
3783            hh_aklink.pszKeywords = ""  ;
3784          HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ;
3785          return (true) ;
3786 
3787     case TASKBAR_NOTIFY_MESSAGE :
3788          if (lParam == WM_LBUTTONDBLCLK)
3789          {
3790            if (ListenMode)
3791            {
3792              char *s = "POV-Ray is in network listen mode. Press OK to continue listening or "
3793                        "CANCEL to shut down and exit." ;
3794              if (MessageBox (main_window, s, "POV-Ray - Network Listen Mode", MB_OKCANCEL | MB_SYSTEMMODAL) == IDOK)
3795                return (0) ;
3796              TaskBarDeleteIcon (main_window, 0) ;
3797              DestroyWindow (main_window) ;
3798              return (0) ;
3799            }
3800            ShowWindow (main_window, SW_SHOW) ;
3801            ShowWindow (main_window, SW_RESTORE) ;
3802            if (RenderwinIsChild == false && HideRenderWithMain == true)
3803              if (GetRenderWindow() != NULL)
3804                GetRenderWindow()->Show();
3805            PVModifyMenu (CM_SHOWMAINWINDOW, MF_STRING, CM_SHOWMAINWINDOW, "Minimize to System &Tray\tAlt+W") ;
3806            main_window_hidden = 0 ;
3807            TaskBarDeleteIcon (main_window, 0) ;
3808            return (0) ;
3809          }
3810          if (lParam == WM_RBUTTONDOWN)
3811          {
3812            if (ListenMode)
3813              return (0) ;
3814            if (hPopupMenus != NULL)
3815            {
3816              GetCursorPos (&pt) ;
3817              SetForegroundWindow (main_window) ;
3818              TrackPopupMenu (GetSubMenu (hPopupMenus, 0), TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, main_window, NULL) ;
3819              return (0) ;
3820            }
3821          }
3822          return (0) ;
3823 
3824     case WM_ENTERSIZEMOVE :
3825          if (!IsW95UserInterface)
3826            break ;
3827          resizing = true ;
3828          break ;
3829 
3830     case WM_EXITSIZEMOVE :
3831          if (!IsW95UserInterface)
3832            break ;
3833          resizing = false ;
3834          InvalidateRect (message_window, NULL, true) ;
3835          break ;
3836 
3837     case WM_SETFOCUS :
3838          // After a dialog has been displayed, Windows will give the focus
3839          // back to our main window. We need to farm the focus off to whatever
3840          // window should have it. EditSetFocus () will handle this for us.
3841          EditSetFocus () ;
3842          return (0) ;
3843 
3844     case EDITOR_RENDER_MESSAGE :
3845          if (rendering)
3846          {
3847            if (OkToStopRendering ())
3848            {
3849              stop_rendering = true ;
3850              cancel_render () ;
3851            }
3852            return (0) ;
3853          }
3854          strcpy (source_file_name, (char *) lParam) ;
3855          if (is_non_primary_file(source_file_name))
3856          {
3857            char fn[_MAX_PATH + 1];
3858 
3859            strcpy(fn, source_file_name);
3860            _strlwr(fn);
3861 
3862            // see if we have a previous decision recorded for this file.
3863            std::map<string, bool>::const_iterator altit = IncludeAlternateDecisionMap.find(fn);
3864            if (altit == IncludeAlternateDecisionMap.end() || altit->second == true)
3865            {
3866              // either there is no decision recorded, or the decision was 'yes'
3867              // in either case we need to find the alternate filename
3868              std::map<string, string>::const_iterator it = IncludeToSourceMap.find(fn);
3869              if (it != IncludeToSourceMap.end())
3870              {
3871                // we've found the alternate filename. do we need to ask the user about it?
3872                if (altit == IncludeAlternateDecisionMap.end())
3873                {
3874                  // yes we do.
3875                  switch (DialogBoxParam (hInstance, MAKEINTRESOURCE (IDD_RENDERALTERNATEFILE), main_window, (DLGPROC) RenderAlternativeFileDialogProc, (LPARAM) it->second.c_str()))
3876                  {
3877                    case IDYES:
3878                      // record the decision
3879                      IncludeAlternateDecisionMap.insert(std::pair<string, bool>(fn, true));
3880                      strcpy(source_file_name, it->second.c_str());
3881                      break;
3882 
3883                    case IDOK:
3884                      // we don't record this decision
3885                      strcpy(source_file_name, it->second.c_str());
3886                      break;
3887 
3888                    case IDNO:
3889                      // record the decision
3890                      IncludeAlternateDecisionMap.insert(std::pair<string, bool>(fn, false));
3891                      break;
3892 
3893                    case IDCANCEL:
3894                      return (0) ;
3895                  }
3896                }
3897                else
3898                  strcpy(source_file_name, it->second.c_str());
3899              }
3900            }
3901          }
3902          splitpath (source_file_name, lastRenderPath, lastRenderName) ;
3903          if (!ExternalDragFunction (source_file_name, dfRenderEditor))
3904            start_rendering (false) ;
3905          return (0) ;
3906 
3907     case CREATE_RENDERWIN_MESSAGE :
3908          if (dynamic_cast<WinDisplay *>(reinterpret_cast<WinDisplay *>(lParam)) != NULL)
3909            return (dynamic_cast<WinDisplay *>(reinterpret_cast<WinDisplay *>(lParam))->CreateRenderWindow());
3910          return (0) ;
3911 
3912     case GUIEXT_CREATE_EDITOR :
3913          if (wParam == 0)
3914          {
3915            message_printf ("External application or GUIEXT sent zero-length wParam for GUIEXT_CREATE_EDITOR\n") ;
3916            return (0) ;
3917          }
3918          if (IsBadReadPtr ((void *) lParam, wParam + 1))
3919          {
3920            message_printf ("External application or GUIEXT sent bad paramstr address for GUIEXT_CREATE_EDITOR\n") ;
3921            return (0) ;
3922          }
3923          if (((char *) lParam) [wParam] != '\0')
3924          {
3925            message_printf ("External application or GUIEXT sent non-NULL terminated paramstr for GUIEXT_CREATE_EDITOR\n") ;
3926            return (0) ;
3927          }
3928          return (EditExternalOpenFile ((char *) lParam)) ;
3929 
3930     case WM_NOTIFY :
3931          nmh = (NMHDR *) lParam ;
3932          if (nmh->hwndFrom == tab_window)
3933          {
3934            EditPassOnMessage (hwnd, message, wParam, lParam, &result) ;
3935            break ;
3936          }
3937          if (nmh->hwndFrom == rebar_window)
3938          {
3939            switch (nmh->code)
3940            {
3941              case RBN_HEIGHTCHANGE :
3942                   if (!use_toolbar)
3943                     break ;
3944                   GetClientRect (rebar_window, &rect) ;
3945 
3946                   // under XP with comctrl v6 it has been noticed that this event will occur
3947                   // when the main window is minimized, before the parent's WM_SIZE message
3948                   // is received, and that the return value from GetClientRect () seems to
3949                   // be rather strange (e.g. 0,0,202,0 where the actual height is about 75.)
3950                   if (rect.right == rect.left)
3951                     break ;
3952 
3953                   toolheight = rect.bottom ;
3954                   CalculateClientWindows (true) ;
3955 
3956                   // need this due to an issue with Windows 95
3957                   if (top_message_row)
3958                   {
3959                     ShowScrollBar (message_window, SB_VERT, false) ;
3960                     ShowScrollBar (message_window, SB_VERT, true) ;
3961                   }
3962                   if (need_hscroll ())
3963                   {
3964                     ShowScrollBar (message_window, SB_HORZ, false) ;
3965                     ShowScrollBar (message_window, SB_HORZ, true) ;
3966                   }
3967                   break ;
3968            }
3969            break ;
3970          }
3971          if (nmh->hwndFrom == StatusTooltip)
3972          {
3973            if (HandleStatusTooltip(nmh))
3974              return 0;
3975            break;
3976          }
3977          switch (nmh->code)
3978          {
3979            case TTN_NEEDTEXT :
3980                 t = (TOOLTIPTEXT *) lParam ;
3981                 if (use_tooltips == 0)
3982                 {
3983                   t->lpszText = NULL ;
3984                   t->hinst = 0 ;
3985                   break ;
3986                 }
3987                 t->hinst = hInstance ;
3988                 t->lpszText = MAKEINTRESOURCE (t->hdr.idFrom) ;
3989                 return (0) ;
3990          }
3991          break ;
3992 
3993     case RENDER_MESSAGE :
3994          s = getCommandLine () ;
3995          if (rendering && (strlen (s) || wParam))
3996          {
3997            PovMessageBox ("Cannot accept new command - already rendering", "Warning") ;
3998            return (0) ;
3999          }
4000          if (main_window_hidden)
4001          {
4002            ShowWindow (main_window, SW_SHOW) ;
4003            ShowWindow (main_window, SW_RESTORE) ;
4004            if (RenderwinIsChild == false && HideRenderWithMain == true)
4005              if (GetRenderWindow() != NULL)
4006                GetRenderWindow()->Show();
4007            PVModifyMenu (CM_SHOWMAINWINDOW, MF_STRING, CM_SHOWMAINWINDOW, "Minimize to System &Tray\tAlt+W") ;
4008            main_window_hidden = 0 ;
4009            TaskBarDeleteIcon (main_window, 0) ;
4010            return (0) ;
4011          }
4012          if (wParam == 0)
4013          {
4014            if (strlen (s) == 0)
4015              return (0) ;
4016            if (!restore_command_line)
4017              strcpy (old_command_line, command_line) ;
4018            restore_command_line = true ;
4019            strcpy (command_line, s) ;
4020            start_rendering (true) ;
4021            strcpy (command_line, old_command_line) ;
4022            SendMessage (toolbar_cmdline, WM_SETTEXT, 0, (LPARAM) command_line) ;
4023            restore_command_line = false ;
4024          }
4025          else
4026            handle_main_command (CM_DEMO, 0) ;
4027          return (0) ;
4028 
4029     case WM_CREATE :
4030          main_window = hwnd ;
4031          hMainMenu = CreateMenu () ;
4032          build_main_menu (hMainMenu, false) ;
4033          SetMenu (main_window, hMainMenu) ;
4034          break ;
4035 
4036     case WM_QUERYENDSESSION :
4037          if (rendering)
4038          {
4039            if (MessageBox (main_window, "POV-Ray is currently rendering - do you want to stop ?", "Stop rendering ?", MB_ICONQUESTION | MB_YESNO) != IDYES)
4040              return (false) ;
4041            if (!EditCanClose (true))
4042              return (false) ;
4043            if (!quit)
4044              quit = time (NULL) ;
4045            cancel_render () ;
4046            return (true) ;
4047          }
4048          return (EditCanClose (true)) ;
4049 
4050     case WM_ENDSESSION :
4051          if (wParam != 0)
4052          {
4053            setRunOnce () ;
4054            if (save_settings)
4055            {
4056              SendMessage (toolbar_combobox, CB_GETLBTEXT, SendMessage (toolbar_combobox, CB_GETCURSEL, 0, 0), (LPARAM) SecondaryRenderIniFileSection) ;
4057              if (restore_command_line)
4058              {
4059                strcpy (command_line, old_command_line) ;
4060                SendMessage (toolbar_cmdline, WM_SETTEXT, 0, (LPARAM) command_line) ;
4061                restore_command_line = false ;
4062              }
4063              write_INI_settings () ;
4064              EditSaveState () ;
4065            }
4066          }
4067          break ;
4068 
4069     case WM_COMMAND :
4070          if ((HANDLE) lParam == toolbar_cmdline)
4071          {
4072            // need to use EN_CHANGE rather than EN_KILLFOCUS as the command-line dialog
4073            // will grab and possibly modify command_line before focus is lost, should it
4074            // be activated while the edit control has focus.
4075            if (HIWORD (wParam) == EN_CHANGE)
4076            {
4077              SendMessage (toolbar_cmdline, WM_GETTEXT, sizeof (command_line) - 1, (LPARAM) command_line) ;
4078              return (0) ;
4079            }
4080          }
4081          if ((HANDLE) lParam == toolbar_combobox)
4082          {
4083            if (HIWORD (wParam) == CBN_CLOSEUP)
4084            {
4085              cb_expect_selchange++ ;
4086              return (0) ;
4087            }
4088            if (HIWORD (wParam) == CBN_SELCHANGE)
4089            {
4090              i = SendMessage (toolbar_combobox, CB_GETCURSEL, 0, 0) ;
4091              if (i == SendMessage (toolbar_combobox, CB_GETCOUNT, 0, 0) - 1)
4092              {
4093                SendMessage (toolbar_combobox, CB_SETCURSEL, tb_combo_sel, 0) ;
4094                if (cb_expect_selchange)
4095                {
4096                  hh_aklink.pszKeywords = "Adding New Resolutions" ;
4097                  HtmlHelp (NULL, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink) ;
4098                }
4099              }
4100              else
4101                tb_combo_sel = i ;
4102              cb_expect_selchange = 0 ;
4103              return (0) ;
4104            }
4105          }
4106          if (EditPassOnMessage (hwnd, message, wParam, lParam, &result))
4107            return (result) ;
4108          if (ExtensionsEnabled)
4109            if (LOWORD (wParam) >= CM_FIRSTGUIEXT && LOWORD (wParam) <= CM_LASTGUIEXT)
4110              return (ExternalMenuSelect (LOWORD (wParam))) ;
4111          if (handle_main_command (wParam, lParam))
4112            return (0) ;
4113          break ;
4114 
4115     case WM_INITMENU :
4116          EditUpdateMenus ((HMENU) wParam) ;
4117          EditPassOnMessage (hwnd, message, wParam, lParam, &result) ;
4118          break ;
4119 
4120     case WM_ACTIVATEAPP :
4121          EditPassOnMessage (hwnd, message, wParam, lParam, &result) ;
4122          break ;
4123 
4124     case WM_TIMER :
4125          if (!BackendFailedFlag && Session.BackendFailed())
4126          {
4127            BackendFailedFlag = true;
4128            if (rendering)
4129            {
4130              rendering = false;
4131              update_menu_for_render (false) ;
4132              PVEnableMenuItem (CM_FILERENDER, MF_DISABLED) ;
4133              PVEnableMenuItem (CM_STOPRENDER, MF_DISABLED) ;
4134              SendMessage (toolbar_window, TB_HIDEBUTTON, (WPARAM) CM_FILERENDER, MAKELONG (0, 0)) ;
4135              SendMessage (toolbar_window, TB_HIDEBUTTON, (WPARAM) CM_STOPRENDER, MAKELONG (0, 0)) ;
4136              status_buffer [0] = '\0' ;
4137              say_status_message (StatusMessage, "Render backend Failed - please re-start POV-Ray");
4138              delay_next_status = 2500;
4139              buffer_message (mFatal, "Render backend Failed - please re-start POV-Ray\n") ;
4140              if (render_complete_sound_enabled)
4141                PlaySound (render_error_sound, NULL, SND_ASYNC | SND_NODEFAULT) ;
4142            }
4143          }
4144          if (rendering && !Session.BackendFailed() && Session.GetPercentComplete() != LastRenderPercentage)
4145          {
4146            LastRenderPercentage = Session.GetPercentComplete();
4147            if (GetRenderWindow() != NULL)
4148            {
4149              sprintf (str, "%d%% complete", LastRenderPercentage) ;
4150              GetRenderWindow()->SetCaption(str);
4151            }
4152            if (main_window_hidden)
4153            {
4154              sprintf (str, "POV-Ray [%d%% complete] (Restore: DblClk ; Menu: Mouse2)", LastRenderPercentage) ;
4155              TaskBarModifyIcon (main_window, 0, str) ;
4156            }
4157            SendMessage (StatusPanelItems [IDC_STATUS_PROGRESS].hwnd, PBM_SETPOS, (WPARAM) LastRenderPercentage, 0) ;
4158            SetCaption (NULL) ;
4159          }
4160          if (delay_next_status)
4161          {
4162            delay_next_status -= 250 ;
4163            if (delay_next_status < 0)
4164              delay_next_status = 0 ;
4165          }
4166          if (status_buffer [0] != '\0' && delay_next_status == 0)
4167          {
4168            say_status_message (StatusMessage, status_buffer) ;
4169            status_buffer [0] = '\0' ;
4170          }
4171 
4172          memInfo.cb = sizeof(memInfo);
4173          GetProcessMemoryInfo(GetCurrentProcess(), &memInfo, sizeof(memInfo));
4174          status_printf(StatusMem, "\t%uMB", (unsigned int) (memInfo.WorkingSetSize / 1048576));
4175          if (TrackMem && memInfo.WorkingSetSize > PeakMem)
4176            PeakMem = memInfo.WorkingSetSize;
4177 
4178          // NOTE: if we ever change the timer rate, we need to update the editor code too.
4179          EditPassOnMessage (hwnd, message, wParam, lParam, &result) ;
4180          if (timer_ticks++ % 4 != 3)
4181            break ;
4182          seconds++ ;
4183 
4184 #if POV_RAY_IS_OFFICIAL == 1
4185          if (seconds % 600 == 0)
4186            DoUpdateCheck () ;
4187 #endif
4188 
4189          ExternalEvent (EventTimer, seconds) ;
4190          if (MenuBarDraw)
4191          {
4192            DrawMenuBar (main_window) ;
4193            MenuBarDraw = false ;
4194          }
4195          if (!rendering)
4196          {
4197            if (auto_render)
4198            {
4199              if (queued_file_count)
4200              {
4201                queued_file_count-- ;
4202                update_queue_status (true) ;
4203                strcpy (source_file_name, queued_files [0]) ;
4204                memcpy (queued_files [0], queued_files [1], sizeof (queued_files) - sizeof (queued_files [0])) ;
4205                splitpath (source_file_name, dir, NULL) ;
4206                SetCurrentDirectory (dir) ;
4207                if (seconds < 60 && GetHKCU("Info", "Rendering", 0) != 0)
4208                {
4209                  // don't run the file if we were rendering when POV exited.
4210                  // [Rendering should only be set if there was an abnormal exit.]
4211                  PutHKCU ("Info", "Rendering", 0U) ;
4212                  message_printf ("Skipping queued file '%s' (possible abnormal exit)\n", source_file_name) ;
4213                  buffer_message (mDivider, "\n") ;
4214                }
4215                else
4216                  if (!ExternalDragFunction (source_file_name, dfRenderFileQueue))
4217                    start_rendering (false) ;
4218              }
4219            }
4220          }
4221          else
4222          {
4223            PrintRenderTimes (false, false) ;
4224            if (seconds % 10 == 0)
4225            {
4226              if (PreventSleep && !rendersleep)
4227                SetThreadExecutionState(ES_AWAYMODE_REQUIRED | ES_SYSTEM_REQUIRED);
4228              if (rendersleep)
4229                FlashWindow (main_window, true) ;
4230            }
4231          }
4232          return (0) ;
4233 
4234     case WM_PALETTECHANGED :
4235          // make sure it wasn't us who changed the palette, otherwise we can get into an infinite loop.
4236          if ((HWND) wParam == main_window)
4237            return (0) ;
4238          // FALL THROUGH to WM_QUERYNEWPALETTE
4239 
4240     case WM_QUERYNEWPALETTE :
4241          if (hPalApp)
4242          {
4243            hdc = GetDC (main_window) ;
4244            oldPalette = SelectPalette (hdc, hPalApp, false) ;
4245            f = (RealizePalette (hdc) != 0);
4246            SelectPalette (hdc, oldPalette, false) ;
4247            ReleaseDC (main_window, hdc) ;
4248            if (f)
4249            {
4250              PovInvalidateRect (hwnd, NULL, true) ;
4251              if ((EditGetFlags () & EDIT_MSG_SELECTED) == 0)
4252                PovInvalidateRect (message_window, NULL, true) ;
4253              if (GetRenderwinHandle() != NULL)
4254                PovInvalidateRect (GetRenderwinHandle(), NULL, true) ;
4255            }
4256          }
4257          return (0) ;
4258 
4259     case WM_SIZE :
4260          if (main_window_hidden)
4261          {
4262            // perhaps another process has sent us a SIZE_RESTORED or something
4263            if (GetRenderWindow() != NULL)
4264              if (RenderwinIsChild == false && HideRenderWithMain == true)
4265                GetRenderWindow()->Show();
4266            PVModifyMenu (CM_SHOWMAINWINDOW, MF_STRING, CM_SHOWMAINWINDOW, "Minimize to System &Tray\tAlt+W") ;
4267            main_window_hidden = 0 ;
4268            TaskBarDeleteIcon (main_window, 0) ;
4269          }
4270          mainwin_placement.length = sizeof (WINDOWPLACEMENT) ;
4271          GetWindowPlacement (main_window, &mainwin_placement) ;
4272          SendMessage (rebar_window, WM_SIZE, wParam, lParam) ;
4273          SendMessage (StatusWindow, WM_SIZE, wParam, lParam) ;
4274          ResizeStatusBar (StatusWindow) ;
4275          switch (wParam)
4276          {
4277            case SIZE_MINIMIZED :
4278                 SetCaption (rendersleep ? "POV-Ray for Windows (paused)" : "POV-Ray for Windows") ;
4279                 if (GetRenderWindow() != NULL)
4280                   if (RenderwinIsChild == false && HideRenderWithMain == true)
4281                     GetRenderWindow()->Hide();
4282                 ExternalEvent (EventSize, wParam) ;
4283                 return (0) ;
4284 
4285            case SIZE_RESTORED :
4286                 SendMessage (StatusWindow, WM_SIZE, wParam, lParam) ;
4287                 s = EditGetFilename(true) ;
4288                 if (s != NULL && *s != '\0')
4289                 {
4290                   sprintf (str, rendersleep ? "POV-Ray (paused) - %s" : "POV-Ray - %s", s) ;
4291                   SetCaption (str) ;
4292                 }
4293                 else
4294                   SetCaption (rendersleep ? "POV-Ray for Windows (paused)" : "POV-Ray for Windows") ;
4295                 // ***** fall through *****
4296 
4297            case SIZE_MAXIMIZED :
4298                 if (GetRenderwinHandle() != NULL)
4299                   if (RenderwinIsChild == false && HideRenderWithMain == true)
4300                     ShowWindow (GetRenderwinHandle(), MakeRenderwinActive ? SW_SHOW : SW_SHOWNA) ;
4301                 SendMessage (toolbar_window, TB_AUTOSIZE, 0, 0) ;
4302                 if (use_toolbar && rebar_window != NULL)
4303                 {
4304                   GetClientRect (rebar_window, &rect) ;
4305                   toolheight = rect.bottom ;
4306                 }
4307                 CalculateClientWindows (true) ;
4308 
4309                 // need this due to an issue with Windows 95
4310                 if (top_message_row)
4311                 {
4312                   ShowScrollBar (message_window, SB_VERT, false) ;
4313                   ShowScrollBar (message_window, SB_VERT, true) ;
4314                 }
4315                 if (need_hscroll ())
4316                 {
4317                   ShowScrollBar (message_window, SB_HORZ, false) ;
4318                   ShowScrollBar (message_window, SB_HORZ, true) ;
4319                 }
4320                 ExternalEvent (EventSize, wParam) ;
4321                 break ;
4322 
4323            case SIZE_MAXHIDE :
4324            case SIZE_MAXSHOW :
4325            default :
4326                 ExternalEvent (EventSize, wParam) ;
4327                 return (0) ;
4328          }
4329          return (0) ;
4330 
4331     case WM_MOVE :
4332          mainwin_placement.length = sizeof (WINDOWPLACEMENT) ;
4333          GetWindowPlacement (main_window, &mainwin_placement) ;
4334          ExternalEvent (EventMove, lParam) ;
4335          return (0) ;
4336 
4337     case WM_ERASEBKGND :
4338          if (IsIconic (main_window))
4339          {
4340            BitBlt ((HDC) wParam, 0, 0, 36, 36, NULL, 0, 0, BLACKNESS) ;
4341            return (1) ;
4342          }
4343          break ;
4344 
4345     case WM_DROPFILES :
4346          DragFunction ((HDROP) wParam) ;
4347          return (0) ;
4348 
4349     case WM_CHAR :
4350          switch ((char) wParam)
4351          {
4352            case 0x0f : // ctrl-o
4353                 EditBrowseFile (true) ;
4354                 return (0) ;
4355 
4356            case 0x0e : // ctrl-n (close enough to shift-ctrl-n ;)
4357                 EditOpenFile (NULL) ;
4358                 return (0) ;
4359          }
4360          if (EditPassOnMessage (hwnd, message, wParam, lParam, &result))
4361            return (0) ;
4362          break ;
4363 
4364     case WM_KEYDOWN :
4365          for (i = 0 ; key2scroll [i].wVirtkey != 0xffff ; i++)
4366          {
4367            if (wParam == key2scroll [i].wVirtkey)
4368            {
4369              SendMessage (message_window, key2scroll [i].iMessage, key2scroll [i].wRequest, 0L) ;
4370              return (0) ;
4371            }
4372          }
4373          break ;
4374 
4375     case WM_MENUSELECT :
4376          if (EditPassOnMessage (hwnd, message, wParam, lParam, &result))
4377            return (result) ;
4378          handle_menu_select (wParam, lParam) ;
4379          return (0) ;
4380 
4381     case WM_SHOWWINDOW :
4382          break ;
4383 
4384     case WM_CLOSE :
4385          if (debugging)
4386            message_printf ("Close requested, rendering is %d, quit is %u\n", rendering, quit) ;
4387          if (rendering && !quit)
4388          {
4389            if (MessageBox (main_window,
4390                            "POV-Ray is currently rendering - do you want to stop ?",
4391                            "Stop rendering",
4392                            MB_ICONQUESTION | MB_YESNO) == IDNO)
4393            {
4394              if (debugging)
4395                message_printf ("User tells us we can't close\n") ;
4396              return (0) ;
4397            }
4398          }
4399          if (!EditCanClose (true))
4400          {
4401            if (debugging)
4402              message_printf ("Editor tells us we can't close\n") ;
4403            return (0) ;
4404          }
4405          ExternalEvent (EventClose, 0) ;
4406          if (timer_id != 0)
4407            KillTimer (main_window, timer_id) ;
4408          DragAcceptFiles (main_window, false) ;
4409          if (!rendering || quit)
4410          {
4411            DestroyWindow (main_window) ;
4412          }
4413          else
4414          {
4415            if (!quit)
4416              quit = time (NULL) ;
4417            cancel_render () ;
4418          }
4419          return (0) ;
4420 
4421     case WM_DESTROY :
4422          if (debugging)
4423            message_printf ("Destroy requested, rendering is %d, quit is %u\n", rendering, quit) ;
4424          if (!quit)
4425          {
4426            quit = time (NULL) ;
4427            if (rendering)
4428              cancel_render () ;
4429          }
4430          ExternalEvent (EventDestroy, 0) ;
4431          if (save_settings)
4432          {
4433            SendMessage (toolbar_combobox, CB_GETLBTEXT, SendMessage (toolbar_combobox, CB_GETCURSEL, 0, 0), (LPARAM) SecondaryRenderIniFileSection) ;
4434            if (restore_command_line)
4435            {
4436              strcpy (command_line, old_command_line) ;
4437              SendMessage (toolbar_cmdline, WM_SETTEXT, 0, (LPARAM) command_line) ;
4438              restore_command_line = false ;
4439            }
4440            write_INI_settings () ;
4441            EditSaveState () ;
4442          }
4443          PostQuitMessage (0) ;
4444          return (0) ;
4445   }
4446 
4447   return (DefWindowProc (hwnd, message, wParam, lParam)) ;
4448 }
4449 
PovMessageWndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)4450 LRESULT CALLBACK PovMessageWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4451 {
4452   int                   nhs ;
4453   int                   msg ;
4454   int                   mousewheel ;
4455   HDC                   hdc ;
4456   RECT                  rect ;
4457   POINT                 pt ;
4458   PAINTSTRUCT           ps ;
4459   static bool           captured = false ;
4460   static POINT          mbdownPoint ;
4461 
4462   switch (message)
4463   {
4464     case WM_MOUSEWHEEL :
4465          mousewheel = (short) (wParam >> 16) / WHEEL_DELTA ;
4466          if ((LOWORD (wParam) & (MK_MBUTTON | MK_CONTROL)) == 0)
4467          {
4468            msg = mousewheel < 0 ? SB_LINEDOWN : SB_LINEUP ;
4469            mousewheel *= 3 ;
4470          }
4471          else
4472            msg = mousewheel < 0 ? SB_PAGEDOWN : SB_PAGEUP ;
4473          mousewheel = abs (mousewheel) ;
4474          while (mousewheel--)
4475            PovMessageWndProc (hwnd, WM_VSCROLL, msg, 0) ;
4476          return (0) ;
4477 
4478     case WM_KEYDOWN :
4479          PostMessage (main_window, message, wParam, lParam) ;
4480          return (0) ;
4481 
4482     case WM_LBUTTONDOWN :
4483          SetCapture (hwnd) ;
4484          captured = true ;
4485          GetCursorPos (&mbdownPoint) ;
4486          return (0) ;
4487 
4488     case WM_LBUTTONUP :
4489          if (!captured)
4490            return (0) ;
4491          ReleaseCapture () ;
4492          captured = false ;
4493          GetCursorPos (&pt) ;
4494          GetWindowRect (hwnd, &rect) ;
4495          if (pt.x < rect.left || pt.y < rect.top || pt.x > rect.right || pt.y > rect.bottom)
4496            return (0) ;
4497          if (abs (mbdownPoint.x - pt.x) > 3 || abs (mbdownPoint.y - pt.y) > 3)
4498          {
4499            hh_aklink.pszKeywords = "text streams" ;
4500            MessageBox (hwnd,
4501                        "You may use the Edit menu to copy the contents of this message pane to the clipboard\n\n"
4502                        "Press Help to learn how to direct the POV-Ray text output streams to a file",
4503                        "Text Selection Not Supported In This Window",
4504                        MB_OK | MB_ICONINFORMATION | MB_HELP) ;
4505          }
4506          return (0) ;
4507 
4508     case WM_RBUTTONDOWN :
4509          if (hPopupMenus != NULL)
4510          {
4511            pt.x = LOWORD (lParam) ;
4512            pt.y = HIWORD (lParam) ;
4513            ClientToScreen (hwnd, &pt) ;
4514            TrackPopupMenu (GetSubMenu (hPopupMenus, 0),
4515                            TPM_LEFTALIGN | TPM_RIGHTBUTTON,
4516                            pt.x,
4517                            pt.y,
4518                            0,
4519                            main_window,
4520                            NULL) ;
4521          }
4522          return (0) ;
4523 
4524     case WM_ERASEBKGND :
4525          return (1) ;
4526 
4527     case WM_PAINT :
4528          hdc = BeginPaint (hwnd, &ps) ;
4529          if (hPalApp)
4530          {
4531            SelectPalette (hdc, hPalApp, false) ;
4532            RealizePalette (hdc) ;
4533          }
4534          paint_display_window (hdc) ;
4535          EndPaint (hwnd, &ps) ;
4536          return (0) ;
4537 
4538     case WM_SIZE :
4539          if (message_count)
4540          {
4541            GetClientRect (hwnd, &rect) ;
4542            message_scroll_pos_x = 0 ;
4543            message_scroll_pos_y = message_count - rect.bottom / message_ychar ;
4544            if (message_scroll_pos_y < 0)
4545              message_scroll_pos_y = 0 ;
4546          }
4547          update_message_display (None) ;
4548          PovInvalidateRect (hwnd, NULL, true) ;
4549          return (0) ;
4550 
4551     case WM_VSCROLL :
4552          switch (LOWORD (wParam))
4553          {
4554            case SB_LINEDOWN :
4555                 if (message_scroll_pos_y < message_count - message_rows)
4556                 {
4557                   message_scroll_pos_y++ ;
4558                   ScrollWindow (hwnd, 0, -message_ychar, NULL, NULL) ;
4559                   update_message_display (None) ;
4560                   UpdateWindow (hwnd) ;
4561                 }
4562                 break ;
4563 
4564            case SB_LINEUP :
4565                 if (message_scroll_pos_y > 0)
4566                 {
4567                   message_scroll_pos_y-- ;
4568                   ScrollWindow (hwnd, 0, message_ychar, NULL, NULL) ;
4569                   update_message_display (None) ;
4570                   UpdateWindow (hwnd) ;
4571                 }
4572                 break ;
4573 
4574            case SB_PAGEDOWN :
4575                 if (message_scroll_pos_y < message_count - message_rows)
4576                 {
4577                   message_scroll_pos_y += message_rows ;
4578                   if (message_scroll_pos_y > message_count - message_rows)
4579                     message_scroll_pos_y = message_count - message_rows ;
4580                   PovInvalidateRect (hwnd, NULL, true) ;
4581                   update_message_display (None) ;
4582                 }
4583                 break ;
4584 
4585            case SB_PAGEUP :
4586                 if (message_scroll_pos_y > 0)
4587                 {
4588                   message_scroll_pos_y -= message_rows ;
4589                   if (message_scroll_pos_y < 0)
4590                     message_scroll_pos_y = 0 ;
4591                   PovInvalidateRect (hwnd, NULL, true) ;
4592                   update_message_display (None) ;
4593                 }
4594                 break ;
4595 
4596            case SB_THUMBPOSITION :
4597            case SB_THUMBTRACK :
4598                 message_scroll_pos_y = HIWORD (wParam) ;
4599                 PovInvalidateRect (hwnd, NULL, true) ;
4600                 update_message_display (None) ;
4601                 break ;
4602          }
4603          return (0) ;
4604 
4605     case WM_HSCROLL :
4606          nhs = need_hscroll () ;
4607          switch (LOWORD (wParam))
4608          {
4609            case SB_LINERIGHT :
4610                 if (message_scroll_pos_x < nhs)
4611                 {
4612                   message_scroll_pos_x++ ;
4613                   ScrollWindow (hwnd, -message_xchar, 0, NULL, NULL) ;
4614                   update_message_display (None) ;
4615                   UpdateWindow (hwnd) ;
4616                 }
4617                 break ;
4618 
4619            case SB_LINELEFT :
4620                 if (message_scroll_pos_x > 0)
4621                 {
4622                   message_scroll_pos_x-- ;
4623                   ScrollWindow (hwnd, message_xchar, 0, NULL, NULL) ;
4624                   update_message_display (None) ;
4625                   UpdateWindow (hwnd) ;
4626                 }
4627                 break ;
4628 
4629            case SB_PAGERIGHT :
4630                 if (message_scroll_pos_x < nhs)
4631                 {
4632                   message_scroll_pos_x += message_cols ;
4633                   if (message_scroll_pos_x > nhs)
4634                     message_scroll_pos_x = nhs ;
4635                   PovInvalidateRect (hwnd, NULL, true) ;
4636                   update_message_display (None) ;
4637                 }
4638                 break ;
4639 
4640            case SB_PAGELEFT :
4641                 if (message_scroll_pos_x > 0)
4642                 {
4643                   message_scroll_pos_x -= message_cols ;
4644                   if (message_scroll_pos_x < 0)
4645                     message_scroll_pos_x = 0 ;
4646                   PovInvalidateRect (hwnd, NULL, true) ;
4647                   update_message_display (None) ;
4648                 }
4649                 break ;
4650 
4651            case SB_THUMBPOSITION :
4652            case SB_THUMBTRACK :
4653                 message_scroll_pos_x = HIWORD (wParam) ;
4654                 PovInvalidateRect (hwnd, NULL, true) ;
4655                 update_message_display (None) ;
4656                 break ;
4657          }
4658          return (0) ;
4659   }
4660   return (DefWindowProc (hwnd, message, wParam, lParam)) ;
4661 }
4662 
PovStatusPanelDialogProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)4663 INT_PTR CALLBACK PovStatusPanelDialogProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
4664 {
4665   switch (message)
4666   {
4667     case WM_INITDIALOG :
4668          MoveWindow (hDlg, 0, 0, 204, 41, false) ;
4669          SetupStatusPanel (hDlg) ;
4670          SetStatusPanelItemText (IDC_STATUS_DATA_FRAME, "N/A") ;
4671          return (false) ;
4672   }
4673   return (false) ;
4674 }
4675 
PovAboutWndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)4676 LRESULT CALLBACK PovAboutWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4677 {
4678   int                   button;
4679   int                   offset = 0;
4680   int                   i;
4681   HDC                   hdc ;
4682   HDC                   hdcMemory ;
4683   bool                  f ;
4684   DWORD                 threadId = 0 ;
4685   DWORD                 threadParam = 0 ;
4686   POINT                 pt;
4687   HBITMAP               oldBmp ;
4688   HPALETTE              oldPalette ;
4689   PAINTSTRUCT           ps ;
4690   struct stat           st ;
4691   LPDRAWITEMSTRUCT      lpdis ;
4692   static char           *url = NULL;
4693 
4694   switch (message)
4695   {
4696     case WM_CREATE :
4697          about_showing = true ;
4698          url = NULL;
4699          break ;
4700 
4701     case WM_DESTROY :
4702          about_showing = false ;
4703          EnableWindow (main_window, TRUE) ;
4704          DeleteObject (hBmpAbout) ;
4705          if (about_palette)
4706          {
4707            DeleteObject (about_palette) ;
4708            about_palette = NULL ;
4709          }
4710          hBmpAbout = NULL ;
4711          break ;
4712 
4713     case WM_MOUSEMOVE:
4714          pt.x = LOWORD (lParam);
4715          pt.y = HIWORD (lParam);
4716          for (i = 0; i < NUM_ABOUT_LINKS; i++)
4717          {
4718            if (PtInRect(AboutLinks + i, pt))
4719            {
4720              SetCursor(LoadCursor(NULL, IDC_HAND));
4721              url = AboutURLs[i];
4722              return 0;
4723            }
4724          }
4725          SetCursor(LoadCursor(NULL, IDC_ARROW));
4726          url = NULL;
4727          return 0;
4728 
4729     case WM_SETCURSOR:
4730          return 1;
4731 
4732     case WM_LBUTTONUP:
4733          if (url != NULL)
4734          {
4735            SetCursor(LoadCursor(NULL, IDC_WAIT)); // will get changed on next mouse move
4736            ShellExecute (NULL, NULL, url, NULL, NULL, SW_SHOWNORMAL) ;
4737          }
4738          return (0) ;
4739 
4740     case WM_COMMAND :
4741          if (HIWORD (wParam) != BN_CLICKED)
4742            return (false) ;
4743          for (button = 0 ; button < 3 ; button++)
4744            if (about_buttons [button] == (HWND) lParam)
4745              break ;
4746          if (button == 3)
4747            break ;
4748          switch (button)
4749          {
4750            case 0 :
4751                 // if help file is missing or something, default to internal viewer
4752                 if (stat (engineHelpPath, &st) == 0)
4753                 {
4754                   hh_aklink.pszKeywords = "POV-Ray License" ;
4755                   if (HtmlHelp (main_window, engineHelpPath, HH_KEYWORD_LOOKUP, (DWORD_PTR) &hh_aklink))
4756                     return (0) ;
4757                 }
4758                 DialogBoxParam (hInstance, MAKEINTRESOURCE (IDD_VIEW), main_window, (DLGPROC) PovLegalDialogProc, (LPARAM) main_window) ;
4759                 break ;
4760 
4761            case 1 :
4762                 save_povlegal () ;
4763                 break ;
4764 
4765            case 2 :
4766                 about_showing = false ;
4767                 EnableWindow (main_window, TRUE) ;
4768                 SetFocus (main_window) ;
4769                 DestroyWindow (hwnd) ;
4770                 break ;
4771          }
4772          return (0) ;
4773 
4774     case WM_DRAWITEM :
4775          lpdis = (LPDRAWITEMSTRUCT) lParam ;
4776          for (button = 0 ; button < 3 ; button++)
4777            if (about_buttons [button] == lpdis->hwndItem)
4778              break ;
4779          if (button == 3)
4780            return (0) ;
4781          if ((lpdis->itemState & ODS_SELECTED) != 0)
4782            offset = 400;
4783          else if (GetWindowLongPtr(lpdis->hwndItem, GWLP_USERDATA) != 0)
4784            offset = 200;
4785          hdc = lpdis->hDC ;
4786          if (about_palette)
4787            SelectPalette (hdc, about_palette, true) ;
4788          hdcMemory = CreateCompatibleDC (hdc) ;
4789          oldBmp = (HBITMAP) SelectObject (hdcMemory, hBmpAbout) ;
4790          BitBlt (hdc, 0, 0, 165, 30, hdcMemory, offset, button * 30 + about_height, SRCCOPY) ;
4791          SelectObject (hdcMemory, oldBmp) ;
4792          DeleteDC (hdcMemory) ;
4793          return (1) ;
4794 
4795     case WM_KEYDOWN :
4796          if (wParam == VK_RETURN || wParam == VK_ESCAPE || wParam == VK_SPACE)
4797          {
4798            EnableWindow (main_window, TRUE) ;
4799            SetFocus (main_window) ;
4800            DestroyWindow (hwnd) ;
4801            return (0) ;
4802          }
4803          return (0) ;
4804 
4805     case WM_PAINT :
4806          hdc = BeginPaint (hwnd, &ps) ;
4807          if (about_palette)
4808          {
4809            SelectPalette (hdc, about_palette, false) ;
4810            RealizePalette (hdc) ;
4811          }
4812          hdcMemory = CreateCompatibleDC (hdc) ;
4813          oldBmp = (HBITMAP) SelectObject (hdcMemory, hBmpAbout) ;
4814          BitBlt (hdc, 0, 0, about_width, about_height, hdcMemory, 0, 0, SRCCOPY) ;
4815          SelectObject (hdcMemory, oldBmp) ;
4816          DeleteDC (hdcMemory) ;
4817          EndPaint (hwnd, &ps) ;
4818          return (0) ;
4819 
4820     case WM_PALETTECHANGED :
4821          // make sure it wasn't us who changed the palette, otherwise we can get into an infinite loop.
4822          if ((HWND) wParam == hwnd)
4823            return (0) ;
4824          // FALL THROUGH to WM_QUERYNEWPALETTE
4825 
4826     case WM_QUERYNEWPALETTE :
4827          if (about_palette)
4828          {
4829            hdc = GetDC (hwnd) ;
4830            oldPalette = SelectPalette (hdc, about_palette, false) ;
4831            f = (RealizePalette (hdc) != 0);
4832            SelectPalette (hdc, oldPalette, false) ;
4833            ReleaseDC (hwnd, hdc) ;
4834            if (f)
4835              PovInvalidateRect (hwnd, NULL, true) ;
4836          }
4837          return (0) ;
4838   }
4839   return (DefWindowProc (hwnd, message, wParam, lParam)) ;
4840 }
4841 
PovAboutButtonWndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)4842 LRESULT CALLBACK PovAboutButtonWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4843 {
4844   TRACKMOUSEEVENT       tme;
4845 
4846   switch (message)
4847   {
4848     case WM_MOUSEMOVE:
4849          if (GetWindowLongPtr(hwnd, GWLP_USERDATA) != 0)
4850            break;
4851          tme.cbSize = sizeof(tme);
4852          tme.dwFlags = TME_LEAVE;
4853          tme.dwHoverTime = 0;
4854          tme.hwndTrack = hwnd;
4855          TrackMouseEvent(&tme);
4856          InvalidateRect (hwnd, NULL, false);
4857          SetWindowLongPtr(hwnd, GWLP_USERDATA, 1);
4858          break;
4859 
4860     case WM_MOUSELEAVE:
4861          InvalidateRect (hwnd, NULL, false);
4862          SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
4863          break;
4864 
4865     case WM_KEYDOWN:
4866          if (wParam != VK_ESCAPE)
4867            break;
4868          EnableWindow (main_window, TRUE) ;
4869          SetFocus (main_window) ;
4870          DestroyWindow (about_window) ;
4871          return (0) ;
4872   }
4873   return (CallWindowProc (about_button_wndproc, hwnd, message, wParam, lParam)) ;
4874 }
4875 
ShowAboutBox(void)4876 void ShowAboutBox (void)
4877 {
4878   int         oldMode ;
4879   MSG         msg ;
4880   HDC         hdcMemory ;
4881   char        *s = POV_RAY_VERSION COMPILER_VER SSE2_INCLUDED "." PVENGINE_VER ;
4882   SIZE        size ;
4883   HFONT       oldFont ;
4884   BITMAP      bm ;
4885   HBITMAP     oldBmp ;
4886   COLORREF    oldColour ;
4887 
4888   if ((hBmpAbout = NonBogusLoadBitmapAndPalette (hInstance, MAKEINTRESOURCE (BMP_ABOUT))) != NULL)
4889   {
4890     GetObject (hBmpAbout, sizeof (BITMAP), (LPSTR) &bm) ;
4891     about_width = bm.bmWidth ;
4892     about_height = bm.bmHeight - 180 ;
4893     about_palette = hPalBitmap ;
4894 
4895     if (about_font == NULL)
4896       create_about_font () ;
4897 
4898     hdcMemory = CreateCompatibleDC (NULL) ;
4899     oldFont = (HFONT) SelectObject (hdcMemory, about_font) ;
4900     oldMode = SetBkMode (hdcMemory, TRANSPARENT) ;
4901     oldColour = SetTextColor (hdcMemory, RGB (0x96, 0xD3, 0xFF)) ;
4902     oldBmp = (HBITMAP) SelectObject (hdcMemory, hBmpAbout) ;
4903     GetTextExtentPoint (hdcMemory, s, (int) strlen (s), &size) ;
4904     ExtTextOut (hdcMemory, 387, 14, 0, NULL, s, (int) strlen (s), NULL) ;
4905     SetTextColor (hdcMemory, oldColour) ;
4906     SetBkMode (hdcMemory, oldMode) ;
4907     SelectObject (hdcMemory, oldFont) ;
4908     SelectObject (hdcMemory, oldBmp) ;
4909     DeleteDC (hdcMemory) ;
4910 
4911     about_window = CreateWindowEx (0,//WS_EX_TOOLWINDOW,
4912                                    PovAboutWinClass,
4913                                    "POV-Ray",
4914                                    WS_POPUP,
4915                                    (screen_width - about_width) / 2,
4916                                    (screen_height - about_height) / 2,
4917                                    about_width,
4918                                    about_height,
4919                                    main_window,
4920                                    NULL,
4921                                    hInstance,
4922                                    NULL) ;
4923     for (int i = 0; i < 3; i++)
4924     {
4925       about_buttons[i] = CreateWindow ("BUTTON", "", WS_VISIBLE | WS_CHILD | BS_OWNERDRAW, i * 184 + 27, 451, 165, 30, about_window, NULL, hInstance, NULL) ;
4926       about_button_wndproc = (WNDPROC) (ULONG_PTR) SetWindowLongPtr (about_buttons[i], GWLP_WNDPROC, (ULONG_PTR) PovAboutButtonWndProc) ;
4927     }
4928     CenterWindowRelative (main_window, about_window, false, true) ;
4929     ShowWindow (about_window, SW_SHOWNORMAL) ;
4930     SetFocus (about_window) ;
4931     EnableWindow (main_window, FALSE) ;
4932     while (about_showing && GetMessage (&msg, NULL, 0, 0) != 0 && quit == 0)
4933     {
4934       if (!TranslateAccelerator (main_window, hAccelerators, &msg))
4935       {
4936         TranslateMessage (&msg) ;
4937         DispatchMessage (&msg) ;
4938       }
4939     }
4940   }
4941 }
4942 
4943 /**************************************************************************************/
4944 /*                                 END OF WINDOW PROCEDURES                           */
4945 /**************************************************************************************/
4946 
register_classes(void)4947 int register_classes (void)
4948 {
4949   WNDCLASSEX  wc ;
4950 
4951   // the parameter to RegisterClass is considered CONST, so we
4952   // can assume that the structure is not changed by the calls.
4953   wc.cbSize        = sizeof (wc) ;
4954   wc.hIconSm       = NULL ;
4955   wc.cbClsExtra    = 0 ;
4956   wc.cbWndExtra    = 0 ;
4957   wc.hInstance     = hInstance ;
4958   wc.lpszMenuName  = NULL ;
4959   wc.hbrBackground = NULL ;
4960 
4961   // Register the main window class.
4962   wc.style         = CS_BYTEALIGNCLIENT ;
4963   wc.lpfnWndProc   = PovMainWndProc ;
4964   wc.hIcon         = ourIcon ;
4965   wc.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
4966   wc.lpszClassName = PovMainWinClass ;
4967   if (RegisterClassEx (&wc) == false)
4968     return (false) ;
4969 
4970   // Register the message window class.
4971   wc.style         = CS_BYTEALIGNCLIENT ;
4972   wc.lpfnWndProc   = PovMessageWndProc ;
4973   wc.hIcon         = NULL ;
4974   wc.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
4975   wc.lpszClassName = PovMessageWinClass ;
4976   if (RegisterClassEx (&wc) == false)
4977     return (false) ;
4978 
4979   // Register the about window class.
4980   wc.style         = CS_BYTEALIGNCLIENT ;
4981   wc.lpfnWndProc   = PovAboutWndProc ;
4982   wc.hIcon         = ourIcon ;
4983   wc.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
4984   wc.lpszClassName = PovAboutWinClass ;
4985   if (RegisterClassEx (&wc) == false)
4986     return (false) ;
4987 
4988   // Register the render window classes
4989   wc.style         = CS_BYTEALIGNCLIENT ;
4990   wc.lpfnWndProc   = WinLegacyDisplay::StaticWindowProc ;
4991   wc.hIcon         = renderIcon ;
4992   wc.hCursor       = LoadCursor (NULL, IDC_CROSS) ;
4993   wc.hbrBackground = NULL ;
4994   wc.lpszClassName = PovLegacyRenderWinClass ;
4995   wc.cbWndExtra    = 8 ;
4996   if (RegisterClassEx (&wc) == false)
4997     return (false) ;
4998 
4999   return (true) ;
5000 }
5001 
cleanup_all(void)5002 void cleanup_all (void)
5003 {
5004   // TODO: nuke any render threads still running
5005   ExternalCleanupAll () ;
5006   EditUnload () ;
5007   if (use_taskbar)
5008     TaskBarDeleteIcon (main_window, 0) ;
5009   clear_messages (false) ;
5010   clear_dir_restrictions () ;
5011   DeleteCriticalSection (&critical_section) ;
5012   display_cleanup (true) ;
5013   if (hBmpBackground != NULL)
5014     DeleteObject (hBmpBackground) ;
5015   if (hBmpRendering != NULL)
5016     DeleteObject (hBmpRendering) ;
5017   if (hBmpIcon != NULL)
5018     DeleteObject (hBmpIcon) ;
5019   if (hMenuBar)
5020     DestroyMenu (hMenuBar) ;
5021   if (hMainMenu)
5022     DestroyMenu (hMainMenu) ;
5023   if (hPopupMenus)
5024     DestroyMenu (hPopupMenus) ;
5025   if (hPalApp)
5026     DeleteObject (hPalApp) ;
5027   if (message_font)
5028     DeleteObject (message_font) ;
5029   if (about_font)
5030     DeleteObject (about_font) ;
5031   if (tab_font)
5032     DeleteObject (tab_font) ;
5033   if (ourIcon)
5034     DestroyIcon (ourIcon) ;
5035   if (renderIcon)
5036     DestroyIcon (renderIcon) ;
5037 
5038   UnregisterClass (PovLegacyRenderWinClass, hInstance) ;
5039   UnregisterClass (PovMessageWinClass, hInstance) ;
5040   UnregisterClass (PovMainWinClass, hInstance) ;
5041 }
5042 
5043 #ifdef _MSC_VER
LZTimerOn(void)5044 void LZTimerOn (void)
5045 {
5046   if (!QueryPerformanceCounter ((LARGE_INTEGER *) &PerformanceCounter1))
5047     PerformanceCounter1 = 0 ;
5048 }
5049 
LZTimerOff(void)5050 void LZTimerOff (void)
5051 {
5052   if (!QueryPerformanceCounter ((LARGE_INTEGER *) &PerformanceCounter2))
5053     PerformanceCounter2 = 0 ;
5054 }
5055 
LZTimerCount(void)5056 ulong LZTimerCount (void)
5057 {
5058   if (PerformanceCounter1 == 0 || PerformanceCounter2 < PerformanceCounter1)
5059     return (0) ;
5060   return ((ulong) ((PerformanceCounter2 - PerformanceCounter1) / PerformanceScale)) ;
5061 }
5062 
LZTimerRawCount(void)5063 __int64 LZTimerRawCount (void)
5064 {
5065   if (PerformanceCounter1 == 0 || PerformanceCounter2 < PerformanceCounter1)
5066     return (0) ;
5067   return (PerformanceCounter2 - PerformanceCounter1) ;
5068 }
5069 #endif // #ifdef _MSC_VER
5070 
5071 }
5072 
newhandler(void)5073 static void __cdecl newhandler (void)
5074 {
5075   throw std::bad_alloc () ;
5076 }
5077 
5078 using namespace povwin ;
5079 
GenerateDumpMeta(bool brief)5080 void GenerateDumpMeta(bool brief)
5081 {
5082   char                  str[128];
5083   char                  *s = DumpMeta;
5084   char                  *InstalledOn ;
5085   HDC                   hdc ;
5086   HKEY                  key ;
5087   DWORD                 len;
5088   DWORD                 header = 0 ;
5089   DWORD                 n ;
5090   FILETIME              file_time ;
5091   SYSTEMTIME            system_time ;
5092   SYSTEM_INFO           sysinfo ;
5093   OSVERSIONINFO         version_info ;
5094   MEMORYSTATUSEX        mem_status ;
5095 
5096   GetNativeSystemInfo(&sysinfo) ;
5097   if (!brief)
5098   {
5099     if ((InstalledOn = GetInstallTime()) == NULL)
5100     {
5101       GetSystemTime (&system_time) ;
5102       if (SystemTimeToFileTime (&system_time, &file_time))
5103         reg_printf (true, "Software\\POV-Ray", INSTALLTIMEKEY, "%I64u", ((__int64) file_time.dwHighDateTime << 32) | file_time.dwLowDateTime) ;
5104       if ((InstalledOn = GetInstallTime ()) == NULL)
5105         InstalledOn = "Unknown" ;
5106     }
5107     s += sprintf(s, "installdate=%s\n", InstalledOn) ;
5108   }
5109   s += sprintf(s, "cpuarchitecture=%u\n", (DWORD) sysinfo.wProcessorArchitecture) ;
5110   s += sprintf(s, "numberofcpus=%u\n", sysinfo.dwNumberOfProcessors) ;
5111   s += sprintf(s, "processortype=%u\n", sysinfo.dwProcessorType) ;
5112   s += sprintf(s, "processorlevel=%u\n", (DWORD) sysinfo.wProcessorLevel) ;
5113   s += sprintf(s, "processorrevision=%u\n", (DWORD) sysinfo.wProcessorRevision) ;
5114 
5115   if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, "HARDWARE\\Description\\System\\CentralProcessor\\0", 0, KEY_READ, &key) == ERROR_SUCCESS)
5116   {
5117     len = sizeof (n) ;
5118     if (RegQueryValueEx (key, "~MHZ", 0, NULL, (BYTE *) &n, &len) == ERROR_SUCCESS)
5119       s += sprintf(s, "cpufrequency=%u\n", n) ;
5120 
5121     len = sizeof (n) ;
5122     if (RegQueryValueEx (key, "FeatureSet", 0, NULL, (BYTE *) &n, &len) == ERROR_SUCCESS)
5123       s += sprintf(s, "cpufeatureset=%u\n", n) ;
5124 
5125     len = sizeof (str) ;
5126     if (RegQueryValueEx (key, "ProcessorNameString", 0, NULL, (BYTE *) str, &len) == ERROR_SUCCESS)
5127       s += sprintf(s, "cpuname=%s\n", str) ;
5128 
5129     len = sizeof (str) ;
5130     if (RegQueryValueEx (key, "Identifier", 0, NULL, (BYTE *) str, &len) == ERROR_SUCCESS)
5131       s += sprintf(s, "cpuidentifier=%s\n", str) ;
5132 
5133     len = sizeof (str) ;
5134     if (RegQueryValueEx (key, "VendorIdentifier", 0, NULL, (BYTE *) str, &len) == ERROR_SUCCESS)
5135       s += sprintf(s, "cpuvendoridentifier=%s\n", str) ;
5136 
5137     RegCloseKey (key) ;
5138   }
5139 
5140   version_info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO) ;
5141   GetVersionEx (&version_info) ;
5142   s += sprintf(s, "osversion=%u.%u\n", version_info.dwMajorVersion, version_info.dwMinorVersion) ;
5143   s += sprintf(s, "osbuild=%u\n", version_info.dwBuildNumber) ;
5144   s += sprintf(s, "csdversion=%s\n", version_info.szCSDVersion) ;
5145 
5146   if (!brief)
5147   {
5148     hdc = GetDC (NULL) ;
5149     s += sprintf(s, "bitsperpixel=%u\n", GetDeviceCaps (hdc, BITSPIXEL)) ;
5150     s += sprintf(s, "horzres=%u\n", GetDeviceCaps (hdc, HORZRES)) ;
5151     s += sprintf(s, "vertres=%u\n", GetDeviceCaps (hdc, VERTRES)) ;
5152     ReleaseDC (NULL, hdc) ;
5153   }
5154 
5155   mem_status.dwLength = sizeof (MEMORYSTATUSEX) ;
5156   GlobalMemoryStatusEx(&mem_status) ;
5157   s += sprintf(s, "physicalmemory=%I64u\n", mem_status.ullTotalPhys) ;
5158 }
5159 
WriteDumpMeta(struct _EXCEPTION_POINTERS * ExceptionInfo,const char * filename)5160 bool WriteDumpMeta(struct _EXCEPTION_POINTERS *ExceptionInfo, const char *filename)
5161 {
5162   FILE          *f;
5163   PCONTEXT      c = ExceptionInfo->ContextRecord ;
5164   static char   fn[_MAX_PATH];
5165 
5166   strcpy(fn, filename);
5167   strcat(fn, ".metadata");
5168 
5169   if ((f = fopen(fn, "wt")) == NULL)
5170     return false;
5171   fwrite(DumpMeta, strlen(DumpMeta), 1, f);
5172   fprintf(f, "faulttype=%u\n", ExceptionInfo->ExceptionRecord->ExceptionCode);
5173 #ifdef _WIN64
5174   fprintf(f, "faultaddress=%I64u\n", ExceptionInfo->ContextRecord->Rip);
5175   fprintf(f, "faultplatform=win64\n");
5176 #else
5177   fprintf(f, "faultaddress=%u\n", ExceptionInfo->ContextRecord->Eip);
5178   fprintf(f, "faultplatform=win32\n");
5179 #endif
5180   fprintf(f, "povversion=%s\n", POV_RAY_VERSION) ;
5181   fprintf(f, "compilerversion=%s\n", COMPILER_VER) ;
5182   fprintf(f, "platformversion=%s\n", PVENGINE_VER) ;
5183   fprintf(f, "remotesession=%u\n", GetSystemMetrics(SM_REMOTESESSION)) ;
5184   fclose(f);
5185   return true;
5186 }
5187 
5188 // TODO: re-write this!!!
WriteDump(struct _EXCEPTION_POINTERS * pExceptionInfo,bool full,long timestamp)5189 char *WriteDump(struct _EXCEPTION_POINTERS *pExceptionInfo, bool full, long timestamp)
5190 {
5191   // firstly see if dbghelp.dll is around and has the function we need
5192   // look next to the EXE first, as the one in System32 might be old
5193   // (e.g. Windows 2000)
5194   HMODULE hDll = NULL;
5195   static char szDbgHelpPath[_MAX_PATH];
5196 
5197   if (GetModuleFileName(NULL, szDbgHelpPath, _MAX_PATH ))
5198   {
5199     char *pSlash  = findLastPathSeparator( szDbgHelpPath );
5200     if (pSlash)
5201     {
5202       strcpy( pSlash+1, "DBGHELP.DLL" );
5203       hDll = ::LoadLibrary( szDbgHelpPath );
5204     }
5205   }
5206 
5207   if (hDll==NULL)
5208   {
5209     // load any version we can
5210     hDll = ::LoadLibrary( "DBGHELP.DLL" );
5211   }
5212 
5213   LPCTSTR szResult = NULL;
5214 
5215   if (hDll)
5216   {
5217     MINIDUMPWRITEDUMP pDump = (MINIDUMPWRITEDUMP)::GetProcAddress( hDll, "MiniDumpWriteDump" );
5218     if (pDump)
5219     {
5220       char szScratch [_MAX_PATH];
5221       static char szDumpPath[_MAX_PATH];
5222 
5223       if (full)
5224         sprintf(szScratch, "POV-Ray-" POV_RAY_VERSION COMPILER_VER SSE2_INCLUDED "." PVENGINE_VER "-%08X.dmp", timestamp);
5225       else
5226         sprintf(szScratch, "POV-Ray-" POV_RAY_VERSION COMPILER_VER SSE2_INCLUDED "." PVENGINE_VER "-%08X.minidump", timestamp);
5227 
5228       // work out a good place for the dump file
5229       if (!GetTempPath( _MAX_PATH - 64, szDumpPath))
5230         _tcscpy( szDumpPath, "c:\\" );
5231 
5232       _tcscat( szDumpPath, szScratch );
5233 
5234       // create the file
5235       HANDLE hFile = ::CreateFile( szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
5236 
5237       if (hFile!=INVALID_HANDLE_VALUE)
5238       {
5239         _MINIDUMP_EXCEPTION_INFORMATION ExInfo;
5240 
5241         ExInfo.ThreadId = ::GetCurrentThreadId();
5242         ExInfo.ExceptionPointers = pExceptionInfo;
5243         ExInfo.ClientPointers = NULL;
5244 
5245         // write the dump
5246         BOOL bOK = pDump(GetCurrentProcess(),
5247                          GetCurrentProcessId(),
5248                          hFile,
5249                          full ? MiniDumpWithFullMemory :
5250                                 (MINIDUMP_TYPE)(MiniDumpWithDataSegs|MiniDumpWithHandleData|MiniDumpWithIndirectlyReferencedMemory), &ExInfo, NULL, NULL );
5251         ::CloseHandle(hFile);
5252         if (bOK)
5253         {
5254           if (!WriteDumpMeta(pExceptionInfo, szDumpPath))
5255           {
5256             MessageBox (main_window, "Failed to save dump metadata file", "POV-Ray for Windows", MB_OK | MB_ICONEXCLAMATION);
5257             return NULL;
5258           }
5259           return szDumpPath;
5260         }
5261         sprintf( szScratch, "Failed to save dump file to '%s' (error %d)", szDumpPath, GetLastError() );
5262         MessageBox (main_window, szScratch, "POV-Ray for Windows", MB_OK | MB_ICONEXCLAMATION);
5263         return NULL;
5264       }
5265       sprintf( szScratch, "Failed to create dump file '%s' (error %d)", szDumpPath, GetLastError() );
5266       MessageBox (main_window, szScratch, "POV-Ray for Windows", MB_OK | MB_ICONEXCLAMATION);
5267       return NULL;
5268     }
5269     MessageBox (main_window, "Sorry, DBGHELP.DLL is too old - cannot create dump.", "POV-Ray for Windows", MB_OK | MB_ICONEXCLAMATION);
5270     return NULL;
5271   }
5272   MessageBox (main_window, "Sorry, we can't locate DBGHELP.DLL - cannot create dump.", "POV-Ray for Windows", MB_OK | MB_ICONEXCLAMATION);
5273   return NULL;
5274 }
5275 
5276 #ifdef BUILD_SSE2
NoSSE2(void)5277 void NoSSE2 (void)
5278 {
5279   MessageBox (NULL,
5280               "This build of POV-Ray requires that your processor provides SSE2 support.\n"
5281               "Please use the standard non-SSE2 version of POV-Ray on this computer.",
5282               "POV-Ray for Windows",
5283               MB_ICONSTOP | MB_OK) ;
5284   exit (-1) ;
5285 }
5286 
TestSSE2(void)5287 inline int TestSSE2 (void)
5288 {
5289   __try
5290   {
5291     __asm { movapd xmm0,xmm1 }
5292   }
5293   __except(NoSSE2(),1)
5294   {
5295   }
5296   return (0) ;
5297 }
5298 #endif
5299 
InvalidParameterHandler(const wchar_t * expression,const wchar_t * function,const wchar_t * file,unsigned int line,uintptr_t pReserved)5300 void InvalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved)
5301 {
5302   throw POV_EXCEPTION(kParamErr, "Run-Time Library Invalid Parameter Handler invoked");
5303 }
5304 
WinMain(HINSTANCE hInst,HINSTANCE hPrev,LPSTR szCmdLine,int sw)5305 int PASCAL WinMain (HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
5306 {
5307 #ifdef BUILD_SSE2
5308   TestSSE2 () ;
5309 #endif
5310 
5311   int                   show_state ;
5312   int                   i ;
5313   int                   id = 0 ;
5314   int                   w, h ;
5315   char                  str [_MAX_PATH * 2] ;
5316   char                  *s = szCmdLine ;
5317   bool                  exit_loop = false ;
5318   bool                  have_cpu_info = false;
5319   unsigned              n ;
5320   MSG                   msg ;
5321   HDC                   hDC ;
5322   HDIB                  hDIB ;
5323   RECT                  rect ;
5324   HWND                  hwnd ;
5325   DWORD                 help_cookie ;
5326   DWORD                 threadId = 0 ;
5327   DWORD                 threadParam = 0 ;
5328   BITMAP                bm ;
5329   HBITMAP               hBMP ;
5330   struct stat           statbuf ;
5331   SYSTEM_INFO           sysinfo ;
5332   WINDOWPLACEMENT       placement ;
5333 
5334   // REMINDER: don't try to write to the message pane until initialise_message_display() has been called.
5335 
5336   _set_invalid_parameter_handler(InvalidParameterHandler);
5337 
5338 #ifdef _DEBUG
5339   _unlink ("c:\\temp\\povdebug.txt") ;
5340   _unlink ("c:\\temp\\povmem.txt") ;
5341 #endif
5342 
5343   GenerateDumpMeta(false);
5344   std::set_new_handler(newhandler) ;
5345   SetUnhandledExceptionFilter(ExceptionHandler);
5346 
5347   // need this now to set virtual_screen_width etc., in case we display a dialog
5348   // before the main setup (we call it again once we've read the INI file).
5349   detect_graphics_config () ;
5350 
5351   try
5352   {
5353     CreateFrontend();
5354   }
5355   catch (pov_base::Exception& e)
5356   {
5357     sprintf (str, "Failed to initialize frontend: %s", e.what()) ;
5358     MessageBox (NULL, str, "POV-Ray Critical Error", MB_ICONSTOP) ;
5359     return (1) ;
5360   }
5361 
5362   hInstance = hInst ;
5363   hMainThread = GetCurrentThread () ;
5364 
5365   GetSystemInfo (&sysinfo) ;
5366   ThreadCount = sysinfo.dwNumberOfProcessors ;
5367   NumberOfCPUs = sysinfo.dwNumberOfProcessors ;
5368 
5369   if (GetCPUCount(&NumLogicalCPUs, &NumCPUCores, &NumPhysicalCPUs) && NumLogicalCPUs > 1)
5370   {
5371     have_cpu_info = true;
5372     ThreadCount = NumLogicalCPUs ;
5373     NumberOfCPUs = NumCPUCores ;
5374   }
5375 
5376   while (*s == ' ' || *s == '\t')
5377     s++ ;
5378   if (_stricmp (s, "/install") == 0 || _strnicmp (s, "/install ", 9) == 0 || _stricmp (s, "/qinstall") == 0 || _strnicmp (s, "/qinstall ", 10) == 0)
5379   {
5380     bool quiet = s [1] == 'q' || s [1] == 'Q' ;
5381     while (*s && *s != ' ')
5382       s++ ;
5383     argv[1] = argv[2] = NULL;
5384     parse_commandline(s);
5385     return (InstallSettings (argv[1], argv[2], quiet)) ;
5386   }
5387 
5388   getHome () ;
5389   if (BinariesPath [0] == '\0')
5390   {
5391     inferHome () ;
5392     if (BinariesPath [0] == '\0')
5393     {
5394       MessageBox (NULL,
5395                   "ERROR : Cannot find Home entry in registry (and cannot infer it).\n\n"
5396                   "This entry should have been set by the installation program.\n\n"
5397                   "POV-Ray can usually infer the installation path but that requires a\n"
5398                   "standard layout of directories, which also seems to be absent.\n\n"
5399                   "If you did not install using the correct installation procedure, please\n"
5400                   "do this before running POV-Ray for Windows. You can also try running\n"
5401                   "with the '/INSTALL' or '/INSTALL <bindir> [<docdir>]' option.",
5402                   "Critical Error",
5403                   MB_ICONSTOP) ;
5404       return (1) ;
5405     }
5406   }
5407   appendPathSeparator(BinariesPath) ;
5408   if (DocumentsPath[0] == '\0')
5409   {
5410     if (SHGetFolderPath (NULL, CSIDL_MYDOCUMENTS, NULL, SHGFP_TYPE_CURRENT, DocumentsPath) != S_OK)
5411     {
5412       MessageBox (NULL,
5413                   "ERROR : Cannot find DocPath entry in registry (and cannot infer it).\n\n"
5414                   "This entry should have been set by the installation program.\n\n"
5415                   "POV-Ray can usually infer the installation path but that requires a\n"
5416                   "standard layout of directories, which also seems to be absent.\n\n"
5417                   "If you did not install using the correct installation procedure, please\n"
5418                   "do this before running POV-Ray for Windows. You can also try running\n"
5419                   "with the '/INSTALL' or '/INSTALL <bindir> <docdir>' option.",
5420                   "Critical Error",
5421                   MB_ICONSTOP) ;
5422     }
5423     strcat(DocumentsPath, "\\" REGKEY);
5424     if (!dirExists(DocumentsPath))
5425       CreateDirectory(DocumentsPath, NULL);
5426     strcat(DocumentsPath, "\\" REGVERKEY);
5427     if (!dirExists(DocumentsPath))
5428       CreateDirectory(DocumentsPath, NULL);
5429   }
5430   appendPathSeparator(DocumentsPath) ;
5431   sprintf(str, "%sini", DocumentsPath);
5432   if (!dirExists(str))
5433     CreateDirectory(str, NULL);
5434   sprintf(ToolIniFileName, "%sini\\pvtools.ini", DocumentsPath);
5435   sprintf(EngineIniFileName, "%sini\\pvengine.ini", DocumentsPath);
5436 
5437   if (checkEditKey37() == false && checkEditKey36() == true)
5438     copy36EditSettings();
5439 
5440   if (checkRegKey () == false || FreshInstall == true)
5441     if (!CloneOptions())
5442       MessageBox (NULL, "ERROR : Could not clone options - POV-Ray may not work correctly for this user.", "Critical Error", MB_ICONERROR) ;
5443 
5444 #ifdef POVRAY_IS_BETA
5445   if (FreshInstall)
5446   {
5447     // on installing a new beta, we always turn on check new version now that we no longer
5448     // implement a short timeout. the user may switch it off if they like; we will not perform
5449     // an automatic version check in this session since FreshInstall is set, in order to give
5450     // them a chance to do it.
5451     check_new_version = true;
5452     PutHKCU("General", "CheckNewVersion", true);
5453   }
5454 #endif
5455 
5456 #ifndef MAP_INI_TO_REGISTRY
5457   if (!fileExists(EngineIniFileName))
5458   {
5459     // no INI file: see if we can copy the 3.6 INI options, should they exist
5460     if (debugging)
5461       debug_output("no pvengine.ini: seeing if there is a v3.6 ini\n") ;
5462 
5463     string str(get36Home());
5464     if (str.empty() == false)
5465     {
5466       string oldINIpath = str + "ini\\pvengine.ini";
5467       if (fileExists(oldINIpath.c_str()))
5468       {
5469         if (debugging)
5470           debug_output("cloning INI file %s to %s\n", oldINIpath.c_str(), EngineIniFileName) ;
5471         cloneOldIni(str, DocumentsPath);
5472       }
5473       else
5474       {
5475         if (debugging)
5476           debug_output("creating default INI file %s\n", EngineIniFileName) ;
5477         cloneOldIni("", DocumentsPath);
5478       }
5479     }
5480     else
5481     {
5482       if (debugging)
5483         debug_output("creating default INI file %s\n", EngineIniFileName) ;
5484       cloneOldIni("", DocumentsPath);
5485     }
5486   }
5487 #endif
5488 
5489   if (homeInferred)
5490   {
5491     if (_stricmp (LastInferredHome, BinariesPath) != 0)
5492     {
5493       sprintf (str, "POV-Ray for Windows did not find the expected registry entries present.\n"
5494                     "This typically means that it has not been installed via the installation program.\n"
5495                     "You can correct this by running with the '/INSTALL' or '/INSTALL <installdir>' option.\n\n"
5496                     "POV-Ray has inferred the installation path to be the following:\n\n"
5497                     "\t%s\n\n"
5498                     "This message will be displayed each time the inferred path changes.",
5499                     BinariesPath) ;
5500       MessageBox (NULL, str, "Warning", MB_ICONINFORMATION) ;
5501     }
5502     reg_printf (true, "Software\\" REGKEY "\\" REGVERKEY "\\Windows", "LastInferredHome", "%s", BinariesPath) ;
5503   }
5504 
5505   sprintf(ToolIniFileName, "%sini\\pvtools.ini", DocumentsPath);
5506   sprintf (DefaultRenderIniFileName, "%sini\\povray.ini", DocumentsPath) ;
5507   GetModuleFileName (hInst, str, sizeof (str) - 1) ;
5508   splitpath (str, modulePath, NULL) ;
5509   validatePath (modulePath) ;
5510 
5511   sprintf (engineHelpPath, "%shelp\\povray37.chm", BinariesPath) ;
5512   HtmlHelp (NULL, NULL, HH_INITIALIZE, (DWORD_PTR) &help_cookie) ;
5513   memset (&hh_aklink, 0, sizeof (hh_aklink)) ;
5514   hh_aklink.cbStruct = sizeof (hh_aklink) ;
5515   hh_aklink.fIndexOnFail = true ;
5516   hh_aklink.pszWindow = "POV-Ray Help" ;
5517 
5518   SHGetFolderPath (NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, FontPath) ;
5519 
5520   one_instance = GetHKCU("General", "OneInstance", 1) != 0 ;
5521   if ((hwnd = FindWindow (PovMainWinClass, NULL)) != NULL)
5522   {
5523     if (one_instance)
5524     {
5525       if (IsIconic (hwnd))
5526         ShowWindow (hwnd, SW_RESTORE) ;
5527       SetForegroundWindow (hwnd) ;
5528       FeatureNotify ("OneInstanceSet",
5529                      "POV-Ray - 'Keep Single Instance' Feature",
5530                      "You have started POV-Ray for Windows while another copy is running, "
5531                      "and the 'Keep Single Instance' option is turned on (see Options menu). "
5532                      "In this case the other copy is activated rather than starting a new "
5533                      "instance of the program.\n\nClick &Help for information on this feature.",
5534                      "Keep Single Instance",
5535                      false) ;
5536 
5537       // special case: there's a chance we're being called as a result of a windows file association
5538       // default, which allows users to associate POV-Ray with arbitrary files. in this case, no
5539       // /EDIT or /RENDER verb will be present; just the filename. what we do here is see if the
5540       // passed string is a real file by calling fileExists(). if it is, then we assume /EDIT is
5541       // desired.
5542       n = strlen(szCmdLine);
5543       if (n < _MAX_PATH && n > 2 && szCmdLine[0] == '"' && szCmdLine[n - 1] == '"')
5544       {
5545         memcpy(str, szCmdLine + 1, n - 2);
5546         str[n - 2] = '\0';
5547         if (fileExists(str))
5548         {
5549           FeatureNotify ("EditByDefault",
5550                           "POV-Ray - Filename passed on command-line",
5551                           "Quoted filenames which are the sole command-line parameter are now "
5552                           "opened in the editor by default. If you wish to render them instead "
5553                           "please pass the /RENDER switch, provide more than one parameter, or "
5554                           "use single quotes around the path.\n\n"
5555                           "Click &Help for more information.",
5556                           "associations", false) ;
5557           add_edit_file(str);
5558           szCmdLine = "";
5559         }
5560       }
5561 
5562       SetForegroundWindow (hwnd) ;
5563       if ((s = preparse_instance_commandline (szCmdLine)) != NULL)
5564       {
5565         parse_commandline(s);
5566         if (argc > 1)
5567         {
5568           PovMessageBox ("Only /EDIT and /RENDER may be passed to previous instance", "Commandline processing error") ;
5569           return (1) ;
5570         }
5571         COPYDATASTRUCT cd ;
5572         cd.dwData = EDIT_FILE ;
5573         for (i = 0 ; i < EditFileCount ; i++)
5574         {
5575           s = EditFiles [i] ;
5576           if ((isalpha (s [0]) && s [1] == ':') || (isPathSeparator(s [0]) && isPathSeparator(s [1])))
5577           {
5578             cd.cbData = (int) strlen (s) + 1 ;
5579             cd.lpData = s ;
5580           }
5581           else
5582           {
5583             GetCurrentDirectory (sizeof (str), str) ;
5584             if (!isPathSeparator(s [0]))
5585             {
5586               strcat (str, "\\") ;
5587               strcat (str, s) ;
5588             }
5589             else
5590               strcpy (str + 2, s) ;
5591             cd.cbData = (int) strlen (str) + 1 ;
5592             cd.lpData = str ;
5593           }
5594           SendMessage (hwnd, WM_COPYDATA, NULL, (LPARAM) &cd) ;
5595           free (EditFiles [i]) ;
5596           EditFiles [i] = NULL ;
5597         }
5598         EditFileCount = 0 ;
5599         if (render_requested)
5600         {
5601           cd.dwData = RENDER_FILE ;
5602           s = requested_render_file ;
5603           if ((isalpha (s [0]) && s [1] == ':') || (isPathSeparator(s [0]) && isPathSeparator(s [1])))
5604           {
5605             cd.cbData = (int) strlen (s) + 1 ;
5606             cd.lpData = s ;
5607           }
5608           else
5609           {
5610             GetCurrentDirectory (sizeof (str), str) ;
5611             if (!isPathSeparator(s [0]))
5612             {
5613               strcat (str, "\\") ;
5614               strcat (str, s) ;
5615             }
5616             else
5617               strcpy (str + 2, s) ;
5618             cd.cbData = (int) strlen (str) + 1 ;
5619             cd.lpData = str ;
5620           }
5621           SendMessage (hwnd, WM_COPYDATA, NULL, (LPARAM) &cd) ;
5622         }
5623         SetForegroundWindow (hwnd) ;
5624       }
5625       else
5626         return (1) ;
5627       return (0) ;
5628     }
5629     else
5630     {
5631       // one_instance isn't set. we should continue as per normal.
5632       // however see if we need to notify the user about this.
5633       FeatureNotify ("OneInstanceUnset",
5634                      "POV-Ray - 'Keep Single Instance' Feature",
5635                      "You have started POV-Ray for Windows while another copy is running, "
5636                      "and the 'Keep Single Instance' option is turned off (see Options menu). "
5637                      "In this case a new instance of the program is started rather than "
5638                      "activating the existing instance of the program.\n\nClick &Help for more "
5639                      "information on this feature.",
5640                      "Keep Single Instance",
5641                      false) ;
5642     }
5643   }
5644 
5645   if (_strnicmp (szCmdLine, "/DEBUG", 6) == 0)
5646   {
5647     debugging = true ;
5648     debug_output(NULL) ;
5649   }
5650 
5651   SetThreadPriority (hMainThread, THREAD_PRIORITY_ABOVE_NORMAL) ;
5652   version_info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO) ;
5653   GetVersionEx (&version_info) ;
5654   use_editors = editors_enabled ;
5655 
5656   IsW98 = HaveWin98OrLater () ;
5657   IsWNT = HaveNT4OrLater () ;
5658   IsW2k = HaveWin2kOrLater () ;
5659   IsWXP = HaveWinXPOrLater () ;
5660   IsVista = HaveVistaOrLater () ;
5661 
5662   // yes, we actually used to support the windows 3.1 UI ...
5663   IsW95UserInterface = true ;
5664 
5665   ourIcon = LoadIcon (hInstance, MAKEINTRESOURCE (IsWXP ? IDI_PVENGINE_XP : IDI_PVENGINE)) ;
5666   renderIcon = LoadIcon (hInstance, MAKEINTRESOURCE (IsWXP ? IDI_RENDERWINDOW_XP : IDI_RENDERWINDOW)) ;
5667 
5668   if (hPrev == NULL)
5669     if (register_classes () == false)
5670       MessageBox (NULL, "ERROR : Could not register classes", "Error", MB_ICONSTOP) ;
5671 
5672   IsComCtl5 = GetDllVersion (TEXT ("comctl32.dll")) >= MAKELONG (5,0) ;
5673   IsComCtl6 = GetDllVersion (TEXT ("comctl32.dll")) >= MAKELONG (6,0) ;
5674 
5675   // need to init menus before we read INI settings
5676   init_menus () ;
5677 
5678   // need to do this before we detect the graphics config
5679   read_INI_settings () ;
5680 
5681   detect_graphics_config () ;
5682   clear_system_palette () ;
5683   hPalApp = WinLegacyDisplay::CreatePalette (NULL, 0, render_bitmap_depth != 24) ;
5684 
5685   if (!QueryPerformanceFrequency ((LARGE_INTEGER *) &PerformanceFrequency))
5686     PerformanceFrequency = 0 ;
5687   if (PerformanceFrequency > 1999999)
5688     PerformanceScale = PerformanceFrequency / 1000000 ;
5689 
5690   // 'IsW95UserInterface' dates from when Windows 95 and NT4 were introduced
5691   // (at that time we still supported the old Windows 3.1 UI)
5692   // IsW95UserInterface = GetHKCU("General", "UseW95UserInterface", 1) != 0 ;
5693   IsW95UserInterface = true;
5694   info_render_complete = GetHKCU("Info", "RenderCompleteSound", 0) != 0 ;
5695 
5696   SetupFrontend();
5697 
5698   if (!IsW95UserInterface)
5699   {
5700     PVEnableMenuItem (CM_SHOWMAINWINDOW, MF_GRAYED) ;
5701     use_taskbar = false ;
5702   }
5703 
5704   create_about_font () ;
5705 
5706   InitializeCriticalSection (&critical_section) ;
5707 
5708   GetHKCU("General", "CommandLine", "", old_command_line, sizeof (old_command_line)) ;
5709   strcpy (command_line, old_command_line) ;
5710 
5711   // special case: POV may get associated with an arbitrary file type by the user.
5712   // in such cases we won't be given any verbs to indicate what to do with the file,
5713   // and in many instances our default action (which is to assume the file is either
5714   // SDL or INI) is not appropriate. so we make an exception here for such cases.
5715   //
5716   // if the sole command-line parameter is a QUOTED filename referring to a file which
5717   // exists, we assume /EDIT is desired (this may break some scripts that assume the
5718   // default; in such cases the script should explicitly pass /RENDER). the shell
5719   // always quotes files passed in this way; by testing for the quotes we can
5720   // eliminate some unnecessary tests.
5721   n = strlen(szCmdLine);
5722   if (n < _MAX_PATH && n > 2 && szCmdLine[0] == '"' && szCmdLine[n - 1] == '"')
5723   {
5724     memcpy(str, szCmdLine + 1, n - 2);
5725     str[n - 2] = '\0';
5726     if (fileExists(str))
5727     {
5728       FeatureNotify ("EditByDefault",
5729                       "POV-Ray - Filename passed on command-line",
5730                       "Quoted filenames which are the sole command-line parameter are now "
5731                       "opened in the editor by default. If you wish to render them instead "
5732                       "please pass the /RENDER switch (or provide more than one parameter).\n\n"
5733                       "Click &Help for more information.",
5734                       "associations", false) ;
5735       add_edit_file(str);
5736       szCmdLine = "";
5737     }
5738   }
5739 
5740   if ((szCmdLine = preparse_commandline (szCmdLine)) != NULL)
5741   {
5742     if (benchmark_mode)
5743       demo_mode = false;
5744     if (parse_commandline (szCmdLine) > 1 && !demo_mode && !benchmark_mode)
5745     {
5746       restore_command_line = true ;
5747       strncpy (command_line, szCmdLine, sizeof (command_line) - 1) ;
5748     }
5749   }
5750 
5751   if (debugging)
5752     if (_getcwd (str, sizeof (str) - 1) != NULL)
5753       debug_output("CWD is %s\n", str) ;
5754 
5755   if (editors_enabled)
5756   {
5757     if (EditDLLPath != NULL)
5758     {
5759       sprintf (str, "%s" EDITDLLNAME, EditDLLPath) ;
5760       if (!LoadEditorDLL (str, false))
5761         use_editors = false ;
5762     }
5763     else
5764     {
5765       sprintf (str, "%s\\" EDITDLLNAME, modulePath) ;
5766       if (!LoadEditorDLL (str, true))
5767       {
5768         sprintf (str, "%sbin\\" EDITDLLNAME, BinariesPath) ;
5769         if (!LoadEditorDLL (str, false))
5770           use_editors = false ;
5771       }
5772     }
5773   }
5774   else
5775     use_editors = false;
5776 
5777   GetHKCU("General", VERSIONVAL, "[unknown]", str, (DWORD) strlen (str)) ;
5778   if (debugging)
5779     debug_output("Registry records version %s, and we are %s\n", str, POV_RAY_VERSION COMPILER_VER SSE2_INCLUDED "." PVENGINE_VER) ;
5780 
5781   if (strcmp (str, POV_RAY_VERSION COMPILER_VER "." PVENGINE_VER) != 0)
5782   {
5783     // we don't want to set the newVersion flag if the only thing that changed
5784     // was the compiler used to generate the binary. in this case we add an
5785     // explicit check for the intel, msvc, and watcom versions.
5786     if ((s = strstr (str, ".icl")) != NULL)
5787       strcpy (s, s + 4) ;
5788     else if ((s = strstr (str, ".msvc")) != NULL)
5789       strcpy (s, s + 5) ;
5790     else if ((s = strstr (str, ".watcom")) != NULL)
5791       strcpy (s, s + 7) ;
5792     // strip off any trailing digits from the compiler version
5793     if (s)
5794       while (isdigit (*s))
5795         strcpy (s, s + 1) ;
5796     if (strcmp (str, POV_RAY_VERSION "." PVENGINE_VER) != 0)
5797       newVersion = true ;
5798   }
5799 
5800   if ((run_count = GetHKCU("General", "RunCount", 0)) == 0 || newVersion)
5801   {
5802     if (screen_depth < 8)
5803     {
5804       MessageBox (NULL,
5805                   "NOTE : POV-Ray for Windows was not designed to run in 16-color mode. "
5806                   "While the program will operate, it is recommended that you use a minimum "
5807                   "graphics mode of 800x600x256.",
5808                   "Warning - running in 16-color mode",
5809                   MB_ICONEXCLAMATION) ;
5810       tile_background = false ;
5811     }
5812     if (screen_width < 800)
5813     {
5814       MessageBox (NULL,
5815                   "NOTE : POV-Ray for Windows was not designed to run at less than 800x600.\n\n"
5816                   "While the program will operate, it is recommended that you use a minimum "
5817                   "graphics mode of 800x600x256.",
5818                   "Warning - running at less than 800x600",
5819                   MB_ICONEXCLAMATION) ;
5820     }
5821   }
5822   PutHKCU ("General", "RunCount", ++run_count) ;
5823 
5824   if (screen_depth < 8)
5825     tile_background = false ;
5826 
5827   /* Create the main window */
5828   placement = mainwin_placement ;
5829   placement.length = sizeof (WINDOWPLACEMENT) ;
5830   w = mainwin_placement.rcNormalPosition.right - mainwin_placement.rcNormalPosition.left ;
5831   h = mainwin_placement.rcNormalPosition.bottom - mainwin_placement.rcNormalPosition.top ;
5832   if (w <= 128)
5833     w = 700 ;
5834   if (h <= 128)
5835     h = screen_height - 75 ;
5836   main_window = CreateWindowEx (0,
5837                                 PovMainWinClass,
5838                                 "POV-Ray for Windows",
5839                                 WS_OVERLAPPEDWINDOW,
5840                                 mainwin_placement.rcNormalPosition.left,
5841                                 mainwin_placement.rcNormalPosition.top,
5842                                 w,
5843                                 h,
5844                                 NULL,
5845                                 NULL,
5846                                 hInst,
5847                                 NULL) ;
5848 
5849   if (main_window == NULL)
5850   {
5851     MessageBox (NULL, "ERROR : Could not create main window.", "Critical Error", MB_ICONSTOP) ;
5852     cleanup_all () ;
5853     return (1) ;
5854   }
5855 
5856   EditSetNotifyBase (main_window, CM_FIRSTEDITNOTIFY) ;
5857 
5858   if ((StatusWindow = CreateStatusbar (main_window)) == NULL)
5859   {
5860     MessageBox (main_window, "ERROR : Could not create statusbar", "Critical Error", MB_ICONSTOP) ;
5861     cleanup_all () ;
5862     return (1) ;
5863   }
5864 
5865   if (tile_background && background_file [1])
5866   {
5867     if ((hDIB = LoadDIB (background_file)) != NULL)
5868     {
5869       hBmpBackground = DIBToBitmap (hDIB, hPalApp) ;
5870       DeleteObject (hDIB) ;
5871       GetObject (hBmpBackground, sizeof (BITMAP), (LPSTR) &bm) ;
5872       background_width = bm.bmWidth ;
5873       background_height = bm.bmHeight ;
5874     }
5875     else
5876     {
5877       PovMessageBox ("Failed to load bitmap file", "Error") ;
5878       strcpy (background_file, "0") ;
5879     }
5880   }
5881 
5882   if (tile_background && hBmpBackground == NULL && screen_depth >= 8)
5883   {
5884     if (isdigit (background_file [0]) && background_file [1] == '\0')
5885       id = background_file [0] - '0' ;
5886     SendMessage (main_window, WM_COMMAND, CM_BACKGROUNDSTD + id, 1L) ;
5887   }
5888 
5889   if ((hBMP = LoadBitmap (hInstance, MAKEINTRESOURCE (BMP_ICON))) != NULL)
5890     hBmpIcon = hBMP ;
5891 
5892   if (lastBitmapPath [0] == '\0')
5893     sprintf (lastBitmapPath, "%sTiles", BinariesPath) ;
5894   if (lastRenderPath [0] == '\0')
5895   {
5896     sprintf (lastRenderPath, "%sScenes\\Advanced", DocumentsPath) ;
5897     strcpy (lastRenderName, "Biscuit.pov") ;
5898   }
5899   if (lastQueuePath [0] == '\0')
5900     sprintf (lastQueuePath, "%sScenes", DocumentsPath) ;
5901   GetHKCU("Editor", "LastPath", "", str, sizeof (str)) ;
5902   validatePath (lastRenderPath) ;
5903   if (str [0] == '\0')
5904     PutHKCU("Editor", "LastPath", lastRenderPath) ;
5905   if (lastRenderName [0] != '\0' && !demo_mode && !benchmark_mode)
5906     joinPath (source_file_name, lastRenderPath, lastRenderName) ;
5907 
5908   if (use_editors)
5909     if ((tab_window = InitialiseEditor (main_window, StatusWindow, BinariesPath, DocumentsPath)) == NULL)
5910       use_editors = false ;
5911 
5912   message_window = CreateWindowEx (WS_EX_CLIENTEDGE,
5913                                    PovMessageWinClass,
5914                                    "",
5915                                    WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
5916                                    0,
5917                                    0,
5918                                    0,
5919                                    0,
5920                                    use_editors ? tab_window : main_window,
5921                                    NULL,
5922                                    hInst,
5923                                    NULL) ;
5924   if (message_window == NULL)
5925   {
5926     MessageBox (NULL, "ERROR : Could not create message window.", "Critical Error", MB_ICONSTOP) ;
5927     cleanup_all () ;
5928     return (1) ;
5929   }
5930 
5931   if (initialise_message_display ())
5932   {
5933     cleanup_all () ;
5934     return (1) ;
5935   }
5936   EditSetMessageWindow (message_window) ;
5937 
5938   if ((rebar_window = create_rebar (main_window)) == NULL)
5939   {
5940     MessageBox (main_window, "ERROR : Could not create internal window #1", "Critical Error", MB_ICONSTOP) ;
5941     cleanup_all () ;
5942     return (1) ;
5943   }
5944   if ((toolbar_window = create_toolbar (rebar_window)) == NULL)
5945   {
5946     MessageBox (main_window, "ERROR : Could not create internal window #2", "Critical Error", MB_ICONSTOP) ;
5947     cleanup_all () ;
5948     return (1) ;
5949   }
5950   if (!use_toolbar)
5951   {
5952     ShowWindow (rebar_window, SW_HIDE) ;
5953     toolheight = 0 ;
5954   }
5955   extract_ini_sections_ex (SecondaryRenderIniFileName, toolbar_combobox) ;
5956   SendMessage (toolbar_combobox, CB_ADDSTRING, 0, (LPARAM) "More Resolutions ...") ;
5957   tb_combo_sel = select_combo_item_ex (toolbar_combobox, SecondaryRenderIniFileSection) ;
5958   if (tb_combo_sel == -1)
5959     tb_combo_sel = 0 ;
5960 
5961   setup_menus (use_editors) ;
5962   build_main_menu (hMainMenu, use_editors) ;
5963 
5964   set_toggles () ;
5965 
5966   if (!use_editors)
5967   {
5968     SendMessage (toolbar_window, TB_ENABLEBUTTON, CM_FILENEW, 0L) ;
5969     SendMessage (toolbar_window, TB_ENABLEBUTTON, CM_FILEOPEN, 0L) ;
5970     SendMessage (toolbar_window, TB_ENABLEBUTTON, CM_FILESAVE, 0L) ;
5971   }
5972   else
5973     EditRestoreState (!NoRestore) ;
5974 
5975   if (editors_enabled)
5976     PVCheckMenuItem (CM_USEEDITOR, MF_CHECKED) ;
5977   PVEnableMenuItem (CM_RENDERHIDE, RenderwinIsChild ? MF_GRAYED : MF_ENABLED) ;
5978   PVEnableMenuItem (CM_RENDERACTIVE, RenderwinIsChild ? MF_GRAYED : MF_ENABLED) ;
5979   PVCheckMenuItem (on_completion, MF_CHECKED) ;
5980   PVEnableMenuItem (CM_RENDERSHOW, MF_GRAYED) ;
5981   PVEnableMenuItem (CM_RENDERSLEEP, MF_GRAYED) ;
5982 
5983   PVCheckMenuRadioItem (CM_RENDERPRIORITY_BACKGROUND, CM_RENDERPRIORITY_HIGH, render_priority) ;
5984 
5985   PVCheckMenuItem (drop_to_editor ? CM_DROPEDITOR : CM_DROPRENDERER, MF_CHECKED) ;
5986 
5987   PVEnableMenuItem (CM_RENDERSHOW, MF_GRAYED) ;
5988   PVEnableMenuItem (CM_RENDERCLOSE, MF_GRAYED) ;
5989   PVModifyMenu (CM_TILEDBACKGROUND,
5990                 MF_STRING,
5991                 CM_TILEDBACKGROUND,
5992                 tile_background ? "&Select Plain Background" : "&Select Tiled Background") ;
5993   PVCheckMenuRadioItem (CM_DUTYCYCLE_10, CM_DUTYCYCLE_100, CM_DUTYCYCLE_10 + Duty_Cycle) ;
5994   if (screen_depth < 8)
5995   {
5996     PVEnableMenuItem (CM_TILEDBACKGROUND, MF_GRAYED) ;
5997     PVEnableMenuItem (CM_BACKGROUNDBITMAP, MF_GRAYED) ;
5998     for (i = 0 ; i < 16 ; i++)
5999       PVEnableMenuItem (CM_BACKGROUNDSTD + i, MF_GRAYED) ;
6000   }
6001   set_newuser_menus (hide_newuser_help) ;
6002 
6003   if (ThreadCount == 1)
6004   {
6005     PVDeleteMenuItem (CM_BENCHMARK) ;
6006     PVModifyMenu (CM_BENCHMARKONETHREAD, MF_STRING, CM_BENCHMARKONETHREAD, "Run &Benchmark") ;
6007   }
6008 
6009   switch (placement.showCmd)
6010   {
6011     case SW_SHOWNORMAL :
6012          show_state = SW_SHOW ;
6013          break ;
6014 
6015     case SW_SHOWMINIMIZED :
6016 //       show_state = SW_SHOWMINNOACTIVE ;
6017          show_state = SW_SHOW ;
6018          break ;
6019 
6020     case SW_SHOWMAXIMIZED :
6021          show_state = SW_SHOWMAXIMIZED ;
6022          break ;
6023 
6024     default :
6025          show_state = SW_SHOW ;
6026          break ;
6027   }
6028 
6029   if (ListenMode)
6030     show_state = SW_HIDE ;
6031 
6032   placement.showCmd = show_state ;
6033   placement.flags = (placement.ptMinPosition.x == -1 && placement.ptMinPosition.y == -1) ? 0 : WPF_SETMINPOSITION ;
6034   if (placement.rcNormalPosition.right <= 0 || placement.rcNormalPosition.bottom <= 0)
6035   {
6036     placement.rcNormalPosition.right = placement.rcNormalPosition.left + message_xchar * 115 ;
6037     placement.rcNormalPosition.bottom = placement.rcNormalPosition.top + message_ychar * 75 ;
6038   }
6039 
6040   placement.length = sizeof (WINDOWPLACEMENT) ;
6041   SetWindowPlacement (main_window, &placement) ;
6042   if (show_state != SW_SHOWMAXIMIZED)
6043     FitWindowInWindow (NULL, main_window) ;
6044 
6045   if ((timer_id = SetTimer (main_window, 1, 250, NULL)) != 0)
6046     DragAcceptFiles (main_window, true) ;
6047 
6048   // only needed for earlier versions of common control DLL ...
6049   if (use_toolbar && !IsComCtl5)
6050   {
6051     hDC = GetDC (toolbar_window) ;
6052     GetClientRect (toolbar_window, &rect) ;
6053     FillRect (hDC, &rect, (HBRUSH) GetStockObject (LTGRAY_BRUSH)) ;
6054     ReleaseDC (toolbar_window, hDC) ;
6055   }
6056 
6057   // fixes visual glitch with ComCtl6
6058   if (use_toolbar && IsComCtl6)
6059   {
6060     hDC = GetDC (main_window) ;
6061     GetClientRect (rebar_window, &rect) ;
6062     FillRect (hDC, &rect, (HBRUSH) GetStockObject (LTGRAY_BRUSH)) ;
6063     ReleaseDC (main_window, hDC) ;
6064   }
6065 
6066   if (ExtensionsEnabled)
6067     LoadGUIExtensions () ;
6068 
6069   if (renderwin_left < 0 || renderwin_left > screen_width - 32 || renderwin_top < 0 || renderwin_top > screen_height - 32)
6070   {
6071     MONITORINFO mi;
6072     mi.cbSize = sizeof(MONITORINFO);
6073     if (GetMonitorInfo(MonitorFromWindow(main_window, MONITOR_DEFAULTTOPRIMARY), &mi))
6074     {
6075       // apply the principle of least astonishment: otherwise the render window could
6076       // turn up on a monitor which may be switched off or otherwise not being paid
6077       // attention to, with no (obvious) way for the user to move it. we make one
6078       // exception: if the render window is placed on the primary display, we won't
6079       // move it to the current display, since it's assumed the primary display is
6080       // always going to be visible.
6081         if (renderwin_left < mi.rcWork.left)
6082           renderwin_left = mi.rcWork.left ;
6083         if (renderwin_top < mi.rcWork.top)
6084           renderwin_top = mi.rcWork.top ;
6085         if (renderwin_left > mi.rcWork.right - 128)
6086           renderwin_left = mi.rcWork.right - 128 ;
6087         if (renderwin_top > mi.rcWork.bottom - 128)
6088           renderwin_top = mi.rcWork.bottom - 128 ;
6089     }
6090   }
6091 
6092   buffer_message (mIDE, "Persistence of Vision Raytracer(tm) for Windows.\n") ;
6093   buffer_message (mIDE, "POV-Ray for Windows is part of the POV-Ray(tm) suite of programs.\n") ;
6094   buffer_message (mIDE, "  This is version " POV_RAY_VERSION COMPILER_VER SSE2_INCLUDED "." PVENGINE_VER ".\n") ;
6095   buffer_message (mIDE, "Copyright 1991-2013 Persistence of Vision Raytracer Pty. Ltd.\n") ;
6096   buffer_message (mIDE, "  " DISCLAIMER_MESSAGE_1 "\n") ;
6097   buffer_message (mIDE, "  " DISCLAIMER_MESSAGE_2 "\n") ;
6098   buffer_message (mIDE, "  Select Help|About (or press Alt+B) for more information and a copy of the license.\n") ;
6099   buffer_message (mIDE, "The terms POV-Ray and Persistence of Vision Raytracer are trademarks of\n") ;
6100   buffer_message (mIDE, "  Persistence of Vision Raytracer Pty. Ltd.\n") ;
6101   if (render_bitmap_depth != 24)
6102   {
6103     buffer_message (mIDE, "\n") ;
6104     buffer_message (mIDE, renderwin_8bits ? "Using 8-bit dithered internal bitmap (menu setting)\n" :
6105                                             "Using 8-bit dithered internal bitmap (4 or 8-bit video mode)\n") ;
6106   }
6107 
6108   buffer_message (mIDE, "\n") ;
6109   strcpy (tool_commands [0], "notepad.exe \"%ipovray.ini\"") ;
6110 
6111 #if POV_RAY_IS_OFFICIAL != 1
6112   WIN_PrintOtherCredits () ;
6113   buffer_message (mIDE, "This unofficial build is derived from the POV-Ray for Windows source code.\n") ;
6114 #endif
6115   buffer_message (mDivider, "\n") ;
6116 
6117 #if defined(USE_AVX_FMA4_FOR_NOISE)
6118   // technically we should ask the backend what it's using, but given this is not a remoted version
6119   // of POVWIN, we just call the test here.
6120   if (CPU_FMA4_DETECT() != 0)
6121   {
6122     buffer_message (mIDE, "FMA4 instruction support detected: using FMA4-optimized noise functions.\n") ;
6123     buffer_message (mDivider, "\n") ;
6124   }
6125 #endif
6126 
6127   load_tool_menu (ToolIniFileName) ;
6128   if (GetHKCU("FileQueue", "ReloadOnStartup", 0))
6129   {
6130     queued_file_count = GetHKCU("FileQueue", "QueueCount", 0) ;
6131     if (queued_file_count > MAX_QUEUE)
6132       queued_file_count = MAX_QUEUE ;
6133     for (i = 0 ; i < queued_file_count ; i++)
6134     {
6135       sprintf (str, "QueuedFile%d", i) ;
6136       GetHKCU("FileQueue", str, "", queued_files [i], sizeof (queued_files [0])) ;
6137     }
6138     if (queued_file_count != 0)
6139       message_printf ("Loaded %d entr%s into file queue\n", queued_file_count, queued_file_count == 1 ? "y" : "ies") ;
6140     update_queue_status (false) ;
6141   }
6142 
6143   if (have_cpu_info)
6144     message_printf("Detected %u CPU%s providing %u physical core%s and %u logical one%s.\n",
6145                    NumPhysicalCPUs, NumPhysicalCPUs > 1 ? "'s" : "",
6146                    NumCPUCores, NumCPUCores > 1 ? "s" : "",
6147                    NumLogicalCPUs, NumLogicalCPUs > 1 ? "s" : "");
6148 
6149   buffer_message (mDivider, "\n") ;
6150 
6151   if (GetHKCU("General", "CheckColorsInc", 1) == 1)
6152   {
6153     sprintf (str, "%sinclude\\colors.inc", DocumentsPath) ;
6154     if (stat (str, &statbuf) != 0)
6155     {
6156       char temp[2048];
6157       sprintf(temp,
6158               "WARNING : Cannot find COLORS.INC in expected location:\n\n%s\n\n"
6159               "This file is important for the normal operation of POV-Ray. It is included "
6160               "with the POV-Ray for Windows distribution. If you did not install using the "
6161               "correct installation procedure please attend to this before running POV-Ray "
6162               "for Windows.\n\nIf, however, you have chosen to change the location of this file "
6163               "or do not need it, you may ignore this warning as long as you have updated "
6164               "POVRAY.INI to the new path, or do not use any standard scenes that require it.\n\n"
6165               "Do you want to see this warning again ?",
6166               str);
6167       if (MessageBox (NULL, temp, "Warning - COLORS.INC is missing", MB_ICONEXCLAMATION | MB_YESNO) == IDNO)
6168         PutHKCU ("General", "CheckColorsInc", 0U) ;
6169     }
6170   }
6171 
6172   if (demo_mode)
6173   {
6174     message_printf ("Running demonstration\n") ;
6175     argc = 0 ;
6176     handle_main_command (CM_DEMO, 0) ;
6177   }
6178 
6179   if (benchmark_mode)
6180   {
6181     message_printf ("Running benchmark\n") ;
6182     argc = 0 ;
6183     handle_main_command (CM_BENCHMARK, 0) ;
6184   }
6185 
6186   SendMessage (toolbar_cmdline, WM_SETTEXT, 0, (LPARAM) command_line) ;
6187 
6188   if (debugging)
6189   {
6190     message_printf ("My window handle is %p\n", main_window) ;
6191 
6192     if (HaveWin95OrLater ())
6193       message_printf ("Win95 or later detected\n") ;
6194     if (HaveWin98OrLater ())
6195       message_printf ("Win98 or later detected\n") ;
6196     if (HaveNT4OrLater ())
6197       message_printf ("WinNT or later detected\n") ;
6198     if (HaveWin2kOrLater ())
6199       message_printf ("Win2k or later detected\n") ;
6200     if (HaveWinXPOrLater ())
6201       message_printf ("WinXP or later detected\n") ;
6202     if (IsW95UserInterface)
6203       message_printf ("Windows 95 user interface flag is set\n") ;
6204   }
6205 
6206   for (i = 0 ; i < EditFileCount ; i++)
6207   {
6208     if (EditGetFlags () & EDIT_CAN_OPEN)
6209       EditOpenFile (EditFiles [i]) ;
6210     free (EditFiles [i]) ;
6211     EditFiles [i] = NULL ;
6212   }
6213   EditFileCount = 0 ;
6214 
6215   if (newVersion || FreshInstall)
6216   {
6217     if (EditGetFlags() & EDIT_CAN_OPEN)
6218     {
6219       sprintf(str, "%srevision.txt", DocumentsPath);
6220       if (fileExists(str))
6221         EditOpenFile(str) ;
6222       if (EditGetFlags() & EDIT_CAN_OPEN)
6223       {
6224         sprintf(str, "%schanges.txt", DocumentsPath);
6225         if (fileExists(str))
6226           EditOpenFile(str) ;
6227       }
6228     }
6229 
6230     // TODO: remove this after a few betas
6231     tile_background = false;
6232     text_colours[0] = RGB (255, 255, 255);
6233     text_colours[1] = RGB (255, 255, 0);
6234     text_colours[2] = RGB (0, 255, 255);
6235     background_colour = RGB (31, 0, 63);
6236   }
6237 
6238   if (run_count > 1 && !demo_mode && !benchmark_mode)
6239   {
6240     n = GetHKCU("General", "ItsAboutTime", 0) ;
6241     if (_time32 (NULL) > n /*|| newVersion*/)
6242     {
6243       ShowAboutBox () ;
6244       PutHKCU ("General", "ItsAboutTime", n ? _time32 (NULL) + DAYS(14) : _time32 (NULL) + DAYS(1)) ;
6245     }
6246   }
6247 
6248 #if POV_RAY_IS_OFFICIAL == 1
6249   DoUpdateCheck () ;
6250 #endif
6251 
6252   // automatically call the rendering engine if there were any parameters on the command line
6253   if (!rendering && (argc > 1 || render_requested))
6254   {
6255     if (render_requested)
6256     {
6257       wrapped_printf ("Requested render file is '%s'", requested_render_file) ;
6258       strcpy (source_file_name, requested_render_file) ;
6259     }
6260     if (argc > 1)
6261       wrapped_printf ("Calling rendering engine with parameters '%s'", command_line) ;
6262     start_rendering (!render_requested) ;
6263   }
6264 
6265   if (homeInferred)
6266     message_printf ("Warning: running with inferred home path due to missing registry entry.\n\n") ;
6267 
6268 #ifdef _DEBUG
6269   if (sizeof (ExternalVarStruct) != 0x9350)
6270     PovMessageBox ("Compatibility problem - ExternalVarStruct has changed size", "Warning") ;
6271 #endif
6272 
6273   if (ListenMode)
6274     handle_main_command (CM_SHOWMAINWINDOW, 0) ;
6275 
6276   if (debugging)
6277     debug_output("Entering GetMessage loop\n") ;
6278 
6279   try
6280   {
6281     while (!exit_loop)
6282     {
6283       // since the render thread can really slow things down for the UI (this becomes
6284       // a problem if the user sets the render priority to high and then finds the
6285       // UI unresponsive when attempting to change it back), we only sleep here if
6286       // there's no events in the queue that we feel the need to handle immediately.
6287       // (if one of these messages turns up while we're sleeping we'll get woken).
6288       // N.B. longer wait times resulted in complaints from some testers, apparently
6289       // there's some machines out there that don't exit the wait for some types of
6290       // input.
6291       MsgWaitForMultipleObjects (0, NULL, FALSE, 10, QS_ALLINPUT) ;
6292   //  MsgWaitForMultipleObjects (0, NULL, FALSE, 10, QS_HOTKEY | QS_KEY | QS_MOUSEBUTTON) ;
6293 
6294       if (StartInsertRender)
6295       {
6296         if (!rendering)
6297           start_rendering (false) ;
6298         StartInsertRender = false ;
6299       }
6300 
6301       if (quit != 0)
6302         if (quit + 15 < time (NULL))
6303           break ;
6304 
6305       ProcessSession();
6306       while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
6307       {
6308         if (msg.message == WM_QUIT)
6309         {
6310           exit_loop = true ;
6311           break ;
6312         }
6313 
6314         // we have to disable all these calls because HTML Help has a bug (on some
6315         // platforms - I can't work out the exact conditions that trigger it) which
6316         // will cause the cursor to flash between normal and the busy state (normally
6317         // an hourglass) several times a second, continually (even if help isn't open).
6318         // See job #124.
6319     #ifdef HTMLHELP_FIXED
6320         if (HtmlHelp (NULL, NULL, HH_PRETRANSLATEMESSAGE, (DWORD) &msg))
6321           continue ;
6322     #else
6323         // we need to pass on these messages, otherwise help navigation messages
6324         // will go to us instead of the help window
6325         if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN)
6326           if (!IsChild (main_window, msg.hwnd))
6327             if (HtmlHelp (NULL, NULL, HH_PRETRANSLATEMESSAGE, (DWORD_PTR) &msg))
6328               continue ;
6329     #endif
6330         if (!TranslateAccelerator (main_window, hAccelerators, &msg))
6331         {
6332           TranslateMessage (&msg) ;
6333           if (msg.hwnd == toolbar_cmdline)
6334           {
6335             if (msg.message == WM_CHAR)
6336               if (handle_toolbar_cmdline (msg.wParam, msg.lParam))
6337                 continue ;
6338           }
6339           DispatchMessage (&msg) ;
6340         }
6341         ProcessSession();
6342       }
6343     }
6344   }
6345   catch(std::exception& e)
6346   {
6347     sprintf (str, "Caught exception: %s", e.what()) ;
6348     if (debugging)
6349       debug_output ("%s\n", str) ;
6350     MessageBox (NULL, str, "POV-Ray Critical Error", MB_ICONSTOP) ;
6351     exit(1);
6352   }
6353 
6354   if (debugging)
6355     debug_output ("Dropping out of message loop\n") ;
6356 
6357   try
6358   {
6359     DeleteFrontend();
6360     cleanup_all () ;
6361   }
6362   catch(pov_base::Exception& e)
6363   {
6364     // don't do much about POV exceptions here: often, they will relate to the front end
6365     // not cleaning up fast enough (i.e. due to a lot of memory de-allocation)
6366     if (debugging)
6367       debug_output ("Caught exception: %s\n", e.what()) ;
6368   }
6369   catch(std::exception& e)
6370   {
6371     sprintf (str, "Caught exception: %s", e.what()) ;
6372     if (debugging)
6373       debug_output ("%s\n", str) ;
6374     MessageBox (NULL, str, "POV-Ray Critical Error", MB_ICONSTOP) ;
6375   }
6376 
6377   _fcloseall () ;
6378 #ifndef _WIN64
6379   // win64 - get exception during HH_UNINITIALIZE
6380   HtmlHelp (NULL, NULL, HH_UNINITIALIZE, (DWORD) help_cookie) ;
6381 #endif
6382 
6383   if (debugging)
6384     debug_output ("exiting WinMain()\n") ;
6385   return (0) ;
6386 }
6387