Announcement

Collapse
No announcement yet.

Using C Runtime Library With PBWin

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • 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!
    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...

    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
    ...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...

    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.
    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...

    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
    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...

    Code:
    hCrt =
    _open_osfhandle
    (
       (long) GetStdHandle(STD_OUTPUT_HANDLE),
       _O_TEXT
    );
    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.
    Last edited by Fred Harris; 25 Sep 2007, 09:50 AM.
    Fred
    "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

  • #2
    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
    Michael Mattias
    Tal Systems (retired)
    Port Washington WI USA
    [email protected]
    http://www.talsystems.com

    Comment


    • #3
      Originally posted by Fred Harris View Post
      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:
      /***
      *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) */
      --pdf

      Comment


      • #4
        Working on it...

        Thanks Michael and Paul. I'm working on it!

        Fred
        Fred
        "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

        Comment


        • #5
          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
          I tried the PBWin version with GetProcAddress() and as above but still no luck. The problem described by Microsoft still exists. However, the good news is that with Paul's help on _O_TEXT I finally found that equate. Also, I found _open_osfhandle in io.h. That raises the interesting question of how to find these blasted things when they could be scattered among hundreds of header files with which one may not be familiar?

          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;
          }
          Fred
          "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

          Comment


          • #6
            Originally posted by Fred Harris View Post
            Where I'm stuck now is trying to find where in the devil _fdopen is!
            stdio.h

            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...
            --pdf

            Comment


            • #7
              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!
              Fred
              "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

              Comment


              • #8
                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
                Michael Mattias
                Tal Systems (retired)
                Port Washington WI USA
                [email protected]
                http://www.talsystems.com

                Comment


                • #9
                  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
                  A FILE * object is defined like so in stdio.h...

                  Code:
                  struct _iobuf
                  {
                   char *_ptr;
                   int   _cnt;
                   char *_base;
                   int   _flag;
                   int   _file;
                   int   _charbuf;
                   int   _bufsiz;
                   char *_tmpfname;
                  };
                  and then _iobuf renamed to FILE

                  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
                  ...I may give up. Don't know for sure if I'm on the right track. WriteConsole() is looking better all the time!
                  Fred
                  "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

                  Comment


                  • #10
                    USING$ is looking better and better every minute, isn't it?
                    Michael Mattias
                    Tal Systems (retired)
                    Port Washington WI USA
                    [email protected]
                    http://www.talsystems.com

                    Comment


                    • #11
                      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.
                      hutch at movsd dot com
                      The MASM Forum

                      www.masm32.com

                      Comment


                      • #12
                        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

                        Comment


                        • #13
                          Originally posted by Steve Hutchesson View Post
                          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.
                          IIRC, I tried this in the past with the same results. Things like \t, \n, etc. that help to make printf so useful are not processed, as Steve says, and just pass through to stdout as is.

                          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.
                          --pdf

                          Comment


                          • #14
                            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;
                            }
                            ...and that works!

                            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
                            Where I'm stuck is understanding what is occurring in stdio.h in relation to that last of the three required piecies...

                            *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])
                            What I'm seeing there that is so confusing to me is that the FILE struct is being defined here and yet it is being defined as an extern. Then after that a macro is being used to redefine it again as stdout, and so forth. And while the macro doesn't actually access memory, the *stdout=*hf certainly does, and where is memory being allocated for stdout, _iob[], whatever????????? Using Bob Scott's utility MCM turned me on to I've searched my MS C++ includes and Dev C++ includes to no avail for any further enlightenment on this. Any thoughts?

                            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.
                            Fred
                            "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

                            Comment


                            • #15
                              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))
                              Call me crazy but...
                              Code:
                                sngWeight = 240.5!
                                STDOUT USING$("My name is Greg and I weigh #.# pounds_! " & $CRLF, sngWeight)
                              .. seems a heck of lot easier to both code and understand.

                              MCM
                              Michael Mattias
                              Tal Systems (retired)
                              Port Washington WI USA
                              [email protected]
                              http://www.talsystems.com

                              Comment


                              • #16
                                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.
                                Fred
                                "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

                                Comment


                                • #17
                                  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...
                                  Fred
                                  "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

                                  Comment


                                  • #18
                                    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.
                                    hutch at movsd dot com
                                    The MASM Forum

                                    www.masm32.com

                                    Comment


                                    • #19
                                      I added some code re "importing and exporting variables" at http://www.powerbasic.com/support/pb...ad.php?t=35026
                                      Michael Mattias
                                      Tal Systems (retired)
                                      Port Washington WI USA
                                      [email protected]
                                      http://www.talsystems.com

                                      Comment

                                      Working...
                                      X