There is a procedure looking like this:
procedure blabla;
var buffer: array of byte;
begin
Setlength(buffer, 10);
Setlength(buffer, someinteger);
end
after both calls buffer is still nil <- this is my problem
I normally consider myself an experienced programmer and i use this fundamental method on various other occasions. This is driving me nuts.
Did anyone of you have similar issues in the past?
If so, what was the problem?
My code is somewhat spaghetti because i had changed any line that seemed suspicious, but here is the full code:
full procedure
#Edit:
i have this code in another part of the same project:
procedure interleaveVertexes;
var
interleavedArray: array of TVec3Coord2;
begin
SetLength(interleavedArray, vertexcount);
end;
and it works.. like it should
i was using gdb and the lazarus ide to debug and apparently..
Both of them dont like variables called 'buffer' or 'Data'.
I understand the lazarus ide internally is using gdb anyway.
Even a variable is just named 'h' wouldn't let itself be inspected properly.
i just renamed them to 'buffa' and 'howdy' and now it seems to be working.
Got there by doing old-fashioned print-debugging and storing the pointer of my array in a cardinal variable. There they were fine. (Apart from the actual content of the array)
annoingly funny
Related
I am looking for a simple and ideally general (or using generics) way to convert an array to an array of const (=array of TVarRec). My specific case is that I have an array of Variant and want to pass it to the Format() function.
This is what I've found so far, but it looks hackish to me:
function MyFormat(const Fmt: string; const Args: TArray<Variant>): string;
var
A: array of TVarRec;
I: Integer;
begin
SetLength(A, Length(Args));
for I:= Low(Args) to High(Args) do begin
A[I].VType:= vtVariant;
A[I].VVariant:= #Args[I];
end;
Result:= Format(Fmt, A);
end;
It seems to work. Is it safe?
Could it be done shorter, better, faster, or can I use something ready instead? :)
Just some additional thoughts and fun facts:
System.Rtti.TValue recently became my friend. However, it seems it is missing a feature here. I am able to read my array using TValue.From(), but it seems there is no way to get it out as array of TVarRec. There is a wonderful TValueArrayToArrayOfConst, but it doesn't really help, because I had to construct an array of TValue first, which is different from an array stored in a single TValue... :(
At least TValue is able to output a single element as TVarRec, so I thought I could create a generic converter for all types of arrays. But...
Would you think this works?
for I:= Low(Args) to High(Args) do A[I]:= TValue.From(Args[I]).AsVarRec;
It compiles, but TValue's memory is released after use, and since TVarRec.VVariant is a pointer, it then points to some old location which is overridden on next cycle.
Your function is safe and fast. It only allocates a small memory array A[], and passes all values by reference. I can't think on anything faster - without being premature optimization. I may only do some refactoring to reuse the TArray<variant> into TArray<TVarRec> conversion routine.
Using TValue.From().AsVarRec will definitively be slower, if your input is indeed a TArray<Variant>.
About TVarRec dandling references, you are right: those structures are just simple pointers on the stack, with no allocation, so all the referred variables should be available during the function call. So if you use a TArray<TVarRec> local conversion, you should ensure that the TArray<variant> is still allocated when calling the format() function.
A straight forward and short solution (in code). If your formatstring (fmt) and array of values (sa) are unknown.
setlength(sa,5); // or more
result := format(fmt,[sa[0],sa[1],sa[2],sa[3],sa[4]];
I started using a lot of generics but now I find it harder and harder to debug, to know which array is actually begin worked on. See example:
Type
TData = record
DataID:integer;
DataName:string;
end;
var DataArr1,DataArr2,DataArr3:TArray<TData>;
procedure WorkOnData(Data:TArray<TData>);
begin
if Data = DataArr1 then // <-- PARKING HERE ON DEBUG I CAN SEE ARRAY DATA, BUT NOT WHICH ARRAY IT IS
ProcessA(DataArr1)
else if Data = DataArr2 then
ProcessB(DataArr2)
else if Data = DataArr3 then
ProcessC(DataArr3);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
if Sender = Button1 then
WorkOnData(DataArr1)
else if Sender = Button2 then
WorkOnData(DataArr2)
else if Sender = Button3 then
WorkOnData(DataArr3);
end;
So, I can identify the array by comparison to get True/False:
Data = DataArr1
but, this doesn't give me info which array it is, before the comparison. So, I would need to put breakpoints after each comparison to know which one is True.
These obviously don't work:
Data.Name
TArray<Data>.Name
Is there any other way to know which array has been passed that I can see in debugger (Watch)?
Answer/Solution:
For anybody who faces the same problem, question: As Remy says in accepted answer that what I would like to achieve, is not possible. OK, now the quick workaround is to put the comparison (Data = DataArr1) into Watch and see which one resolves to True. Not best, but still usable as now we can see which array is actually being used.
There are no variable names once the code gets compiled. When you debug WorkOnData(), the only variable name it can display is Data, and there is no way for the debugger to know what Data is pointing at without evaluating an expression that you provide. So no, what you are asking for is basically not possible.
What you would likely have to do is wrap your array inside of another record that has a Name string field, and then pass that record around as needed. When you inspect it in the debugger, you would see its Name value.
I'm having trouble with a clear statement. I've got an array that gets sized dynamically, filled, and then passed to a function to be converted to some custom objects.
After that conversion I want to clear the array. I use
Array.Clear(FileData, 0, FileData.Length)
as this thread suggests (reset-an-array-to-default-in-visual-basic). However, every time I get to that point in the script the try-catch wrapping the Clear catches an out of bounds exception on the Clear.
The array is not empty (actually it's got ~34900 items) so it's not that the array has zero length. The one thing that it might be that isn't discussed in the question I referenced above is that my array is 2 dimensional.
All that said, I'm fairly well stumped. Any help would be appreciated.
UPDATE: For those experiencing this issue, I ultimately just left the step commented out, so that instead of clearing and then setting the array to Nothing, I just set it to Nothing. Doesn't really solve the underlying issue, but (should) free up memory all the same.
Been struggling with this one for a while. We have a old table (SQL Server) that has image type data. I want to get the text.
So far this is what I've done.
Try to convert or cast it (not allowed)
Try to bring over the data into delphi by calling a SP (I got to the point of having the data assigned to a variant)
Looked into a RTF to text function (found something here on SO, if i can just get the image data into a string).
This is the code I have so far. It's attached to a button click for now (will be running in a service). I think the assignment to the report var is not right, and SetString may not be right either. I'm not even sure if i am going about this the right way.
var
report: array of byte;
s: string;
begin
ADOStoredProc1.Parameters.ParamByName('#EncounterID').Value := '7';
ADOStoredProc1.Open;
while not ADOStoredProc1.EOF do
begin
report := ADOStoredProc1.FieldByName('Report').Value;
SetString(s, PAnsiChar(#report[0]), length(report));
Memo1.Lines.Add(s);
ADOStoredProc1.Next;
end;
I'm a little confused by "RTF image". Do you mean RTF text? Or an image (picture)? From the code, I'm suspecting the former...
I'm not sure why you're using an array of byte and then immediately putting that into a string.
This should work just as well (actually, better, because it doesn't use Value (which is a Variant conversion) and avoids the SetString function call):
while not ADOStoredProc.Eof do
begin
Memo1.Lines.Add(ADOStoredProc1.FieldByName('Report').AsString;
ADOStoredProc1.Next;
end;
You'll probably get the RTF formatting in the memo this way, though. If you're trying to strip the formatting, you'll need to use a TRichEdit instead, and use the EM_STREAMIN message to add the content, and then use the TRichEdit.PlainText property. There's an example of doing that here.
I create a form inside the Dll. But it compile is not successfully.Some Error below.
" Access violation at address 004EB784 in module 'Project1dll.dll'.Read of address 00000048"
Thanks.....
You are dereferencing a nil pointer somehow. Perhaps an object that hasn't been created?
here's something i've found necessary to do this. see my example function below:
procedure DoSomething(hApp:THandle); export;
var
hDllApplication:THandle;
begin
hDllApplication:=Application.Handle;
Application.Handle:=hApp;
try
DoItNow;
finally
Application.Handle:=hDllApplication;
end;
end;
As well you should have a look here, it might help if your trouble is elsewhere ..
Forms in dll