Solved

Termination of Dos based app with Win32 thread.

Posted on 2004-08-02
6
336 Views
Last Modified: 2010-07-27
I have an application. It uses a thread to call up an external application. A dos based app called WGet. WGet retrieves files for me.

Since WGet is ran in a thread (as I need it to be) I provide a way for the early termination of the thread.

But when the thread is terminated early by my choice (a button) I find that I need to close the window. I use FindWindow with the classname of the WGet application. Then I use SendMessage with WM_CLOSE.

What happens is I get that annoying Dos type messagebox...

Windows cannot shut down this program automatically.
It is recommended that you exit the program with it's quit or exit command....

Do you wish to terminate the program now... (Yes) (No).

I would like to either force the dos app to close without this message.
Or hear a better solution?

RJ
0
Comment
Question by:RJSoft
  • 3
  • 3
6 Comments
 
LVL 86

Expert Comment

by:jkr
Comment Utility
See http://support.microsoft.com/default.aspx?scid=http://support.microsoft.com:80/support/kb/articles/Q178/8/93.ASP&NoWebContent=1 ("How To Terminate an Application "Cleanly" in Win32") - it comes with all the code you need :o)
0
 
LVL 86

Expert Comment

by:jkr
Comment Utility
BTW, to sum it up - the idea is to call 'TerminateProcess()', since a console application has now window to which you can send a message. The code is

   //******************
   //Header
   //******************

   #include <windows.h>

   #define TA_FAILED 0
   #define TA_SUCCESS_CLEAN 1
   #define TA_SUCCESS_KILL 2
   #define TA_SUCCESS_16 3

   DWORD WINAPI TerminateApp( DWORD dwPID, DWORD dwTimeout ) ;
   DWORD WINAPI Terminate16App( DWORD dwPID, DWORD dwThread,
                        WORD w16Task, DWORD dwTimeout );

   //******************
   //Source
   //******************

   #include "TermApp.h"
   #include <vdmdbg.h>

   typedef struct
   {
      DWORD   dwID ;
      DWORD   dwThread ;
   } TERMINFO ;

   // Declare Callback Enum Functions.
   BOOL CALLBACK TerminateAppEnum( HWND hwnd, LPARAM lParam ) ;

   BOOL CALLBACK Terminate16AppEnum( HWND hwnd, LPARAM lParam ) ;

   /*----------------------------------------------------------------
   DWORD WINAPI TerminateApp( DWORD dwPID, DWORD dwTimeout )

   Purpose:
      Shut down a 32-Bit Process (or 16-bit process under Windows 95)

   Parameters:
      dwPID
         Process ID of the process to shut down.

      dwTimeout
         Wait time in milliseconds before shutting down the process.

   Return Value:
      TA_FAILED - If the shutdown failed.
      TA_SUCCESS_CLEAN - If the process was shutdown using WM_CLOSE.
      TA_SUCCESS_KILL - if the process was shut down with
         TerminateProcess().
      NOTE:  See header for these defines.
   ----------------------------------------------------------------*/
   DWORD WINAPI TerminateApp( DWORD dwPID, DWORD dwTimeout )
   {
      HANDLE   hProc ;
      DWORD   dwRet ;

      // If we can't open the process with PROCESS_TERMINATE rights,
      // then we give up immediately.
      hProc = OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE, FALSE,
         dwPID);

      if(hProc == NULL)
      {
         return TA_FAILED ;
      }

      // TerminateAppEnum() posts WM_CLOSE to all windows whose PID
      // matches your process's.
      EnumWindows((WNDENUMPROC)TerminateAppEnum, (LPARAM) dwPID) ;

      // Wait on the handle. If it signals, great. If it times out,
      // then you kill it.
      if(WaitForSingleObject(hProc, dwTimeout)!=WAIT_OBJECT_0)
         dwRet=(TerminateProcess(hProc,0)?TA_SUCCESS_KILL:TA_FAILED);
      else
         dwRet = TA_SUCCESS_CLEAN ;

      CloseHandle(hProc) ;

      return dwRet ;
   }

   /*----------------------------------------------------------------
   DWORD WINAPI Terminate16App( DWORD dwPID, DWORD dwThread,
                        WORD w16Task, DWORD dwTimeout )

   Purpose:
      Shut down a Win16 APP.

   Parameters:
      dwPID
         Process ID of the NTVDM in which the 16-bit application is
         running.

      dwThread
         Thread ID of the thread of execution for the 16-bit
         application.

      w16Task
         16-bit task handle for the application.

      dwTimeout
         Wait time in milliseconds before shutting down the task.

   Return Value:
      If successful, returns TA_SUCCESS_16
      If unsuccessful, returns TA_FAILED.
      NOTE:  These values are defined in the header for this
      function.

   NOTE:
      You can get the Win16 task and thread ID through the
      VDMEnumTaskWOW() or the VDMEnumTaskWOWEx() functions.
   ----------------------------------------------------------------*/
   DWORD WINAPI Terminate16App( DWORD dwPID, DWORD dwThread,
                        WORD w16Task, DWORD dwTimeout )
   {
      HINSTANCE      hInstLib ;
      TERMINFO      info ;

      // You will be calling the functions through explicit linking
      // so that this code will be binary compatible across
      // Win32 platforms.
      BOOL (WINAPI *lpfVDMTerminateTaskWOW)(DWORD dwProcessId,
         WORD htask) ;

      hInstLib = LoadLibraryA( "VDMDBG.DLL" ) ;
      if( hInstLib == NULL )
         return TA_FAILED ;

      // Get procedure addresses.
      lpfVDMTerminateTaskWOW = (BOOL (WINAPI *)(DWORD, WORD ))
         GetProcAddress( hInstLib, "VDMTerminateTaskWOW" ) ;

      if( lpfVDMTerminateTaskWOW == NULL )
      {
         FreeLibrary( hInstLib ) ;
         return TA_FAILED ;
      }

      // Post a WM_CLOSE to all windows that match the ID and the
      // thread.
      info.dwID = dwPID ;
      info.dwThread = dwThread ;
      EnumWindows((WNDENUMPROC)Terminate16AppEnum, (LPARAM) &info) ;

      // Wait.
      Sleep( dwTimeout ) ;

      // Then terminate.
      lpfVDMTerminateTaskWOW(dwPID, w16Task) ;

      FreeLibrary( hInstLib ) ;
      return TA_SUCCESS_16 ;
   }

   BOOL CALLBACK TerminateAppEnum( HWND hwnd, LPARAM lParam )
   {
      DWORD dwID ;

      GetWindowThreadProcessId(hwnd, &dwID) ;

      if(dwID == (DWORD)lParam)
      {
         PostMessage(hwnd, WM_CLOSE, 0, 0) ;
      }

      return TRUE ;
   }

   BOOL CALLBACK Terminate16AppEnum( HWND hwnd, LPARAM lParam )
   {
      DWORD      dwID ;
      DWORD      dwThread ;
      TERMINFO   *termInfo ;

      termInfo = (TERMINFO *)lParam ;

      dwThread = GetWindowThreadProcessId(hwnd, &dwID) ;

      if(dwID == termInfo->dwID && termInfo->dwThread == dwThread )
      {
         PostMessage(hwnd, WM_CLOSE, 0, 0) ;
      }

      return TRUE ;
   }
0
 
LVL 3

Author Comment

by:RJSoft
Comment Utility
Well I am not even sure if WGet is a 16 bit app. But I see the code covers both scenarios (16 and 32).

So what's the quick way to find out if WGet is 16 bit or not. Not even sure what version I have. But I could probably figure it out with WGet --help.

Also about the closing of WGet. The way my application uses WGet there is only one thread at a time. So I wind up with only one Dos dialog to close.

Does it allways mean that an app is 16 bit if it displays the dialog as previous mention. Or could it also be a Win32 console app that behaves that way.

I am stuck at the crossroads now. I could remake the WGet with Perl scripting that I can use within my application. This would also allow me to display values obtained like file download progress etc.. in a dialog that belongs to my app. I wish WGet had a library version. Then I would be set.

On one hand I am not overly concearned if the termination of WGet causes resource problem. The article seems to indicate that it is never perfect. But close.

Then another consideration is to just allow the dialog to show and having the user close it.

I dont know. What is your opinion? I am thinking seriously about trying to find library or Perl modules to help me replace WGet. A library would be the best answer. Because I want to provide visual feedback.

My app is a scraper of sorts. It scrapes files from a list of URLs using WGet. It takse a long long time scraping. I usually use it over night. For each URL it parses other html links to other pages and then downloads any files found as source. At 5 to 10 levels deep it can scrape quite a few pages per each URL. So you can understand that a user using my app maybe a bit confused by a Please Wait dialog that does not display anyhing but animation.

Unless there was a way to make WGet output obtainable to a dialog. Maybe output to text and the dialog uses a timer to read the text. But I dont know.

Anyway, any comments apreciated.
RJ

Thanks for the link much apreciated.

0
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 
LVL 86

Accepted Solution

by:
jkr earned 500 total points
Comment Utility
>>So what's the quick way to find out if WGet is 16 bit or not

Check the file's properties or call 'GetBinaryType()' :o)

>>I dont know. What is your opinion?

Good question - if you 'only' want to download files, I'd use 'URLDownloadToFile()' instead. But, you can always terminate the application also. And, since wget is already there...

>>Unless there was a way to make WGet output obtainable to a dialo

There for sure is one - check http://support.microsoft.com/default.aspx?scid=http://support.microsoft.com:80/support/kb/articles/Q190/3/51.ASP&NoWebContent=1 ("How To Spawn Console Processes with Redirected Standard Hand") - this way, you can read all the output of wget.

0
 
LVL 3

Author Comment

by:RJSoft
Comment Utility
Thanks!

RJ
0
 
LVL 3

Author Comment

by:RJSoft
Comment Utility
Notes:

http://www.codeproject.com/dialog/bmpdlg01.asp

Code project class with piping.
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

What is C++ STL?: STL stands for Standard Template Library and is a part of standard C++ libraries. It contains many useful data structures (containers) and algorithms, which can spare you a lot of the time. Today we will look at the STL Vector. …
Many modern programming languages support the concept of a property -- a class member that combines characteristics of both a data member and a method.  These are sometimes called "smart fields" because you can add logic that is applied automaticall…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

763 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now