?
Solved

Casting an untyped method parameter

Posted on 2011-09-27
10
Medium Priority
?
1,564 Views
Last Modified: 2012-05-12
I am working with some legacy Delphi (5) code whereby I have to process a reference to an untyped method parameter.

      function TPort.ReadFromBuffer(var prmBfr; prmMaxBytes: longint): longint;

I get an error on compilation "operator not applicable to this operand type" when trying to associate a value to prmBfr.

The call to ReadFromBuffer contains a dereferenced pointer as the parameter:
e.g.
      bytesToRead := myPort.ReadFromBuffer(fDataBfr^, bytesToRead);

Whereby fDataBfr is declared as:

      fDataBfr: ^TDataBuffer;

And type:
      TDataBuffer = array [1..65535] of char;

How am I supposed to cast for prmBfr?
0
Comment
Question by:brenlex
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 2
  • 2
10 Comments
 
LVL 37

Expert Comment

by:TommySzalapski
ID: 36710646
The only operator I see in your code are the pointer dereference operator ^ and the assignment operator :=
 "operator not applicable to this operand type" means that you tried to use an operator on some variable that you can't use it on.

Exactly what line is that error pointing to? What is the type of bytesToRead?
0
 

Author Comment

by:brenlex
ID: 36710974
Within the method TPort.ReadFromBuffer the compiler error points to any attempt to assign a value to prmBfr (prmBfr := ...) I've tried an assortment of attempts using  @, Addr, ^, xxx as TDataBuffer etc with no joy.  Always the same compiler error.

bytesToRead is just an integer.  Please regard as irrelevant in this context.  For purpose, just read as:

      procedure TPort.ReadFromBuffer(var prmBfr; prmMaxBytes: longint);
0
 
LVL 25

Expert Comment

by:epasquier
ID: 36711491
You just have to cast it with the correct type.

example (without other parameters) :
procedure ReadFromBuffer(var prmBfr);
begin
 TDataBuffer(prmBfr)[2]:='B';
end;

procedure Test;
Var
 DataBuf:TDataBuffer;
begin
 FillChar(DataBuf,10,'a');
 DataBuf[10]:=#0; // Input = 'aaaaaaaaaa'
 ReadFromBuffer(DataBuf);
 ShowMessage(pChar(@DataBuf)); // Output = 'aBaaaaaaaa'
end;

Open in new window

0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 37

Expert Comment

by:TommySzalapski
ID: 36711718
In order to use the assignment operator := the compiler needs to know how to handle the data on the right hand side. So it needs to know what type it is converting to and the simple cast of the left side will work. But if prmBuffer is untyped, I assume you want to be able to use it for more than just TDataBuffers otherwise why not just use TDataBuffer instead of var?

0
 
LVL 25

Expert Comment

by:epasquier
ID: 36713073
procedures that have untyped var parameters are often just convenient generic functions, such as Move or FillChar, that are given an indication of the real type or the memory size of the parameter on another parameter. They are more versatile than typed parameters, and the compiler won't go crazy if you call the above ReadFromBuffer function with a string for example :

Var s:String;
begin
 s:='aaaaaaaaaa';
 ReadFromBuffer(s[1]); // Output s = 'aBaaaaaaaa'
end;

Open in new window


Those 'untyped var parameters' (UVP) are to be considered as generic pointers, that you have to cast. The difference with pointers parameters is that when you cast UVP you use directly the dereferenced type. It is totally equivalent, but with less fuss than this :
procedure ReadFromBuffer(prmBfr:Pointer);
begin
 pDataBuffer(prmBfr) ^ [2]:='B';
 // here you have to dereference, and also you need the declaration of the pointer type pDataBuffer,
 // where in the previous case I don't really need declaring pDataBuffer, as TDataBuffer is enough
end;

procedure Test;
Var
 DataBuf:TDataBuffer;
begin
 FillChar(DataBuf,10,'a');
 DataBuf[10]:=#0;
 ReadFromBuffer(@DataBuf); // here you have to get the pointer
 ShowMessage(pChar(@DataBuf));
end;

Open in new window


Another funny kind of parameters are Variant open array parameters, like the one used in Format function :
function Format(const Format: string; const Args: array of const): string;

these kind of parameters are also extremely useful to make generic functions, AND these provide the type of each parameter, that can be used inside the function
 for I := 0 to High(Args) do
    with Args[I] do
      case VType of
        vtInteger: ...

Open in new window

have a look in Delphi help for Variant open array parameters if you want to know more
0
 

Author Comment

by:brenlex
ID: 36715937
Thanks for the responses but it differs slightly from my initial question.

The call to ReadFromBuffer involves the passing of a dereferenced pointer as the untyped parameter:
      myPort.ReadFromBuffer(fDataBfr^, bytesToRead);
where fDataBfr : ^TDataBfr;

I am unable to change this call -- it must remain the same in existing code. I therefore am unable to apply your code logic in the examples to pass in ReadFromBuffer(@DataBuf) or casting ReadFromBuffer(DataBuf) where Databuf:TDataBuffer, and hence cast to TDataBuffer from within the method.

I am struggling with my syntax within the ReadFromBuffer method to assign a value to which fDataBfr points to.
0
 
LVL 25

Accepted Solution

by:
epasquier earned 2000 total points
ID: 36716005
I don't see in what way what you want differs from what you need.
procedure ReadFromBuffer(var prmBfr);
begin
 FillChar(TDataBuffer(prmBfr),10,'a');
 TDataBuffer(prmBfr)[2]:='B';
 TDataBuffer(prmBfr)[10]:=#0;
end;

procedure Test;
Var
 DataBuf:pDataBuffer;
begin
 New(DataBuf);
 ReadFromBuffer(DataBuf^); // you can use dereferenced pointer 
 ShowMessage(pChar(DataBuf)); // Output = 'aBaaaaaaaa'
 Dispose(DataBuf);
end;

Open in new window

0
 
LVL 25

Expert Comment

by:epasquier
ID: 36716009
I meant "in what way what you want differs from what I gave you "
0
 
LVL 25

Expert Comment

by:epasquier
ID: 36716394
you should have select the post #36713073 as answer, don't forget that when others will be looking for answers in the knowledge DB, they will see the selected answer first. And the one you selected is not going to help them much
I'll call a moderator, if he can fix that
0

Featured Post

On Demand Webinar - Networking for the Cloud Era

This webinar discusses:
-Common barriers companies experience when moving to the cloud
-How SD-WAN changes the way we look at networks
-Best practices customers should employ moving forward with cloud migration
-What happens behind the scenes of SteelConnect’s one-click button

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

One of the most frequent problems a "newbie" developer may encounter is having to deal with different data formats. One for all: THE DATE We, as humans, need to "see" a date and then interpret it (much of the times this is an automatic operation)…
Introduction This article discusses the Chain of Responsibility pattern, explaining What it is;Why it is; andHow it is At the end of this article, I hope you will be able to describe the use and benefits of Chain of Responsibility.  Backgrou…
NetCrunch network monitor is a highly extensive platform for network monitoring and alert generation. In this video you'll see a live demo of NetCrunch with most notable features explained in a walk-through manner. You'll also get to know the philos…
Do you want to know how to make a graph with Microsoft Access? First, create a query with the data for the chart. Then make a blank form and add a chart control. This video also shows how to change what data is displayed on the graph as well as form…
Suggested Courses
Course of the Month12 days, 8 hours left to enroll

777 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question