GetStdHandle .NET

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Dragon

    #1

    GetStdHandle .NET

    Hello all,
    I ran into trouble with GetStdHandle API. When I'm trying to get standard
    output with GetStdHandle(-11I), it returns strange values such as 1548,
    1876. If I try to WriteConsole() into these handles, it does not work, and
    GetLastError returns ERROR_INVALID_H ANDLE. But when I CloseHandle() them, it
    succeeds! I tested this in VC++ and VBA, and GetStdHandle(-11) always
    returns 7, which is valid. There is the same problem with standard error,
    but no problems with standard input.
    I declare GetStdHandle as follows:
    Declare Function GetStdHandle Lib "kernel32.d ll" (ByVal nStdHandle As _
    Int32) As IntPtr

    Any suggestions? Thank you in advance.





  • stand__sure

    #2
    Re: GetStdHandle .NET

    can you give us more code? how are you dereferencing the value?

    Comment

    • Jay B. Harlow [MVP - Outlook]

      #3
      Re: GetStdHandle .NET

      Dragon,
      Not sure what your error is about, as strand__sure suggests, can you show
      more of your code you are attempting to use.

      Rather then use Win32 APIs from .NET, have you considered using the
      System.Console class instead? It encapsulates most of the Win32 Console API
      functions. With .NET 2.0 (aka VS 2005, aka Whidbey, due out later in 2005.
      See http://lab.msdn.microsoft.com/vs2005/ for details) providing even more
      support.

      You can use Console.OpenSta ndardOutput in VS 2002 & 2003 to get the standard
      output stream. You can use Console.SetOut to set tell Console.Write what
      TextWriter (Stream) to use.

      Hope this helps
      Jay

      "Dragon" <no@spam.please > wrote in message news:d8pre1$csh $1@news.rol.ru. ..
      | Hello all,
      | I ran into trouble with GetStdHandle API. When I'm trying to get standard
      | output with GetStdHandle(-11I), it returns strange values such as 1548,
      | 1876. If I try to WriteConsole() into these handles, it does not work, and
      | GetLastError returns ERROR_INVALID_H ANDLE. But when I CloseHandle() them,
      it
      | succeeds! I tested this in VC++ and VBA, and GetStdHandle(-11) always
      | returns 7, which is valid. There is the same problem with standard error,
      | but no problems with standard input.
      | I declare GetStdHandle as follows:
      | Declare Function GetStdHandle Lib "kernel32.d ll" (ByVal nStdHandle As _
      | Int32) As IntPtr
      |
      | Any suggestions? Thank you in advance.
      |
      |
      |
      |
      |


      Comment

      • Dragon

        #4
        Re: GetStdHandle .NET


        "stand__sur e" <stand__sure@ho tmail.com> ???????/???????? ? ????????
        ?????????: news:1118863294 .867387.255650@ g49g2000cwa.goo glegroups.com.. .[color=blue]
        > can you give us more code? how are you dereferencing the value?
        >[/color]
        Well, that's my code:
        ~
        Private Declare Function AllocConsole Lib "kernel32.d ll" () As Int32

        Private Declare Function FreeConsole Lib "kernel32.d ll" () As Int32

        Private Declare Function GetStdHandle Lib "kernel32.d ll" (ByVal nStdHandle
        As Int32) As IntPtr

        Private Declare Function CloseHandle Lib "kernel32.d ll" (ByVal hObject As
        IntPtr) As Int32

        Private Declare Function WriteConsole Lib "kernel32.d ll" Alias
        "WriteConso leA" (ByVal hConsoleOutput As IntPtr, ByVal lpBuffer As IntPtr,
        ByVal nNumberOfCharsT oWrite As Int32, ByRef lpNumberOfChars Written As Int32,
        ByVal lpReserved As IntPtr) As Int32

        Private Declare Function GetLastError Lib "kernel32.d ll" () As Int32

        Private Const STD_OUTPUT_HAND LE As Int32 = -11I

        Private Sub SomeButton_Clic k(ByVal sender As Object, ByVal e As
        System.EventArg s) Handles SomeButton.Clic k

        If AllocConsole() = 0 Then Debug.WriteLine ("AllocConso le failed: " &
        GetLastError.To String)

        Dim hOutPut As IntPtr = GetStdHandle(ST D_OUTPUT_HANDLE )

        If hOutPut.ToInt32 = 0 Then Debug.WriteLine ("GetStdHand le failed: " &
        GetLastError.To String)

        Debug.WriteLine ("Standard output: " & hOutPut.ToStrin g)

        Dim str As String = "It's working!"

        Dim written As Int32

        Dim handle As IntPtr = Marshal.StringT oHGlobalAnsi(st r)

        If WriteConsole(hO utPut, handle, str.Length, written, New IntPtr(0)) = 0
        Then Debug.WriteLine ("WriteConso le failed: " & GetLastError)

        If CloseHandle(hOu tPut) = 0 Then Debug.WriteLine ("CloseHandl e failed: " &
        GetLastError)

        Threading.Threa d.Sleep(1000)

        If FreeConsole() = 0 Then Debug.WriteLine ("FreeConsol e failed: " &
        GetLastError.To String)

        End Sub

        ~

        When I click SomeButton for first time I get following output:

        Standard output: 1912 (or any other bad value)

        WriteConsole failed: 6

        If I keep clicking it prints:

        Standard output: 1912

        WriteConsole failed: 6

        CloseHandle failed: 6

        When I restart application number 1912 changes to another number and
        situation repeats.


        Comment

        • stand__sure

          #5
          Re: GetStdHandle .NET

          I am unable to duplicate your problem (i.e the code works)... the only
          change that I made is to throw your code into a separate module file
          from the form (this was so that I could just modify the click event on
          an existing form).

          I called your function in a module that I named StdHandle as follows
          from within a click handler for a button on my form:
          StdHandle.SomeB utton_Click(sen der, e)

          since it works on my dev box and not on yours I suspect that something
          else may be going on. take a look at your debug output window to see
          if you notice anything else (e.g. exceptions). also, test your code in
          a new windows form app...

          Comment

          • Jay B. Harlow [MVP - Outlook]

            #6
            Re: GetStdHandle .NET

            Dragon,
            As stand__sure suggests, this works on my dev box also; that is if I run it
            without the debugger (VS.NET = "Debug - Start Without Debugging").

            If I attempt to run it inside the debugger it fails! Failing inside the
            debugger is curious in that I would not expect it to actually fail, I would
            expect different handle values (as actual handle values are opaque, in that
            they represent a HANDLE to a resource & their actual value has no meaning).
            Remember VB.NET redirects console output to the Debug window, it would
            appear when it does this it causes GetStdHandle to behave oddly...

            If you call Console.Write instead of the WriteConsole API in your sample,
            the output goes to the Debugger's output window, as evidence of the above
            redirection.

            Unfortunately I have not used consoles enough to offer any suggestions on
            how to "work around" the above behavior... Reading the Remarks of
            GetStdHandle offers a suggestion. Open CONIN$ or CONOUT$ to get a handle to
            a "console's active screen buffer":

            http://msdn.microsoft.com/library/de...tstdhandle.asp


            Rather then Declare GetLastError, you need to call
            System.Runtime. InteropServices .Marshal.GetLas tWin32Error, for details see:

            http://msdn.microsoft.com/library/de...errortopic.asp


            Something like:

            Imports System.Runtime. InteropServices

            Private Declare Function AllocConsole Lib "kernel32.d ll" () As Int32

            Private Declare Function FreeConsole Lib "kernel32.d ll" () As Int32

            Private Declare Function GetStdHandle Lib "kernel32.d ll" (ByVal
            nStdHandle As Int32) As IntPtr

            Private Declare Function CloseHandle Lib "kernel32.d ll" (ByVal hObject
            As IntPtr) As Int32

            Private Declare Function WriteConsole Lib "kernel32.d ll" Alias
            "WriteConso leA" (ByVal hConsoleOutput As IntPtr, ByVal lpBuffer As IntPtr,
            ByVal nNumberOfCharsT oWrite As Int32, ByRef lpNumberOfChars Written As Int32,
            ByVal lpReserved As IntPtr) As Int32

            'Private Declare Function GetLastError Lib "kernel32.d ll" () As Int32

            Private Const STD_OUTPUT_HAND LE As Int32 = -11I

            Public Shared Sub SomeButton_Clic k(ByVal sender As Object, ByVal e As
            System.EventArg s)

            If AllocConsole() = 0 Then Debug.WriteLine ("AllocConso le failed: " &
            Marshal.GetLast Win32Error().To String)

            Dim hOutPut As IntPtr = GetStdHandle(ST D_OUTPUT_HANDLE )

            If hOutPut.ToInt32 = 0 Then Debug.WriteLine ("GetStdHand le failed: "
            & Marshal.GetLast Win32Error().To String)

            Debug.WriteLine ("Standard output: " & hOutPut.ToStrin g)

            Dim str As String = "It's working!"

            Dim written As Int32

            Dim handle As IntPtr = Marshal.StringT oHGlobalAnsi(st r)

            If WriteConsole(hO utPut, handle, str.Length, written, Intptr.Zero) =
            0 Then Debug.WriteLine ("WriteConso le failed: " &
            Marshal.GetLast Win32Error())

            If CloseHandle(hOu tPut) = 0 Then Debug.WriteLine ("CloseHandl e
            failed: " & Marshal.GetLast Win32Error())

            Threading.Threa d.Sleep(1000)

            If FreeConsole() = 0 Then Debug.WriteLine ("FreeConsol e failed: " &
            Marshal.GetLast Win32Error().To String)

            End Sub


            Hope this helps
            Jay

            "Dragon" <no@spam.please > wrote in message news:d90vv6$c6i $1@news.rol.ru. ..
            |
            | "stand__sur e" <stand__sure@ho tmail.com> ???????/???????? ? ????????
            | ?????????: news:1118863294 .867387.255650@ g49g2000cwa.goo glegroups.com.. .
            | > can you give us more code? how are you dereferencing the value?
            | >
            | Well, that's my code:
            | ~
            | Private Declare Function AllocConsole Lib "kernel32.d ll" () As Int32
            |
            | Private Declare Function FreeConsole Lib "kernel32.d ll" () As Int32
            |
            | Private Declare Function GetStdHandle Lib "kernel32.d ll" (ByVal nStdHandle
            | As Int32) As IntPtr
            |
            | Private Declare Function CloseHandle Lib "kernel32.d ll" (ByVal hObject As
            | IntPtr) As Int32
            |
            | Private Declare Function WriteConsole Lib "kernel32.d ll" Alias
            | "WriteConso leA" (ByVal hConsoleOutput As IntPtr, ByVal lpBuffer As IntPtr,
            | ByVal nNumberOfCharsT oWrite As Int32, ByRef lpNumberOfChars Written As
            Int32,
            | ByVal lpReserved As IntPtr) As Int32
            |
            | Private Declare Function GetLastError Lib "kernel32.d ll" () As Int32
            |
            | Private Const STD_OUTPUT_HAND LE As Int32 = -11I
            |
            | Private Sub SomeButton_Clic k(ByVal sender As Object, ByVal e As
            | System.EventArg s) Handles SomeButton.Clic k
            |
            | If AllocConsole() = 0 Then Debug.WriteLine ("AllocConso le failed: " &
            | GetLastError.To String)
            |
            | Dim hOutPut As IntPtr = GetStdHandle(ST D_OUTPUT_HANDLE )
            |
            | If hOutPut.ToInt32 = 0 Then Debug.WriteLine ("GetStdHand le failed: " &
            | GetLastError.To String)
            |
            | Debug.WriteLine ("Standard output: " & hOutPut.ToStrin g)
            |
            | Dim str As String = "It's working!"
            |
            | Dim written As Int32
            |
            | Dim handle As IntPtr = Marshal.StringT oHGlobalAnsi(st r)
            |
            | If WriteConsole(hO utPut, handle, str.Length, written, New IntPtr(0)) = 0
            | Then Debug.WriteLine ("WriteConso le failed: " & GetLastError)
            |
            | If CloseHandle(hOu tPut) = 0 Then Debug.WriteLine ("CloseHandl e failed: " &
            | GetLastError)
            |
            | Threading.Threa d.Sleep(1000)
            |
            | If FreeConsole() = 0 Then Debug.WriteLine ("FreeConsol e failed: " &
            | GetLastError.To String)
            |
            | End Sub
            |
            | ~
            |
            | When I click SomeButton for first time I get following output:
            |
            | Standard output: 1912 (or any other bad value)
            |
            | WriteConsole failed: 6
            |
            | If I keep clicking it prints:
            |
            | Standard output: 1912
            |
            | WriteConsole failed: 6
            |
            | CloseHandle failed: 6
            |
            | When I restart application number 1912 changes to another number and
            | situation repeats.
            |
            |


            Comment

            • stand__sure

              #7
              Re: GetStdHandle .NET

              very good tips.

              the code also works in a vs debug on my box (I'm still running 2005
              beta 1 though -- been too busy to install beta 2...) the output is to
              a new console window in a debug session (and this is not the console
              window that vs knows -- I had it open as well). one quirk is that the
              technique in the OP doesn't seem to work in a console application (I am
              assuming that only one console window is allowed???)

              Comment

              • Jay B. Harlow [MVP - Outlook]

                #8
                Re: GetStdHandle .NET

                stand__sure,
                | the code also works in a vs debug on my box (I'm still running 2005
                | beta 1 though -- been too busy to install beta 2...) the output is to
                | a new console window in a debug session (and this is not the console
                It sounds like 2005 "fixes" the odd behavior that I am seeing in 2003...

                I'll try this on beta 2 later tonight or Monday & report back.

                Hopefully Dragon finds a solution...


                | one quirk is that the
                | technique in the OP doesn't seem to work in a console application (I am
                | assuming that only one console window is allowed???)

                My understanding is that a Console application can only have a single
                Console window open at a time. Based on the remarks on AllocConsole.

                Jay


                "stand__sur e" <stand__sure@ho tmail.com> wrote in message
                news:1119229194 .199158.141050@ z14g2000cwz.goo glegroups.com.. .
                | very good tips.
                |
                | the code also works in a vs debug on my box (I'm still running 2005
                | beta 1 though -- been too busy to install beta 2...) the output is to
                | a new console window in a debug session (and this is not the console
                | window that vs knows -- I had it open as well). one quirk is that the
                | technique in the OP doesn't seem to work in a console application (I am
                | assuming that only one console window is allowed???)
                |


                Comment

                • stand__sure

                  #9
                  Re: GetStdHandle .NET

                  that's also my understanding, but it comes from a non .NET source...

                  Comment

                  • Jay B. Harlow [MVP - Outlook]

                    #10
                    Re: GetStdHandle .NET

                    stand__sure,
                    I tried Dragon's code on VS 2005 Beta 2, it works as Dragon expects.

                    Seeing as Dragon's code works outside of VS 2003, & it works inside or
                    outside of VS 2005. It appears VS 2003 has a quirk/bug that is preventing
                    Dragon's code from working...

                    My testing was on Windows XP Pro.

                    NOTE to Dragon. You only need to the Declare the AllocConsole & FreeConsole
                    API calls, all the other Console API calls are handled by the System.Console
                    class...

                    Hope this helps
                    Jay

                    "stand__sur e" <stand__sure@ho tmail.com> wrote in message
                    news:1119242831 .506898.191730@ g49g2000cwa.goo glegroups.com.. .
                    | that's also my understanding, but it comes from a non .NET source...
                    |


                    Comment

                    Working...