comp.lang.ada
 help / color / mirror / Atom feed
* Thick Ada bindings to C Win32
@ 2004-11-10  2:41 Brian May
  2004-11-10  4:36 ` tmoran
                   ` (2 more replies)
  0 siblings, 3 replies; 18+ messages in thread
From: Brian May @ 2004-11-10  2:41 UTC (permalink / raw)


Hello,

I have a program that uses Win32 serial I/O. Initially I found a set
of thick bindings to do this on the Internet, but I found a number of
limitations, and have been working to enhance it.

One issue that still remains though.

I have the following functions:

type Byte_Array is array (Positive range <>) of Byte;
procedure Get(Handle : in Handle_Type; Item : out Byte; Done : out Boolean);
procedure Put(Handle : Handle_Type; Item : in Byte_Array);

(hmmm... ideally the Get function should read in a Byte_Array, but
lets not confuse matters... My application only wants one byte at a
time anyway)

However, the equivalent Win32 functions require a Win32.Lpcvoid (null
terminator not required). How do I convert to/from the required types?

At the moment, my somewhat not-elegant code, found via
trial-and-error, is:

function Convert_Char_Ptr_To_Lpvoid is new
      Ada.Unchecked_Conversion
      (Source => Char_Ptr,
      Target => Win32.Lpvoid);

function Convert_Byte_Array_Ptr_To_Char_Array_Ptr is new
      Ada.Unchecked_Conversion
      (Source => Byte_Array_Access,
      Target => Interfaces.C.Strings.Char_Array_Access);

function Convert_Chars_Ptr_To_Lpcvoid is new
      Ada.Unchecked_Conversion
      (Source => Interfaces.C.Strings.Chars_Ptr,
      Target => Win32.Lpcvoid);


procedure Get(Handle : in Handle_Type; Item : out Byte; Done : out Boolean) is

...

   char_item : character;
   Bool_Result : Win32.Bool;
   NumberOfBytesRead : aliased Win32.dword;
   Char_Buffer : aliased Interfaces.C.Char;

...

begin
        ...
        Result := Win32.Winbase.ReadFile( ...
        lpBuffer => Convert_Char_Ptr_To_Lpvoid(Char_Buffer'Unchecked_Access),           nNumberOfBytesToRead => Win32.Dword(1),
        ....);

        ...

        char_item := Interfaces.C.To_Ada(Char_Buffer);
        Item := char_to_byte(char_item);

        ...
end Get;

procedure Put(Handle : Handle_Type; Item : in Byte_Array) is

   ...

   Buffer : aliased Byte_Array := Item;

   A : Interfaces.C.Strings.Char_Array_Access
        := Convert_Byte_Array_Ptr_To_Char_Array_Ptr(Buffer'Unchecked_Access);

   B : Interfaces.C.Strings.Chars_Ptr
        := Interfaces.C.Strings.To_Chars_Ptr(A,False);

   Buffer_Ptr : Win32.Lpcvoid
        := Convert_Chars_Ptr_To_Lpcvoid(B);

begin
   Bool_Result :=
      Win32.Winbase.WriteFile
      ( ...
       lpBuffer => Buffer_Ptr,                              -- Win32.Lpcvoid
       nNumberOfBytesToWrite => Win32.Dword(Item'Length),   -- Win32.Dword  => 1 bytes
       ... )

end Put;


While the get function is OK, I think the put function is horrible. It
also requires copying the data, ideally I don't want this as I want to
maximize efficiency, even for large transactions (not currently a
strict requirement though). Is there anyway this could be improved?

Thanks in advance for any suggestions.


Alternatively, if somebody knows of a good quality set of thick
bindings that I could use, preferably GPL (or compatible), then please
let me know. Thanks.
-- 
Brian May <bam@snoopy.apana.org.au>



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Thick Ada bindings to C Win32
  2004-11-10  2:41 Thick Ada bindings to C Win32 Brian May
@ 2004-11-10  4:36 ` tmoran
  2004-11-10 19:31 ` Jeffrey Carter
  2004-11-12 12:09 ` Nick Roberts
  2 siblings, 0 replies; 18+ messages in thread
From: tmoran @ 2004-11-10  4:36 UTC (permalink / raw)


> procedure Put(Handle : Handle_Type; Item : in Byte_Array) is
>
>    ...
>
>    Buffer : aliased Byte_Array := Item;
>
>    A : Interfaces.C.Strings.Char_Array_Access
>         := Convert_Byte_Array_Ptr_To_Char_Array_Ptr(Buffer'Unchecked_Access);
>
>    B : Interfaces.C.Strings.Chars_Ptr
>         := Interfaces.C.Strings.To_Chars_Ptr(A,False);
>
>    Buffer_Ptr : Win32.Lpcvoid
>         := Convert_Chars_Ptr_To_Lpcvoid(B);
>
> begin
>    Bool_Result :=
>       Win32.Winbase.WriteFile
>       ( ...
>        lpBuffer => Buffer_Ptr,                              -- Win32.Lpcvoid
>        nNumberOfBytesToWrite => Win32.Dword(Item'Length),   -- Win32.Dword  => 1 bytes
>        ... )
>
> end Put;
>
> While the get function is OK, I think the put function is horrible.

Did you try:

  function WriteFile(...
                     Item : in Byte_Array;
                     nNumberOfBytesToWrite : in Win32.DWord,
                      ...) return c_bool;
  pragma Import(StdCall, WriteFile, "WriteFile");

  procedure Put(Handle : Handle_Type; Item : in Byte_Array) is
     ...
  begin
     Bool_Result :=
        Win32.Winbase.WriteFile
        ( ...
         Item => Item,
         nNumberOfBytesToWrite => Win32.Dword(Item'Length),
         ... )

  end Put;



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Thick Ada bindings to C Win32
  2004-11-10  2:41 Thick Ada bindings to C Win32 Brian May
  2004-11-10  4:36 ` tmoran
@ 2004-11-10 19:31 ` Jeffrey Carter
  2004-11-12  1:51   ` Brian May
  2004-11-12 12:09 ` Nick Roberts
  2 siblings, 1 reply; 18+ messages in thread
From: Jeffrey Carter @ 2004-11-10 19:31 UTC (permalink / raw)


Brian May wrote:

>        nNumberOfBytesToWrite => Win32.Dword(Item'Length),   -- Win32.Dword  => 1 bytes

This conversion is unnecessary. 'Length is universal integer, and so may 
be used with any integer type.

-- 
Jeff Carter
"When danger reared its ugly head, he bravely
turned his tail and fled."
Monty Python and the Holy Grail
60




^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Thick Ada bindings to C Win32
  2004-11-10 19:31 ` Jeffrey Carter
@ 2004-11-12  1:51   ` Brian May
  0 siblings, 0 replies; 18+ messages in thread
From: Brian May @ 2004-11-12  1:51 UTC (permalink / raw)


>>>>> "Jeffrey" == Jeffrey Carter <spam@spam.com> writes:

    Jeffrey> Brian May wrote:
    >> nNumberOfBytesToWrite => Win32.Dword(Item'Length),   -- Win32.Dword  => 1 bytes

    Jeffrey> This conversion is unnecessary. 'Length is universal
    Jeffrey> integer, and so may be used with any integer type.

Hmmm... I was thinking that when I copied it here.

I suspect the original author who created this package wasn't exactly
sure of what he was doing.

I think I have fixed all the bugs though (e.g. previously the get
procedure was a function that returned the byte read; this was fine
except for when no byte is read, due to timeout, in which case the
return value was undefined).
-- 
Brian May <bam@snoopy.apana.org.au>



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Thick Ada bindings to C Win32
  2004-11-10  2:41 Thick Ada bindings to C Win32 Brian May
  2004-11-10  4:36 ` tmoran
  2004-11-10 19:31 ` Jeffrey Carter
@ 2004-11-12 12:09 ` Nick Roberts
  2004-11-12 17:57   ` tmoran
  2004-11-12 23:29   ` Brian May
  2 siblings, 2 replies; 18+ messages in thread
From: Nick Roberts @ 2004-11-12 12:09 UTC (permalink / raw)


Try:


   function Addr (S : BYTE_Array) return LPCVOID is

      function To_LPCVOID is new
        Ada.Unchecked_Conversion (System.Address, LPCVOID);

   begin
      return To_LPCVOID( S(S'First)'Address );
   end;

   pragma Inline(Addr);


   procedure Put(Handle : Handle_Type; Item : in Byte_Array) is

      Successful: Win32.BOOL;
   begin

      Successful :=
         Win32.Winbase.WriteFile
         ( ...
          lpBuffer              => Addr(Item),  -- Win32.Lpcvoid
          nNumberOfBytesToWrite => Item'Length, -- Win32.Dword  => 1 bytes
          ... );

      if not Successful then raise ???_Error; end if;
   end Put;


I haven't tested this. It might be GNAT-specific. Must dash!

-- 
Nick Roberts



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Thick Ada bindings to C Win32
  2004-11-12 12:09 ` Nick Roberts
@ 2004-11-12 17:57   ` tmoran
  2004-11-12 18:50     ` Martin Krischik
  2004-11-12 23:29   ` Brian May
  1 sibling, 1 reply; 18+ messages in thread
From: tmoran @ 2004-11-12 17:57 UTC (permalink / raw)


>     function To_LPCVOID is new
>       Ada.Unchecked_Conversion (System.Address, LPCVOID);
  The Ada 95 language designers went to the trouble of including
a package, System.Address_To_Access_Conversion, specifically to
accomplish converting an Address to an Access.  They wouldn't
have bothered if Unchecked_Conversion could be relied on for
that job.



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Thick Ada bindings to C Win32
  2004-11-12 17:57   ` tmoran
@ 2004-11-12 18:50     ` Martin Krischik
  0 siblings, 0 replies; 18+ messages in thread
From: Martin Krischik @ 2004-11-12 18:50 UTC (permalink / raw)


tmoran@acm.org wrote:

>>     function To_LPCVOID is new
>>       Ada.Unchecked_Conversion (System.Address, LPCVOID);

>   The Ada 95 language designers went to the trouble of including
> a package, System.Address_To_Access_Conversion, specifically to
> accomplish converting an Address to an Access.  They wouldn't
> have bothered if Unchecked_Conversion could be relied on for
> that job.

True in general use. However types with names like "LPCVOID" are likely to
be of pragma Convention(C, ...); and here other rules apply. Prehaps
LPCVOID is a "mod 2*32" and not an access.

With Regards

Martin

-- 
mailto://krischik@users.sourceforge.net
http://www.ada.krischik.com



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Thick Ada bindings to C Win32
  2004-11-12 12:09 ` Nick Roberts
  2004-11-12 17:57   ` tmoran
@ 2004-11-12 23:29   ` Brian May
  2004-11-13  0:51     ` Jeffrey Carter
  1 sibling, 1 reply; 18+ messages in thread
From: Brian May @ 2004-11-12 23:29 UTC (permalink / raw)


>>>>> "Nick" == Nick Roberts <nick.roberts@acm.org> writes:

    Nick> Try:
    Nick> function Addr (S : BYTE_Array) return LPCVOID is

    Nick> function To_LPCVOID is new
    Nick> Ada.Unchecked_Conversion (System.Address, LPCVOID);

    Nick> begin
    Nick> return To_LPCVOID( S(S'First)'Address );
    Nick> end;

Is that legal? I would have thought it would return the address of the
local variable S, which might be different to what is passed as the
parameter.

It compiles OK, but it is dodgy.

As an example, I rewrote my get routine to use this function:

--- cut ---
procedure Get(Handle : in Handle_Type; Item : out Byte; Done : out Boolean) is

   Port_Handle : constant Win32.Winnt.Handle := Win32.Winnt.Handle(Handle);

   Item_Buffer : Byte_Array(1..1);
   Bool_Result : Win32.Bool;
   NumberOfBytesRead : aliased Win32.dword;

   nulla       : System.Address := Null_Address;

begin
   if Hack then M.Acquire; end if;

--Read in a byte of information
   Bool_Result :=
      Win32.Winbase.ReadFile
      (hFile => Port_Handle,                                -- Win32.Winnt.Handl
e
       lpBuffer => Addr(Item_Buffer),                       -- Win32.Lpvoid
       nNumberOfBytesToRead => 1,                           -- Win32.Dword
       lpNumberOfBytesRead => NumberOfBytesRead'Unchecked_Access,
                                                            -- Win32.Lpdword
       lpOverlapped => Convert_Pvoid_To_Lpoverlapped(nulla));-- Lpoverlapped

   if Bool_Result = Win32.False then
      Ada.Exceptions.Raise_Exception(Operation_Failed'Identity,
         "ReadFile returned False");
   end if;

   if NumberOfBytesRead = 0 then
       Item := 0;
       Done := False;
   else
--This sets the exportable character type from the character buffer
--*****NOTE: Need to change this to a 'byte' type*****
       Item := Item_Buffer(1);
       Done := True;
   end if;
   if Hack then M.Release; end if;

end Get;
--- cut ---

This, amazingly, seems to work fine. However, gnat warns me that
item_buffer is never assigned a value. So I changed the code to
initialise it:

   Item_Buffer : Byte_Array(1..1) := ( 1 => 0 );

Now all values read by the get function are 0. If I change the 0 to 1
all values are read as 1.

Just to make sure, I changed the code back again (removed the
initialisation) and it started working.

To me this doesn't make any sense.
-- 
Brian May <bam@snoopy.apana.org.au>



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Thick Ada bindings to C Win32
  2004-11-12 23:29   ` Brian May
@ 2004-11-13  0:51     ` Jeffrey Carter
  2004-11-25 23:19       ` Brian May
  0 siblings, 1 reply; 18+ messages in thread
From: Jeffrey Carter @ 2004-11-13  0:51 UTC (permalink / raw)


Brian May wrote:
>>>>>>"Nick" == Nick Roberts <nick.roberts@acm.org> writes:
> 
> 
>     Nick> Try:
>     Nick> function Addr (S : BYTE_Array) return LPCVOID is
> 
>     Nick> function To_LPCVOID is new
>     Nick> Ada.Unchecked_Conversion (System.Address, LPCVOID);
> 
>     Nick> begin
>     Nick> return To_LPCVOID( S(S'First)'Address );
>     Nick> end;
> 
> Is that legal? I would have thought it would return the address of the
> local variable S, which might be different to what is passed as the
> parameter.

If S is passed by copy, you'll get garbage. If it's passed by reference, 
you may still get garbage, since there's no guarantee that an address 
has the same representation as a convention-C access value. Since 
Byte_Array is not a by-copy nor a by-reference type, the compiler is 
free to choose. GNAT seems to have chosen by reference, not surprising 
for an unconstrained array type, and does use the same representation. 
But be aware that you are relying on implementation dependencies here. 
Rational, for example, does not use the same representation for 
addresses and access values. (I've been around code that was being 
ported from GNAT to rational that did this, and it didn't smell nice.)

> It compiles OK, but it is dodgy.

Yes, and not portable, either.

Assuming that Lp[c?]void is a convention-C access type, you can safely 
convert between convention-C access types using Unchecked_Conversion. 
Your best bet may be to declare such an access type designating a 
Byte_Array (maybe you want Storage_Array here?), declare Item_Buffer 
aliased, store its 'Unchecked_Access in a variable of the appropriate 
type, and convert it to the Win32 access type.

You might also want to declare Item_Buffer volatile, so the compiler 
thinks its contents might spontaneously change.

-- 
Jeff Carter
"Monsieur Arthur King, who has the brain of a duck, you know."
Monty Python & the Holy Grail
09




^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Thick Ada bindings to C Win32
  2004-11-13  0:51     ` Jeffrey Carter
@ 2004-11-25 23:19       ` Brian May
  2004-11-26  9:50         ` Martin Krischik
  2004-11-26 19:19         ` Jeffrey Carter
  0 siblings, 2 replies; 18+ messages in thread
From: Brian May @ 2004-11-25 23:19 UTC (permalink / raw)


>>>>> "Jeffrey" == Jeffrey Carter <spam@spam.com> writes:

    Jeffrey> Assuming that Lp[c?]void is a convention-C access type,
    Jeffrey> you can safely convert between convention-C access types
    Jeffrey> using Unchecked_Conversion. Your best bet may be to
    Jeffrey> declare such an access type designating a Byte_Array
    Jeffrey> (maybe you want Storage_Array here?), declare Item_Buffer
    Jeffrey> aliased, store its 'Unchecked_Access in a variable of the
    Jeffrey> appropriate type, and convert it to the Win32 access
    Jeffrey> type.

The most obvious problem is as soon as I make Item_Buffer aliased, I
need to make a complete copy of it.

Question:

Is S'Address the same as S(S'First)'Address?

Maybe the best approach might be:

   function To_LPCVOID is new
      Ada.Unchecked_Conversion (System.Address, Win32.LPCVOID);

To_LPCVOID(Item'Address)

or 

To_LPCVOID(Item(Item'First)'Address)

Depending on the answer to my previous question.
-- 
Brian May <bam@snoopy.apana.org.au>



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Thick Ada bindings to C Win32
  2004-11-25 23:19       ` Brian May
@ 2004-11-26  9:50         ` Martin Krischik
  2004-11-26 12:23           ` Frank J. Lhota
  2004-11-26 19:19         ` Jeffrey Carter
  1 sibling, 1 reply; 18+ messages in thread
From: Martin Krischik @ 2004-11-26  9:50 UTC (permalink / raw)


Brian May wrote:

>>>>>> "Jeffrey" == Jeffrey Carter <spam@spam.com> writes:
> 
>     Jeffrey> Assuming that Lp[c?]void is a convention-C access type,
>     Jeffrey> you can safely convert between convention-C access types
>     Jeffrey> using Unchecked_Conversion. Your best bet may be to
>     Jeffrey> declare such an access type designating a Byte_Array
>     Jeffrey> (maybe you want Storage_Array here?), declare Item_Buffer
>     Jeffrey> aliased, store its 'Unchecked_Access in a variable of the
>     Jeffrey> appropriate type, and convert it to the Win32 access
>     Jeffrey> type.
> 
> The most obvious problem is as soon as I make Item_Buffer aliased, I
> need to make a complete copy of it.
> 
> Question:
> 
> Is S'Address the same as S(S'First)'Address?

Depends on the compiler used and if the array is definite or indefinite.
Remember: Indefinite Arrays need to store 'First and 'Last.

With GNAT I have succesfully converted definite arrays from C to Ada using
'Address.
 
With Regards

Martin
-- 
mailto://krischik@users.sourceforge.net
http://www.ada.krischik.com



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Thick Ada bindings to C Win32
  2004-11-26  9:50         ` Martin Krischik
@ 2004-11-26 12:23           ` Frank J. Lhota
  0 siblings, 0 replies; 18+ messages in thread
From: Frank J. Lhota @ 2004-11-26 12:23 UTC (permalink / raw)


"Martin Krischik" <martin@krischik.com> wrote in message 
news:1810244.ahSE8CPTEK@linux1.krischik.com...
>> Question:
>>
>> Is S'Address the same as S(S'First)'Address?
>
> Depends on the compiler used and if the array is definite or indefinite.
> Remember: Indefinite Arrays need to store 'First and 'Last.

The Ada 83 standard did not specify whether S'Address is the same as 
S(S'First)'Address, and there were some Ada 83 compilers where S'Address 
could be the address of the array bounds. This was cleared up in the 95 
standard, and now S'Address is required to be S(S'First)'Address.





^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Thick Ada bindings to C Win32
  2004-11-25 23:19       ` Brian May
  2004-11-26  9:50         ` Martin Krischik
@ 2004-11-26 19:19         ` Jeffrey Carter
  2004-11-27 23:56           ` Brian May
  1 sibling, 1 reply; 18+ messages in thread
From: Jeffrey Carter @ 2004-11-26 19:19 UTC (permalink / raw)


Brian May wrote:
>>>>>>"Jeffrey" == Jeffrey Carter <spam@spam.com> writes:
> 
>     Jeffrey> Assuming that Lp[c?]void is a convention-C access type,
>     Jeffrey> you can safely convert between convention-C access types
>     Jeffrey> using Unchecked_Conversion. Your best bet may be to
>     Jeffrey> declare such an access type designating a Byte_Array
>     Jeffrey> (maybe you want Storage_Array here?), declare Item_Buffer
>     Jeffrey> aliased, store its 'Unchecked_Access in a variable of the
>     Jeffrey> appropriate type, and convert it to the Win32 access
>     Jeffrey> type.
> 
> The most obvious problem is as soon as I make Item_Buffer aliased, I
> need to make a complete copy of it.

I don't see that a copy is necessary:

type Buf_Ptr is access all Buffer;
pragma Convention (C, Buf_Ptr);

function To_Lpcvoid is new Ada.Unchecked_Conversion
    (Source => Buf_Ptr, Target => Win32.Lpcvoid);

Item_Buffer : aliased Buffer ...;
Ada_Ptr     : Buf_Ptr       := Buffer'Unchecked_Access;
Win_Ptr     : Win32.Lpcvoid := To_Lpcvoid (Ada_Ptr);

and call the operation with Win_Ptr;

> Maybe the best approach might be:
> 
>    function To_LPCVOID is new
>       Ada.Unchecked_Conversion (System.Address, Win32.LPCVOID);

There's no guarantee that an Ada Address has the same representation as 
a convention-C access value.

-- 
Jeff Carter
"There's no messiah here. There's a mess all right, but no messiah."
Monty Python's Life of Brian
84




^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Thick Ada bindings to C Win32
  2004-11-26 19:19         ` Jeffrey Carter
@ 2004-11-27 23:56           ` Brian May
  2004-11-28 18:57             ` Jeffrey Carter
  2004-11-28 23:45             ` Brian May
  0 siblings, 2 replies; 18+ messages in thread
From: Brian May @ 2004-11-27 23:56 UTC (permalink / raw)


>>>>> "Jeffrey" == Jeffrey Carter <spam@spam.com> writes:

    Jeffrey> I don't see that a copy is necessary:

    Jeffrey> Item_Buffer : aliased Buffer ...;

You seem to be assuming I am using the thin layer directly in my
program, in actual fact I have a thick layer:

procedure Put(Handle : Handle_Type; Item : in Byte_Array) is

  Item_Buffer : aliased Buffer ...;

begin
  ...
end Put;


I believe this does require a copy.

I want a thick layer binding, so I have to option available to port
code to Linux, should the need either occur, just be changing the
serial IO module.

I seem to remember that I encountered problems doing things as simply
as you suggest, but I can't remember why nor can I imagine why - I
will try it again and report back here with details of any errors
encountered.
-- 
Brian May <bam@snoopy.apana.org.au>



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Thick Ada bindings to C Win32
  2004-11-27 23:56           ` Brian May
@ 2004-11-28 18:57             ` Jeffrey Carter
  2004-11-28 23:45             ` Brian May
  1 sibling, 0 replies; 18+ messages in thread
From: Jeffrey Carter @ 2004-11-28 18:57 UTC (permalink / raw)


Brian May wrote:
> You seem to be assuming I am using the thin layer directly in my
> program, in actual fact I have a thick layer:
> 
> procedure Put(Handle : Handle_Type; Item : in Byte_Array) is
> 
>   Item_Buffer : aliased Buffer ...;

The stuff I suggested would go here.

> 
> begin
>   ...
> end Put;
> 
> I believe this does require a copy.

You may have to copy from Item_Buffer to Item, but that's inherent in 
the thick binding layer.

-- 
Jeff Carter
"Pray that there's intelligent life somewhere up in
space, 'cause there's bugger all down here on earth."
Monty Python's Meaning of Life
61




^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Thick Ada bindings to C Win32
  2004-11-27 23:56           ` Brian May
  2004-11-28 18:57             ` Jeffrey Carter
@ 2004-11-28 23:45             ` Brian May
  2004-11-29  7:50               ` Message-ID: <sa4vfbpzgfu.fsf@snoo tmoran
  2004-11-29 14:34               ` Thick Ada bindings to C Win32 Frank J. Lhota
  1 sibling, 2 replies; 18+ messages in thread
From: Brian May @ 2004-11-28 23:45 UTC (permalink / raw)


>>>>> "Brian" == Brian May <bam@snoopy.apana.org.au> writes:

    Brian> I seem to remember that I encountered problems doing things
    Brian> as simply as you suggest, but I can't remember why nor can
    Brian> I imagine why - I will try it again and report back here
    Brian> with details of any errors encountered.

Unfortunately, I was right, I did have problems:

     type Byte_Array_Access is access all Byte_Array;
     pragma Convention (C,Byte_Array_Access);

produces:

serial.adb:107:11: warning: this access type does not correspond to C pointer

and:

   function To_LPCVOID is new 
      Ada.Unchecked_Conversion (Byte_Array_Access, Win32.LPCVOID);

produces:

serial.adb:144:04: warning: types for unchecked conversion have different sizes

So I tried:

   Type Char_Array_Ptr is access all Interfaces.c.Char_Array;
   pragma Convention (C,Char_Array_Ptr);

which produces:

serial.adb:89:09: warning: this access type does not correspond to C pointer

I still am not sure of the proper way of creating a C pointer in
Ada. So far I have see advice don't user 'Access and don't use
'Address as neither of these are portable. What is the correct way?

This is why my complicated solution was so complicated, I ended up:

1. Creating an aliased Byte_Array.
2. Creating a Interfaces.C.Strings.Char_Array_Access,
   copy access type using uchecked_conversion.
3. Converting to C pointer using Interfaces.C.Strings.To_Chars_Ptr.
4. Convert to LPCVOID using unchecked conversion.

Hmmm... I wonder if what I need is
system.address_to_access_conversions and/or
System.Storage_Elements.To_Integer?

However, all of this is complicated by the fact LPVOID and LPCVOID in
Ada is defined as a subtype of System.Address in the Windows bindings,
which implies the correct way to pass the parameter to
Item'Address. This is also the simplest way.

So I know people have said this is wrong, but I am going to assume if
the windows bindings use System.Address then this method will work on
Windows.
-- 
Brian May <bam@snoopy.apana.org.au>



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Message-ID: <sa4vfbpzgfu.fsf@snoo
  2004-11-28 23:45             ` Brian May
@ 2004-11-29  7:50               ` tmoran
  2004-11-29 14:34               ` Thick Ada bindings to C Win32 Frank J. Lhota
  1 sibling, 0 replies; 18+ messages in thread
From: tmoran @ 2004-11-29  7:50 UTC (permalink / raw)


>However, all of this is complicated by the fact LPVOID and LPCVOID in
>Ada is defined as a subtype of System.Address in the Windows bindings,
  '"the" Windows bindings'?  You must be refering to a particular Windows
binding, probably supplied by a compiler vendor to work with (ie, lock
you into) their particular compiler.  Other Windows bindings define
LPVoid differently.



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Thick Ada bindings to C Win32
  2004-11-28 23:45             ` Brian May
  2004-11-29  7:50               ` Message-ID: <sa4vfbpzgfu.fsf@snoo tmoran
@ 2004-11-29 14:34               ` Frank J. Lhota
  1 sibling, 0 replies; 18+ messages in thread
From: Frank J. Lhota @ 2004-11-29 14:34 UTC (permalink / raw)


"Brian May" <bam@snoopy.apana.org.au> wrote in message 
news:sa4vfbpzgfu.fsf@snoopy.apana.org.au...
>>>>>> "Brian" == Brian May <bam@snoopy.apana.org.au> writes:
>
>    Brian> I seem to remember that I encountered problems doing things
>    Brian> as simply as you suggest, but I can't remember why nor can
>    Brian> I imagine why - I will try it again and report back here
>    Brian> with details of any errors encountered.
>
> Unfortunately, I was right, I did have problems:
>
>     type Byte_Array_Access is access all Byte_Array;
>     pragma Convention (C,Byte_Array_Access);
>
> produces:
>
> serial.adb:107:11: warning: this access type does not correspond to C 
> pointer
>
> and:
>
>   function To_LPCVOID is new
>      Ada.Unchecked_Conversion (Byte_Array_Access, Win32.LPCVOID);
>
> produces:
>
> serial.adb:144:04: warning: types for unchecked conversion have different 
> sizes
>
> So I tried:
>
>   Type Char_Array_Ptr is access all Interfaces.c.Char_Array;
>   pragma Convention (C,Char_Array_Ptr);
>
> which produces:
>
> serial.adb:89:09: warning: this access type does not correspond to C 
> pointer

The reason for this is that Ada needs to keep track of the array bounds of 
an Byte_Array object. In the case of Byte_Array_Access, the GNAT compiler 
choose the "fat pointer" approach of including the array bounds as part of 
the access type. In other words, a Byte_Array_Access object contains a 
pointer to the bytes, and additional components specifying 'First and 'Last. 
This is why the pragma Convention stuff failed.

You could fix this problem in one of two ways. One way is that use a 
representation clause to specify the size of a Byte_Array_Access object to 
be the size of a pointer, e.g.

    for Byte_Array_Access'Size use 32;

This forces GNAT to not include array bounds in a Byte_Array_Access object.

A cleaner and more portable approach would be to apply the 'Access attribute 
to the first element of the array. We can do this using the following 
definitions:

    type Byte_Array is array (Positive range <>) of aliased Byte;    -- Note 
the addition of "aliased"
    type Byte_Array_Access is access all Byte;
    pragma Convention (C,Byte_Array_Access);

By declaring the components of Byte_Array to be aliased, we guarantee that 
Byte_Array objects will never be packed in such a way that the components 
are not individually addressable, and hence we are free to apply 'Access or 
'Unchecked_Access to the components of a Byte_Array object. Then we define 
the Byte_Array_Access as a pointer to one of the components.

Now assume that we have the object

    Data : Byte_Array( 1 .. Data_Length );

and that we want to pass it to the subprogram

    function DoSomethingInC (
        lpBytes : in Byte_Array_Access
        ) return Interfaces.C.Int;
    pragma Import (C, DoSomethingInC );

then we could do this by applying 'Unchecked_Access to the first component 
of the array, as follows:

    Result := DoSomethingInC( lpBytes => 
Data(Data'First)'Unchecked_Access );

Hope this helps.








^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2004-11-29 14:34 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-11-10  2:41 Thick Ada bindings to C Win32 Brian May
2004-11-10  4:36 ` tmoran
2004-11-10 19:31 ` Jeffrey Carter
2004-11-12  1:51   ` Brian May
2004-11-12 12:09 ` Nick Roberts
2004-11-12 17:57   ` tmoran
2004-11-12 18:50     ` Martin Krischik
2004-11-12 23:29   ` Brian May
2004-11-13  0:51     ` Jeffrey Carter
2004-11-25 23:19       ` Brian May
2004-11-26  9:50         ` Martin Krischik
2004-11-26 12:23           ` Frank J. Lhota
2004-11-26 19:19         ` Jeffrey Carter
2004-11-27 23:56           ` Brian May
2004-11-28 18:57             ` Jeffrey Carter
2004-11-28 23:45             ` Brian May
2004-11-29  7:50               ` Message-ID: <sa4vfbpzgfu.fsf@snoo tmoran
2004-11-29 14:34               ` Thick Ada bindings to C Win32 Frank J. Lhota

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox