From 9b4243f9bfdb5653c0320e26ea708953ca82afce Mon Sep 17 00:00:00 2001 From: abv Date: Sun, 18 Nov 2018 19:53:10 +0300 Subject: [PATCH] 0030377: DRAW, Windows - command executed via option -c fails on puts When DRAW on Windows is launched with option -c, the command is now properly transferred to Tcl thread (separate thread that runs Tcl interpretor on Windows except when DRAW is run in batch mode) for execution, instead of being evaluated in the main thread. Execution of DRAW in batch mode (option -b) is fixed by enabling proper initialization of the Tcl interpretor and replacement of backslashes in path to startup script by straight slashes on Windows in that mode. Declaration of global variables used for communication of console command between threads is moved to Draw_Window.hxx to ensure consistency. Function wscpy_s is used instead of memcpy to avoid possible buffer overrun. --- src/Draw/CommandWindow.cxx | 5 +--- src/Draw/Draw.cxx | 55 +++++++++++++++++++++++--------------- src/Draw/Draw_Window.cxx | 11 ++++---- src/Draw/Draw_Window.hxx | 7 +++++ 4 files changed, 47 insertions(+), 31 deletions(-) diff --git a/src/Draw/CommandWindow.cxx b/src/Draw/CommandWindow.cxx index 5e9909dd5a..6d85fe9914 100644 --- a/src/Draw/CommandWindow.cxx +++ b/src/Draw/CommandWindow.cxx @@ -156,9 +156,6 @@ int GetCommand (HWND hWnd, wchar_t* theBuffer) return aNbChar; } -extern console_semaphore_value volatile console_semaphore; -extern wchar_t console_command[1000]; - /*--------------------------------------------------------*\ | EDIT WINDOW PROCEDURE \*--------------------------------------------------------*/ @@ -191,7 +188,7 @@ LRESULT APIENTRY EditProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam ) //TCollection_AsciiString aCmdUtf8 (aCmdBuffer + sizeof(THE_PROMPT) / sizeof(wchar_t) - 1); //Draw_Interprete (aCmdUtf8.ToCString()); //if (toExit) { DestroyProc (hWnd); } - wcscpy (console_command, aCmdBuffer + sizeof(THE_PROMPT) / sizeof(wchar_t) - 1); + wcscpy_s (console_command, aCmdBuffer + sizeof(THE_PROMPT) / sizeof(wchar_t) - 1); console_semaphore = HAS_CONSOLE_COMMAND; // Purge the buffer nbline = SendMessageW (hWnd, EM_GETLINECOUNT, 0l, 0l); diff --git a/src/Draw/Draw.cxx b/src/Draw/Draw.cxx index e6292aeb27..81a4567f86 100644 --- a/src/Draw/Draw.cxx +++ b/src/Draw/Draw.cxx @@ -66,8 +66,6 @@ filebuf Draw_Spyfile; static ostream spystream(&Draw_Spyfile); -static Standard_Boolean XLoop; - static Handle(Draw_ProgressIndicator) PInd = NULL; Standard_EXPORT Standard_Boolean Draw_Interprete(const char* command); @@ -76,23 +74,20 @@ Standard_EXPORT Standard_Boolean Draw_Interprete(const char* command); // ******************************************************************* // read an init file // ******************************************************************* -#ifdef _WIN32 -extern console_semaphore_value volatile console_semaphore; -extern wchar_t console_command[1000]; -#endif static void ReadInitFile (const TCollection_AsciiString& theFileName) { TCollection_AsciiString aPath = theFileName; #ifdef _WIN32 + aPath.ChangeAll('\\', '/'); if (!Draw_Batch) { try { - aPath.ChangeAll ('\\', '/'); { - const TCollection_ExtendedString aCmdWide = TCollection_ExtendedString ("source -encoding utf-8 \"") + TCollection_ExtendedString (aPath) + "\""; - memcpy (console_command, aCmdWide.ToWideString(), Min (aCmdWide.Length() + 1, 980) * sizeof(wchar_t)); + TCollection_ExtendedString aCmdWide ("source -encoding utf-8 \""); + aCmdWide += TCollection_ExtendedString (aPath) + "\""; + wcscpy_s (console_command, aCmdWide.ToWideString()); } console_semaphore = HAS_CONSOLE_COMMAND; while (console_semaphore == HAS_CONSOLE_COMMAND) @@ -286,10 +281,13 @@ void Draw_Appli(int argc, char** argv, const FDraw_InitAppli Draw_InitAppli) Draw_Batch=!Init_Appli(); #endif else + { cout << "DRAW is running in batch mode" << endl; + theCommands.Init(); + Tcl_Init(theCommands.Interp()); + } - XLoop = !Draw_Batch; - if (XLoop) + if (! Draw_Batch) { // Default colors for (int i = 0; i < MAXCOLOR; ++i) @@ -364,8 +362,21 @@ void Draw_Appli(int argc, char** argv, const FDraw_InitAppli Draw_InitAppli) } // execute command from command line - if (!aCommand.IsEmpty()) { - Draw_Interprete (aCommand.ToCString()); + if (!aCommand.IsEmpty()) + { +#ifdef _WIN32 + if (!Draw_Batch) + { + // on Windows except batch mode, commands are executed in separate thread + while (console_semaphore == HAS_CONSOLE_COMMAND) Sleep(10); + TCollection_ExtendedString aCmdWide(aCommand); + wcscpy_s(console_command, aCmdWide.ToWideString()); + console_semaphore = HAS_CONSOLE_COMMAND; + while (console_semaphore == HAS_CONSOLE_COMMAND) Sleep(10); + } + else +#endif + Draw_Interprete (aCommand.ToCString()); // Linux and Windows batch mode // provide a clean exit, this is useful for some analysis tools if ( ! isInteractiveForced ) #ifndef _WIN32 @@ -378,7 +389,7 @@ void Draw_Appli(int argc, char** argv, const FDraw_InitAppli Draw_InitAppli) // ***************************************************************** // X loop // ***************************************************************** - if (XLoop) { + if (! Draw_Batch) { #ifdef _WIN32 Run_Appli(hWnd); #else @@ -387,15 +398,15 @@ void Draw_Appli(int argc, char** argv, const FDraw_InitAppli Draw_InitAppli) } else { - char cmd[255]; - for (;;) + const int MAXCMD = 2048; + char cmd[MAXCMD]; + for (int ncmd = 1;; ++ncmd) { - cout << "Viewer>"; - int i = -1; - do { - cin.get(cmd[++i]); - } while ((cmd[i] != '\n') && (!cin.fail())); - cmd[i] = '\0'; + cout << "Draw[" << ncmd << "]> "; + if (cin.getline (cmd, MAXCMD).fail()) + { + break; + } Draw_Interprete(cmd); } } diff --git a/src/Draw/Draw_Window.cxx b/src/Draw/Draw_Window.cxx index 7aab0be547..2ffd7eeafd 100644 --- a/src/Draw/Draw_Window.cxx +++ b/src/Draw/Draw_Window.cxx @@ -30,6 +30,7 @@ #include #include +extern Standard_Boolean Draw_Batch; extern Standard_Boolean Draw_VirtualWindows; static Tcl_Interp *interp; /* Interpreter for this application. */ static NCollection_List MyCallbacks; @@ -2021,8 +2022,7 @@ static Tk_Window mainWindow; //* threads sinchronization *// DWORD dwMainThreadId; console_semaphore_value volatile console_semaphore = WAIT_CONSOLE_COMMAND; -#define THE_COMMAND_SIZE 1000 /* Console Command size */ -wchar_t console_command[THE_COMMAND_SIZE]; +wchar_t console_command[DRAW_COMMAND_SIZE + 1]; bool volatile isTkLoopStarted = false; /*--------------------------------------------------------*\ @@ -2051,6 +2051,7 @@ Standard_Boolean Init_Appli(HINSTANCE hInst, &IDThread); if (!hThread) { cout << "Tcl/Tk main loop thread not created. Switching to batch mode..." << endl; + Draw_Batch = Standard_True; #ifdef _TK try { OCC_CATCH_SIGNALS @@ -2125,7 +2126,7 @@ static DWORD WINAPI readStdinThreadFunc() && isConsoleInput) { DWORD aNbRead = 0; - if (ReadConsoleW (anStdIn, console_command, THE_COMMAND_SIZE, &aNbRead, NULL)) + if (ReadConsoleW (anStdIn, console_command, DRAW_COMMAND_SIZE, &aNbRead, NULL)) { console_command[aNbRead] = L'\0'; console_semaphore = HAS_CONSOLE_COMMAND; @@ -2145,7 +2146,7 @@ static DWORD WINAPI readStdinThreadFunc() } // fgetws() works only for characters within active locale (see setlocale()) - if (fgetws (console_command, THE_COMMAND_SIZE, stdin)) + if (fgetws (console_command, DRAW_COMMAND_SIZE, stdin)) { console_semaphore = HAS_CONSOLE_COMMAND; } @@ -2373,7 +2374,7 @@ static DWORD WINAPI tkLoop(VOID) } #ifdef _TK // We should not exit until the Main Tk window is closed - toLoop = (Tk_GetNumMainWindows() > 0) || Draw_VirtualWindows; + toLoop = (Draw_VirtualWindows || Tk_GetNumMainWindows() > 0); #endif } Tcl_Exit(0); diff --git a/src/Draw/Draw_Window.hxx b/src/Draw/Draw_Window.hxx index 05ea5497cf..2b9614ce85 100644 --- a/src/Draw/Draw_Window.hxx +++ b/src/Draw/Draw_Window.hxx @@ -516,6 +516,13 @@ typedef enum { WAIT_CONSOLE_COMMAND, HAS_CONSOLE_COMMAND} console_semaphore_value; +// global variable describing console state +extern console_semaphore_value volatile console_semaphore; + +// Console command buffer +#define DRAW_COMMAND_SIZE 1000 +extern wchar_t console_command[DRAW_COMMAND_SIZE + 1]; + // PROCEDURE DE DRAW WINDOW Standard_EXPORT Standard_Boolean Init_Appli(HINSTANCE,HINSTANCE,int,HWND&);