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 |
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 > > |
Free forum by Nabble | Edit this page |