You are not logged in. You can browse in the PowerBASIC Community, but you must click Login (top right) before you can post. If this is your first visit, check out the FAQ or Sign Up.
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.
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!)
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]
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
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
We process personal data about users of our site, through the use of cookies and other technologies, to deliver our services, and to analyze site activity. For additional details, refer to our Privacy Policy.
By clicking "I AGREE" below, you agree to our Privacy Policy and our personal data processing and cookie practices as described therein. You also acknowledge that this forum may be hosted outside your country and you consent to the collection, storage, and processing of your data in the country where this forum is hosted.
Comment