Announcement
Collapse
No announcement yet.
Using C Runtime Library With PBWin
Collapse
X
-
I added some code re "importing and exporting variables" at http://www.powerbasic.com/support/pb...ad.php?t=35026
-
Fred,
If you have a leading underscore name that you need to use from a DLL or similar, write a prototype (declaration) using normal PB notation that renames the variable slightly so it does not have the leading underscore.
There are over 700 functions in the MSVCRT DLL and while PB does many of these things very well, they are there to use if you need them.
Leave a comment:
-
Ah Haaa!
Yes, _iob[] is exported from msvcrt.dll! There's probably a declension specification attribute attached to it ..
__declspec(dllexport) FILE iob[];
...or something. The C code that works can be modified to...
_iob[1]=*hf;
...and that replaces the standard output handle with a valid one. I'm still not sure though how to get that working in PB though. PB doesn't like leading underscores on variables any more than the printf function likes four byte floats. This doesn't seem to want to fly...
Call AllocConsole()
hCrt=Open_OSFileHandle(GetStdHandle(%STD_OUTPUT_HANDLE),%O_TEXT)
hf=FDOpen(hCrt,"w")
_iob[1][email protected]
printf("My Name Is Fred!")
I'm bound to get lucky soon...
Leave a comment:
-
Hmmmm
...and I thought you were going to say we both need to go on a diet!
Seriously though, could that _iob[] variable be exported from msvcrt.dll?
extern FILE _iob[];
...in which case...
@[email protected]
Hmmmm.
Leave a comment:
-
Code:sngWeight = 240.5! dblWeight = CDBL(sngWeight) ' printf doesn't accept SINGLES, the C compiler converts them to DOUBLES behind the scenes. printf("My name is Greg and I weigh %f pounds!" & $CR & $LF, PEEK(DWORD, VARPTR(dblWeight)), PEEK(DWORD, VARPTR(dblWeight)+4))
Code:sngWeight = 240.5! STDOUT USING$("My name is Greg and I weigh #.# pounds_! " & $CRLF, sngWeight)
MCM
Leave a comment:
-
Stuck and stuck good!
I only started this little endeavor on a 'lark', as a challenge, so to speak. I figured perhaps I'd learn a few things about cross language function calls and so forth.
And by golly, I got pretty close, but now I'm stuck and stuck but good. What has me stuck is the statement as follows in Microsoft's 'fix' which I outlined above...
*stdout = *hf;
Reproduced below is the full message handler again which I wrote in the C program also above somewhere in one of the posts...
Code:long fnWndProc_OnCommand(lpWndEventArgs Wea) { unsigned int i; int hCrt; FILE *hf; if(LOWORD(Wea->wParam)==IDC_BUTTON) { AllocConsole(); hCrt=_open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE),_O_TEXT); hf = _fdopen( hCrt, "w" ); *stdout = *hf; i = setvbuf( stdout, NULL, _IONBF, 0 ); printf("My Name Is Fred!\n"); MessageBox(Wea->hWnd,"Hopefully, You See A Console?","See A Console?",MB_ICONINFORMATION); } return 0; }
There are essentially three critical statements and they are...
hCrt=_open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE),_O_TEXT);
hf = _fdopen( hCrt, "w" );
*stdout = *hf;
I have satisfactorily accomplished the first two. In terms of that meaner than a junkyard dog third one I have made some significant progress. It was necessary for me to make absolutely sure my translation of the stdio.h FILE structure to PowerBASIC was on track and working so I made the following program to test it and it worked...
Code:'Console Compiler Program #Compile Exe #Dim All Type FILE pChar As Asciiz Ptr cnt As Long pBase As Asciiz Ptr flag As Long fil As Long charbuf As Long bufsize As Long TmpFileName As Asciiz Ptr End Type Declare Function fopen CDecl Lib "msvcrt.dll" Alias "fopen" _ ( _ ByRef pszFileName As Asciiz, _ ByRef pszAttributes As Asciiz _ ) As Dword Declare Function fprintf CDecl Lib "msvcrt.dll" Alias "fprintf" _ ( _ Byval fPtr As FILE Ptr, _ szFmtStr As Asciiz _ [, _ Byval lpVar1 As Any, _ Byval lpVar2 As Any, _ Byval lpVar4 As Any _ ] _ ) As Long Declare Function fclose CDecl Lib "msvcrt.dll" Alias "fclose" _ ( _ Byval fPtr As FILE Ptr _ ) As Long Function PBMain() As Long Local fp As FILE Ptr fp=fopen("Junk.txt", "w") fprintf(fp,"My Name Is Fred"+Chr$(13)+Chr$(10)) fclose(fp) Waitkey$ PBMain=0 End Function
*stdout = *hf;
The really relavant code from stdio.h is as follows...
Code:struct _iobuf { char *_ptr; int _cnt; char *_base; int _flag; int _file; int _charbuf; int _bufsiz; char *_tmpfname; }; typedef struct _iobuf FILE; #ifndef _STDIO_DEFINED _CRTIMP extern FILE _iob[]; #endif /* _STDIO_DEFINED */ #define stdin (&_iob[0]) #define stdout (&_iob[1]) #define stderr (&_iob[2])
PS Greg, you're right. printf hates 4 byte floats! I never went into it in the detail you did, I simply gave up using them years ago to keep C compilers from spitting at me!Last edited by Fred Harris; 26 Sep 2007, 02:38 PM.
Leave a comment:
-
Originally posted by Steve Hutchesson View PostFred,
I have not read all the other postings in detail but you will not get the complete functionality of "printf" from another compiler as a C compiler does a certain amount of pre-processing on the printf control string and other data before it calls the library routine as either a C static library or a DLL call in MSVCRT.DLL.
Also, MCM, Real Men prefer the commandline tools
I switch between Linux, Solaris and Windows all day long, so it's just second nature to run a bash shell (MSYS/MinGW) on Windows.
Leave a comment:
-
Using printf is possible but it really gets clunky, when using PowerBASIC, I would much rather use PowerBASIC functions.
Code:#COMPILE EXE #DIM ALL DECLARE FUNCTION printf CDECL LIB "msvcrt.dll" ALIAS "printf" (szFmtStr AS ASCIIZ, OPTIONAL BYVAL Var1 AS ANY, OPTIONAL BYVAL Var2 AS ANY, OPTIONAL BYVAL Var3 AS ANY, OPTIONAL BYVAL Var4 AS ANY) AS LONG FUNCTION PBMAIN() AS LONG LOCAL strWeight AS STRING LOCAL lWeight AS LONG LOCAL sngWeight AS SINGLE LOCAL dblWeight AS DOUBLE strWeight = "240.5" printf("My name is Greg and I weigh %s pounds!" & $CR & $LF, STRPTR(strWeight)) lWeight = 240.5! printf("My name is Greg and I weigh %d pounds!" & $CR & $LF, lWeight) sngWeight = 240.5! dblWeight = CDBL(sngWeight) ' printf doesn't accept SINGLES, the C compiler converts them to DOUBLES behind the scenes. printf("My name is Greg and I weigh %f pounds!" & $CR & $LF, PEEK(DWORD, VARPTR(dblWeight)), PEEK(DWORD, VARPTR(dblWeight)+4)) dblWeight = 240.5# printf("My name is Greg and I weigh %f pounds!" & $CR & $LF, PEEK(DWORD, VARPTR(dblWeight)), PEEK(DWORD, VARPTR(dblWeight)+4)) STDOUT $CRLF & "Press any key to exit ... "; WAITKEY$ STDOUT END FUNCTION
Leave a comment:
-
Fred,
I have not read all the other postings in detail but you will not get the complete functionality of "printf" from another compiler as a C compiler does a certain amount of pre-processing on the printf control string and other data before it calls the library routine as either a C static library or a DLL call in MSVCRT.DLL.
Having seen and used it in the past I would prefer the different capacity of a basic compiler for doing this type of string display as its composite string handling capacity is both more powerful and flexible than the C printf.
Leave a comment:
-
USING$ is looking better and better every minute, isn't it?
Leave a comment:
-
Bob Scott's Disk Utility
Just got Bob Scott's Disk Utility and am using it. Thanks for turning me on to that Michael. Its definitely nice. I need to give that man a big Thanks!
It appears I've hit the big stumbling block. stdio.h. Over the years, whenever I had occasion to look in that file, I always left it with the hope I'd never have to did around in there! _fdopen appears to be something of a problem as it returns a C FILE * object. I can't return a type/structure with power basic but it returns a pointer to one of the above, so I'm thinking I might be able to just return a dword, something like this...
'_CRTIMP FILE * __cdecl _fdopen(int, const char *);
Code:Declare Function FDOpen CDecl Lib "msvcrt.dll" Alias "_fdopen" _ ( _ Byval hHandle As Long, _ Byval pszStr As Asciiz Ptr _ ) As Dword
Code:struct _iobuf { char *_ptr; int _cnt; char *_base; int _flag; int _file; int _charbuf; int _bufsiz; char *_tmpfname; };
typedef struct _iobuf FILE;
So if what I've done above works I'll end up getting a pointer to one of those, which, looks something like this I guess...
Code:Type FILE _ptr As Asciiz Ptr _cnt As Long _Base As Asciiz Ptr _flag As Long _file As Long _charbuf As Long _bufsize As Long TmpFileName As Asciiz Ptr End Type
Leave a comment:
-
What I did/do for all those equates and declares and structures was to download the Borland C compiler (free). I never use anything of that 'install' except for the 'include' folder which is all the *.h files referenced in the MS documentation.
Then to search it - because the new Explorer search is so crummy - I use the "disk utility" created by Bob Scott. I'm not sure it's in the source code section, but I think he has a link where you can download a precompiled version. Extract from ZIP, add a desktop icon, phhhht! you're in business. Mr. Scott's program even 'remembers' that your last search was in folder D:\Software_Development\bcc\include and you want files *.h, , so you just type in the name of the equate and you got it.
MCM
Leave a comment:
-
grep
Thanks again Paul. I had in the back of my mind that there was a *nix tool in common use for that. Never really had occasion for it till now!
Leave a comment:
-
Originally posted by Fred Harris View PostWhere I'm stuck now is trying to find where in the devil _fdopen is!
Get yourself a copy of a windows port of grep, one of the many useful *nix tools that ought to be in every programmer's toolkit...
Leave a comment:
-
Makin progress here but not quite there yet!
You're right Michael, its not necessary to call LoadLibrary() for msvcrt.dll because its apparently in memory all the time I guess...
Anyway, here is a simpler Console Compiler program without the LoadLibrary()
Code:#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 dwWeight=210 printf("My Name Is Fred And I Weigh %u Pounds!"+Chr$(13)+Chr$(10),dwWeight) Waitkey$ PBMain=0 End Function
Anyway, I did get the 'fix' working in a VC++ GUI C program. All I need to do now I guess is translate those several functions in the 'fix' over to PB and try to get it to work there. Where I'm stuck now is trying to find where in the devil _fdopen is! Anyway, below is my C program that throws up a window with a button on it that when you click the button you get a console window that does output text satisfactorily with printf. The 'fix' code is in fnWndProc_OnCommand()...
Code:#include <windows.h> #include <stdio.h> #include <stdlib.h> #include <fcntl.h> //contains equate _O_TEXT #include <io.h> //contains declare for _open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE),_O_TEXT); #define IDC_BUTTON 1500 typedef struct WindowsEventArguments //Package Window Procedure Parameters into structure { HWND hWnd; //Handle of Window WPARAM wParam; //Window Parameter LPARAM lParam; //Long Parameter HINSTANCE hIns; //Instance Handle (Resolves To Process Address) }WndEventArgs, *lpWndEventArgs; long fnWndProc_OnCreate(lpWndEventArgs Wea) //Called One Time During Window Creatiion { HWND hButton; Wea->hIns=((LPCREATESTRUCT)Wea->lParam)->hInstance; hButton=CreateWindow("button","Execute",WS_CHILD|WS_VISIBLE,70,70,141,30,Wea->hWnd,(HMENU)IDC_BUTTON,Wea->hIns,0); return 0; } long fnWndProc_OnCommand(lpWndEventArgs Wea) { unsigned int i; int hCrt; FILE *hf; if(LOWORD(Wea->wParam)==IDC_BUTTON) { AllocConsole(); hCrt=_open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE),_O_TEXT); hf = _fdopen( hCrt, "w" ); *stdout = *hf; i = setvbuf( stdout, NULL, _IONBF, 0 ); printf("My Name Is Fred!\n"); MessageBox(Wea->hWnd,"Hopefully, You See A Console?","See A Console?",MB_ICONINFORMATION); } return 0; } long fnWndProc_OnClose(lpWndEventArgs Wea) //This function handles the WM_CLOSE message { //sent when the 'x' button is clicked. if(MessageBox(Wea->hWnd,"Do You Wish To Exit This App?","Exit Check?",MB_YESNO)==IDYES) { DestroyWindow(Wea->hWnd); PostQuitMessage(WM_QUIT); } return 0; } long __stdcall fnWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) //This is the all important Window { //Procedure. Note that in WinMain() WndEventArgs wea; //the WNDCLASSEX variable wc has a //field lpfnWndProc. This is pro- switch (msg) //nounced long pointer to Window { //Procedure. Below you can see where case WM_CREATE: //this variable was set to the wea.hWnd=hwnd, wea.wParam=wParam, wea.lParam=lParam; //address of this function. All return fnWndProc_OnCreate(&wea); //messages destined for this program case WM_COMMAND: //Windows will package up into a wea.hWnd=hwnd, wea.wParam=wParam, wea.lParam=lParam; //message packet consisting of the four return fnWndProc_OnCommand(&wea); //parameters to this function and case WM_CLOSE: //and it will come blowing through wea.hWnd=hwnd, wea.wParam=wParam, wea.lParam=lParam; //here at blinding speed. return fnWndProc_OnClose(&wea); } return DefWindowProc(hwnd,msg,wParam,lParam); } int __stdcall WinMain(HINSTANCE hIns,HINSTANCE hPrevIns,LPSTR lpszArgument,int iShow) { //The program starts in WinMain(). The WNDCLASSEX structure variable char szClassName[]="Form1"; //wc is filled out with general characteristics of a window. Then WNDCLASSEX wc; //the class is RegisteredClassEx()'ed. Directly after that a MSG messages; //CreateWindow() call instantiates an instance of the class. Then HWND hWnd; //the program drops into a message processing loop in which any messages //destined for this program are DispatchMessage()'ed to the fnWndProc(). wc.lpszClassName=szClassName; wc.lpfnWndProc=fnWndProc; wc.cbSize=sizeof (WNDCLASSEX); wc.style=CS_DBLCLKS; wc.hIcon=LoadIcon(NULL,IDI_APPLICATION); wc.hInstance=hIns; wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION); wc.hCursor=LoadCursor(NULL,IDC_ARROW); wc.hbrBackground=(HBRUSH)COLOR_BACKGROUND; wc.cbWndExtra=0; wc.lpszMenuName=NULL; wc.cbClsExtra=0; RegisterClassEx(&wc); hWnd=CreateWindow(szClassName,"Form1",WS_OVERLAPPEDWINDOW,200,100,300,250,HWND_DESKTOP,0,hIns,0); ShowWindow(hWnd,iShow); while(GetMessage(&messages,NULL,0,0)) { TranslateMessage(&messages); DispatchMessage(&messages); } return messages.wParam; }
Leave a comment:
-
Working on it...
Thanks Michael and Paul. I'm working on it!
Fred
Leave a comment:
-
Originally posted by Fred Harris View Postit 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:/*** *fcntl.h - file control options used by open() * * Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved. * *Purpose: * This file defines constants for the file control options used * by the _open() function. * [System V] * * [Public] * ****/ ... /* O_TEXT files have <cr><lf> sequences translated to <lf> on read()'s, ** and <lf> sequences translated to <cr><lf> on write()'s */ #define _O_TEXT 0x4000 /* file mode is text (translated) */ #define _O_BINARY 0x8000 /* file mode is binary (untranslated) */
Leave a comment:
-
One of your problems might be....
Since you DECLARE 'printf' as an external and use the symbol 'printf' in your program, the c runtime (msvcrt.dll) is loaded at execution time and the printf function is available without the need to call LoadLibrary.
You are calling the function from the library loaded at execution time anyway; you'd have to use GetProcAddress/CALL DWORD to be using the 'printf' in the library you loaded with LoadLibrary.
Maybe the second handle to the library is causing problems or at least funkyness?
(Check it out: use Show exports and imports for PB/Win 6x, 7x (original by Torsten Reinow) to list imports, you'll see msvcrt.dll there... if it wasnt' already anyway.)
Still not convinced? As written, GetModuleHandle ("msvcrt.dll") will return TRUE if you call it as the first thing, meaning that module is already loaded.
MCM
Leave a comment:
-
Using C Runtime Library With PBWin
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....
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
http://support.microsoft.com/kb/105305
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.
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.Last edited by Fred Harris; 25 Sep 2007, 09:50 AM.Tags: None
Leave a comment: