Wed Jun 27 22:04:41 2012: Request 78081 was acted upon.
Transaction: Ticket created by BULKDD
       Queue: Win32-API
     Subject: ::Struct inside ::Struct is always inline, never a pointer
   Broken in: 0.68
    Severity: Normal
       Owner: Nobody
  Requestors: bul...@cpan.org
      Status: new
 Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=78081 >


I am filing this as a RT bug, but I hope I get responses from libwin32
readers and not just API's 2 maintainers.

It seems to me that currently, in 0.68, and 0.70, if you create a
::Struct, with another ::Struct, as a member, the child ::Struct is
always inlined into the parent struct. A ::Struct can not have a
::Struct pointer as a member. There is no code path to create such a
thing. Also there is no public api way of obtaining a pointer to the
packed ::Struct string scalar. So I ask, how should the API to create a
::Struct * member of a ::Struct be?

My currently I have 5 ideas
currently ::Struct::typedef is

=item C<typedef NAME, TYPE, MEMBER, TYPE, MEMBER, ...>

idea 1:
typedef(POINTERNAME, EXISTING_TYPE)
or
typedef(NAME, TYPE, MEMBER, TYPE, MEMBER, ...) #legacy proto

with 

die "usage Win32::API::Struct::typedef( NAME, [NON_POINTER_STRUCT_NAME]
| [TYPE, MEMBER, TYPE, MEMBER, ...])" if scalar(@_) % 2 == 0 &&
scalar(@_) != 2;

an even @_ is broken usage currently, if @_ is even and @_ has 2 slices,
instead of broken usage, have that be pointer typedef mode

idea 2:
::Struct::typedef unchanged
::Struct::make_pointer($name, $existing_struct); # named after private
is_pointer()
or decl_pointer instead of make_pointer? someone might think
make_pointer returns an IV to the packed struct.

idea 3:
::Struct::typedef unchanged
::Struct::is_pointer($name [, $set_bool]) #name after private api in
::Type, proto diff tho

permanently converts struct $name to a struct pointer, user should
probably have $name begin with LP or P for user's sanity but not
enforced, you must call typedef again and recreate the struct from the
member elements all over again under a new name if you want the
non-pointer version after calling is_pointer

idea 4:
::Type::typedef has * detection in,
so "Win32::API::Type->typedef('LPMY_STRUCT', 'MY_STRUCT *');"

idea 5:
expose as public api getting the pointer suitable for passing to a
UINT_PTR or 'N' letter param, from a Win32::API::Struct object instance.
Document it in POD how to get raw pointer from a Win32::API::Struct
object instance. Dont mess with the type databases.  This is easiest
solution BTW

quasi idea 6:
change ::Type::typedef to have 3 parameters, 3rd param signals struct
pointer creation mode

I dont like it.

not an idea:
No extending the "LP" detection. Many late 2000s added to Platform SDK
MS structs only come in P variants, not LP. Something like 

typedef struct pvalueW {           // Provider supplied value/context.
    LPWSTR  pv_valuename;          // The value name pointer
    int pv_valuelen;
    LPVOID pv_value_context;
    DWORD pv_type;
}PVALUEW, FAR *PPVALUEW;

would be a problem.

Some background comments. There is also no integration between ::Type's
type database (%Pointer, %Known) and ::Struct's type database (%Known).
Ideally one day ::Type and ::Struct will be merged much closer, so
::Type's Pack()/Unpack() processes ::Struct types rather than current
the separate callbacks into Perl language in API.xs but I don't have
time to rewrite so much code. There is also the separate issue of no
pass by copy structs support. On x86 pass by copy structs are placed on
the stack, it can be work arounded today by unpacking the packed struct
into a bunch of Ns, then prototyping the func as Ns. On x64, AFAIK, >8
becomes pointer so the workaround isn't portable.

Reply via email to