Results 1 to 14 of 14

Thread: Console Application ReadConsoleOutputCharacter or .NET alternative?

  1. #1

    Thread Starter
    Addicted Member ZenDisaster's Avatar
    Join Date
    Dec 2006
    Location
    Bay Area, CA
    Posts
    140

    Question Console Application ReadConsoleOutputCharacter or .NET alternative?

    I'm working on a roguelike similar to nethack (a console game where the graphics are simply unicode characters). However, I have reached a barrier when trying to identify what character the cursor is on. Is the cursor positioned over the character that represents a pile of gold or a wall, etc.?

    The ReadConsoleOutputCharacter API would seem to be what is required here, but there is something wrong with my declaration and/or my method of calling it, as I apparently am unbalancing the stack.

    Does the .NET Framework provide an internal method equivalent to the above API call? If not, could someone provide me with assistance on getting the declaration and function call to work as intended?

    Code:
        Structure COORD
            Dim x As Integer
            Dim y As Integer
        End Structure
    
        Declare Function ReadConsoleOutputCharacter Lib "kernel32" Alias "ReadConsoleOutputCharacterA" (ByVal hConsoleOutput As IntPtr, ByRef lpCharacter As String, ByVal nLength As Integer, dwReadCoord As COORD, lpNumberOfCharsRead As IntPtr) As Integer

    Code:
            Dim chrX As Char = ""
    
            Dim xCoord As New COORD
            xCoord.x = 5
            xCoord.y = 5
    
            ReadConsoleOutputCharacter(Process.GetCurrentProcess().MainWindowHandle, chrX, 1, xCoord, 1)
    
            MsgBox(chrX)
    The obvious solution would be, since I am writing the output in the first place, I could simply trap the data and maintain it all internally, but if there is a simple way to just grab the information from the console, I would stand to save myself a lot of extra work. Plus, now I'm rather determined to gain the experience of seeing this method through.

    Any assistance would be greatly appreciated.

  2. #2
    PowerPoster dunfiddlin's Avatar
    Join Date
    Jun 2012
    Posts
    8,245

    Re: Console Application ReadConsoleOutputCharacter or .NET alternative?

    Can't really be definitive on this at the moment as pinvoke.net seems to have gone belly up but as a first step, turn Option Strict On and it will identify a few places where you have declared one type and inserted another. API calls are very sensitive to type so it pays to at least be consistent!

    I suspect that you'll need to introduce marshalling but I'll need to do some experimenting.
    As the 6-dimensional mathematics professor said to the brain surgeon, "It ain't Rocket Science!"

    Reviews: "dunfiddlin likes his DataTables" - jmcilhinney

    Please be aware that whilst I will read private messages (one day!) I am unlikely to reply to anything that does not contain offers of cash, fame or marriage!

  3. #3

    Thread Starter
    Addicted Member ZenDisaster's Avatar
    Join Date
    Dec 2006
    Location
    Bay Area, CA
    Posts
    140

    Re: Console Application ReadConsoleOutputCharacter or .NET alternative?

    Option Strict is now on!

    I've been able to execute the program, but I'm getting an invalid handle. Let me update the code here.

    Code:
        Private Declare Function GetStdHandle Lib "kernel32.dll" (ByVal nStdHandle As Integer) As Integer
        Public Const STD_OUTPUT_HANDLE = -11&
    
        <DllImport("Kernel32", SetLastError:=True)>
        Function ReadConsoleOutputCharacter(ByRef hConsoleOutput As Integer, ByRef lpCharacter As String, ByVal nLength As Integer, ByVal dwReadCoord As COORD, ByRef lpNumberOfCharsRead As Integer) As Boolean
        End Function
    
        <StructLayout(LayoutKind.Sequential)>
        Structure COORD
            Dim X As Short
            Dim Y As Short
        End Structure

    Code:
            Console.WriteLine("Test")
    
            Dim xCoord As New COORD
            xCoord.X = 0
            xCoord.Y = 0 'This should point to the 'T' in Test.
    
            Dim lngRet1 As IntPtr = Process.GetCurrentProcess.MainWindowHandle
            Debug.WriteLine(lngRet1)
    
            Dim lngRet As Integer = GetStdHandle(STD_OUTPUT_HANDLE)
            Debug.WriteLine("GetStdHandle: " & lngRet)
    
            Dim iret As Integer
            Dim chrX As String
            Call ReadConsoleOutputCharacter(lngRet, chrX, 1, xCoord, iret)
            Debug.WriteLine("GetLastError: " & GetLastError)
    Both MainWindowHandle & GetStdHandle throw error 6 ERROR_INVALID_HANDLE.

    Please advise.

    Thank you very much for taking the time to look into my issue with me. It is very nice to have helpful and knowledgeable individuals lend a hand. It is greatly appreciated.
    Last edited by ZenDisaster; Aug 10th, 2013 at 11:24 AM.

  4. #4
    Stack Overflow mod​erator
    Join Date
    May 2008
    Location
    British Columbia, Canada
    Posts
    2,824

    Re: Console Application ReadConsoleOutputCharacter or .NET alternative?

    You should keep an internal state. It’ll be shorter than all this, more efficient, and probably more reliable, especially if you ever decide to add some kind of feature that interacts with a part of the map that’s not in the console.

  5. #5

    Thread Starter
    Addicted Member ZenDisaster's Avatar
    Join Date
    Dec 2006
    Location
    Bay Area, CA
    Posts
    140

    Re: Console Application ReadConsoleOutputCharacter or .NET alternative?

    Hi minitech, I was hoping you'd bring your oversized brain into this.

    I agree with you. However, in the back of my head I have an idea for a future project that would enable me to macro other ascii console games. 8) Or whatever. But now that I can't get this code to work, I have the sudden urge to get many very-important characters from command windows.

  6. #6
    PowerPoster dunfiddlin's Avatar
    Join Date
    Jun 2012
    Posts
    8,245

    Re: Console Application ReadConsoleOutputCharacter or .NET alternative?

    GetStdHandle Lib "kernel32.dll" (ByVal nStdHandle As Int64) As Int64 I think. I'm also deeply suspicious of ...

    Public Const STD_OUTPUT_HANDLE = -11&

    ... although I've yet to confirm my doubts. I'm sure it should be a Hex value apart from anything else. I'll let you know if I get anything definite on this.
    As the 6-dimensional mathematics professor said to the brain surgeon, "It ain't Rocket Science!"

    Reviews: "dunfiddlin likes his DataTables" - jmcilhinney

    Please be aware that whilst I will read private messages (one day!) I am unlikely to reply to anything that does not contain offers of cash, fame or marriage!

  7. #7
    Stack Overflow mod​erator
    Join Date
    May 2008
    Location
    British Columbia, Canada
    Posts
    2,824

    Re: Console Application ReadConsoleOutputCharacter or .NET alternative?

    Probably not the main issue, but I don’t think you can use a String like that. Try a StringBuffer with an appropriate initial size, or a Char(). Also, try modifying GetStdHandle to return an IntPtr.

  8. #8
    Stack Overflow mod​erator
    Join Date
    May 2008
    Location
    British Columbia, Canada
    Posts
    2,824

    Re: Console Application ReadConsoleOutputCharacter or .NET alternative?

    Aha! Thanks for pointing out STD_OUTPUT_HANDLE. I think the definition is

    Code:
    Public Const STD_OUTPUT_HANDLE As Short = -11

  9. #9
    PowerPoster dunfiddlin's Avatar
    Join Date
    Jun 2012
    Posts
    8,245

    Re: Console Application ReadConsoleOutputCharacter or .NET alternative?

    There are days when I'd gladly take the editors at MSDN out to lunch. And there are days, when trying to make sense of API, when I'd gladly take said editors out and eat them for lunch! Today is one of the latter!

    It has taken several hours to get to the point where I now know that GetStdHandle(STD_OUTPUT_HANDLE) is not guaranteed to return the handle of the screen buffer which is the one you actually need and, thanks to the complete lack of information provided by the aforesaid MSDN it will no doubt take several more to discover the values of the dozen or so constants to execute the method which is "guaranteed" (yeah, right) to get the necessary handle. However, in order to maintain sufficient calm to not throw my computer out of a window, I'm afraid such research will have to wait for a more opportune moment.
    As the 6-dimensional mathematics professor said to the brain surgeon, "It ain't Rocket Science!"

    Reviews: "dunfiddlin likes his DataTables" - jmcilhinney

    Please be aware that whilst I will read private messages (one day!) I am unlikely to reply to anything that does not contain offers of cash, fame or marriage!

  10. #10

    Thread Starter
    Addicted Member ZenDisaster's Avatar
    Join Date
    Dec 2006
    Location
    Bay Area, CA
    Posts
    140

    Re: Console Application ReadConsoleOutputCharacter or .NET alternative?

    Well you gentlemen certainly have my thanks for asserting yourselves on my behalf. I'll bookmark this thread and update it if I'm able to make an progress.

    Quick update. I decided to run the call in C++ and it returned the same error code (7) as in vb.net.

    Code:
    GetStdhandle:00000007 ERROR_ARENA_TRASHED The storage control blocks were destroyed.
    What does that mean? Is this api obsolete in windows 7? What is the new method? I don't mind researching but I have no idea where to start at this point.
    Last edited by ZenDisaster; Aug 10th, 2013 at 08:58 PM.

  11. #11
    Frenzied Member
    Join Date
    Jul 2011
    Location
    UK
    Posts
    1,335

    Re: Console Application ReadConsoleOutputCharacter or .NET alternative?

    Not wishing to step on dunfiddlin's toes here, but in the meantime your code from Post#3 should work if you fix a few simple errors.

    I think your main problem is you are declaring the hConsoleOutput parameter ByRef when it should be declared ByVal.

    Also, not critical but something I'd do all the same, is to alter a few of the Types you are using, such as using intPtr instead of Integer for the handles.

    Finally, if you are happy only fetching one character at a time, I'd use a Char for the lpCharacter parameter instead of a String because that simplifies things somewhat.


    What I'd suggest is something like the following Console application based on your original code:
    VB.NET Code:
    1. Option Strict On
    2.  
    3. Imports System.Runtime.InteropServices
    4.  
    5.  
    6. Module Module1
    7.  
    8.     Private Declare Function GetLastError Lib "kernel32.dll" () As Integer
    9.  
    10.     Private Declare Function GetStdHandle Lib "kernel32.dll" (ByVal nStdHandle As Integer) As IntPtr
    11.  
    12.     Public Const STD_OUTPUT_HANDLE As Integer = -11
    13.  
    14.     <DllImport("Kernel32", SetLastError:=True)> _
    15.     Function ReadConsoleOutputCharacter(ByVal hConsoleOutput As IntPtr, _
    16.                                         ByRef lpCharacter As Char, _
    17.                                         ByVal nLength As Integer, _
    18.                                         ByVal dwReadCoord As COORD, _
    19.                                         ByRef lpNumberOfCharsRead As Integer) As Integer
    20.     End Function
    21.  
    22.     <StructLayout(LayoutKind.Sequential)>
    23.     Structure COORD
    24.         Dim X As Short
    25.         Dim Y As Short
    26.     End Structure
    27.  
    28.  
    29.  
    30.     Sub Main()
    31.         Console.WriteLine("Test")
    32.  
    33.         Dim xCoord As New COORD
    34.         xCoord.X = 0
    35.         xCoord.Y = 0 'This should point to the 'T' in Test.
    36.  
    37.  
    38.         Dim hndl As IntPtr = GetStdHandle(STD_OUTPUT_HANDLE)
    39.  
    40.         Dim iret As Integer
    41.         Dim chrx As Char
    42.         Dim result As Integer
    43.  
    44.         result = ReadConsoleOutputCharacter(hndl, chrx, 1, xCoord, iret)
    45.  
    46.         If result = 0 Then
    47.             Debug.WriteLine("ReadConsoleOutputCharacter GetLastError: " & GetLastError)
    48.         ElseIf iret = 1 Then
    49.             MsgBox(chrx)
    50.         Else
    51.             ' ????? hopefully never hit
    52.         End If
    53.     End Sub
    54.  
    55. End Module

    Note that if you do need to use a String type for the lpCharacter parameter, then there are quite a few changes that will need to be made.

  12. #12
    PowerPoster dunfiddlin's Avatar
    Join Date
    Jun 2012
    Posts
    8,245

    Re: Console Application ReadConsoleOutputCharacter or .NET alternative?

    Not wishing to step on dunfiddlin's toes here
    Never stopped you before!

    You're welcome to it, as it happens. I've looked at so many examples with totally contradictory advice that my eyes are beginning to twitch! The main issue seems to be whether ...

    Dim hndl As IntPtr = GetStdHandle(STD_OUTPUT_HANDLE)

    ... actually returns hConsoleInput at all, and if it does, whether it can be relied upon to do so consistently. As pinvoke.net wasn't working over the weekend I sort of gave up trying to make sense of it but now it's back to health I'll see if I can rustle up the energy to take on the mysterious constants again. It's high time somebody, apparently not MSDN, came up with a reference system/database whatever, for all of them though I appreciate that as a project it's not exactly enticing!
    As the 6-dimensional mathematics professor said to the brain surgeon, "It ain't Rocket Science!"

    Reviews: "dunfiddlin likes his DataTables" - jmcilhinney

    Please be aware that whilst I will read private messages (one day!) I am unlikely to reply to anything that does not contain offers of cash, fame or marriage!

  13. #13
    Frenzied Member
    Join Date
    Jul 2011
    Location
    UK
    Posts
    1,335

    Re: Console Application ReadConsoleOutputCharacter or .NET alternative?

    Quote Originally Posted by dunfiddlin View Post
    Not wishing to step on dunfiddlin's toes here
    Never stopped you before!
    I think you're going to need a bigger boot!

  14. #14
    PowerPoster dunfiddlin's Avatar
    Join Date
    Jun 2012
    Posts
    8,245

    Re: Console Application ReadConsoleOutputCharacter or .NET alternative?

    Well, it works, which is more than I can say for any of my efforts! Still not quite sure what the crucial difference is/was but you can definitely have an extra biscuit with your cocoa tonight!

    Might one suggest that you post your example on pinvoke.net. There have been many questions on this over the years but no definitive answers.
    As the 6-dimensional mathematics professor said to the brain surgeon, "It ain't Rocket Science!"

    Reviews: "dunfiddlin likes his DataTables" - jmcilhinney

    Please be aware that whilst I will read private messages (one day!) I am unlikely to reply to anything that does not contain offers of cash, fame or marriage!

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width