Announcement

Collapse
No announcement yet.

C call PBDLL

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

  • C call PBDLL


    Hi, looked around but couldn't find an answer

    How can a c program - receive data back from a
    function of a PowerBasic DLL.

    Code:
    #COMPILE DLL
    
    FUNCTION GetSqr(BYVAL v as long) EXPORT AS STRING
    
          ' source goes here
          '
          a$ = TRIM$(STR$(SQR(v&)))
          '
          GetSqr = a$
    
    END FUNCTION
    My question is, how can I call GetSqr from c?
    Right now, All I get back is "0"

    Thanks
    Mike



    ------------------
    mwm
    mwm

  • #2
    it seems the informatively named "calling a powerbasic dll from c"
    escaped you.

    you can find it at: http://www.powerbasic.com/support/pb...ead.php?t=2557

    cheers

    florent

    ------------------

    Comment


    • #3

      Florent

      Can you email me,
      Appears you know 'c' better than I do!

      Thanks
      Mike
      [email protected]


      ------------------
      mwm
      mwm

      Comment


      • #4
        Michael;

        PB uses the Windows OLE engine for passing variable length strings
        and C does not, so the format you describe can't be done.

        Now, the Windows API (written in C) uses a different approach in
        returning strings, which you can use in a C app calling PB.

        Create a memory buffer large enough to return the string. Pass
        a pointer to the buffer to a PB function and put the string in
        the buffer in your PB function. Put a null (zero) at the engine
        of the string data.

        The C app then should retrieve the string from the buffer it passed
        to your PB DLL.



        ------------------
        Chris Boss
        Computer Workshop
        Developer of "EZGUI"
        http://cwsof.com
        http://twitter.com/EZGUIProGuy

        Comment


        • #5

          Thanks Chris,

          I'll give it a shot! So far are nothing else has worked!

          I have always'd assume that a dll created by PowerBasic could be called
          by any program that could call a dll. It Appears that DLL's
          created by PowerBasic can only be accessed by PB or Visual Basic,
          unless you have access to the c or c++ source (which isn't always the case!)

          I was wrong!

          Mike



          ------------------
          mwm
          mwm

          Comment


          • #6
            Tom and Lance both mentioned re-defining our PB functions to
            receive ASCIIZ's. I noticed in both of their posts they don't
            define how long the ASCIIZ should be. For example, in the PB
            help file it shows declaring an ASCIIZ like this:

            DIM SomeVariable AS ASCIIZ * 255

            What is the length of the variable if you don't define a length?
            Is the ASCIIZ datatype going to be the lowest common denominator
            (when dealing with STRING type data) for creating EXPORTED functions
            in PB/DLL dll's when they need to be called from multiple other
            languages? It would be a pain to create, say, three different
            functions (that do the same thing) for 3 different languages.


            BSTR handling is quirky in a number of respects and, if
            possible, you may wish to redefine the function to pass
            (s AS ASCIIZ). That will allow you to use normal C data
            types:
            Code:
            FUNCTION MyFunc2(XYZ AS ASCIIZ) EXPORT AS LONG
                 MSGBOX XYZ
            END FUNCTION
            ------------------




            [This message has been edited by Scott Wolfington (edited September 10, 2000).]
            Scott Wolfington
            [url="http://www.boogietools.com"]http://www.boogietools.com[/url]

            Comment


            • #7
              Scott, when a Sub/Function receives an BYREF ASCIIZ, it actually receives a pointer to the storage of the actual string data elsewhere in memory. The length of the target data can be easily determined by the first incidence of a NUL (CHR$(0)) byte in the data (assuming that the data was correctly created with a null-terminating byte!)

              Of course you could also define the length of the ASCIIZ string in your Sub/Function parameter definition.

              In essence, you should always be sure that if you change the data who memory was no allocated by your module, you do not read or write beyond the amount of memory allocated for it. ie, if the C code passes a pointer to an ASCIIZ string, the C code should have preallocated enough memory to cope with any data that could be written into that storage.

              This is why many API functions require you to pass the buffer length as a separate parameter, to ensure a GPF does not occur, without the need to interogate the data storage (and for when the data storage contains undefined data). No good reading a string buffer whose 1st byte happens to be a null byte!

              I have always'd assume that a dll created by PowerBasic could be called by any program that could call a dll. It Appears that DLL's created by PowerBasic can only be accessed by PB or Visual Basic, unless you have access to the c or c++ source (which isn't always the case!)
              I was wrong!
              Actually this statement is wrong!
              You can certainly write a DLL that can be called by any Windows language that can use DLL's, but the other language has to be able to cope with the data being passed. As pointed out, a dynamic string in PB is equivalent to a BSTR in C. Once you get the data types matched correctly, it should work fine for you.

              Maybe you just need to rethink the way you are passing string data back and forwards? The most common and easiest approach is to use pointers to null-terminated string buffers, or in other words, ASCIIZ and AZSTRING strings. That is the beauty of BASIC - dynamic strings are much easier to cope with than BSTR's

              ------------------
              Lance
              PowerBASIC Support
              mailto:[email protected][email protected]</A>
              Lance
              mailto:[email protected]

              Comment


              • #8
                It seems there is some amount of confusion. I pointed the
                "Calling a PowerBASIC dll from C" as an example of passing
                dynamic strings to a pb dll. The only difference with what
                Michael wants to do is that he wants to return a string so I
                didn't show that part.

                It's very easy and you don't need to mess around with BSTR
                for returning the string. Here's an example (notice) that
                all I did was change the prototype and return types from the
                previous example:

                Code:
                // C CODE
                #include <windows.h>
                #include <stdio.h>
                #include <oleauto.h>
                 
                /* just change the prototype to char* to receive strings back from PB functions */
                typedef char* __stdcall LPFNCALLDLL( int DBNumber, BSTR DBName, int &prompt  );
                 
                int __cdecl main( int argc, char *argv[], char *envp[] ) 
                {
                	HMODULE hLib;
                	LPFNCALLDLL* lpCallDll;
                	BSTR bString;
                	char *chDSN;
                	int prompt;
                	char *chReturn;
                 	
                	hLib = LoadLibrary( "mydll.dll" );
                	if ( hLib == NULL )
                	{
                		printf( "Could not load mydll.dll" );
                		return FALSE;
                	}
                	lpCallDll = (LPFNCALLDLL*)GetProcAddress( hLib, "MyFunction" );
                	if ( lpCallDll == NULL )
                	{
                		FreeLibrary( hLib );
                		return FALSE;
                	}
                	chDSN = "  DRIVER=SQL Server;server=DevTestServer;database=DB1;uid=dbuser;pwd=pwrd  ";
                	/* Use OLE strings */
                	bString = SysAllocStringByteLen( chDSN, strlen(chDSN) ); 
                	if ( bString==NULL ) 
                	{
                		printf( "Could not allocate string" );
                		return FALSE;
                	}
                	prompt = 123;
                	chReturn = lpCallDll( 1, bString, prompt );
                	if ( strlen(chReturn) != 0 )
                		printf( "Function returned\n'%s'\n", chReturn );
                
                	/* OLE String must be freed afer use */
                	SysFreeString( bString );
                	FreeLibrary( hLib );
                	return TRUE;
                }
                The PB DLL code to go with it:

                Code:
                'BASIC code
                
                #DIM ALL
                #COMPILE DLL
                
                #INCLUDE "win32api.inc"
                
                FUNCTION MyFunction ALIAS "MyFunction" ( BYVAL lDbNumber AS LONG, BYVAL sDBName AS STRING, BYREF lPrompt AS LONG ) EXPORT AS STRING
                
                  FUNCTION = TRIM$(sDBName)
                
                END FUNCTION
                
                FUNCTION LibMain(BYVAL hInstance   AS LONG, _
                                 BYVAL fwdReason   AS LONG, _
                                 BYVAL lpvReserved AS LONG) EXPORT AS LONG
                
                  SELECT CASE fwdReason
                
                    CASE %DLL_PROCESS_ATTACH
                       LibMain = 1   'success!
                      EXIT FUNCTION
                
                    CASE %DLL_PROCESS_DETACH
                       LibMain = 1   'success!
                      EXIT FUNCTION
                
                    CASE %DLL_THREAD_ATTACH
                       LibMain = 1   'success!
                       EXIT FUNCTION
                
                    CASE %DLL_THREAD_DETACH
                       LibMain = 1   'success!
                
                      EXIT FUNCTION
                
                  END SELECT
                
                END FUNCTION

                ------------------

                Comment

                Working...
                X