Announcement

Collapse
No announcement yet.

Byval String$

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

  • Byval String$

    I am completely out in the dark here.
    Someone able to shed some light
    I have this PB-DLL with a Exported function like this...
    Function MyFunction(Byval S as String)as long
    Now to the question:
    How would this be prototyped in/called from C/C++


    -------------
    Fred
    mailto:[email protected][email protected]</A>
    http://www.oxenby.se

    Fred
    mailto:[email protected][email protected]</A>
    http://www.oxenby.se

  • #2
    Fred,
    Sorry for interrupting your thread, but as I don't know C\C++ I have a similar question for those 'in the know'

    Is it possible to call a PowerBasic function (exported in a DLL) that is a string, is there some way (such as inline ASM) or is it impossible?

    Cheers

    ------------------
    Kev G Peel
    KGP Software
    Bridgwater, UK.
    mailto:[email protected][email protected]</A>

    Comment


    • #3
      Sure, that it's not a problem for C.
      Because I don't know C, I'll show on PB code.

      What is a string in PB ?
      This is a pointer to structure of two elements:
      a) Dword - Length of string
      b) Asciiz * x
      This pointer shows address of Asciiz.
      You should transfer address of this pointer to PB function

      DLL:
      Code:
         #Compile Dll "Tmp.Dll"
         #Register None
         Function aa Alias "aa" (St As String) Export As Long
            MsgBox St,, Str$(Len(St))
         End Function
      "C"-Exe

      Code:
         #Compile Exe
         #Register None
         #Dim All
         Type tpStr
            L As Long
            S As Asciiz * 6
         End Type
      
         Declare Function aa Lib "Tmp.Dll" Alias "aa" (p As Dword) As Long
      
         Function PbMain
            Dim s As tpstr, p As Dword
            s.s = "Hello": s.l = 5: p = VarPtr(s.s): aa p
         End Function
      [This message has been edited by Semen Matusovski (edited May 08, 2000).]

      Comment


      • #4
        It would be easier if you received the "string" as an ASCIIZ instead of a dynamic string... PB dynamic strings are actually allocated by the OLE string engine (which is like a BSTR in Delphi), but with C it is quite common to work with "char" arrays (MyStr CHAR[30], etc).

        If you write your DLL to accept an ASCIIZ string string (which is effectively a pointer to the actual string data storage), then you can just pass a pointer to the string data from C.

        A simple PB prototype would look like:

        FUNCTION MyFunc1(XYZ AS ASCIIZ PTR) EXPORT AS LONG
        MSGBOX @XYZ
        END FUNCTION
        or
        FUNCTION MyFunc2(XYZ AS ASCIIZ) EXPORT AS LONG
        MSGBOX XYZ
        END FUNCTION

        Internally, these functions can be called identically, the difference in choice comes down to which is easier for your code.

        OTOH, it's probably quite simple for C to use the OLE string engine too, but as I'm not a C programmer, I cannot show you how!



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

        Comment


        • #5
          Fred,

          The prototyping in "C" would be in one of the home grown resource header files that gets compiled in the exe program, ie Whatever.h!!! I have been learning C but not yet that advanced. Tom could readily answer the prototyping setup, I bet.

          Cheers,
          Cecil

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

          Comment


          • #6
            Fred,

            I agree with Lance here, using a zero terminated string in C/C++
            is normal where I suspect it would be few who would know how to
            correctly handle an OLE string from C/C++.

            char szMyString[] = "Hi folks, this is a test !";

            in Microsoft C is much the same as an ASCIIZ string in PowerBASIC.
            Are they simple strings that must be passed to it or are they larger
            addresses, this will effect what you will do with it on the other end.

            [email protected]

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


            [This message has been edited by Steve Hutchesson (edited May 09, 2000).]
            hutch at movsd dot com
            The MASM Forum

            www.masm32.com

            Comment


            • #7
              Unfortunatly there is no choice here.
              My Dll use "Byval String" that is as I understand it
              the value is placed on the stack, not the address of the string.
              I have tried to find some guidence in the documentation,
              but there is none (I can find).
              Looking in the mirror, I should have been warned by this fact,
              but I was not...


              ------------------
              Fred
              mailto:[email protected][email protected]</A>
              http://www.oxenby.se

              Fred
              mailto:[email protected][email protected]</A>
              http://www.oxenby.se

              Comment


              • #8
                Hi

                BSTR's (OLE strings) are allocated in C just like in PB - with the SysAllocString_ function family as in:

                example:
                BSTR bstrMyString = SysAllocStringLen( szString, len )

                If you're passing OLE strings try a function prototype like:

                void MyCSub ( BSTR bstrString )

                Cheers

                Florent



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

                Comment


                • #9
                  Originally posted by Fred Oxenby:
                  I have this PB-DLL with a Exported function like this...
                  Function MyFunction(Byval S as String)as long
                  Now to the question:
                  How would this be prototyped in/called from C/C++
                  Ok. STRING parameters are always passed by reference. When you say BYVAL, it tells PowerBASIC to make a copy of the string, then pass the copy of the string by reference. So, the declaration on the C/C++ end is going to be the same, in this case, as if you were passing BYREF:
                  Code:
                  long MyFunction (BSTR s);
                  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:
                  long MyFunction (LPSTR s);
                  // or use "char *" instead of "LPSTR"
                  ------------------
                  Tom Hanlin
                  PowerBASIC Staff

                  Comment


                  • #10
                    Hi

                    Here's some example code to illustrate this process:

                    Oops - the string I'm passing is UNICODE changed SysAllocString( L"DoThis" ); to SysAllocString( (const unsigned short *)"DoThis" );

                    Code:
                    // C CODE
                    #include <windows.h>
                    #include <stdio.h>
                    
                    int lpFunction( BSTR bCallMe );
                    
                    int main( int argc, char *argv[], char *envp[] ) 
                    {
                    	HANDLE hLib;
                    	FARPROC lpFunction;
                            BSTR bString;
                    	int lReturn;
                    
                    	hLib = LoadLibrary( "mydll.dll" );
                    	if ( hLib == NULL )
                    	{
                    		printf( "Could not load mydll.dll" );
                    		return FALSE;
                    	}
                    	lpFunction = GetProcAddress( hLib, "MyFunction" );
                    	if ( lpFunction == NULL )
                    	{
                    		FreeLibrary( hLib );
                    		return FALSE;
                    	}
                    	bString = SysAllocString( (const unsigned short *)"DoThis" );
                    	lReturn = lpFunction( bString );
                    	if ( lReturn != 0 )
                    		printf( "String length %d", lReturn );
                            FreeLibrary( hLib );
                    	return TRUE;
                    
                    }
                    
                    -------------
                    'BASIC code
                    
                    $COMPILE DLL
                    
                    #INCLUDE "win32api.inc"
                    
                    FUNCTION MyFunction ALIAS "MyFunction" ( BYVAL sString AS STRING ) EXPORT AS LONG
                       
                       FUNCTION = LEN(sString)
                       
                    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
                    Cheers

                    Florent


                    [This message has been edited by Florent Heyworth (edited May 09, 2000).]

                    Comment


                    • #11
                      Fred, what you are after can be done, in masm it looks as follows
                      so to convert it to C would be no big deal.

                      invoke SysAllocStringByteLen,0,ln ; allocate the string
                      mov hMem, eax

                      ; ----------------------------------------------------
                      ; Pass hMem which is the starting address to the DLL.
                      ; ----------------------------------------------------

                      invoke SysFreeString,hMem ; de-allocate it.

                      This is normal stuff but at the DLL end you would have to test what is
                      received. The hMem is a 32 bit integer value which can be either DWORD or
                      LONG, it would not matter either way.

                      You could have the parameter at the DLL end, LONG but it means you would
                      need to put it into a string variable handle. Unless you want to commit
                      the C/C++ user to having to work with OLE string, I would be inclined to
                      do it in the older style C setup where you either pass the address of a
                      zero terminated string and work on it directly in your DLL, or pass a
                      second buffer to receive the output from the DLL.

                      [email protected]


                      ------------------
                      hutch at movsd dot com
                      The MASM Forum

                      www.masm32.com

                      Comment


                      • #12
                        Tom,

                        Thanks a lot for clarifying the STRING parameter passing info. I didn't realize the copy was passed by reference.

                        Cecil

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

                        Comment


                        • #13
                          Thanks everybody, This is an important topic.
                          As I said earlier, I was blind to the fact that there were no
                          description to 'BYVAL STRING' except for some comparison to
                          Visual Basic 'BYVAL STRING'. I wish I paid more attention to that line of text..
                          ---
                          Anyhow, There are a lot of functions in my library which could
                          be wrapped using Asciiz-strings, but for some of the them it
                          will not be possible. I need all 256 characters in our char-set.
                          ---
                          I have been investigating use of BSTR, but as I see it BSTR is
                          Wide-character string, exception is strings created with SysAllocStringByteLen (SysAllocStringLen).
                          A BSTR (Basic STRing) is a structured data type that contains a character string and the string's length. COM provides methods to allocate, manipulate, and free a BSTR.
                          ---
                          I am not going to change my DLL-s.
                          If someone calls my function with a ptr to this BSTR-structure
                          I must be able to treat it like any other "PowerBasic string"
                          MSDN does not give me an straight answer.
                          ---
                          If the C/C++ guys find my SDK hard to use, they can always use
                          PB as the development-platform instead (?)
                          ---
                          If I understood Tom Hanlin III there is no need for Visual Basic-wrappers either.
                          Function MyFunction(Byval S as String) as long
                          can be declared as BYREF in VB and it will not GPF (!)
                          -PS-
                          My spellchecker wants to change C++ programmers into CHIHUAHUA
                          Is that a yoke or does it know something I dont


                          ------------------
                          Fred
                          mailto:[email protected][email protected]</A>
                          http://www.oxenby.se

                          Fred
                          mailto:[email protected][email protected]</A>
                          http://www.oxenby.se

                          Comment


                          • #14
                            If I understood Tom Hanlin III there is no need for Visual Basic-wrappers either.
                            Function MyFunction(Byval S as String) as long
                            can be declared as BYREF in VB and it will not GPF (!)
                            Internally, VB stores strings in unicode format, but specifically handles the passing of strings to DLL's differently to when VB code calls other VB code/functions.

                            Specifically, when VB needs to pass a string to a DLL, it converts the string from unicode to ANSI, an then passes a pointer to the ANSI string handle to the DLL (as allocated by the OLE string engine) - this means that you can write your (PB) DLL code to receive a dynamic string BYREF and pass the string directly (BYREF) from VB. Vb handles the data manipulation transparently, but with some cost in terms of execution speed.

                            If the PB code expects an ASCIIZ string (BYREF), then you must pass the string from VB using BYVAL. Again, VB handles the unicode conversion before passing a pointer to the PB code.

                            In either case, VB converts the resulting string back to unicode when the function call returns, but there are key differences between the two methods - when PB expects an ASCIIZ, you cannot extend the string beyond it's initial length, and the VB code must explicitly truncate the return string at the first NUL byte.

                            See Appendix B of the PB/DLL 6.0 help file for more information on this topic.

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

                            Comment


                            • #15
                              Originally posted by Fred Oxenby:

                              I have been investigating use of BSTR, but as I see it BSTR is
                              Wide-character string, exception is strings created with SysAllocStringByteLen (SysAllocStringLen).
                              This is an important point. BSTR values typically use Unicode, rather than ANSI. Microsoft's docs have been known to say that BSTRs are always in Unicode, although we know better . Still, since PowerBASIC uses ANSI, and many other implementations assume Unicode, this is a fine opportunity for confusion and conflicts.

                              It might actually be easier for you to use ASCIIZ strings or BYTE arrays to pass the values. Although ASCIIZ strings are normally interpreted as being terminated at the first NUL character, that's just a convention. Provided that the caller passes you the actual length of the string, you are not required to pay any attention to the NUL character-- although you would probably want to employ conversion functions to translate the results to/from regular PowerBASIC strings for convenient handling.

                              ------------------
                              Tom Hanlin
                              PowerBASIC Staff

                              Comment


                              • #16
                                > I need all 256 characters in our char-set.

                                To amplify Tom's last point, Fred, ASCIIZ strings can contain all 256 ASCII characters, even CHR$(0) There are a number of API functions that return both an ASCIIZ string and a "length" indicator. You're supposed to use the length indicator to determine the length of the string, instead of looking for the CHR$(0) terminator. Of course you will need to add special handling, because if you treat the return value as an ASCIIZ string many different functions will truncate it at the first CHR$(0), but it is relatively easy to covert an ASCIIZ string that contains nuls into a "regular" PB string. For example, you could use PEEK$.

                                -- Eric




                                ------------------
                                Perfect Sync: Perfect Sync Development Tools
                                Email: mailto:[email protected][email protected]</A>

                                "Not my circus, not my monkeys."

                                Comment


                                • #17
                                  Originally posted by Lance Edmonds:
                                  See Appendix B of the PB/DLL 6.0 help file for more information on this topic.
                                  Appendix B
                                  It is also important to note that a string ByVal in PowerBASIC is not the same thing as a string ByVal in Visual Basic. That is, since PowerBASIC natively supports ASCIIZ strings, it does not convert a dynamic string into an ASCIIZ string, as does Visual Basic. PowerBASIC does what you tell it, it makes a copy of the string and passes the new string handle to the API or DLL.
                                  Perhaps my limited knowledge in english is 'pulling my leg' here but
                                  Byval String in powerbasic mean 'a copy of the string is passed By reference'
                                  If I pass a string ByRef from VB to my DLL , my code in PB/DLL would not know that the stringhandle is to the original string
                                  and not to a copy.



                                  ------------------
                                  Fred
                                  mailto:[email protected][email protected]</A>
                                  http://www.oxenby.se

                                  Fred
                                  mailto:[email protected][email protected]</A>
                                  http://www.oxenby.se

                                  Comment


                                  • #18
                                    BTW

                                    as a C programmer you've got the choice of whether you want to pass ANSI strings or UNICODE strings:

                                    SysAlloc( L"Dothis" );

                                    will pass a unicode string of length 12 whereas:

                                    SysAlloc( (USHORT *) "Dothis" );
                                    or
                                    SysAlloc( (unsigned short *) "DoThis" );
                                    (other variations are possible) will pass an ANSI string. If you're going to have C programmers use OLE strings you should document that your DLL expects ANSI strings and not UNICODE strings.

                                    The API leaves it up to the programmer what he/she wants to produce.

                                    Cheers

                                    Florent


                                    [This message has been edited by Florent Heyworth (edited May 10, 2000).]

                                    Comment

                                    Working...
                                    X