*i used this code :
but ther is an errore on ADS_SEARCH_HANDLE
can any body help me?*
Code :
unit Unapp;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TFormApp = class(TForm)
Button1: TButton;
private
function GetADDisplayName(const Username: String): String;
{ Private declarations }
public
{ Public declarations }
end;
var
FormApp: TFormApp;
implementation
uses
ActiveX,
JwaAdsTlb, JwaActiveDS; // From Jedi ApiLib
{$R *.dfm}
function TFormApp.GetADDisplayName(const Username: String): String;
var
hr: HRESULT;
DirSearch: IDirectorySearch;
SearchInfo: ADS_SEARCHPREF_INFO;
hSearch: ADS_SEARCH_HANDLE; // ************this has error**************
col: ADS_SEARCH_COLUMN;
Filter: String;
Attributes: array of PChar;
begin
Result := 'Undefined Result';
// Initialize COM
CoInitialize(nil);
try
// Change line below with your domain name
hr := ADsGetObject('LDAP://dc=Tbco,dc=com',
IID_IDirectorySearch, Pointer(DirSearch));
Win32Check(Succeeded(hr));
SearchInfo.dwSearchPref := ADS_SEARCHPREF_SEARCH_SCOPE;
SearchInfo.vValue.dwType := ADSTYPE_INTEGER;
SearchInfo.vValue.dwType := ADS_SCOPE_SUBTREE;
hr := DirSearch.SetSearchPreference(SearchInfo,1);
Win32Check(Succeeded(hr));
Filter := Format('(&(objectClass=user)(sAMAccountName=%s))',
[Username]);
SetLength(Attributes, 1);
Attributes[0] := 'displayName';
// When using Dynamic Array with WinApi ALWAYS use pointer to first element!
hr := DirSearch.ExecuteSearch(PWideChar(Filter),PWideChar(Attributes[0]),Length(Attributes), Pointer(hSearch));
Win32Check(Succeeded(hr));
try
hr := DirSearch.GetFirstRow(Pointer(hSearch));
Win32Check(Succeeded(hr));
hr := DirSearch.GetColumn(hSearch, Attributes[0], col);
if Succeeded(hr) then
begin
Result := col.pADsValues^.CaseIgnoreString;
DirSearch.FreeColumn(#col);
end;
finally
DirSearch.CloseSearchHandle(hSearch);
end;
finally
// UnInitialize COM
CoUninitialize;
end;
end;
end.
Delphi Error;
[Error] Unapp.pas(33): Undeclared identifier: 'ADS_SEARCH_HANDLE'
[Error] Unapp.pas(70): Types of actual and formal var parameters must be identical
[Error] Unapp.pas(70): Incompatible types: 'Char' and 'WideChar'
[Error] Unapp.pas(73): Undeclared identifier: 'CaseIgnoreString'
[Error] Unapp.pas(74): Types of actual and formal var parameters must be identical
[Error] Unapp.pas(77): Types of actual and formal var parameters must be identical
[Fatal Error] ProjApp.dpr(5): Could not compile used unit 'Unapp.pas'
Looks like DirSearch wasn't initialized
Use this code in order to initialize it
AdsGetObject(PWideChar('LDAP://YourDomain'), IDirectorySearch, DirSearch);
Don't forget to replace YourDomain with your actual domain
Related
Delphi XE added an Encoding property to the TStrings class, which stores the encoding read from the BOM when LoadFromFile() is called.
Delphi 2010 does not have this property.
I would like to emulate it.
I created the below class helper for TStrings.
The helper works, but to get the file's BOM, the only solution I have found is to reload the same file in a FileStream. I would like to avoid this since TStrings.LoadFromFile() already got the BOM.
How can I tell the helper to re-use the BOM that was already found?
unit TestEncodingName_00;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtDlgs;
type
TForm1 = class(TForm)
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TMyStrings = class helper for TStrings // emulate TStrings.Encoding
private
function GetEncodingName(fPath:string):string;
public
property EncodingName[fPath:string]:string read GetEncodingName;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
function TMyStrings.GetEncodingName(fPath:string):string;
var
fLen : integer;
fBuffer : TBytes;
fEncoding : TEncoding;
fName : string;
fFs : TFileStream;
begin
fFs := TFileStream.Create(fPath, fmOpenRead);
try
SetLength(fBuffer, 4);
flen := fFs.Read(fBuffer[0], 4);
if flen < 4 then
SetLength(fBuffer, flen);
fEncoding := nil;
TEncoding.GetBufferEncoding(fBuffer, fEncoding);
if fEncoding = TEncoding.Unicode then
fName := 'Unicode'
else if fEncoding = TEncoding.UTF8 then
fName := 'UTF8'
else fName := 'Default';
finally
fFs.Free;
end;
result := fName;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
EncName : string;
begin
(* sample UTF8.txt
Ā ā Ă ă
Ρ Σ Τ Υ
ぁ あ ぃ
*)
Memo1.Lines.LoadFromFile('Sample UTF8.txt');
//from here TStrings knows the BOM but I don't know
// how to refer to it...
// so I have to create again a stream of the same file to
// get the BOM. I don't like that.
EncName := Memo1.Lines.EncodingName['Sample UTF8.txt'];
Memo1.Lines.Add(#13#10'Encoding : ' + EncName);
end;
end.
First off, it is LoadFromStream() that discovers the BOM encoding, not LoadFromFile(). LoadFromFile() simply opens the file into a TFileStream and then calls LoadFromStream().
In Delphi (2009 and) 2010, the discovered BOM encoding is not stored anywhere that you can access. That is the very problem that XE solved by adding the new Encoding property. The encoding is only used as a local variable inside of LoadFromStream() when decoding the file data to a UnicodeString prior to parsing, and then it gets discarded when LoadFromStream() exits. There is nothing you can do to change that behavior.
So, the only solution is to load the file manually so you can discover its BOM. Ideally, you would override LoadFromStream() in a descendant class, but you can't make TMemo.Lines use a custom class. And a class helper cannot override virtual methods, either.
However, you can derive a custom class from TStringList to override LoadFromStream(), load the file yourself, and then Assign() the TStringList to TMemo.Lines. For example:
unit TestEncodingName_00;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtDlgs;
type
TForm1 = class(TForm)
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TMyStringList = class(TStringList)
private
fEncoding: TEncoding;
public
{ The single-parameter LoadFromStream(Stream: TStream) simply
calls LoadFromStream(Stream: TStream; Encoding: TEncoding) with
the Encoding parameter set to nil, so you only have to override
that version of LoadFromStream()... }
procedure LoadFromStream(Stream: TStream; Encoding: TEncoding); override;
property Encoding: TEncoding read fEncoding;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TMyStringList.LoadFromStream(Stream: TStream; Encoding: TEncoding);
var
Size: Integer;
Buffer: TBytes;
begin
{ this is similar to the implementation that LoadFromStream()
uses in XE+, but with some differences:
1. the Encoding property is assigned a bit differently, as XE+
utilizes a TEncoding.Clone() method when the specified Encoding
is not a standard RTL encoding (ie, is a custom user class), but
Clone() does not exist in D2009/2010.
2. XE+ has a TStrings.DefaultEncoding property, which is passed
to TEncoding.GetBufferEncoding() as the default to return if no
BOM is detected, but that property and parameter do not exist in
D2009/2010.
3. TStrings.LoadFromStream() does not check if Size is 0 (file is empty)
before dereferencing the Buffer that is passed to Stream.Read().
That is a runtime crash waiting to happen! }
BeginUpdate;
try
Size := Stream.Size - Stream.Position;
SetLength(Buffer, Size);
if Size > 0 then
Stream.Read(Buffer[0], Size);
Size := TEncoding.GetBufferEncoding(Buffer, Encoding);
fEncoding := Encoding;
SetTextStr(Encoding.GetString(Buffer, Size, Length(Buffer) - Size));
finally
EndUpdate;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
EncName : string;
List: TMyStringList;
begin
List := TMyStringList.Create;
try
List.LoadFromFile('Sample UTF8.txt');
if List.Encoding = TEncoding.Unicode then
EncName := 'Unicode'
else if List.Encoding = TEncoding.UTF8 then
EncName := 'UTF8'
else
EncName := 'Default';
Memo1.Lines.Assign(List);
Memo1.Lines.Add;
Memo1.Lines.Add('Encoding : ' + EncName);
finally
List.Free;
end;
end;
end.
I have a web service that I have created using Delphi and I want to connect to sql server with it so I have added to the project an ADO Connection and ADOQuery had both of them configured and ready to use, there was only a small problem, there are two units on my project and those objects were added to Unit1 and I am working with my ImplUnit whitch is another unit, and can`t find a way to reference or include one unit inside the other unit.
unit1
{ SOAP WebModule}
unit Unit1;
interface
uses
SysUtils, Classes, HTTPApp, InvokeRegistry, WSDLIntf, TypInfo,
WebServExp, WSDLBind, XMLSchema, WSDLPub, SOAPPasInv, SOAPHTTPPasInv,
SOAPHTTPDisp, WebBrokerSOAP, DB, ADODB;
type
TWebModule1 = class(TWebModule)
HTTPSoapDispatcher1: THTTPSoapDispatcher;
HTTPSoapPascalInvoker1: THTTPSoapPascalInvoker;
WSDLHTMLPublish1: TWSDLHTMLPublish;
ADOConnection1: TADOConnection;
ADODataSet1: TADODataSet;
ADOQuery1: TADOQuery;
procedure WebModule1DefaultHandlerAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
private
{ Private declarations }
public
{ Public declarations }
end;
var
WebModule1: TWebModule1;
implementation
{$R *.dfm}
procedure TWebModule1.WebModule1DefaultHandlerAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
WSDLHTMLPublish1.ServiceInfo(Sender, Request, Response, Handled);
end;
end.
My unit
unit UTImplementacao;
interface
uses
InvokeRegistry,DB, ADODB;
type
IInterface = interface(IInvokable)
['{EFF30FFA-DA0C-433A-832A-0BA057B55103}']
function ReceiveUser(username : String; password : String) :
Boolean; stdcall;
end;
TImplementacao = class(TInvokableClass, IInterface)
public
function ReceiveUser(username : String; password : String) :
Boolean; stdcall;
end;
implementation
{ TImplementacao }
function TImplementacao.ReceiveUser(username, password: String): Boolean;
var
ADOConnection1: TADOConnection;
ADOQuery1: TADOQuery;
begin
try
ADOConnection1 := TADOConnection.Create(nil);
ADOConnection1.LoginPrompt := False;
ADOConnection1.ConnectionString:= 'Provider=SQLOLEDB.1;Integrated Security=SSPI;' +
'Persist Security Info=False;' +
'User ID=Diego;'+
'Catalog=OnlineShopping;' +
'Data Source=DIEGO-PC\SQLEXPRESS'+
';Use Procedure for Prepare=1;' +
'Auto Translate=True;Packet Size=4096;'+
'Workstation ID=DIEGO-PC;'+
'Use Encryption for Data=False;'+
'Tag with column collation when possible=False;';
ADOConnection1.Connected := True;
ADOQuery1.Connection := ADOConnection1;
ADOQuery1.SQL.Add('select username,upassword from Users '+
'where username = :usernamep and upassword = '+
':upasswordp');
ADOQuery1.Parameters.ParamByName('upasswordp').Value := password;
ADOQuery1.Parameters.ParamByName('usernamep').Value := username;
ADOQuery1.ExecSQL;
Result := True;
finally
ADOQuery1.Free;
if ADOConnection1.Connected then
ADOConnection1.Close;
ADOConnection1.Free;
end;
Result := False;
end;
initialization
InvRegistry.RegisterInvokableClass(TImplementacao);
InvRegistry.RegisterInterface(TypeInfo(IInterface));
end.
please disregard the ADOConnection and ADOQuery that I have added to my unit i got a little desperate ad duplicade the code... Yeah, I know yachs!!!!
#SilverWarrior
If declare Unit1 inside the uses of UTImplementacao will I have access to the componemts below:
type
ADOConnection1: TADOConnection;
ADODataSet1: TADODataSet;
ADOQuery1: TADOQuery;
or should I declare for each one of the types variable inside var clause ?
If you want to access objects declared in Unit1 from other units in your project you need to add Unit1 into interface uses section (the one at top) of those units.
unit ImplUnit;
interface
uses
SysUtils, Classes, ... , Unit1;
...
That is the same way as Delphi automatically adds other units like Sysutils, Classes, etc.
Also I would strongly recomend you change the name of your unit to somethng more meaningfull so that when you will be looking at your code after some time you will quickly know what code does that unit contains and what it is used for.
EDIT: Based on your edit of the question I suspect you want to acces the components from your Unit1 directly by calling:
Unit1.AdoConnection1
That won't work. Why? Becouse the components are declared within the scope of the TWebModule1 class.
So you need to access them like this:
Unit1.WebModule1.AdoConnection1;
NOTE: If Unit1 is added into interface uses section of your UTImplementacao unit you can also directly call:
WebModule1.AdoConnection1
You don't have to prefix every command with Unit1. I have written this in such way to be hopefully more understandable which unit mebers are you accessing. Especially for other people which might be reading this thread and not knowing the structure of your program.
I am absolutely new at calling functions from DLLs (call it bad programming habits, but I never needed to).
I have this C++ dll (CidGen32.dll at https://skydrive.live.com/redir?resid=4FA1892BF2106B62!1066) that is supposed to export a function with the following signature:
extern "C" __declspec(dllexport) int GetCid(const char* pid, char* cid);
What it should do is to get a 13 char string such as '1111111111118' and return a 20 char hash.
I have tried for the last couple of days to call this function in Delphi 6 but to no avail. I have desperately tried I guess 50+ combinations and I got quite close on one occasion but my computer froze and I lost all my effort. Since it was based on luck, I could not redo it anymore.
I am also aiming not to register the DLL, but rather place it in the same folder.
Anyway, the plan was to have something like this:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
function GenerateCID(Prm: string): string;
var
aCID: PAnsiChar;
uCID: AnsiString;
i: integer;
Hbar: Thandle;
GetCID: function (X: PAnsiChar; Y: PAnsiChar): integer; {$IFDEF WIN32} stdcall; {$ENDIF}
begin
ucid := '';
hbar := LoadLibrary('CidGen32.dll');
if Hbar >= 32 then
begin
#GetCID := GetProcAddress(HBar, 'GetCID');
if Assigned(GetCID) then
begin
i := GetCID(pAnsiChar(prm), aCID);
uCID := aCID;
end;
FreeLibrary(HBar);
end
else
begin
//ShowMessage('Error: could not find dll');
end;
result := uCID;
end;
begin
ShowMessage(GenerateCID('1111111111118'));
end;
end.
But it seems I am dead wrong.
You are using the wrong name to import the function. Its name is GetCid but you are trying to import GetCID. Letter case matters when you call GetProcAddress. If that still doesn't result in the GetProcAddress call succeeding, double check the name with which the function is exported using a tool like Dependency Walker.
The function is cdecl so you should declare it like this:
GetCID: function(pid, cid: PAnsiChar): Integer; cdecl;
And the other problem is that you are responsible for allocating the buffer behind cid. You did not do that. Do it like this:
SetLength(uCID, 20);
i := GetCID(pAnsiChar(prm), pAnsiChar(uCID));
And delete the aCID variable. And that >32 error check is wrong, compare against 0.
Delphi XE. Windows 7.
There is a function (please see a code below) or I:=0 that causes an AV error in a big project. There is no the error with the same function in a new project!!! I deleted everything from the big project, and I left only a button and that function. It still causes the error...
A line with the error:
if ISAeroEnabled then // this line is a cause
i:=0; // or this line
I set breakpoints everywhere (I checked the whole function, I set breakpoints on EACH LINE -> no errors in the function), a debugger shows me that the error is in i:=0;
If to delete a function (and leave i:=0;) -> all is ok!
The error message: First chance exception at $747FB727. Exception class EAccessViolation with message 'Access violation at address 004AE5AF in module 'MngProject.exe'. Write of address 0017FFF8'. Process MngProject.exe (4980)
Why does it work in a new project but not in mine?
Here's the whole project: http://www.2shared.com/file/UP22Om4j/Bug.html
The code:
unit MainFormModule;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
StdCtrls;
type
TMainForm = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
mainform:tmainform;
implementation
{$R *.dfm}
function ISAeroEnabled: Boolean;
type
_DwmIsCompositionEnabledFunc = function(IsEnabled: PBoolean): HRESULT; stdcall;
var
Flag : Boolean;
DllHandle : THandle;
OsVersion : TOSVersionInfo;
DwmIsCompositionEnabledFunc: _DwmIsCompositionEnabledFunc;
begin
Result:=False;
ZeroMemory(#OsVersion, SizeOf(OsVersion));
OsVersion.dwOSVersionInfoSize := SizeOf(TOSVERSIONINFO);
if ((GetVersionEx(OsVersion)) and (OsVersion.dwPlatformId = VER_PLATFORM_WIN32_NT) and (OsVersion.dwMajorVersion >= 6)) then //is Vista or Win7?
begin
DllHandle := LoadLibrary('dwmapi.dll');
if DllHandle <> 0 then
begin
#DwmIsCompositionEnabledFunc := GetProcAddress(DllHandle, 'DwmIsCompositionEnabled');
if (#DwmIsCompositionEnabledFunc <> nil) then
begin
DwmIsCompositionEnabledFunc(#Flag);
Result:=Flag;
end;
end;
FreeLibrary(DllHandle);
end;
end;
procedure Tmainform.Button1Click(Sender: TObject);
var i:integer;
begin
if ISAeroEnabled then // AV is here
i:=0; // Or here
end;
end.
Try changing PBoolean to PBOOL
function(IsEnabled: PBOOL): HRESULT; stdcall;
var
Flag: BOOL;
PBoolean is a pointer to a Pascal Boolean which is 1 byte in size. PBOOL is a pointer to a Windows (C based) BOOL, which is 4 bytes in size. You need to match the size expected by windows.
In general, when translating Windows API calls to Delphi, use the same named data type as the API. Windows.pas has type definitions mapping these to Delphi types, e.g. type BOOL = LongBool;
Also it is usual (but not required) in Delphi to change pointer parameters to var. A var parameter is Pascal syntactic sugar for pass-by-reference which isn't available in C.
function(var IsEnabled: BOOL): HRESULT; stdcall;
....
DwmIsCompositionEnabledFunc(Flag); // no # operator
NOTE: I can't test this, as I only have XP available.
I need to use a DLL file from qsBarcode http://www.qsbarcode.de/en/index.htm (here is the download link http://www.qsbarcode.de/en/download/qsbar39.zip). The dll will decode a bitmap image that contain barcode code39 into a string.
In their example there are only VB and C example, but I need to use it in Delphi.
here is the official example code in C:
#include <windows.h>
#include <stdio.h>
typedef int (WINAPI * CODE39_PROC)(char *, char *);
int main(int argc, char* argv[])
{
HINSTANCE hinstLib;
CODE39_PROC ProcAdd;
BOOL fFreeResult;
char cFileName[512] = "\0";
char cResult[512] = "\0";
int iReturn = 0;
if(argc < 2) return 0; //no bitmap filename in argv[1]
strcpy(cFileName,argv[1]);
hinstLib = LoadLibrary("qsBar39");
if (hinstLib == NULL) return -1; //can't load lib
ProcAdd = (CODE39_PROC) GetProcAddress(hinstLib, "ReadCode39");
if (NULL == ProcAdd) return -1; //can't access Proc
//dll Proc call
iReturn = (ProcAdd) (cFileName, cResult);
printf("%s", cResult);
fFreeResult = FreeLibrary(hinstLib);
return iReturn;
}
and this is what I try to code in Delphi
unit uRead;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Mask, JvExMask, JvToolEdit;
type
TDLLFunc = function(namafile: PChar; hasil:PChar):integer;
TForm2 = class(TForm)
JvFilenameEdit1: TJvFilenameEdit;
Edit1: TEdit;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
const
DLLFunc: TDLLFunc = nil;
var
Form2: TForm2;
DLLHandle: THandle;
implementation
{$R *.dfm}
procedure TForm2.Button1Click(Sender: TObject);
var
feedback : integer;
hasil:PChar;
begin
DLLHandle := LoadLibrary('qsBar39.dll');
if (DLLHandle < HINSTANCE_ERROR) then
raise Exception.Create('library can not be loaded or not found. ' + SysErrorMessage(GetLastError));
try
{ load an address of required procedure}
#DLLFunc := GetProcAddress(DLLHandle, 'ReadCode39');
{if procedure is found in the dll}
if Assigned(DLLFunc) then
feedback := DLLFunc(PChar(JvFilenameEdit1.Text), PChar(hasil));
showmessage(hasil);
finally
{unload a library}
FreeLibrary(DLLHandle);
end;
end;
end.
When I execute this code and debug, hasil only contains #$11'½
while it should return some character in the barcode image (you can get the file image in the zip file).
Please help me, thank you.
latest update:
#500, thanks, I have put stdcall
#dthorpe, thanks, done
Actually the advice is great, my code is supposed to running well, but I've mistakenly put JvFilenameEdit1.text instead of JvFilenameEdit1.FileName, my bad :)
Thank you again for the advice, so here is the working code:
unit uRead;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Mask, JvExMask, JvToolEdit;
type
TDLLFunc = function(namafile: PAnsiChar; hasil:PAnsiChar):integer; stdcall;
TForm2 = class(TForm)
JvFilenameEdit1: TJvFilenameEdit;
Edit1: TEdit;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
const
DLLFunc: TDLLFunc = nil;
var
Form2: TForm2;
DLLHandle: THandle;
implementation
{$R *.dfm}
procedure TForm2.Button1Click(Sender: TObject);
var
feedback : integer;
hasil: array [0..512] of char;
begin
DLLHandle := LoadLibrary('qsBar39.dll');
if (DLLHandle < HINSTANCE_ERROR) then
raise Exception.Create('library can not be loaded or not found. ' + SysErrorMessage(GetLastError));
try
{ load an address of required procedure}
#DLLFunc := GetProcAddress(DLLHandle, 'ReadCode39');
{if procedure is found in the dll}
if Assigned(DLLFunc) then
feedback := DLLFunc(PAnsiChar(JvFilenameEdit1.FileName), #hasil);
edit1.Text := StrPas(#hasil);
finally
{unload a library}
FreeLibrary(DLLHandle);
end;
end;
end.
If I were you I would take the opportunity to wrap this function call up in a more Delphi like wrapper.
function ReadCode39(FileName, Result: PAnsiChar): LongBool; stdcall;
external 'qsBar39';
function ReadCode(const FileName: string): string;
var
cResult: array [0..512-1] of AnsiChar;
begin
if not ReadCode39(PAnsiChar(AnsiString(FileName)), #cResult[0]) then
raise Exception.Create('ReadCode39 failed');
Result := string(cResult);
end;
Notes:
I'm using an implicit DLL import (using external) rather than an explicit GetProcAddress. This reduces the amount of boilerplate code considerably.
I'm converting the C style integer code error handling into a Delphi exception. Based on your comment I'm guessing that a non-zero return value means success. Older versions of C do not have a boolean type and use 0 to mean false and every non-zero value evaluates as true. The natural way to map this to a Delphi boolean type is with LongBool. This means that your calling code doesn't need to worry about error codes.
All the conversion to and from null-terminated strings is handled in one routine and your calling code again need not concern itself over such trivia.
I've written the code so that it is portable between both ANSI and Unicode versions of Delphi.
This allows your calling code to read much more clearly:
procedure TForm2.Button1Click(Sender: TObject);
var
hasil: string;
begin
hasil := ReadCode(JvFilenameEdit1.Text);
ShowMessage(hasil);
end;
Stick a stdcall; directive at the end of your TDLLFunc declaration to tell the compiler that it's using the WINAPI calling convention, and, as Dorin points out, if you're using a unicode-based version of Delphi you probably want to use PAnsiChar.
In addition to the stdcall mentioned in another answer, you also need to allocate space for the pchar pointers you're passing into the DLLFunc. Notice that in the C code the cResult var is defined as char cResult[512]; That means the caller is reserving space for a char buffer of 512 chars and passing the address of that buffer to the DLL func.
You're not doing the equivalent in your Delphi code.
Change your Delphi code to define hasil as an array of char:
var hasil: array [0..512] of char;
then pass the address of hasil to the DLLFunc call:
DLLFunc(PChar(JvFilenameEdit1.Text), #hasil);