FFI Structure Help

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

FFI Structure Help

Ron Teitelbaum
Hello all,

I'm still having some trouble with FFI and was wondering if someone could
help explain why this is not working.

The following works on C++

typedef struct _CRYPT_KEY_PROV_INFO {
    LPWSTR                  pwszContainerName;
    LPWSTR                  pwszProvName;
    DWORD                   dwProvType;
    DWORD                   dwFlags;
    DWORD                   cProvParam;
    PCRYPT_KEY_PROV_PARAM   rgProvParam;
    DWORD                   dwKeySpec;
} CRYPT_KEY_PROV_INFO, *PCRYPT_KEY_PROV_INFO;

typedef struct _CRYPT_KEY_PROV_PARAM {
    DWORD           dwParam;
    BYTE            *pbData;
    DWORD           cbData;
    DWORD           dwFlags;
} CRYPT_KEY_PROV_PARAM, *PCRYPT_KEY_PROV_PARAM;

The equivilent on squeak:

Win32FFICertKeyProviderInfo class>>fields
fields

        ^#(
                (pwszContainerName 'char *')
                (pwszProvName 'char *')
            (dwProvType 'long')
                (dwFlags 'long')
                (cProvParam 'long')
                (rgProvParam 'Win32FFICertKeyProviderParameter')
                (dwKeySpec 'long')
           )

Win32FFICertKeyProviderParameter class >> fields
       
        ^#(
                (dwParam 'long')
                (pbData 'byte *')
                (cbData 'long')
                (dwFlags 'long')
           )

The calls in C++:

CertGetCertificateContextProperty(
    pCertContext,                 // A pointer to the certificate
                                  // where the property will be set.
    CERT_KEY_PROV_INFO_PROP_ID,   // An identifier of the property to get.
                                  // In this case,
                                  // CERT_KEY_PROV_INFO_PROP_ID
    NULL,                         // NULL on the first call to get the
                                  // length.
    &cbData)

Returns 200.

In squeak:

getCertProviderInfoSize

        "#define CERT_KEY_PROV_INFO_PROP_ID          2"
       
        | buffer result |
        [buffer := (ExternalAddress allocate: 4).
        self class certGetCertificateContextProperty: self
selectedCertificate getHandle asInteger property: 2 structPointerOrNull: nil
buffer: buffer asInteger
       
        ] ensure: [
                result := buffer unsignedLongAt: 1.
                buffer free.
        ].
        ^result

Returns 200.  So this apparently works!

Here is the problem:

In C++:

if(!(pCryptKeyProvInfo = (CRYPT_KEY_PROV_INFO *)malloc(cbData)))
     {
             MyHandleError("Error in allocation of memory.");
     }
     if(CertGetCertificateContextProperty(
                pCertContext,
                CERT_KEY_PROV_INFO_PROP_ID,
                pCryptKeyProvInfo,
                &cbData))
     {
               printf("\n The current key container is %S.",
                   pCryptKeyProvInfo->pwszContainerName);
     }

Works fine.

In squeak:

Win32FFICertificateStore>>getCertProviderInfo

        "#define CERT_KEY_PROV_INFO_PROP_ID          2"
       
        | providerInfo aHandle |
        aHandle := ExternalAddress allocate: self getCertProviderInfoSize.
        providerInfo := Win32FFICertKeyProviderInfo fromHandle: aHandle.
        self class certGetCertificateContextProperty: self
selectedCertificate getHandle asInteger property: 2 structPointerOrNull:
aHandle asInteger buffer: self getCertProviderInfoSize.
        self certProviderInfo: providerInfo.


Win32FFICertificateStore class>>certGetCertificateContextProperty: aContext
property: aProperty structPointerOrNull: pvData buffer: aBuffer

"BOOL WINAPI CertGetCertificateContextProperty(
  PCCERT_CONTEXT pCertContext,
  DWORD dwPropId,
  void* pvData,
  DWORD* pcbData
);
"

        <apicall: bool 'CertGetCertificateContextProperty' (long long long
long) module: 'crypt32.dll'>
        ^self externalCallFailed

Blows up with a C0000005 access violation error.  

I've tried changing the external type form long to
Win32FFICertKeyProviderInfo, and I've tried initializing the
Win32FFICertKeyProviderInfo rgProvParam: Win32FFICertKeyProviderParameter
new.

I've tried using externalNew instead of allocating 200 bytes in an external
address on both structures.  But that hasn't worked; I still get the same
error.

I've even tried sending in a ByteArray new: 200, as a handle but that came
back with can not coerce arguments.

Sorry if I've been a bit of a pest.  Now that I have the code I need working
in C++ I was hoping that the translation to squeak would go smoothly.  I'm
sure I'm missing something, any suggestions are welcome!

Ron Teitelbaum


Reply | Threaded
Open this post in threaded view
|

RE: FFI Structure Help

Ron Teitelbaum
All,

I answered my own question.  As it turned out the problem was not the
structure, but the size.  I thought, incorrectly, that the size could be
sent in as an integer, now that we had a value.  That was wrong; the
function was expecting an external buffer with the size value.  Once I
changed the size function to return the buffer and used:

getCertProviderInfo

        "#define CERT_KEY_PROV_INFO_PROP_ID          2"
       
        | providerInfo aHandle buffer |
        aHandle := ExternalAddress allocate: ((buffer := self
getCertProviderInfoSize) unsignedLongAt: 1).
        providerInfo := Win32FFICertKeyProviderInfo fromHandle: aHandle.
        self class certGetCertificateContextProperty: self
selectedCertificate getHandle asInteger property: 2 structPointerOrNull:
aHandle asInteger buffer: buffer asInteger.
        buffer free.
        self certProviderInfo: providerInfo.

It worked!

If you read the previous email, thank you for considering the problem!

Ron Teitelbaum

> -----Original Message-----
> From: [hidden email] [mailto:squeak-dev-
> [hidden email]] On Behalf Of Ron Teitelbaum
> Sent: Monday, August 14, 2006 4:32 PM
> To: 'The general-purpose Squeak developers list'
> Subject: FFI Structure Help
>
> Hello all,
>
> I'm still having some trouble with FFI and was wondering if someone could
> help explain why this is not working.
>
> The following works on C++
>
> typedef struct _CRYPT_KEY_PROV_INFO {
>     LPWSTR                  pwszContainerName;
>     LPWSTR                  pwszProvName;
>     DWORD                   dwProvType;
>     DWORD                   dwFlags;
>     DWORD                   cProvParam;
>     PCRYPT_KEY_PROV_PARAM   rgProvParam;
>     DWORD                   dwKeySpec;
> } CRYPT_KEY_PROV_INFO, *PCRYPT_KEY_PROV_INFO;
>
> typedef struct _CRYPT_KEY_PROV_PARAM {
>     DWORD           dwParam;
>     BYTE            *pbData;
>     DWORD           cbData;
>     DWORD           dwFlags;
> } CRYPT_KEY_PROV_PARAM, *PCRYPT_KEY_PROV_PARAM;
>
> The equivilent on squeak:
>
> Win32FFICertKeyProviderInfo class>>fields
> fields
>
> ^#(
> (pwszContainerName 'char *')
> (pwszProvName 'char *')
>   (dwProvType 'long')
> (dwFlags 'long')
> (cProvParam 'long')
> (rgProvParam 'Win32FFICertKeyProviderParameter')
> (dwKeySpec 'long')
>   )
>
> Win32FFICertKeyProviderParameter class >> fields
>
> ^#(
> (dwParam 'long')
> (pbData 'byte *')
> (cbData 'long')
> (dwFlags 'long')
>   )
>
> The calls in C++:
>
> CertGetCertificateContextProperty(
>     pCertContext,                 // A pointer to the certificate
>                                   // where the property will be set.
>     CERT_KEY_PROV_INFO_PROP_ID,   // An identifier of the property to get.
>                                   // In this case,
>                                   // CERT_KEY_PROV_INFO_PROP_ID
>     NULL,                         // NULL on the first call to get the
>                                   // length.
>     &cbData)
>
> Returns 200.
>
> In squeak:
>
> getCertProviderInfoSize
>
> "#define CERT_KEY_PROV_INFO_PROP_ID          2"
>
> | buffer result |
> [buffer := (ExternalAddress allocate: 4).
> self class certGetCertificateContextProperty: self
> selectedCertificate getHandle asInteger property: 2 structPointerOrNull:
> nil
> buffer: buffer asInteger
>
> ] ensure: [
> result := buffer unsignedLongAt: 1.
> buffer free.
> ].
> ^result
>
> Returns 200.  So this apparently works!
>
> Here is the problem:
>
> In C++:
>
> if(!(pCryptKeyProvInfo = (CRYPT_KEY_PROV_INFO *)malloc(cbData)))
>      {
>              MyHandleError("Error in allocation of memory.");
>      }
>      if(CertGetCertificateContextProperty(
>                 pCertContext,
>                 CERT_KEY_PROV_INFO_PROP_ID,
>                 pCryptKeyProvInfo,
>                 &cbData))
>      {
>                printf("\n The current key container is %S.",
>                    pCryptKeyProvInfo->pwszContainerName);
>      }
>
> Works fine.
>
> In squeak:
>
> Win32FFICertificateStore>>getCertProviderInfo
>
> "#define CERT_KEY_PROV_INFO_PROP_ID          2"
>
> | providerInfo aHandle |
> aHandle := ExternalAddress allocate: self getCertProviderInfoSize.
> providerInfo := Win32FFICertKeyProviderInfo fromHandle: aHandle.
> self class certGetCertificateContextProperty: self
> selectedCertificate getHandle asInteger property: 2 structPointerOrNull:
> aHandle asInteger buffer: self getCertProviderInfoSize.
> self certProviderInfo: providerInfo.
>
>
> Win32FFICertificateStore class>>certGetCertificateContextProperty:
> aContext
> property: aProperty structPointerOrNull: pvData buffer: aBuffer
>
> "BOOL WINAPI CertGetCertificateContextProperty(
>   PCCERT_CONTEXT pCertContext,
>   DWORD dwPropId,
>   void* pvData,
>   DWORD* pcbData
> );
> "
>
> <apicall: bool 'CertGetCertificateContextProperty' (long long long
> long) module: 'crypt32.dll'>
> ^self externalCallFailed
>
> Blows up with a C0000005 access violation error.
>
> I've tried changing the external type form long to
> Win32FFICertKeyProviderInfo, and I've tried initializing the
> Win32FFICertKeyProviderInfo rgProvParam: Win32FFICertKeyProviderParameter
> new.
>
> I've tried using externalNew instead of allocating 200 bytes in an
> external
> address on both structures.  But that hasn't worked; I still get the same
> error.
>
> I've even tried sending in a ByteArray new: 200, as a handle but that came
> back with can not coerce arguments.
>
> Sorry if I've been a bit of a pest.  Now that I have the code I need
> working
> in C++ I was hoping that the translation to squeak would go smoothly.  I'm
> sure I'm missing something, any suggestions are welcome!
>
> Ron Teitelbaum
>
>