This question already has answers here:
Incompatible types: 'string' and 'Double'
(2 answers)
Closed last year.
I have to check for a sound card, so I don't need quality but only one answer yes or no. I used this code:
function IsSoundCardInstalled: Boolean;
Begin
Result := waveOutGetNumDevs > 0;
End;
procedure TForm1.FormCreate(Sender: TObject);
var
ids: TidIpWatch;
Speed: Double;
myStringList: TStringList;
begin
ids := TidIpWatch.Create;
Speed := GetCPUSpeed;
ids.Free;
myStringList:=TStringList.Create;
myStringList.Add('IP:' + (ids.LocalIP));
myStringList.Add('CPU: ' + (Tipo_cpu) + ' ' + Format('%f', [Speed]));
myStringList.Add((IsSoundCardInstalled));
myStringList.Add('etc.');
Memo1.Lines.Assign(myStringList);
myStringList.Free;
end;
But the error returns to me:
[DCC Error] Unit1.pas(138): E2010 Incompatible types: 'string' and 'Boolean'
On the line:
myStringList.Add((IsSoundCardInstalled));
IsSoundCardInstalled() returns a Boolean, but myStringList.Add() expects a string instead. You can't assign a Boolean as-is to a string, you need to use a conversion function (just like in your previous question), such as SysUtils.BoolToStr():
uses
..., SysUtils;
myStringList.Add(BoolToStr(IsSoundCardInstalled));
Or SysUtils.TBooleanHelper.ToString() in XE4+:
uses
..., SysUtils;
myStringList.Add(IsSoundCardInstalled.ToString);
On a side note: you are freeing the TIdIPWatch component before reading its LocalIP property, which is undefined behavior.
For that matter, you should not be using TIdIPWatch in this manner at all. It is meant for notifying you when the local IP changes, and for maintaining a history of local IP changes over time, but that is not how you have been using it lately. The TIdIPWatch.LocalIP property simply reads the global GStack.LocalAddress property, that is what you should be using instead:
uses
..., IdStack;
TIdStack.IncUsage;
try
myStringList.Add('IP:' + GStack.LocalAddress);
finally
TIdStack.DecUsage;
end;
However, a machine can have multiple local IPs, so you really should use GStack.GetLocalAddressList() instead:
uses
..., IdStack;
var
myLocalIPList: TIdStackLocalAddressList;
i: Integer;
begin
...
TIdStack.IncUsage;
try
myLocalIPList := TIdStackLocalAddressList.Create;
try
GStack.GetLocalAddressList(myLocalIPList);
for I := 0 to myLocalIPList.Count-1 do
myStringList.Add('IP:' + myLocalIPList[I].IPAddress);
finally
list.Free;
end;
finally
TIdStack.DecUsage;
end;
...
end;
Related
Can anyone share what are some common Delphi examples of a function that takes a number
and returns a number that is not so obvious?
For example :
function GetNumber(const aSeed: Integer): Integer;
begin
Result := ((aSeed+5) * aSeed) + 15;
end;
So let's say the user knows that sending aSeed = 21 gives 561
and aSeed = 2, gives 29
and so on...
is there a function that makes it hard to reverse engineer the code,
even if one can generate a large number sets of Seed/Result ?
(hard : I do not mean impossible, just need to be non-trivial)
Preferably a function that does not allow in function result exceeding the
Integer result as well.
In any case, if you are not sure whether it's hard/impossible to reverse,
do feel free to share what you have.
some other requirements:
the same input always results in the same output; cannot have Random output
the same output regardless of platform: windows/android/mac/ios
won't result in some extraordinary big number (fit in Integer)
Using a hash is a very good way to achieve what you want. Here is an example that takes an integer, converts it to a string, appends it to a salt, computes the MD5 and returns the integer corresponding to the first 4 bytes:
uses
System.Hash;
function GetHash(const s: string): TBytes;
var
MD5: THashMD5;
begin
MD5 := THashMD5.Create;
MD5.Update(TEncoding.UTF8.GetBytes(s));
Result := MD5.HashAsBytes;
end;
function GetNumber(Input: Integer): Integer;
var
Hash: TBytes;
p: ^Integer;
begin
Hash := GetHash('secret' + IntToStr(Input));
P := #Hash[0];
Result := Abs(P^);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(IntToStr(GetNumber(1))); // 996659739
ShowMessage(IntToStr(GetNumber(2))); // 939216101
ShowMessage(IntToStr(GetNumber(3))); // 175456750
end;
I was trying to use same printing procedure for two types of arrays(1st arry length was 10, 2nd array length was 15).
I could not find any solution over internet. Did any one have any solution for this problem.
this is the Two arrays
program pp1;
const
m=10;
n=15;
type
matrix1=array[1..m] of integer;
matrix2=array[1..n] of integer;
var
m1:matrix1;
m2:matrix2;
this is the method which it tried. in method 'x' mens the length of the array.
procedure writeMatrix(var data: array of integer ;x:integer);
var
j:integer;
begin
for j:=1 to x do
begin
write(data[j]:3);
end;
end;
my main method
begin
writeMatrix(m1,10);
writeMatrix(m2,10);
end.
How can i use the same this writeMatrix method to print both of the arrays.. Is there any stranded way to do it.
As I said in my comment before, your implementation is fine, but you have to put something in your matrix before printing it, or you will get a bunch of zeroes in the screen (in the best).
Try this:
program pp1;
const
m=10;
n=15;
type
matrix1=array[1..m] of integer;
matrix2=array[1..n] of integer;
var
m1:matrix1;
m2:matrix2;
procedure fillMatrix(var data:array of integer; x:integer);
var
j:integer;
begin
for j:= 1 to x do begin
data[j]:=j;
end;
end;
procedure writeMatrix(var data: array of integer; x:integer);
var
j:integer;
begin
for j:=1 to x do
begin
write(data[j]:3);
end;
end;
begin
fillMatrix(m1,10);
fillMatrix(m2,10);
writeMatrix(m1,10);
writeMatrix(m2,10);
readln;
readln;
end.
Hint: consider avoid using global variables, m1 and m2 in this case should be declared in the main program.
How can i use the same this writeMatrix method to print both of the arrays.. Is there any stranded way to do it.
Yes, there is a standard way to this. It is called conformant-array parameters. It is standardized in (level 1) of the ISO standard 7185 (Standard “Unextended” Pascal). It looks like this:
procedure print(protected matrix: array[
columnMinimum..columnMaximum: integer;
rowMinimum..rowMaximum: integer
] of integer);
const
totalWidth = 6;
var
x: type of columnMinimum;
y: type of rowMinimum;
begin
for y := rowMinimum to rowMaximum do
begin
for x := columnMinimum to columnMaximum do
begin
write(matrix[x, y]:totalWidth);
end;
writeLn;
end;
end;
It’s as if there were additional const values, but they are dynamic depending on the passed matrix. This code furthermore uses type inquiries (type of …) and the protected modifier, both defined in ISO 10206 (Extended Pascal) which builds on top of ISO 7185. In EP you could and would also consider schemata to pass such data as parameters.
I have made a function with 2 parameters with the same data type and I have no problem with that.
But I'm having trouble with different data type
Here's my code :
uses crt;
function inputscore(name : string, score:integer) : integer;
begin
writeln('My name is ',name,' and my score is ',score);
inputscore:=0;
end;
begin
clrscr;
inputscore('David',98);
readkey;
end.
But It returned this error message:
multipleparameterfunc.pas(2,34)Fatal syntax error, ")" expected but "," found
In Pascal you separate the arguments with a ;.
So your definition has to look like this:
function inputscore(name: string; score: integer) : integer;
When you call the function then you still use a , to separate the parameters:
inputscore('David', 98);
What I'm trying to do is to get the list of fields in a class without an instance... for example:
TAClass=class
a_: Integer;
b_: Integer;
constructor (a,b Integer);
end;
I'm not being able to get the fieldTable from the VMT:
ovmt: PVmt;
ftable: PVmtFieldTable;
finfo: PVmtFieldEntry;
ovmt:=PVmt(TAClass);
ftable := ovmt^.vfieldtable
finfo := ftable^.fields[0]
this way I'm not gettig the list of fields
any help is welcome,
thanks in advance
Afaik the field tables in classic delphi and FPC only work for published fields. Published fields must be class fields (value types like integer must go via properties). Newer Delphi's also allow RTTI for non published fields, but that works differently (different untis), and FPC doesn't support that yet.
I hacked together a small demonstration example since the help for typinfo seems to be light on examples. Note the tpersistent derivation.
{$mode delphi}
uses typinfo,classes;
type
TAClass=class(Tpersistent)
a: tstringlist;
b: tlist;
end;
var
ovmt: PVmt;
FieldTable: PVMTFieldTable;
PVMTFieldEntry;
i: longint;
begin
ovmt := PVmt(TAClass);
while ovmt <> nil do
begin
FieldTable := PVMTFieldTable(ovmt^.vFieldTable);
if FieldTable <> nil then
begin
FieldInfo := #FieldTable^.Fields[0];
for i := 0 to FieldTable^.Count - 1 do
begin
writeln(fieldinfo^.name);
FieldInfo := PvmtFieldEntry(PByte(#FieldInfo^.Name) + 1 + Length(FieldInfo^.Name));
end;
end;
{ Try again with the parent class type }
ovmt:=ovmt^.vParent;
end;
end.
I have a record that looks similar to:
type
TNote = record
Title : string;
Note : string;
Index : integer;
end;
Simple. The reason I chose to set the variables as string (as opposed to an array of chars) is that I have no idea how long those strings are going to be. They can be 1 char long, 200 or 2000.
Of course when I try to save the record to a type file (file of...) the compiler complains that I have to give a size to string.
Is there a way to overcome this? or a way to save those records to an untyped file and still maintain a sort of searchable way?
Please do not point me to possible solutions, if you know the solution please post code.
Thank you
You can't do it with a typed file. Try something like this, with a TFileStream:
type
TStreamEx = class helper for TStream
public
procedure writeString(const data: string);
function readString: string;
procedure writeInt(data: integer);
function readInt: integer;
end;
function TStreamEx.readString: string;
var
len: integer;
iString: UTF8String;
begin
self.readBuffer(len, 4);
if len > 0 then
begin
setLength(iString, len);
self.ReadBuffer(iString[1], len);
result := string(iString);
end;
end;
procedure TStreamEx.writeString(const data: string);
var
len: cardinal;
oString: UTF8String;
begin
oString := UTF8String(data);
len := length(oString);
self.WriteBuffer(len, 4);
if len > 0 then
self.WriteBuffer(oString[1], len);
end;
function TStreamEx.readInt: integer;
begin
self.readBuffer(result, 4);
end;
procedure TStreamEx.writeInt(data: integer);
begin
self.WriteBuffer(data, 4);
end;
type
TNote = record
Title : string;
Note : string;
Index : integer;
procedure Save(stream: TStream);
end;
procedure TNote.Save(stream: TStream);
var
temp: TMemoryStream;
begin
temp := TMemoryStream.Create;
try
temp.writeString(Title);
temp.writeString(Note);
temp.writeInt(Index);
temp.seek(0, soFromBeginning);
stream.writeInt(temp.size);
stream.copyFrom(temp, temp.size);
finally
temp.Free;
end;
end;
I'll leave the Load procedure to you. Same basic idea, but it shouldn't need a temp stream. With the record size in front of each entry, you can read it and know how far to skip if you're looking for a certain record # instead of reading the whole thing.
EDIT: This was written specifically for versions of Delphi that use Unicode strings. On older versions, you could simplify it quite a bit.
Why not write this out as XML? See my session "Practical XML with Delphi" on how to get started with this.
Another possibility would be to make your records into classes descending form TComponent and store/retreive your data in DFM files.
This Stackoverflow entry shows you how to do that.
--jeroen
PS: Sorry my XML answer was a bit dense; I'm actually on the road for two conferences (BASTA! and DelphiLive! Germany).
Basically what you need to do is very simple: create a sample XML file, then start the Delphi XML Data Binding Wizard (available in Delphi since version 6).
This wizard will generate a unit for you that has the interfaces and classes mapping XML to Delphi objects, and a few helper functions for reading them from file, creating a new object, etc. My session (see the first link above) actually contains most of the details for this process.
The above link is a video demonstrating the usage of the Delphi XML Data Binding Wizard.
You could work with two different files, one that just stores the strings in some convenient way, the other stores the records with a reference to the strings. That way you will still have a file of records for easy access even though you don't know the size of the actual content.
(Sorry no code.)
TNote = record
Title : string;
Note : string;
Index : integer;
end;
could be translated as
TNote = record
Title : string[255];
Note : string[255];
Index : integer;
end;
and use Stream.writebuffer(ANodeVariable, sizeof(TNode), but you said that strings get go over 255 chars in this case IF a string goes over 65535 chars then change WORD to INTEGER
type
TNodeHeader=Record
TitleLen,
NoteLen: Word;
end;
(* this is for writing a TNode *)
procedure saveNodetoStream(theNode: TNode; AStream: TStream);
var
header: TNodeHeader;
pStr: PChar;
begin
...
(* writing to AStream which should be initialized before this *)
Header.TitleLen := Length(theNode.Title);
header.NodeLen := Length(theNode.Note);
AStream.WriteBuffer(Header, sizeof(TNodeHeader);
(* save strings *)
PStr := PChar(theNode.Title);
AStream.writeBuffer(PStr^, Header.TitleLen);
PStr := PChar(theNode.Note);
AStream.writebuffer(PStr^, Header.NoteLen);
(* save index *)
AStream.writebuffer(theNode.Index, sizeof(Integer));
end;
(* this is for reading a TNode *)
function readNode(AStream: TStream): TNode;
var
header: THeader
PStr: PChar;
begin
AStream.ReadBuffer(Header, sizeof(TNodeHeader);
SetLength(Result.Title, Header.TitleLen);
PStr := PChar(Result.Title);
AStream.ReadBuffer(PStr^, Header.TitleLen);
SetLength(Result.Note, Header.NoteLen);
PStr := PChar(Result.Note);
AStream.ReadBuffer(PStr^, Header.NoteLen);
AStream.ReadBuffer(REsult.Index, sizeof(Integer)(* 4 bytes *);
end;
You can use the functions available in this Open Source unit.
It allows you to serialize any record content into binary, including even dynamic arrays within:
type
TNote = record
Title : string;
Note : string;
Index : integer;
end;
var
aSave: TRawByteString;
aNote, aNew: TNote;
begin
// create some content
aNote.Title := 'Title';
aNote.Note := 'Note';
aNote.Index := 10;
// serialize the content
aSave := RecordSave(aNote,TypeInfo(TNote));
// unserialize the content
RecordLoad(aNew,pointer(aSave),TypeInfo(TNote));
// check the content
assert(aNew.Title = 'Title');
assert(aNew.Note = 'Note');
assert(aNew.Index = 10);
end;