External Function C#

Discussion forum about all things SqlBase.
Helmut Mayerhofer
Austria
Posts: 10
Joined: 02 Dec 2019, 23:09
Location: Austria

External Function C#

Post by Helmut Mayerhofer » 16 Nov 2016, 12:35

Hey!

We like to call a external procedure and transfer strings in both directions.

a) The documented function "SalStrSetBufferLength" is not recognized !?! How do you set the bufferlength?

b) We have a problem receiving LPSTRINGs from an external function using a C# dll.
The below code works fine with LPINT, however when using LPSTRINGs the receive string after calling the dll-Functon contains a pointer instead of the string.
Transfering strings from SqlBase to dll-Function works fine.

Using LPSTRING in SQLBase and string in C# dll results in:

string (normal parameter): transfers a string correctly to dll-function,however changes made to that string do not affect the original string in SQLBase - is ok!
out string: changes the original string in SQLBase to some sort of pointer (for example <160>3<192><6> )
ref string: running the function within the same thread and transferring LPSTRINGs shorter than 4 characters causes the database server to crash without warning or error, all other cases (longer strings or running as separate process) results in STATUS_ACCES_VIOLATIONs

All the above methods work perfectly fine with LPINTs

Our dll code:

using RGiesecke.DllExport;

Code: Select all

namespace cstest
{
    public class Class1
    {
        [DllExport]
        public static int cstest(int fu, string testi, out string test)//out: returns pointer; ref: <4characters ->DBCrash, <3characters->STATUS_ACCESS_VIOLATION
        {
	    fu++;
	    test=testi;
            using (System.IO.StreamWriter file =
            new System.IO.StreamWriter(@"E:\TEMP\test.txt", true))
            {
                file.WriteLine(testi+"-"+test);
            }
            return fu;
        }
    }
Any idea how we can properly work with LPSTRINGs in C# or is there any way in SQLBase to read a string from a pointer?

Jeff Luther
Site Admin
Site Admin
United States of America
Posts: 2364
Joined: 04 Mar 2017, 18:34
Location: Palm Springs, California

Re: External Function C#

Post by Jeff Luther » 16 Nov 2016, 17:11

Sorac -- the simplest answer for you is that SalStrSetBufferLength() was deprecated some time ago in an earlier v5.1 TD and (apparently) is now removed from your TD version. If you do a search in TD Help for this old function you will find:

SalStrSetBufferLength
Note: This API is deprecated due to Team Developer's switch from ANSI to Unicode. See SalSetBufferLength.

Take a look in Help for its replacement function, SalSetBufferLength(). Be sure to read the notes in Help for it.
Jeff Luther @ PC Design
Palm Springs, California

Helmut Mayerhofer
Austria
Posts: 10
Joined: 02 Dec 2019, 23:09
Location: Austria

Re: External Function C#

Post by Helmut Mayerhofer » 17 Nov 2016, 22:40

Hi Jeff

Thanks for your reply;

I tried SalSetBufferLength, but that doesn't seem to work either. Can i even use Sal Commands in an Stored Procedure from SQLBase? Usually Sal Commands are TD functions and not SQLBase..!? SalStrSetBufferLength is mentioned in SQLBase 12.0 Language reference Chapter 8: External Functions.

Thanks and best regards

Jeff Luther
Site Admin
Site Admin
United States of America
Posts: 2364
Joined: 04 Mar 2017, 18:34
Location: Palm Springs, California

Re: External Function C#

Post by Jeff Luther » 20 Nov 2016, 17:41

I attempted to reply to your question assuming that Team Dev. was involved. Now that I read your details it sounds like you are trying to interface a C# function/app. Mike Vandine is a better resource for all things SQLBase here but let me mention a few things:

>> In the SQLBase PDF book called sqllang.pdf, there's a "Sal Functions" section. Check that out because the TD Sal string function like SalSetBufferLength() is not listed. So you use the Sal string function from within a TD application.

You wrote:

Code: Select all

We like to call a external procedure and transfer strings in both directions.
Then the solution is to use TD to do this. You can connect to a SQLBase, then fetch and insert strings from SQLBase.

Assuming you have TD v5.2 or later where Unicode was added, then the ext. decl. for your C# function in a DLL would be something like:

Code: Select all

Library name: some.DLL
   ThreadSafe: No
   Function: cstest
      Description:
      Export Ordinal: 0
      Returns
         Number: INT
      Parameters
         Number: INT
         ! "W" strings below assuming you use TD v5.2 or later
         String: LPWSTR
         Receive String: LPWSTR
And a call to that ext. function in TD would be something like:

Code: Select all

Set nRtn = cstest( nFu, sTesti, sRtnTest )
And from your code after the function is called, then:
nRtn = nFu + 1 [because of "fu++;")
sTesti = same value as before the function call [because you declared testi to be passed by value]
sRtnTest = sTesti value [because of "test=testi;" The 'Receive" declaration in the ext. function decl. above means you want TD to pass the string by reference because of "out string"]

MIKE VANDINE -- Hi, and any further thoughts you can provide to assist this user?? TIA!!
Jeff Luther @ PC Design
Palm Springs, California

Igor Ivanovic
Site Admin
Site Admin
Croatia
Posts: 1406
Joined: 05 Mar 2017, 12:37
Location: Zagreb, Croatia

Re: External Function C#

Post by Igor Ivanovic » 24 Nov 2016, 16:47

Hi,

How did you declare the external function in SQLBase?
You can use cdllixx.dll from TD, but we are trying to avoid that because you have to have TD installed with the SQLBase server and we try to avoid that.

Regarding receiving strings from external functions, as there is no other way to allocate memory for them (at least we didn't found the way - maybe Mike has a better solution), we use something like this in our stored procedures:

set sBuffer = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
Make sure that you allocate enough memory for the result (and count the ending zero).

We are using this since SQLBase 8 with no problems whatsoever.
Igor Ivanovic
Image

Jeff Luther
Site Admin
Site Admin
United States of America
Posts: 2364
Joined: 04 Mar 2017, 18:34
Location: Palm Springs, California

Re: External Function C#

Post by Jeff Luther » 24 Nov 2016, 17:33

How did you declare the external function in SQLBase?
I didn't. As I wrote, that ext. function is how it would be declared in TD v5.2 or later. I used TD to declare that so you could see how it would look.

I must be not understanding you then. Since Mike Vandine is the SQLBase expert, perhaps he can better understand what you are asking. Sorry for my misunderstanding :?
Jeff Luther @ PC Design
Palm Springs, California

Igor Ivanovic
Site Admin
Site Admin
Croatia
Posts: 1406
Joined: 05 Mar 2017, 12:37
Location: Zagreb, Croatia

Re: External Function C#

Post by Igor Ivanovic » 25 Nov 2016, 14:46

Sorry Jeff, I was asking the OP about the external declaration but forget to quote to whom my answer was addressed :-)
As I understood, the OP was trying to use an external function inside a stored procedure, so my answer was about the way we are using them.
Sorry for the confusion...
Igor Ivanovic
Image

Helmut Mayerhofer
Austria
Posts: 10
Joined: 02 Dec 2019, 23:09
Location: Austria

Re: External Function C#

Post by Helmut Mayerhofer » 28 Nov 2016, 12:54

Hi Ivan

my external function looks like this (declared through sqltalk):

Code: Select all

create external function "cstest"
parameters (INT,LPCSTR,LPSTR)
returns (INT)
library 'C:\Program Files\Gupta\SQLBase120\cstestdll1.dll'
callstyle STDCALL
execute in same thread;

create public synonym "cstest" for external function "cstest";
grant execute on external function "cstest" to public;

Code: Select all

STORE SYSADM.EXTTEST PROCEDURE: Signieren static
Parameters
	Number: nSID
	Receive String: sText
Local Variables
	Sql Handle: hSql
	String: sStr
	Number: nDummy
	String sDummy
Actions
	Trace nSID
	Trace sText
	Call SqlConnect (hSql)
	! Ist Zahlungsmittel eine Registrierkassa
	Call SqlPrepareAndExecute(hSql,'Select WAREHOUSE into :sSTR from INVENTORY where STYLE_ID= :nSID')
	Call SqlFetchNext(hSql,nDummy)
	Trace sSTR
	Set sDummy=sText
	Set nDummy = cstest(nSID,sDummy,sText)
	Trace nDummy, sDummy,sText
	Call SqlDisconnect (hSql)
	Return 0;
In the meantime i tried using a C++ DLL instead since C++ actually understands LPSTRINGs, however changes made to the LPSTRING are not transferred back to sqlbase, whereas if i read the LPSTRING as char pointer trying to write to that pointer results once again in a STATUS_ACCESS_VIOLATION

Anything I'm doing wrong?

Helmut Mayerhofer
Austria
Posts: 10
Joined: 02 Dec 2019, 23:09
Location: Austria

Re: External Function C#

Post by Helmut Mayerhofer » 02 Dec 2016, 14:14

Got it to work!

In C#:

Code: Select all

public unsafe static int cstest(int fu, char* testi, byte* test)
{
            string temp = "Dass\0";
            byte[] tp = Encoding.ASCII.GetBytes(temp);

            int x = 0;
            while (x < temp.Length)
            {
                test[x] = tp[x];
                x++;
            }
            fu++;
            return fu;
}
In C++:

Code: Select all

__declspec(dllexport) int cpptest(int fu, LPSTR testi, LPSTR test)
{
	char text[] = "urf";
	int x = 0;
	while (x < strlen(text))
	{
		test[x] = text[x];
		x++;
	}
	test[x] = '\0';
	fu++;
	return fu;
}
Guess that solves my problem, thx for all the help :)

Return to “General Discussion”

Who is online

Users browsing this forum: [Ccbot] and 0 guests