-
Aug 10th, 2013, 01:11 AM
#1
Thread Starter
Addicted Member
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.
-
Aug 10th, 2013, 10:14 AM
#2
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!
-
Aug 10th, 2013, 11:10 AM
#3
Thread Starter
Addicted Member
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.
-
Aug 10th, 2013, 11:17 AM
#4
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.
-
Aug 10th, 2013, 11:45 AM
#5
Thread Starter
Addicted Member
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.
-
Aug 10th, 2013, 12:20 PM
#6
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!
-
Aug 10th, 2013, 12:25 PM
#7
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.
-
Aug 10th, 2013, 12:27 PM
#8
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
-
Aug 10th, 2013, 03:06 PM
#9
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!
-
Aug 10th, 2013, 08:35 PM
#10
Thread Starter
Addicted Member
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.
-
Aug 12th, 2013, 11:54 AM
#11
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:
Option Strict On
Imports System.Runtime.InteropServices
Module Module1
Private Declare Function GetLastError Lib "kernel32.dll" () As Integer
Private Declare Function GetStdHandle Lib "kernel32.dll" (ByVal nStdHandle As Integer) As IntPtr
Public Const STD_OUTPUT_HANDLE As Integer = -11
<DllImport("Kernel32", SetLastError:=True)> _
Function ReadConsoleOutputCharacter(ByVal hConsoleOutput As IntPtr, _
ByRef lpCharacter As Char, _
ByVal nLength As Integer, _
ByVal dwReadCoord As COORD, _
ByRef lpNumberOfCharsRead As Integer) As Integer
End Function
<StructLayout(LayoutKind.Sequential)>
Structure COORD
Dim X As Short
Dim Y As Short
End Structure
Sub Main()
Console.WriteLine("Test")
Dim xCoord As New COORD
xCoord.X = 0
xCoord.Y = 0 'This should point to the 'T' in Test.
Dim hndl As IntPtr = GetStdHandle(STD_OUTPUT_HANDLE)
Dim iret As Integer
Dim chrx As Char
Dim result As Integer
result = ReadConsoleOutputCharacter(hndl, chrx, 1, xCoord, iret)
If result = 0 Then
Debug.WriteLine("ReadConsoleOutputCharacter GetLastError: " & GetLastError)
ElseIf iret = 1 Then
MsgBox(chrx)
Else
' ????? hopefully never hit
End If
End Sub
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.
-
Aug 12th, 2013, 12:09 PM
#12
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!
-
Aug 12th, 2013, 01:07 PM
#13
Re: Console Application ReadConsoleOutputCharacter or .NET alternative?
Originally Posted by dunfiddlin
Not wishing to step on dunfiddlin's toes here
Never stopped you before!
I think you're going to need a bigger boot!
-
Aug 12th, 2013, 02:46 PM
#14
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|