naga1979
asked on
Write In Console
Dear Experts
I developed a application which will run continuously. Each and every status of the application will be logged in a log file. I developed my application in such a way that it hides in the task bar when it is minimized. What i want to do is to write each and every status of the application in the dos console. So that the status can be viewed in the console. I am able to write the status in the dos console with the following APIs
Private Declare Function AllocConsole Lib "kernel32" () As Long
Private Declare Function FreeConsole Lib "kernel32" () As Long
Private Declare Function GetStdHandle Lib "kernel32" (ByVal nStdHandle As Long) As Long
Private Declare Function WriteConsole Lib "kernel32" Alias "WriteConsoleA" (ByVal hConsoleOutput As Long, ByVal lpBuffer As Any, ByVal nNumberOfCharsToWrite As Long, lpNumberOfCharsWritten As Long, lpReserved As Any) As Long
The problem here is when the user closes the console using the window close button it is throwing some memory error and terminates the actual application itself. Its not throwing any error if we use FreeConsole API to close the console. How to avoid this error. Can we avoid the user closing the console. How to avoid the memory error.
Cheers!
I developed a application which will run continuously. Each and every status of the application will be logged in a log file. I developed my application in such a way that it hides in the task bar when it is minimized. What i want to do is to write each and every status of the application in the dos console. So that the status can be viewed in the console. I am able to write the status in the dos console with the following APIs
Private Declare Function AllocConsole Lib "kernel32" () As Long
Private Declare Function FreeConsole Lib "kernel32" () As Long
Private Declare Function GetStdHandle Lib "kernel32" (ByVal nStdHandle As Long) As Long
Private Declare Function WriteConsole Lib "kernel32" Alias "WriteConsoleA" (ByVal hConsoleOutput As Long, ByVal lpBuffer As Any, ByVal nNumberOfCharsToWrite As Long, lpNumberOfCharsWritten As Long, lpReserved As Any) As Long
The problem here is when the user closes the console using the window close button it is throwing some memory error and terminates the actual application itself. Its not throwing any error if we use FreeConsole API to close the console. How to avoid this error. Can we avoid the user closing the console. How to avoid the memory error.
Cheers!
ASKER
Dera abel
Here is my code
Private Declare Function AllocConsole Lib "kernel32" () As Long
Private Declare Function FreeConsole Lib "kernel32" () As Long
Private Declare Function GetStdHandle Lib "kernel32" (ByVal nStdHandle As Long) As Long
Private Const STD_INPUT_HANDLE = -10&
Private Const STD_OUTPUT_HANDLE = -11&
Private Const STD_ERROR_HANDLE = -12&
Private Declare Function WriteConsole Lib "kernel32" Alias "WriteConsoleA" (ByVal hConsoleOutput As Long, ByVal lpBuffer As Any, ByVal nNumberOfCharsToWrite As Long, lpNumberOfCharsWritten As Long, lpReserved As Any) As Long
Private Declare Function SetConsoleTitle Lib "kernel32" Alias "SetConsoleTitleA" (ByVal lpConsoleTitle As String) As Long
Private Declare Function SetConsoleActiveScreenBuff er Lib "kernel32" (ByVal hConsoleOutput As Long) As Long
Private Sub Command1_Click()
FreeConsole
End Sub
Private Sub Form_Load()
Dim z As String
AllocConsole
x = GetStdHandle(STD_OUTPUT_HA NDLE)
z = "Hai how are you " + vbCrLf
SetConsoleTitle ("Hello World")
For i = 0 To 50
WriteConsole x, z, Len(z), vbNull, vbNull
Next
End Sub
In this i get error if try to close the console directly.
Cheers!
Here is my code
Private Declare Function AllocConsole Lib "kernel32" () As Long
Private Declare Function FreeConsole Lib "kernel32" () As Long
Private Declare Function GetStdHandle Lib "kernel32" (ByVal nStdHandle As Long) As Long
Private Const STD_INPUT_HANDLE = -10&
Private Const STD_OUTPUT_HANDLE = -11&
Private Const STD_ERROR_HANDLE = -12&
Private Declare Function WriteConsole Lib "kernel32" Alias "WriteConsoleA" (ByVal hConsoleOutput As Long, ByVal lpBuffer As Any, ByVal nNumberOfCharsToWrite As Long, lpNumberOfCharsWritten As Long, lpReserved As Any) As Long
Private Declare Function SetConsoleTitle Lib "kernel32" Alias "SetConsoleTitleA" (ByVal lpConsoleTitle As String) As Long
Private Declare Function SetConsoleActiveScreenBuff
Private Sub Command1_Click()
FreeConsole
End Sub
Private Sub Form_Load()
Dim z As String
AllocConsole
x = GetStdHandle(STD_OUTPUT_HA
z = "Hai how are you " + vbCrLf
SetConsoleTitle ("Hello World")
For i = 0 To 50
WriteConsole x, z, Len(z), vbNull, vbNull
Next
End Sub
In this i get error if try to close the console directly.
Cheers!
Hi naga,
The method I suggested is not usable in this situation. I'm sorry for that, but that's how it is. My search for any other solution appeared to be fruitless and I was about to give up (enough melodrama?) when I finally saw the light!
Here's what the problem is: a console window is not subclassable, end of story. You cannot change its properties, you cannot change its class or the properties of its class. What you CAN do is sending messages to it, like a WM_CLOSE, but that's not going to help us here. In addition, Microsoft does not issue any message when it creates or destroys the window. It does not have a parent window and it does not belong to your application. It runs in its own thread and that's yet another reason why you can do so little with it. As it turns out, consoles have a special place when it comes to windows, and that's all probably due to the fact that it can run full-screen and act as if it were not a window at all. After all, you can run console applications in it, and they differ significantly in design from GUI applications.
But that's not all. In times of Windows 95/98 there were still some possibilities to peek and poke around the memory areas of other processes, including console processes. In Win2k this is not possible at all, unless you design your own device driver to do the tricks.
Just this morning I thought of two possible solutions for you. One is about creating an out of process COM object (EXE) using VB and encapsulate the whole console-story in that object. If the console quits, the object quits, but nobody really cares, right? And that only raises trappable errors, and that's what we were after.
Second is a solution probably way beyond the current scope, but depending on your needs easy to implement: simulate your own console. If it's only about informing the user, you can create a window similar to a console window and use the OEM font to make it look original.
But these two options all faint when I start talking about the one and only solution that is really to your needs (am I overacting?). The cure to all your illnesses: SetConsoleCtrlhandler!
That function does exactly what we need: it creates a handler (some kind of callback function in this case, that you have to provide yourself) that processes close, ctrl-c and ctrl-break messages. And you probably knew that you could also close it not only with the close-button but with ctrl-c/break, and those we are going to catch as well.
This story ends up way beyond moderate level of programming, and not knowing what your level is, I just provide you with the sample code I used while investigating:
'--MODULE
Option Explicit
Public Const CTRL_BREAK_EVENT = 1
Public Const CTRL_C_EVENT = 0
Public Const CTRL_CLOSE_EVENT = 2
Public Const CTRL_LOGOFF_EVENT = 5
Public Const CTRL_SHUTDOWN_EVENT = 6
Public Function HandlerRoutine(ByVal dwCtrlType As Long) As Long 'ByVal is VERY IMPORTANT!!!
Select Case dwCtrlType
Case CTRL_C_EVENT, CTRL_BREAK_EVENT
HandlerRoutine = 1
Case CTRL_CLOSE_EVENT
HandlerRoutine = 1
Form1.tmrShutDownDlg.Enabl ed = True
Case CTRL_LOGOFF_EVENT, CTRL_SHUTDOWN_EVENT
HandlerRoutine = 0
Case Else
MsgBox "A control event unknown and undocumented: " & dwCtrlType
HandlerRoutine = 0
End Select
End Function
'--FORM or whereever
Private Sub Command4_Click()
Dim z As String, x As Long, i As Long
Dim retval As Long
AllocConsole
x = GetStdHandle(STD_OUTPUT_HA NDLE)
z = "Hai how are you " + vbCrLf
SetConsoleTitle ("Hello World")
For i = 0 To 50
WriteConsole x, z, Len(z), vbNull, vbNull
Next
retval = SetConsoleCtrlHandler(Addr essOf HandlerRoutine, True) 'Return val nonzero: succes!
If retval = 0 Then
MsgBox "Problem"
End If
End Sub
Private Sub Command3_Click()
FreeConsole
End Sub
Private Sub tmrShutDownDlg_Timer()
Static count As Long
Dim hwnd As Long, str As String
str = "You tried to close it!" & vbCrLf
count = count + 1
If count > 100 Then '5 seconds passed!
tmrShutDownDlg.Enabled = False
count = 0
End If
hwnd = FindWindow("#32770", "End Program - Hello World")
If hwnd <> 0 Then
SendMessage hwnd, WM_CLOSE, 0, 0
WriteConsole GetStdHandle(STD_OUTPUT_HA NDLE), str, Len(str), 0, 0
If FindWindow("#32770", "End Program - Hello World") = 0 Then
tmrShutDownDlg.Enabled = False
End If
count = 0 'There may have been more then one click on the close button, start again!
End If
End Sub
I'll explain the code in the next post.
The method I suggested is not usable in this situation. I'm sorry for that, but that's how it is. My search for any other solution appeared to be fruitless and I was about to give up (enough melodrama?) when I finally saw the light!
Here's what the problem is: a console window is not subclassable, end of story. You cannot change its properties, you cannot change its class or the properties of its class. What you CAN do is sending messages to it, like a WM_CLOSE, but that's not going to help us here. In addition, Microsoft does not issue any message when it creates or destroys the window. It does not have a parent window and it does not belong to your application. It runs in its own thread and that's yet another reason why you can do so little with it. As it turns out, consoles have a special place when it comes to windows, and that's all probably due to the fact that it can run full-screen and act as if it were not a window at all. After all, you can run console applications in it, and they differ significantly in design from GUI applications.
But that's not all. In times of Windows 95/98 there were still some possibilities to peek and poke around the memory areas of other processes, including console processes. In Win2k this is not possible at all, unless you design your own device driver to do the tricks.
Just this morning I thought of two possible solutions for you. One is about creating an out of process COM object (EXE) using VB and encapsulate the whole console-story in that object. If the console quits, the object quits, but nobody really cares, right? And that only raises trappable errors, and that's what we were after.
Second is a solution probably way beyond the current scope, but depending on your needs easy to implement: simulate your own console. If it's only about informing the user, you can create a window similar to a console window and use the OEM font to make it look original.
But these two options all faint when I start talking about the one and only solution that is really to your needs (am I overacting?). The cure to all your illnesses: SetConsoleCtrlhandler!
That function does exactly what we need: it creates a handler (some kind of callback function in this case, that you have to provide yourself) that processes close, ctrl-c and ctrl-break messages. And you probably knew that you could also close it not only with the close-button but with ctrl-c/break, and those we are going to catch as well.
This story ends up way beyond moderate level of programming, and not knowing what your level is, I just provide you with the sample code I used while investigating:
'--MODULE
Option Explicit
Public Const CTRL_BREAK_EVENT = 1
Public Const CTRL_C_EVENT = 0
Public Const CTRL_CLOSE_EVENT = 2
Public Const CTRL_LOGOFF_EVENT = 5
Public Const CTRL_SHUTDOWN_EVENT = 6
Public Function HandlerRoutine(ByVal dwCtrlType As Long) As Long 'ByVal is VERY IMPORTANT!!!
Select Case dwCtrlType
Case CTRL_C_EVENT, CTRL_BREAK_EVENT
HandlerRoutine = 1
Case CTRL_CLOSE_EVENT
HandlerRoutine = 1
Form1.tmrShutDownDlg.Enabl
Case CTRL_LOGOFF_EVENT, CTRL_SHUTDOWN_EVENT
HandlerRoutine = 0
Case Else
MsgBox "A control event unknown and undocumented: " & dwCtrlType
HandlerRoutine = 0
End Select
End Function
'--FORM or whereever
Private Sub Command4_Click()
Dim z As String, x As Long, i As Long
Dim retval As Long
AllocConsole
x = GetStdHandle(STD_OUTPUT_HA
z = "Hai how are you " + vbCrLf
SetConsoleTitle ("Hello World")
For i = 0 To 50
WriteConsole x, z, Len(z), vbNull, vbNull
Next
retval = SetConsoleCtrlHandler(Addr
If retval = 0 Then
MsgBox "Problem"
End If
End Sub
Private Sub Command3_Click()
FreeConsole
End Sub
Private Sub tmrShutDownDlg_Timer()
Static count As Long
Dim hwnd As Long, str As String
str = "You tried to close it!" & vbCrLf
count = count + 1
If count > 100 Then '5 seconds passed!
tmrShutDownDlg.Enabled = False
count = 0
End If
hwnd = FindWindow("#32770", "End Program - Hello World")
If hwnd <> 0 Then
SendMessage hwnd, WM_CLOSE, 0, 0
WriteConsole GetStdHandle(STD_OUTPUT_HA
If FindWindow("#32770", "End Program - Hello World") = 0 Then
tmrShutDownDlg.Enabled = False
End If
count = 0 'There may have been more then one click on the close button, start again!
End If
End Sub
I'll explain the code in the next post.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Btw, if you use your code on a system other then Win2k: the handler still works, but the reaction of the OS is probably a little different. Like the classname, I guess it won't be "#32770" on all systems. And the searchtext should be adjusted to the name of the caption of the console window you use in the final incarnation of your application.
Ping ;-)
Just curious: did it help?
Just curious: did it help?
ASKER
Dear Abel
Give me some time, as i am busy with my office work.
Cheers!
Give me some time, as i am busy with my office work.
Cheers!
Hi naga1979,
acctually this is not my comment about your question posted here,I just want to tell you there are maybe some
points for you from my question 20400164 posted at somewhere shown as below:
https://www.experts-exchange.com/questions/20400164/Philips-SpeechMania-hddl-question-about-transaction-dll-in-c.html
since I found that you mentioned about Philips SpeechMania before by searching.
anyway it will be very appreciated if you can click and view my question mentioned above.
or could you suggest me any experts or links where I can find somebody who can help me?
thanks in advance
xyan00
supplementary description:
I want to display a parameter which is obtained by hddl from transaction dll,it would be better if the function
calling for the window that showing the parameter is also invoked in the transaction dll.
Hi naga1979,
It appears that you have forgotten this question. I will ask Community Support to close it unless you finalize it within 7 days. I will ask a Community Support Moderator to:
Accept abel's comment(s) as an answer.
naga1979, if you think your question was not answered at all or if you need help, just post a new comment here; Community Support will help you. DO NOT accept this comment as an answer.
EXPERTS: If you disagree with that recommendation, please post an explanatory comment.
==========
DanRollins -- EE database cleanup volunteer
It appears that you have forgotten this question. I will ask Community Support to close it unless you finalize it within 7 days. I will ask a Community Support Moderator to:
Accept abel's comment(s) as an answer.
naga1979, if you think your question was not answered at all or if you need help, just post a new comment here; Community Support will help you. DO NOT accept this comment as an answer.
EXPERTS: If you disagree with that recommendation, please post an explanatory comment.
==========
DanRollins -- EE database cleanup volunteer
You can do that by using SetClassLong, but the window must be in your process space, and I don't know if that is the case. If it is, use it before you create the window, because if you change classes, windows created with that class do not change, only newly created windows do. (note that "class" here has nothing to do with the notion of class most vb-users have).
If you can use it, you should call it with
GCL_STYLE constant and modify the CS_NOCLOSE bit. In pseudocode:
lStyle = GetClassLong(hwnd, GCL_STYLE)
lStyle = lStyle And (Not GCL_STYLE)
SetClassLong(hwnd, GCL_STYLE, lStyle)
CreateWindow(withNewClass)
Hope this helps a bit,
Abel