1 /*******************************************************************************
2  * pvguiext.cpp
3  *
4  * This file contains POV-Ray for Windows GUI Extension support code.
5  *
6  * 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/pvguiext.cpp $
30  * $Revision: #1 $
31  * $Change: 6069 $
32  * $DateTime: 2013/11/06 11:59:40 $
33  * $Author: chrisc $
34  *******************************************************************************/
35 
36 #define POVWIN_FILE
37 #define _WIN32_IE COMMONCTRL_VERSION
38 
39 #include <setjmp.h>
40 #include <string.h>
41 
42 #include <windows.h>
43 #include <commctrl.h>
44 
45 #include "pvengine.h"
46 #include "pvedit.h"
47 #include "resource.h"
48 #include "pvdialog.h"
49 #include "pvguiext.h"
50 
51 // this must be the last file included
52 #include "syspovdebug.h"
53 
54 namespace povwin
55 {
56 
57 typedef struct _RGPB0X0100
58 {
59   DWORD                 Signature ;
60   DWORD                 InstanceID ;
61   BOOL                  (WINAPI *Init) (DWORD InstanceID, int RecSize, GuiExtInitStruct *InitStruct) ;
62   void                  (WINAPI *Destroy) (IDataStruct *InstanceData) ;
63   DWORD                 (WINAPI *MenuSelect) (IDataStruct *InstanceData, WPARAM Code) ;
64   LPSTR                 (WINAPI *MenuTip) (IDataStruct *InstanceData, WPARAM Code) ;
65   DWORD                 (WINAPI *Event) (IDataStruct *InstanceData, ExternalEvents Event, DWORD EventVal) ;
66   void                  (WINAPI *DisplayPlot) (IDataStruct *InstanceData, int x, int y, int Red, int Green, int Blue, int Alpha) ;
67   void                  (WINAPI *DisplayPlotRect) (IDataStruct *InstanceData, int x1, int y1, int x2, int y2, int Red, int Green, int Blue, int Alpha) ;
68   void                  (WINAPI *WinPrePixel) (IDataStruct *InstanceData, int x, int y, COLOUR colour) ;
69   void                  (WINAPI *WinPostPixel) (IDataStruct *InstanceData, int x, int y, COLOUR colour) ;
70   BOOL                  (WINAPI *WinSystem) (IDataStruct *InstanceData, LPSTR command, int *returnval) ;
71   void                  (WINAPI *CleanupAll) (IDataStruct *InstanceData) ;
72   void                  (WINAPI *BufferMessage) (IDataStruct *InstanceData, msgtype message_type, LPSTR message) ;
73   LPSTR                 (WINAPI *ParseToolCommand) (IDataStruct *InstanceData, char command [512]) ;
74   BOOL                  (WINAPI *DragFunction) (IDataStruct *InstanceData, LPSTR szFile, ExternalDropType DropType) ;
75   struct _RGPB0X0100    *Next ;
76   int                   IniID ;
77   IDataStruct           InstanceData ;
78   char                  Name [256] ;
79   char                  Author [256] ;
80   char                  AuthorEmail [256] ;
81   char                  FileName [_MAX_PATH] ;
82 } RealGuiPointerBlock_Version_100 ;
83 
84 typedef struct _RGPB0X0101
85 {
86   DWORD                 Signature ;
87   DWORD                 InstanceID ;
88   BOOL                  (WINAPI *Init) (DWORD InstanceID, int RecSize, GuiExtInitStruct *InitStruct) ;
89   void                  (WINAPI *Destroy) (IDataStruct *InstanceData) ;
90   DWORD                 (WINAPI *MenuSelect) (IDataStruct *InstanceData, WPARAM Code) ;
91   LPSTR                 (WINAPI *MenuTip) (IDataStruct *InstanceData, WPARAM Code) ;
92   DWORD                 (WINAPI *Event) (IDataStruct *InstanceData, ExternalEvents Event, DWORD EventVal) ;
93   void                  (WINAPI *DisplayPlot) (IDataStruct *InstanceData, int x, int y, int Red, int Green, int Blue, int Alpha) ;
94   void                  (WINAPI *DisplayPlotRect) (IDataStruct *InstanceData, int x1, int y1, int x2, int y2, int Red, int Green, int Blue, int Alpha) ;
95   void                  (WINAPI *WinPrePixel) (IDataStruct *InstanceData, int x, int y, COLOUR colour) ;
96   void                  (WINAPI *WinPostPixel) (IDataStruct *InstanceData, int x, int y, COLOUR colour) ;
97   BOOL                  (WINAPI *WinSystem) (IDataStruct *InstanceData, LPSTR command, int *returnval) ;
98   void                  (WINAPI *CleanupAll) (IDataStruct *InstanceData) ;
99   void                  (WINAPI *BufferMessage) (IDataStruct *InstanceData, msgtype message_type, LPSTR message) ;
100   LPSTR                 (WINAPI *ParseToolCommand) (IDataStruct *InstanceData, char command [512]) ;
101   BOOL                  (WINAPI *DragFunction) (IDataStruct *InstanceData, LPSTR szFile, ExternalDropType DropType) ;
102   void                  (WINAPI *AssignPixel) (IDataStruct *InstanceData, int x, int y, COLOUR colour) ;
103   struct _RGPB0X0101    *Next ;
104   int                   IniID ;
105   IDataStruct           InstanceData ;
106   char                  Name [256] ;
107   char                  Author [256] ;
108   char                  AuthorEmail [256] ;
109   char                  FileName [_MAX_PATH] ;
110 } RealGuiPointerBlock_Version_101 ;
111 
112 typedef struct _RGPB
113 {
114   DWORD                 Signature ;
115   DWORD                 InstanceID ;
116   BOOL                  (WINAPI *Init) (DWORD InstanceID, int RecSize, GuiExtInitStruct *InitStruct) ;
117   void                  (WINAPI *Destroy) (IDataStruct *InstanceData) ;
118   DWORD                 (WINAPI *MenuSelect) (IDataStruct *InstanceData, WPARAM Code) ;
119   LPSTR                 (WINAPI *MenuTip) (IDataStruct *InstanceData, WPARAM Code) ;
120   DWORD                 (WINAPI *Event) (IDataStruct *InstanceData, ExternalEvents Event, DWORD EventVal) ;
121   void                  (WINAPI *DisplayPlot) (IDataStruct *InstanceData, int x, int y, int Red, int Green, int Blue, int Alpha) ;
122   void                  (WINAPI *DisplayPlotRect) (IDataStruct *InstanceData, int x1, int y1, int x2, int y2, int Red, int Green, int Blue, int Alpha) ;
123   void                  (WINAPI *WinPrePixel) (IDataStruct *InstanceData, int x, int y, COLOUR colour) ;
124   void                  (WINAPI *WinPostPixel) (IDataStruct *InstanceData, int x, int y, COLOUR colour) ;
125   BOOL                  (WINAPI *WinSystem) (IDataStruct *InstanceData, LPSTR command, int *returnval) ;
126   void                  (WINAPI *CleanupAll) (IDataStruct *InstanceData) ;
127   void                  (WINAPI *BufferMessage) (IDataStruct *InstanceData, msgtype message_type, LPSTR message) ;
128   LPSTR                 (WINAPI *ParseToolCommand) (IDataStruct *InstanceData, char command [512]) ;
129   BOOL                  (WINAPI *DragFunction) (IDataStruct *InstanceData, LPSTR szFile, ExternalDropType DropType) ;
130   void                  (WINAPI *AssignPixel) (IDataStruct *InstanceData, int x, int y, COLOUR colour) ;
131   void                  (WINAPI *DisplayPlotBlock) (IDataStruct *InstanceData, int x1, int y1, int x2, int y2, const GuiRGBA8* colour) ;
132   struct _RGPB          *Next ;
133   int                   IniID ;
134   IDataStruct           InstanceData ;
135   char                  Name [256] ;
136   char                  Author [256] ;
137   char                  AuthorEmail [256] ;
138   char                  FileName [_MAX_PATH] ;
139 } RealGuiPointerBlock ;
140 
141 DWORD                             CooperateLevel = 9 ; // this should really be per-GUIEXT rather than global
142 GuiExtInitStruct                  InitStruct ;
143 RealGuiPointerBlock               *GuiPointerBlocks = NULL ;
144 
145 DWORD (WINAPI *GuiExtGetPointers) (int RecSize, GuiPointerBlock *PointerBlock) ;
146 
147 extern char                       source_file_name [_MAX_PATH] ;
148 extern bool                       ExtensionsEnabled ;
149 extern bool                       rendering ;
150 extern bool                       stop_rendering ;
151 extern bool                       hide_newuser_help ;
152 extern bool                       debugging;
153 extern HWND                       main_window ;
154 extern HMENU                      hPluginsMenu ;
155 
156 void getvars (ExternalVarStruct *v) ;
157 void setvars (ExternalVarStruct *v) ;
158 
ExternalEvent(ExternalEvents Event,DWORD EventVal)159 DWORD ExternalEvent (ExternalEvents Event, DWORD EventVal)
160 {
161   DWORD                 rval = 0 ;
162   RealGuiPointerBlock   *p ;
163 
164   if (!ExtensionsEnabled)
165     return (0) ;
166   if (Event == EventWinCooperate)
167     if (EventVal >= CooperateLevel)
168       return (0) ;
169   p = GuiPointerBlocks ;
170   while (p)
171   {
172     if (p->Event != NULL)
173       rval |= (*p->Event ) (&p->InstanceData, Event, EventVal) ;
174     p = p->Next ;
175   }
176   return (rval) ;
177 }
178 
ExternalDisplayPlot(int x,int y,int Red,int Green,int Blue,int Alpha)179 void ExternalDisplayPlot (int x, int y, int Red, int Green, int Blue, int Alpha)
180 {
181   RealGuiPointerBlock   *p ;
182 
183   if (!ExtensionsEnabled)
184     return ;
185   p = GuiPointerBlocks ;
186   while (p)
187   {
188     if (p->DisplayPlot != NULL)
189       (*p->DisplayPlot) (&p->InstanceData, x, y, Red, Green, Blue, Alpha) ;
190     p = p->Next ;
191   }
192 }
193 
ExternalDisplayPlotBlock(int x1,int y1,int x2,int y2,const GuiRGBA8 * colour)194 void ExternalDisplayPlotBlock (int x1, int y1, int x2, int y2, const GuiRGBA8* colour)
195 {
196   RealGuiPointerBlock   *p ;
197 
198   if (!ExtensionsEnabled)
199     return ;
200 
201   int pixelsCount = ( x2 - x1 + 1 ) * ( y2 - y1 + 1 );
202   GuiRGBA8* localColourCopy = NULL;
203 
204   p = GuiPointerBlocks ;
205   while (p)
206   {
207     if (p->DisplayPlotBlock != NULL)
208 	{
209 		if (localColourCopy == NULL)
210 		  localColourCopy = new GuiRGBA8[ pixelsCount ];
211 		memcpy( localColourCopy, colour, pixelsCount * sizeof( GuiRGBA8 ) );
212 		(*p->DisplayPlotBlock) (&p->InstanceData, x1, y1, x2, y2, localColourCopy ) ;
213 	}
214     p = p->Next ;
215   }
216   delete[] localColourCopy;
217 }
218 
ExternalDisplayPlotRect(int x1,int y1,int x2,int y2,int Red,int Green,int Blue,int Alpha)219 void ExternalDisplayPlotRect (int x1, int y1, int x2, int y2, int Red, int Green, int Blue, int Alpha)
220 {
221   RealGuiPointerBlock   *p ;
222 
223   if (!ExtensionsEnabled)
224     return ;
225   p = GuiPointerBlocks ;
226   while (p)
227   {
228     if (p->DisplayPlotRect != NULL)
229       (*p->DisplayPlotRect) (&p->InstanceData, x1, y1, x2, y2, Red, Green, Blue, Alpha) ;
230     p = p->Next ;
231   }
232 }
233 
ExternalWinPrePixel(int x,int y,COLOUR colour)234 void ExternalWinPrePixel (int x, int y, COLOUR colour)
235 {
236   RealGuiPointerBlock   *p ;
237 
238   if (!ExtensionsEnabled)
239     return ;
240   p = GuiPointerBlocks ;
241   while (p)
242   {
243     if (p->WinPrePixel != NULL)
244       (*p->WinPrePixel) (&p->InstanceData, x, y, colour) ;
245     p = p->Next ;
246   }
247 }
248 
ExternalWinPostPixel(int x,int y,COLOUR colour)249 void ExternalWinPostPixel (int x, int y, COLOUR colour)
250 {
251   RealGuiPointerBlock   *p ;
252 
253   if (!ExtensionsEnabled)
254     return ;
255   p = GuiPointerBlocks ;
256   while (p)
257   {
258     if (p->WinPostPixel != NULL)
259       (*p->WinPostPixel) (&p->InstanceData, x, y, colour) ;
260     p = p->Next ;
261   }
262 }
263 
ExternalAssignPixel(int x,int y,COLOUR colour)264 void ExternalAssignPixel (int x, int y, COLOUR colour)
265 {
266   RealGuiPointerBlock   *p ;
267 
268   if (!ExtensionsEnabled)
269     return ;
270   p = GuiPointerBlocks ;
271   while (p)
272   {
273     if (p->AssignPixel != NULL)
274       (*p->AssignPixel) (&p->InstanceData, x, y, colour) ;
275     p = p->Next ;
276   }
277 }
278 
ExternalWinSystem(LPSTR command,int * returnval)279 BOOL ExternalWinSystem (LPSTR command, int *returnval)
280 {
281   RealGuiPointerBlock   *p ;
282 
283   if (!ExtensionsEnabled)
284     return (false) ;
285   p = GuiPointerBlocks ;
286   while (p)
287   {
288     if (p->WinSystem != NULL)
289       if ((*p->WinSystem) (&p->InstanceData, command, returnval))
290         return (true) ;
291     p = p->Next ;
292   }
293   return (false) ;
294 }
295 
ExternalCleanupAll(void)296 void ExternalCleanupAll (void)
297 {
298   // always enabled
299   while (GuiPointerBlocks)
300   {
301     if (GuiPointerBlocks->Destroy != NULL)
302       (*GuiPointerBlocks->Destroy) (&GuiPointerBlocks->InstanceData) ;
303     GuiPointerBlocks = GuiPointerBlocks->Next ;
304   }
305 }
306 
ExternalBufferMessage(msgtype message_type,LPSTR message)307 void ExternalBufferMessage (msgtype message_type, LPSTR message)
308 {
309   RealGuiPointerBlock   *p ;
310 
311   if (!ExtensionsEnabled)
312     return ;
313   p = GuiPointerBlocks ;
314   while (p)
315   {
316     if (p->BufferMessage != NULL)
317       (*p->BufferMessage) (&p->InstanceData, message_type, message) ;
318     p = p->Next ;
319   }
320 }
321 
ExternalParseToolCommand(char command[512])322 void ExternalParseToolCommand (char command [512])
323 {
324   RealGuiPointerBlock   *p ;
325 
326   if (!ExtensionsEnabled)
327     return ;
328   p = GuiPointerBlocks ;
329   while (p)
330   {
331     if (p->ParseToolCommand != NULL)
332       (*p->ParseToolCommand) (&p->InstanceData, command) ;
333     p = p->Next ;
334   }
335 }
336 
ExternalDragFunction(LPSTR szFile,ExternalDropType DropType)337 BOOL ExternalDragFunction (LPSTR szFile, ExternalDropType DropType)
338 {
339   int                   n ;
340   RealGuiPointerBlock   *p ;
341 
342   if (!ExtensionsEnabled)
343     return (false) ;
344   n = get_file_type (szFile) ;
345   if (n == filePOV || n == fileINI)
346     return (false) ;
347   p = GuiPointerBlocks ;
348   while (p)
349   {
350     if (p->DragFunction != NULL)
351       if ((*p->DragFunction) (&p->InstanceData, szFile, DropType))
352         return (true) ;
353     p = p->Next ;
354   }
355   return (false) ;
356 }
357 
ExternalRequest(ExternalRequests Request,void * RequestBlock)358 ExternalRequestResult WINAPI ExternalRequest (ExternalRequests Request, void *RequestBlock)
359 {
360   if (!ExtensionsEnabled)
361     return (ExRequestDisabled) ;
362   switch (Request)
363   {
364     case RequestGetVars :
365          if (((ExternalVarStruct *) RequestBlock)->RecSize != sizeof (ExternalVarStruct))
366            return (ExRequestBadRecSize) ;
367          getvars ((ExternalVarStruct *) RequestBlock) ;
368          return (ExRequestOK) ;
369 
370     case RequestSetVars :
371          if (((ExternalVarStruct *) RequestBlock)->RecSize != sizeof (ExternalVarStruct))
372            return (ExRequestBadRecSize) ;
373          setvars ((ExternalVarStruct *) RequestBlock) ;
374          return (ExRequestOK) ;
375 
376     case RequestSetCooperateLevel :
377          CooperateLevel = *(DWORD *) RequestBlock ;
378          return (ExRequestOK) ;
379 
380     case RequestStartRendering :
381          if (rendering)
382            return (ExRequestFailedRendering) ;
383          message_printf ("Rendering started by GUI extension\n") ;
384          start_rendering (false) ;
385          return (ExRequestOK) ;
386 
387     case RequestStopRendering :
388          if (!rendering)
389            return (ExRequestFailedNotRendering) ;
390          stop_rendering = true ;
391          message_printf ("Rendering stopped by GUI extension\n") ;
392 		 SendMessage (main_window, WM_COMMAND, CM_STOPRENDER, 0) ;
393          return (ExRequestOK) ;
394 
395     case RequestExit :
396          if (rendering)
397            return (ExRequestFailedRendering) ;
398          message_printf ("Exit requested by GUI extension\n") ;
399          Sleep (1000) ;
400          SendMessage (main_window, WM_CLOSE, 0, 0) ;
401          return (ExRequestOK) ;
402   }
403   return (ExRequestUnknown) ;
404 }
405 
ExternalMenuSelect(WPARAM Code)406 DWORD ExternalMenuSelect (WPARAM Code)
407 {
408   RealGuiPointerBlock   *p ;
409 
410   if (!ExtensionsEnabled)
411     return (1) ;
412   p = GuiPointerBlocks ;
413   while (p)
414   {
415     if (Code >= p->InstanceData.FirstMenuItem && Code <= p->InstanceData.FirstMenuItem + 59)
416       return ((*p->MenuSelect) (&p->InstanceData, Code - p->InstanceData.FirstMenuItem)) ;
417     p = p->Next ;
418   }
419   return (1) ;
420 }
421 
ExternalMenuTip(WPARAM wParam)422 char *ExternalMenuTip (WPARAM wParam)
423 {
424   RealGuiPointerBlock   *p ;
425 
426   if (!ExtensionsEnabled)
427     return ("Extensions Disabled") ;
428   p = GuiPointerBlocks ;
429   while (p)
430   {
431     if (wParam >= p->InstanceData.FirstMenuItem && wParam <= p->InstanceData.FirstMenuItem + 59)
432       return ((*p->MenuTip) (&p->InstanceData, wParam - p->InstanceData.FirstMenuItem)) ;
433     p = p->Next ;
434   }
435   return ("") ;
436 }
437 
ValidateMenu(HMENU hMenu,int first,int last)438 bool ValidateMenu (HMENU hMenu, int first, int last)
439 {
440   int         count ;
441   int         i ;
442   int         id ;
443   HMENU       hSubMenu ;
444 
445   count = GetMenuItemCount (hMenu) ;
446   for (i = 0 ; i < count ; i++)
447   {
448     if ((id = GetMenuItemID (hMenu, i)) == 0xffffffff)
449     {
450       // could be a popup menu
451       if ((hSubMenu = GetSubMenu (hMenu, i)) == NULL)
452         continue ;
453       if (!ValidateMenu (hSubMenu, first, last))
454         return (false) ;
455       continue ;
456     }
457     if (id == 0 || id == 0xffff)
458       continue ;
459     if (id < first || id > last)
460       return (false) ;
461   }
462   return (true) ;
463 }
464 
LoadGUIExtensions(void)465 void LoadGUIExtensions (void)
466 {
467   int                   i ;
468   int                   FirstMenuItem = CM_FIRSTGUIEXT ;
469   char                  str [64] ;
470   char                  filename [_MAX_PATH] ;
471   char                  name [_MAX_PATH] ;
472   bool                  first = true ;
473   bool                  loaded = false ;
474   HINSTANCE             hLib ;
475   GuiPointerBlock       PointerBlock ;
476   RealGuiPointerBlock   *RealPointerBlock ;
477   RealGuiPointerBlock   *LastPointerBlock = NULL ;
478 
479   if (!ExtensionsEnabled)
480     return ;
481   for (i = 0 ; i < MAX_GUI_EXT ; i++)
482   {
483     sprintf (str, "ExtDll%02d", i) ;
484     GetHKCU("GuiExtensions", str, "", filename, sizeof (filename));
485     if (filename [0] != '\0')
486     {
487       if (first)
488       {
489         first = false ;
490         buffer_message (mDivider, "\n") ;
491         message_printf ("DISCLAIMER : The POV-Team takes no responsibility for the operation of third-party GUI Extensions.\n") ;
492         message_printf ("             Please do not send us bug reports if they cause things to go haywire.\n\n") ;
493       }
494 
495       splitpath (filename, NULL, name) ;
496       if ((hLib = LoadLibrary (filename)) == NULL)
497       {
498         if (debugging)
499           debug_output ("Could not load GUI Extension DLL '%s', error code is %08lx\n", filename, GetLastError ()) ;
500         message_printf ("Could not load GUI Extension DLL '%s'\n", name) ;
501         continue ;
502       }
503       GuiExtGetPointers = (unsigned long(WINAPI *)(int, GuiPointerBlock *))GetProcAddress (hLib, "PovGuiExtensionGetPointers") ;
504       if (GuiExtGetPointers == NULL)
505       {
506         if (debugging)
507           debug_output ("Could not get Init process address for GUI extension '%s', error code is %08lx\n", filename, GetLastError ()) ;
508         message_printf ("Could not get Init address for GUI Extension DLL '%s'\n", name) ;
509         message_printf ("  Contact author of '%s'\n", name) ;
510         FreeLibrary (hLib) ;
511         continue ;
512       }
513       memset (&PointerBlock, 0, sizeof (PointerBlock)) ;
514       if (GuiExtGetPointers (sizeof (PointerBlock), &PointerBlock) == 0)
515       {
516         if (debugging)
517           debug_output ("Could not get pointers for GUI extension '%s'\n", filename) ;
518         message_printf ("Could not get pointers for GUI extension '%s'\n", name) ;
519         message_printf ("  Contact author of '%s'\n", name) ;
520         FreeLibrary (hLib) ;
521         continue ;
522       }
523       if (PointerBlock.Init == NULL ||
524           PointerBlock.MenuSelect == NULL ||
525           PointerBlock.MenuTip == NULL ||
526           (PointerBlock.Signature != 'CJC!' && PointerBlock.Signature != '!CJC'))
527       {
528         if (debugging)
529           debug_output ("PointerBlock not correctly initialized by GUI extension '%s'\n", filename) ;
530         message_printf ("PointerBlock not correctly initialized by GUI extension '%s'\n", name) ;
531         message_printf ("  Contact author of '%s'\n", name) ;
532         FreeLibrary (hLib) ;
533         continue ;
534       }
535       memset (&InitStruct, 0, sizeof (InitStruct)) ;
536       InitStruct.PovVersion = "" ;
537       InitStruct.GuiVersion = "" ;
538       InitStruct.GuiInterfaceVersion = GUI_INTERFACE_VERSION ;
539       InitStruct.hInst = hInstance ;
540       InitStruct.MainWindow = main_window ;
541       InitStruct.ExternalRequest = ExternalRequest ;
542       InitStruct.FirstMenuItem = FirstMenuItem ;
543       if ((*PointerBlock.Init) (PointerBlock.InstanceID, sizeof (InitStruct), &InitStruct) == 0)
544       {
545         if (debugging)
546           debug_output ("Init () failed (return code == 0) for GUI extension '%s'\n", filename) ;
547         message_printf ("Init () failed (return code == 0) for GUI extension '%s'\n", name) ;
548         message_printf ("  Contact %s <%s>\n", InitStruct.Author, InitStruct.AuthorEmail) ;
549         FreeLibrary (hLib) ;
550         continue ;
551       }
552       if (InitStruct.Name == NULL || strlen (InitStruct.Name) < 8 ||
553           InitStruct.Author == NULL || strlen (InitStruct.Author) < 8 ||
554           InitStruct.AuthorEmail == NULL || strlen (InitStruct.AuthorEmail) < 8 ||
555           strncmp (InitStruct.Author, "Place ", 6) == 0 ||
556           strncmp (InitStruct.AuthorEmail, "Place ", 6) == 0)
557       {
558         if (debugging)
559           debug_output ("GUI extension '%s' has invalid name/author/email\n", filename) ;
560         message_printf ("GUI extension '%s' has invalid name/author/email. Contact author of add-in.\n", name) ;
561         FreeLibrary (hLib) ;
562         continue ;
563       }
564       if (InitStruct.DLLInterfaceVersion / 100 != GUI_INTERFACE_VERSION / 100)
565       {
566         if (debugging)
567           debug_output ("GUI extension '%s' ('%s') is wrong version (%d)\n", filename, InitStruct.Name, InitStruct.DLLInterfaceVersion) ;
568         message_printf ("GUI extension '%s' ('%s') is wrong version (%d)\n", name, InitStruct.Name, InitStruct.DLLInterfaceVersion) ;
569         message_printf ("  Contact %s <%s>\n", InitStruct.Author, InitStruct.AuthorEmail) ;
570         FreeLibrary (hLib) ;
571         continue ;
572       }
573       if (strcmp (InitStruct.Agreement, "The author of this POV-Ray(tm) GUI Extension DLL certifies that, at the time of "
574                                         "its production or distribution, it complied with the POV-Ray Team's then current "
575                                         "requirements for GUI Extensions to POV-Ray for Windows, and acknowledges that it "
576                                         "is a violation of copyright to fail to do so. This text is copyright (c) the "
577                                         "POV-Team 1996. Used by permission.") != 0)
578       {
579         if (debugging)
580           debug_output ("GUI extension '%s' ('%s') has invalid agreement\n  '%s'", filename, InitStruct.Name, InitStruct.Agreement) ;
581         message_printf ("GUI extension '%s' ('%s') has invalid agreement\n", name, InitStruct.Name) ;
582         message_printf ("  Contact %s at %s\n", InitStruct.Author, InitStruct.AuthorEmail) ;
583         FreeLibrary (hLib) ;
584         continue ;
585       }
586       if (InitStruct.hMenu == NULL || !IsMenu (InitStruct.hMenu))
587       {
588         if (debugging)
589           debug_output ("GUI extension '%s' ('%s') has no menu\n", filename, InitStruct.Name) ;
590         message_printf ("GUI extension '%s' ('%s') has no menu\n", name, InitStruct.Name) ;
591         message_printf ("  Contact %s at %s\n", InitStruct.Author, InitStruct.AuthorEmail) ;
592         FreeLibrary (hLib) ;
593         continue ;
594       }
595       if (!ValidateMenu (InitStruct.hMenu, FirstMenuItem, FirstMenuItem + 59))
596       {
597         if (debugging)
598           debug_output ("GUI extension '%s' ('%s') has invalid menu ID's\n", filename, InitStruct.Name) ;
599         message_printf ("GUI extension '%s' ('%s') has invalid menu ID's\n", name, InitStruct.Name) ;
600         message_printf ("  Contact %s at %s\n", InitStruct.Author, InitStruct.AuthorEmail) ;
601         FreeLibrary (hLib) ;
602         continue ;
603       }
604       if ((RealPointerBlock = (RealGuiPointerBlock *)calloc (sizeof (RealGuiPointerBlock), 1)) == NULL)
605       {
606         message_printf ("Memory allocation error\n") ;
607         FreeLibrary (hLib) ;
608         continue ;
609       }
610       switch (InitStruct.DLLInterfaceVersion)
611       {
612         case 100 :
613              PointerBlock.AssignPixel = NULL ;
614 			 PointerBlock.DisplayPlotBlock = NULL;
615              break ;
616 
617         case 101 :
618 			 PointerBlock.DisplayPlotBlock = NULL;
619              break ;
620 
621 		case 102 :
622 			 break;
623 
624         default :
625              if (debugging)
626                debug_output ("GUI extension '%s' ('%s') is for a later version of POV (DLLInterfaceVersion is %04x)\n",
627                                    filename, InitStruct.Name, InitStruct.DLLInterfaceVersion) ;
628              message_printf ("GUI extension '%s' ('%s') is for a later version of POV-Ray\n", name, InitStruct.Name) ;
629              message_printf ("  Contact %s at %s\n", InitStruct.Author, InitStruct.AuthorEmail) ;
630              FreeLibrary (hLib) ;
631              continue ;
632       }
633       memcpy (RealPointerBlock, &PointerBlock, sizeof (PointerBlock) - sizeof (PointerBlock.Reserved)) ;
634       strncpy (RealPointerBlock->Name, InitStruct.Name, sizeof (RealPointerBlock->Name)) ;
635       strncpy (RealPointerBlock->Author, InitStruct.Author, sizeof (RealPointerBlock->Author)) ;
636       strncpy (RealPointerBlock->AuthorEmail, InitStruct.AuthorEmail, sizeof (RealPointerBlock->AuthorEmail)) ;
637       strncpy (RealPointerBlock->FileName, filename, sizeof (RealPointerBlock->FileName)) ;
638       RealPointerBlock->InstanceData.FirstMenuItem = FirstMenuItem ;
639       RealPointerBlock->InstanceData.InstanceID = PointerBlock.InstanceID ;
640       RealPointerBlock->InstanceData.hMenu = InitStruct.hMenu ;
641       RealPointerBlock->IniID = i ;
642       if (!loaded)
643         DeleteMenu (hPluginsMenu, hide_newuser_help ? 1 : 3, MF_BYPOSITION) ;
644       AppendMenu (hPluginsMenu, MF_POPUP, (UINT_PTR) InitStruct.hMenu, InitStruct.Name) ;
645       FirstMenuItem += 64 ;
646       message_printf ("GUI Extension '%s' loaded from '%s'\n", InitStruct.Name, name) ;
647       message_printf ("  Report any problems to %s <%s>\n", InitStruct.Author, InitStruct.AuthorEmail) ;
648       if (LastPointerBlock != NULL)
649       {
650         LastPointerBlock->Next = RealPointerBlock ;
651         LastPointerBlock = RealPointerBlock ;
652       }
653       else
654         LastPointerBlock = GuiPointerBlocks = RealPointerBlock ;
655       loaded = true ;
656     }
657   }
658   if (!first)
659     buffer_message (mDivider, "\n") ;
660   if (debugging && loaded)
661   {
662     RealPointerBlock = GuiPointerBlocks ;
663     debug_output ("\nGUI extension summary:\n") ;
664     while (RealPointerBlock)
665     {
666       debug_output ("\nExtension DLL '%s'\n\n", RealPointerBlock->FileName) ;
667       debug_output ("  Name             : '%s'\n", RealPointerBlock->Name) ;
668       debug_output ("  Author           : '%s'\n", RealPointerBlock->Author) ;
669       debug_output ("  AuthorEmail      : '%s'\n", RealPointerBlock->AuthorEmail) ;
670       debug_output ("  IniID            : %d\n", RealPointerBlock->IniID) ;
671       debug_output ("  Init             : %p\n", RealPointerBlock->Init) ;
672       debug_output ("  Destroy          : %p\n", RealPointerBlock->Destroy) ;
673       debug_output ("  MenuSelect       : %p\n", RealPointerBlock->MenuSelect) ;
674       debug_output ("  Event            : %p\n", RealPointerBlock->Event) ;
675       debug_output ("  DisplayPlot      : %p\n", RealPointerBlock->DisplayPlot) ;
676       debug_output ("  DisplayPlotRect  : %p\n", RealPointerBlock->DisplayPlotRect) ;
677       debug_output ("  WinPrePixel      : %p\n", RealPointerBlock->WinPrePixel) ;
678       debug_output ("  WinPostPixel     : %p\n", RealPointerBlock->WinPostPixel) ;
679       debug_output ("  WinSystem        : %p\n", RealPointerBlock->WinSystem) ;
680       debug_output ("  CleanupAll       : %p\n", RealPointerBlock->CleanupAll) ;
681       debug_output ("  BufferMessage    : %p\n", RealPointerBlock->BufferMessage) ;
682       debug_output ("  ParseToolCommand : %p\n", RealPointerBlock->ParseToolCommand) ;
683       debug_output ("  DragFunction     : %p\n", RealPointerBlock->DragFunction) ;
684       debug_output ("  FirstMenuItem    : %p\n", RealPointerBlock->InstanceData.FirstMenuItem) ;
685 #ifdef _WIN64
686       debug_output ("  InstanceID       : %016lX\n", RealPointerBlock->InstanceData.InstanceID) ;
687 #else
688       debug_output ("  InstanceID       : %08X\n", RealPointerBlock->InstanceData.InstanceID) ;
689 #endif
690       debug_output ("  hMenu            : %p\n", RealPointerBlock->InstanceData.hMenu) ;
691       debug_output ("  AssignPixel      : %p\n", RealPointerBlock->AssignPixel) ;
692       RealPointerBlock = RealPointerBlock->Next ;
693     }
694     debug_output ("\n") ;
695   }
696 }
697 
CheckGUIExtLoaded(const char * Name)698 BOOL CheckGUIExtLoaded (const char *Name)
699 {
700   RealGuiPointerBlock *pb = GuiPointerBlocks ;
701   while (pb)
702   {
703     if (_stricmp (pb->Name, Name) == 0)
704       return (true) ;
705     pb = pb->Next ;
706   }
707   return (false) ;
708 }
709 
710 }
711