Below is an example of using LoadLibrary() with the Console Compiler to load the C Runtime Library. This allows Console Compiler access to the usual C console functions declared in stdio.h such as printf, puts, etc., that C programmers know and love so well....
Neat, Huh? Anyway, I figured somehow I might be able to make use of this someday in a PowerBASIC GUI Windows program, perhaps on a AllocConsole() output screen in a database related app where a lot of lengthy database transactions were occurring, so as to keep the user informed of progress, etc. Its at least worth having in one's 'bag of tricks', anyway, I think. I didn't think it would be any problem to AllocConsole() in a PBWin GUI program and use this printf instead of WriteConsole(), but I was quite wrong. There does appear to be a significant problem. Now I can surely use WriteConsole() as the PBWin example below shows...
...but it would be neat to get printf working! Surprisingly enough, when I searched MSDN in my Visual Studio 6 documentation an article on the problem and a work around immediately popped up. The artuicle was dated 1997 but a search of MSDN online revealed the same article with a last reviewed date of 2006. Here is that article...
However, I can't seem to get it to work. Reproduced below are excerpts from the above article...
To see this problem in action in a PowerBASIC program all you have to do is put the declare for printf in a PBWin program, allocate a console, load the CRT with LoadLibrary, then try to 'printf'. You won't get any output, even though the exact same setup works with the Console Compiler. Below is such a program that attempts to printf to the top line. After that some text is printed with WriteConsole() to zero based line 5...
I attempted Microsoft's 'fix' but I can't get it working. I first tried a VC++ project in Visual Studio, figuring if I could get it working there I'd convert it to PBWin. When I typed in that first function call...
it was obvious that intellisence recognized _open_osfhandle (God knows I didn't) because it popped up parameter help for me as it always does when it recognizes a function. However, it doesn't know what _O_TEXT is and neither do I. I can't find that equate anywhere. So naturally I can't get it working.
Is there anyone out there who might be interested in this or know anything about it? It has me pretty much stumped.
Code:
'Use Console Compiler #Compile Exe #Dim All #Include "Win32Api.inc" Declare Function printf CDecl Lib "msvcrt.dll" Alias "printf" _ ( _ szFmtStr As Asciiz _ [, _ Byval lpVar1 As Any, _ Byval lpVar2 As Any, _ Byval lpVar3 As Any, _ Byval lpVar4 As Any _ ] _ ) As Long Function PBMain() As Long Local hDll As Dword, dwWeight As Dword hDll=LoadLibrary("msvcrt.dll") If hDll Then Print "hDll = "hDll dwWeight=210 printf("My Name Is Fred And I Weigh %u Pounds!"+Chr$(13)+Chr$(10),dwWeight) Call FreeLibrary(hDll) End If Waitkey$ PBMain=0 End Function
Code:
'Output '===================================== 'hDll = 2013265920 'My Name Is Fred And I Weigh 210 Pounds!
Code:
'Use PBWin #Compile Exe #Dim All #Include "Win32Api.inc" Function PBMain () As Long Local dwInputEvents,dwWritten,dwXY As Dword Local hStdInput,hStdOutput As Dword Local szBuffer As Asciiz*80 Local blnContinue As Long Local ir As INPUT_RECORD Call AllocConsole() hStdInput=GetStdHandle(%STD_INPUT_HANDLE) hStdOutput=GetStdHandle(%STD_OUTPUT_HANDLE) szBuffer="Hello, I'm A PowerBASIC Windows Win32 Console Allocated With AllocConsole()!" Call WriteConsole(hStdOutput,szBuffer,Len(szBuffer),dwWritten,ByVal 0) szBuffer="press any key to continue...." dwXY=MakDwd(48,23) Call SetConsoleCursorPosition(hStdOutput,dwXY) Call WriteConsole(hStdOutput,szBuffer,Len(szBuffer),dwWritten,ByVal 0) blnContinue=%TRUE Do While blnContinue=%TRUE Call ReadConsoleInput(hStdInput,ir,1,dwInputEvents) If ir.EventType=%KEY_EVENT Then blnContinue=%FALSE End If Loop PBMain=0 End Function
However, I can't seem to get it to work. Reproduced below are excerpts from the above article...
To use C Run-time output routines, such as printf(), from a GUI application, it is necessary to create a console. The Win32 application programming interface (API) AllocConsole() creates the console. The CRT routine setvbuf() removes buffering so that output is visible immediately.
Code:
int hCrt; FILE *hf; AllocConsole(); hCrt = _open_osfhandle ( (long) GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT ); hf = _fdopen( hCrt, "w" ); *stdout = *hf; i = setvbuf( stdout, NULL, _IONBF, 0 );
This code opens up a new low-level CRT handle to the correct console output handle, associates a new stream with that low-level handle, and replaces stdout with that new stream. This process takes care of functions that use stdout, such as printf(), puts(), and so forth. Use the same procedure for stdin and stderr. Note that this code does not correct problems with handles 0, 1, and 2. In fact, due to other complications, it is not possible to correct this, and therefore it is necessary to use stream I/O instead of low-level I/O.
When a GUI application is started with the "start" command, the three standard OS handles STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, and 'STD_ERROR_HANDLE are all "zeroed out" by the console initialization routines. These three handles are replaced by valid values when the GUI application calls AllocConsole(). Therefore, once this is done, calling GetStdHandle() will always return valid handle values. The problem is that the CRT has already completed initialization before your application gets a chance to call
AllocConsole(); the three low I/O handles 0, 1, and 2 have already been set up to use the original zeroed out OS handles, so all CRT I/O is sent to invalid OS handles and CRT output does not appear in the console. Use the workaround described above to eliminate this problem.
When a GUI application is started with the "start" command, the three standard OS handles STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, and 'STD_ERROR_HANDLE are all "zeroed out" by the console initialization routines. These three handles are replaced by valid values when the GUI application calls AllocConsole(). Therefore, once this is done, calling GetStdHandle() will always return valid handle values. The problem is that the CRT has already completed initialization before your application gets a chance to call
AllocConsole(); the three low I/O handles 0, 1, and 2 have already been set up to use the original zeroed out OS handles, so all CRT I/O is sent to invalid OS handles and CRT output does not appear in the console. Use the workaround described above to eliminate this problem.
Code:
'Use PBWin #Compile Exe #Dim All #Include "Win32Api.inc" Declare Function printf CDecl Lib "msvcrt.dll" Alias "printf" _ ( _ szFmtStr As Asciiz _ [, _ Byval lpVar1 As Any, _ Byval lpVar2 As Any, _ Byval lpVar3 As Any, _ Byval lpVar4 As Any _ ] _ ) As Long Sub Waitkey(hStdInput As Dword) Local ir As INPUT_RECORD Local blnContinue As Long Local dwInputEvents As Dword blnContinue=%TRUE Do While blnContinue=%TRUE Call ReadConsoleInput(hStdInput,ir,1,dwInputEvents) If ir.EventType=%KEY_EVENT Then blnContinue=%FALSE End If Loop End Sub Function PBMain () As Long Local hDll,dwWeight,hStdInput,hStdOutput,dwXY,dwWritten As Dword Local szBuffer As Asciiz*80 hDll=LoadLibrary("msvcrt.dll") If hDll Then Call AllocConsole() printf("hDll = %u"+Chr$(13)+Chr$(10),hDll) dwWeight=210 printf("My Name Is Fred And I Weigh %u Pounds!"+Chr$(13)+Chr$(10),dwWeight) hStdInput=GetStdHandle(%STD_INPUT_HANDLE) hStdOutput=GetStdHandle(%STD_OUTPUT_HANDLE) szBuffer="WriteConsole() Works But printf Doesn't. Rats!!!" dwXY=MakDwd(0,5) Call SetConsoleCursorPosition(hStdOutput,dwXY) Call WriteConsole(hStdOutput,szBuffer,Len(szBuffer),dwWritten,ByVal 0) Call FreeLibrary(hDll) End If Call Waitkey(hStdInput) PBMain=0 End Function
Code:
hCrt = _open_osfhandle ( (long) GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT );
Is there anyone out there who might be interested in this or know anything about it? It has me pretty much stumped.
Comment