Lazarus
Programming => General => Topic started by: xinyiman on June 24, 2010, 09:39:59 pm
-
I created a C library which allows me to obtain lists of strings! Who will help me turn it into a .dll and .so
Thanks
:)
-
Question ansistring but is equal to the string of C?
-
Question ansistring but is equal to the string of C?
Use PChar when talking to C.
-
Another question I've put in my dll as a parameter of the function PtrMiaLista * MiaLista
How do I declare in Free Pascal? It 'a pointer to a list of structures!
-
Have a look at the RTL sources, there are a lot of declarations, like
TSize = record
cx : Longint;
cy : Longint;
end;
PSize = ^TSize;
-
Suppose I have a dll in the same folder as the software, called miadll.dll and which contains the procedure MiaProcedura (PtrMiaLista MiaLista *);
Correctly filled with dev-cpp. As I recall from lazarus?
-
Then the dll that I wrote with Devcpp function is declared as follows:
EXTERN_C __declspec(dllexport) VOID GetListaDSN (PtrListaODBC * MiaLista);
Instead PtrListaODBC is declared:
typedef struct ListaODBC
{
char dsn[256];
char desc[256];
struct ListaODBC * next;
}PtrListaODBC;
In my example below I tried to interact with lazarus dll. No crashes when I run, but I do not return the result I expect! How do I change it?
unit Unit1;
{$mode objfpc}{$H+}
{$ifdef unix}
{$linklib myfunc}
{$endif}
interface
uses
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
ExtCtrls, StdCtrls;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
type
PtrListaODBC = record
dsn : PChar;
desc : PChar;
next: integer;
end;
var
Form1: TForm1;
function GetListaDSN(MiaLista: PtrListaODBC): PChar; cdecl; external {$ifdef windows} 'ProgettoDLLODBC.dll'{$endif};
implementation
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
var
app: PtrListaODBC;
begin
GetListaDSN(app);
Edit1.Text:=app.dsn;
end;
initialization
{$I unit1.lrs}
end.
-
I changed the source but now crashes when I try to exploit the variable valore with the DSN list! :o :o
unit Unit1;
{$mode objfpc}{$H+}
{$ifdef unix}
{$linklib myfunc}
{$endif}
interface
uses
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
ExtCtrls, StdCtrls;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
PtrListaODBC=^appoggio;
Appoggio = record
dsn : PChar;
desc : PChar;
next: PtrListaODBC;
end;
var
Form1: TForm1;
function GetListaDSN(MiaLista: PtrListaODBC): PChar; cdecl; external {$ifdef windows} 'ProgettoDLLODBC.dll'{$endif};
implementation
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
var
app: PtrListaODBC;
i: integer;
valore: PChar;
begin
app:=new (PtrListaODBC);
GetListaDSN(app);
i:=0;
while (app<>nil) do
begin
valore:=app^.dsn;
app:=app^.next;
end;
end;
initialization
{$I unit1.lrs}
end.
-
In this case, it's not PChar.
h2pas translates:
ListaODBC = record
dsn : array[0..255] of char;
desc : array[0..255] of char;
next : ^ListaODBC;
end;
PtrListaODBC = ListaODBC;
Use h2pas for header translation. Probaby it's stdcall instead of cdecl, I don't know.
-
You can make pascal and C work together?
-
You can make pascal and C work together?
Yes, using DLLs. The whole Windows API is in C, so if this would not work, you would not be able to create a Form or sth. in Pascal.
-
DLL Source
#include <windows.h>
#include <stdio.h>
#include "MyODBCLib.h"
EXTERN_C __declspec(dllexport) INT CountDSN ();
EXTERN_C __declspec(dllexport) VOID GetDSNNum (INT num , CHAR * Dsn,CHAR * Desc);
BOOL WINAPI __declspec(dllexport) LibMain (HINSTANCE hInst, DWORD Reason, LPVOID Reserved)
{
if(Reason==DLL_PROCESS_ATTACH)
{
return TRUE;
}
if(Reason==DLL_PROCESS_DETACH)
{
return TRUE;
}
return FALSE;
}
EXTERN_C __declspec(dllexport) INT CountDSN ()
{
PtrListaODBC * MiaLista;
int ret;
MiaLista=RecuperaListaODBC();
ret=QuantiDSN(MiaLista);
CancellaListaODBC(MiaLista);
return ret;
}
EXTERN_C __declspec(dllexport) VOID GetDSNNum (INT num , CHAR * Dsn,CHAR * Desc)
{
PtrListaODBC * MiaLista;
PtrListaODBC * app;
int ret, i;
MiaLista=RecuperaListaODBC();
app=MiaLista;
i=0;
while(app)
{
//printf("%s - %s\n", app->dsn, app->desc);
if (i==num)
{
Dsn=(char*)malloc(sizeof(char)*strlen(app->dsn));
sprintf(Dsn,app->dsn);
Desc=(char*)malloc(sizeof(char)*strlen(app->desc));
sprintf(Desc,app->desc);
}
i++;
app=app->next;
}
CancellaListaODBC(MiaLista);
}
So given this information, someone can explain why I can not get the data I want?
I changed no more scores for the entire list, but knowing how many dsn tell him to return the first list, the second etc..
Lazarus source
unit Unit1;
{$mode objfpc}{$H+}
{$ifdef unix}
{$linklib myfunc}
{$endif}
interface
uses
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
ExtCtrls, StdCtrls;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
PtrListaODBC=^appoggio;
Appoggio = record
dsn : array[0..255] of char;
desc : array[0..255] of char;
next: PtrListaODBC;
end;
var
Form1: TForm1;
//function GetListaDSN(MiaLista: PtrListaODBC): PChar; cdecl; external {$ifdef windows} 'ProgettoDLLODBC.dll'{$endif};
function CountDSN(): integer;stdcall; cdecl; external {$ifdef windows} 'ProgettoDLLODBC.dll'{$endif};
procedure GetDSNNum (num: integer;Dsn: PChar ;Desc: PChar);stdcall; cdecl; external {$ifdef windows} 'ProgettoDLLODBC.dll'{$endif};
implementation
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
var
app: PtrListaODBC;
i: integer;
valore: string;
MioDsn: Pchar;
MiaDesc: PChar;
begin
i:=CountDSN();
MioDSN:='--';
GetDSNNum(2,MioDSN,MiaDesc);
Edit1.Text:=IntToStr(i) + ' ' + MioDSN ;
end;
initialization
{$I unit1.lrs}
end.
-
function CountDSN(): integer;stdcall; cdecl; external {$ifdef windows} 'ProgettoDLLODBC.dll'{$endif};
You define stdcall AND cdecl? Does this compile?
It's either or..
http://www.freepascal.org/docs-html/prog/progsu80.html
-
function CountDSN(): integer;stdcall; cdecl; external {$ifdef windows} 'ProgettoDLLODBC.dll'{$endif};
You define stdcall AND cdecl? Does this compile?
It's either or..
http://www.freepascal.org/docs-html/prog/progsu80.html
Now modify
//function GetListaDSN(MiaLista: PtrListaODBC): PChar; cdecl; external {$ifdef windows} 'ProgettoDLLODBC.dll'{$endif};
function CountDSN(): integer;cppdecl; external {$ifdef windows} 'ProgettoDLLODBC.dll'{$endif};
procedure GetDSNNum (num: integer;Dsn: PChar ;Desc: PChar);cppdecl; external {$ifdef windows} 'ProgettoDLLODBC.dll'{$endif};
But the result not change!
-
I think you should declare the Pchars as var.
Make this little test in Pascal only:
procedure Getp(p:PChar);
var s:String;
begin
s:='test';
p:=PChar(s);
end;
procedure GetpV(var p:PChar);
var s:String;
begin
s:='test';
p:=PChar(s);
end;
procedure TForm1.Button1Click(Sender:TObject);
var p:PChar;
begin
GetP(p);
ShowMessage(p); //Garbage
GetPV(p);
ShowMessage(p); //Works
end;
-
Ok we are almost, I have to finish some things, but I got the list of odbc and tables!
The only thing that goes wrong when I use:
var:
appoggio: PChar;
LiberaStringa(appoggio);
declared as follows:
procedure LiberaStringa (var val: PChar);cppdecl; external {$ifdef windows} 'ProgettoDLLODBC.dll'{$endif};
and the dll is:
EXTERN_C __declspec(dllexport) VOID LiberaStringa(char * val)
{
delete(val);
}
Why?
-
Of course, your call of "procedure LiberaStringa (var val: PChar);" looks as "void LiberiaStringa(char **val)" not as "void LiberiaStringa(char *val)". Please, remember that PChar are already a pointer type declared as PChar=^Char; and declaration as var variable:type in procedure parameter always looks as a pointer to this variable.
Ahh, yes! Never do this:
EXTERN_C __declspec(dllexport) VOID GetDSNNum (INT num , CHAR * Dsn,CHAR * Desc)
{
PtrListaODBC * MiaLista;
PtrListaODBC * app;
int ret, i;
MiaLista=RecuperaListaODBC();
app=MiaLista;
i=0;
while(app)
{
//printf("%s - %s\n", app->dsn, app->desc);
if (i==num)
{
Dsn=(char*)malloc(sizeof(char)*strlen(app->dsn));
sprintf(Dsn,app->dsn);
Desc=(char*)malloc(sizeof(char)*strlen(app->desc));
sprintf(Desc,app->desc);
}
i++;
app=app->next;
}
CancellaListaODBC(MiaLista);
}
You assigns new pointer to a Dsn parameter, but it has pointer to first byte of string, that's whay you cant receive valid string both in C++ and Pascal, you can do two things:
One way is to pass Dsn as char* and length (uint32_t) of this buffer, and then assign value vith help of memcpy function.
Another way is to declare Dsn as char** and assign new value as code below:
*Dsn=(char*)malloc(strlen(app->dsn)+1); //size of char data type is always equal to one byte (uint8_t) and we need a leading zero!
sprintf(*Dsn,app->dsn);
*Dsn[strlen(app->dsn)]=0; //add leading zero!
Because that you code may looks as:
EXTERN_C __declspec(dllexport) void MyCoolProc(char **MyVal) {
*MyVal=(char*)malloc(64);
strcpy(*MyVal,"Wow!!! It Works"); //strcpy already set leading zero
}
Procedure MyCoolProc(var MyVal:PChar); cppdecl; external;
-
I tried to be so
EXTERN_C __declspec(dllexport) VOID LiberaStringa(char ** val)
{
free(*val);
}
so that
EXTERN_C __declspec(dllexport) VOID LiberaStringa(char ** val)
{
free(val);
}
but in both cases, crashes in the first tells me appears to debug in assembler and the second one I did not return any error type but appears to debug in assembler. Why? :o
-
To address this
http://www.freepascal.org/docs-html/ref/refsu13.html
says PChar is a pointer to a NULL terminated string. So I do not understand the intervention of Whiterawen that says it is a pointer to a pointer to a caratterre. Whiterawen you explain better? Thanks
-
He's trying to say that these two are equal:
procedure p1(var p: pchar);
procedure p2(p: ^pchar);
so a var parameter is the same as if you're passing a pointer, so those two above would equal in C as:
void p1(char** p); // or p2, no problem, both are the same
-
Ok, but even with this information does not change the result. I go into the same error! On a trivial operation as a free area of memory allocated with malloc! Absurd
-
Have you tried using cdecl or stdcall instead of cppdecl ?
-
Have you tried using cdecl or stdcall instead of cppdecl ?
My lazarus source
unit Unit1;
{$mode objfpc}{$H+}
{$ifdef unix}
{$linklib myfunc}
{$endif}
interface
uses
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
ExtCtrls, StdCtrls;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
PtrListaODBC=^appoggio;
Appoggio = record
dsn : array[0..255] of char;
desc : array[0..255] of char;
next: PtrListaODBC;
end;
var
Form1: TForm1;
//function GetListaDSN(MiaLista: PtrListaODBC): PChar; cdecl; external {$ifdef windows} 'ProgettoDLLODBC.dll'{$endif};
function MaxDSN(): integer;cppdecl; external {$ifdef windows} 'ProgettoDLLODBC.dll'{$endif};
function GetDSN (num: integer): PChar;cppdecl; external {$ifdef windows} 'ProgettoDLLODBC.dll'{$endif};
function GetDescDSN (num: integer): PChar;cppdecl; external {$ifdef windows} 'ProgettoDLLODBC.dll'{$endif};
procedure LiberaStringa (var val: PChar);cppdecl; external {$ifdef windows} 'ProgettoDLLODBC.dll'{$endif};
function MaxTabelle(Dsn: PChar; Uid: PChar; Pwd: PChar): integer;cppdecl; external {$ifdef windows} 'ProgettoDLLODBC.dll'{$endif};
function GetNomeTabella(Dsn: PChar; Uid: PChar; Pwd: PChar; num: integer): PChar;cppdecl; external {$ifdef windows} 'ProgettoDLLODBC.dll'{$endif};
implementation
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
var
app: PtrListaODBC;
i: integer;
MioDsn: Pchar;
MiaDesc: PChar;
MiaTab: PChar;
begin
i:=0;
for i:=1 to MaxDSN() do
begin
MioDSN:=GetDSN(i);
MiaDesc:=GetDescDSN(i);
ShowMessage(IntToStr(i) + ' ' + MioDSN + ' [' + MiaDesc + ']');
LiberaStringa(MioDSN);
LiberaStringa(MiaDesc);
end;
for i:=1 to MaxTabelle('MySql_Locale','mycinema','mycinema') do
begin
MiaTab:=GetNomeTabella('MySql_Locale','mycinema','mycinema',i);
ShowMessage(IntToStr(i) + ' ' + MiaTab);
end;
end;
initialization
{$I unit1.lrs}
end.
My DEV CPP dll source
#include <windows.h>
#include <stdio.h>
#include "MyODBCLib.h"
EXTERN_C __declspec(dllexport) INT MaxDSN ();
EXTERN_C __declspec(dllexport) INT MaxTabelle (char * Dsn, char * Uid, char * Pwd);
EXTERN_C __declspec(dllexport) VOID GetDSNNum (INT num , CHAR * Dsn,CHAR * Desc);
EXTERN_C __declspec(dllexport) char * GetDSN (INT num);
EXTERN_C __declspec(dllexport) VOID LiberaStringa(char ** val);
EXTERN_C __declspec(dllexport) char * GetNomeTabella (char * Dsn, char * Uid, char * Pwd, INT num);
BOOL WINAPI __declspec(dllexport) LibMain (HINSTANCE hInst, DWORD Reason, LPVOID Reserved)
{
if(Reason==DLL_PROCESS_ATTACH)
{
return TRUE;
}
if(Reason==DLL_PROCESS_DETACH)
{
return TRUE;
}
return FALSE;
}
EXTERN_C __declspec(dllexport) INT MaxDSN ()
{
PtrListaODBC * MiaLista;
PtrListaODBC * app;
int ret;
MiaLista=RecuperaListaODBC();
app=MiaLista;
ret=0;
while(app)
{
ret++;
app=app->next;
}
CancellaListaODBC(MiaLista);
return ret;
}
EXTERN_C __declspec(dllexport) INT MaxTabelle (char * Dsn, char * Uid, char * Pwd)
{
PtrDatiODBC * MieiDati; //contiene i dati per collegarsi al oDBC
PtrListaTabelle * MieTabelle;
PtrListaTabelle * app;
char * strconn;
int ret;
strconn=(char*)malloc(sizeof(char)*(1+strlen(Dsn)+strlen(Uid)+strlen(Pwd)+strlen("DSN=;UID=;PWD=;")));
strcpy(strconn,"DSN=");
strcat(strconn,Dsn);
strcat(strconn,";UID=");
strcat(strconn,Uid);
strcat(strconn,";PWD=");
strcat(strconn,Pwd);
strcat(strconn,";");
//MieiDati=ApriConnessioneODBC((SQLCHAR*)"DSN=MySql_Locale;UID=mycinema;PWD=mycinema;");
MieiDati=ApriConnessioneODBC((SQLCHAR*)strconn);
free(strconn);
MieTabelle=RecuperaListaTabelle(MieiDati);
app=MieTabelle;
ret=0;
while(app)
{
//printf("%s - %s\n", app->dsn, app->desc);
ret++;
app=app->next;
}
CancellaListaTabelle(MieTabelle);
DisconnettiODBC(MieiDati); //mi disconnetto
return ret;
}
EXTERN_C __declspec(dllexport) VOID GetDSNNum (INT num , char * Dsn, char * Desc)
{
PtrListaODBC * MiaLista;
PtrListaODBC * app;
int ret, i;
char * val1, *val2;
MiaLista=RecuperaListaODBC();
app=MiaLista;
i=0;
while(app)
{
//printf("%s - %s\n", app->dsn, app->desc);
i++;
if (i==num)
{
val1=(char*)malloc(sizeof(char)*strlen(app->dsn));
strcpy(val1,app->dsn);
val2=(char*)malloc(sizeof(char)*strlen(app->desc));
strcpy(val2,app->desc);
Dsn=val1;
Desc=val2;
}
app=app->next;
}
CancellaListaODBC(MiaLista);
}
EXTERN_C __declspec(dllexport) char * GetDSN (INT num)
{
PtrListaODBC * MiaLista;
PtrListaODBC * app;
char * ret;
int i;
MiaLista=RecuperaListaODBC();
app=MiaLista;
i=0;
while(app)
{
//printf("%s - %s\n", app->dsn, app->desc);
i++;
if (i==num)
{
ret=(char*)malloc(sizeof(char)*strlen(app->dsn));
strcpy(ret,app->dsn);
}
app=app->next;
}
CancellaListaODBC(MiaLista);
return ret;
}
EXTERN_C __declspec(dllexport) char * GetDescDSN (INT num)
{
PtrListaODBC * MiaLista;
PtrListaODBC * app;
char * ret;
int i;
MiaLista=RecuperaListaODBC();
app=MiaLista;
i=0;
while(app)
{
//printf("%s - %s\n", app->dsn, app->desc);
i++;
if (i==num)
{
ret=(char*)malloc(sizeof(char)*strlen(app->desc));
strcpy(ret,app->desc);
}
app=app->next;
}
CancellaListaODBC(MiaLista);
return ret;
}
EXTERN_C __declspec(dllexport) char * GetNomeTabella (char * Dsn, char * Uid, char * Pwd, INT num)
{
PtrDatiODBC * MieiDati; //contiene i dati per collegarsi al oDBC
PtrListaTabelle * MieTabelle;
PtrListaTabelle * app;
char * strconn;
int i;
char * ret;
strconn=(char*)malloc(sizeof(char)*(1+strlen(Dsn)+strlen(Uid)+strlen(Pwd)+strlen("DSN=;UID=;PWD=;")));
strcpy(strconn,"DSN=");
strcat(strconn,Dsn);
strcat(strconn,";UID=");
strcat(strconn,Uid);
strcat(strconn,";PWD=");
strcat(strconn,Pwd);
strcat(strconn,";");
//MieiDati=ApriConnessioneODBC((SQLCHAR*)"DSN=MySql_Locale;UID=mycinema;PWD=mycinema;");
MieiDati=ApriConnessioneODBC((SQLCHAR*)strconn);
free(strconn);
MieTabelle=RecuperaListaTabelle(MieiDati);
app=MieTabelle;
ret=NULL;
i=0;
while(app)
{
//printf("%s - %s\n", app->dsn, app->desc);
i++;
if (i==num)
{
ret=(char*)malloc(sizeof(char)*strlen(app->nome));
strcpy(ret,app->nome);
}
app=app->next;
}
CancellaListaTabelle(MieTabelle);
DisconnettiODBC(MieiDati); //mi disconnetto
return ret;
}
EXTERN_C __declspec(dllexport) VOID LiberaStringa(char ** val)
{
free(val);
}
If I comment a free function the program not return a sigsev error.
-
@xinyiman: You clearly have problems with pointer syntax, like many other people have.
A question: why do you want to create a DLL with C and then use it from Object Pascal?
I understand if someone wants to use an existing DLL but you are making it yourself.
Do you feel there is something you can do with C that you cannot do with Object Pascal? Please tell what it is and someone may be able to help you.
Juha
-
So I am not able to find a method crossplatform (win, linux) to get the odbc dsn and related information. Plus I could not get the name of tables with GetTableName (). So I decided to make a dll in C library with my work because I know I've worked on both Linux and Windows to obtain this information. If someone can tell me how to get it again without errors in a cross-platform then me suggest that I avoid creating a dll. Thanks
-
So I am not able to find a method crossplatform (win, linux) to get the odbc dsn and related information.
ODBC is basically Windows only, although there are some Linux libs and other hacks made for it.
If you really want to make a crossplatform application, why would you want to use ODBC?
Juha
-
So I am not able to find a method crossplatform (win, linux) to get the odbc dsn and related information.
ODBC is basically Windows only, although there are some Linux libs and other hacks made for it.
If you really want to make a crossplatform application, why would you want to use ODBC?
Juha
Exist on linux and unix-odbc work quite well. So I would not say that there are only on windows.
-
Exist on linux and unix-odbc work quite well. So I would not say that there are only on windows.
At least it doesn't work well with FPC as you have noticed. If you make a crossplatform DB application using FPC / Lazarus there are much better alternatives than ODBC.
Juha
-
Really works very well, but I can not retrieve the DSN (on linux) and tables (on windows). I suggest some other option for cross-platform
-
Really works very well, but I can not retrieve the DSN (on linux) and tables (on windows).
It means it does not work very well. :-)
Cross platform ODBC seems to be supported by Lazarus, I didn't even know:
http://wiki.lazarus.freepascal.org/ODBCConn
If you still want to use ODBC, you should report / fix bugs for it. A self made DLL coded with C doesn't sound like a good idea.
Anyway, I still recommend to use some other DB connection method for crossplatform.
Firebird and SQLite are crossplatform DBs, commonly used with FPC. There is a Lazarus builtin connection and there is ZEOSlib.
http://wiki.lazarus.freepascal.org/Databases
http://wiki.lazarus.freepascal.org/Lazarus_DB_Faq
You could read messages and maybe ask further questions here :
Forum > Programming > Databases
Juha