passing an LPCSTR or LPCTSTR string to an API routine, CryptAcquireContext() 
Author Message
 passing an LPCSTR or LPCTSTR string to an API routine, CryptAcquireContext()

Hello,

The general question is how can I pass a string from a fortran
routine into an API routine?

In some API routines the pointer of the string is passed in;
for example, using the LOC() function, LOC(string_name), will
send the pointer to the string to the API routine, and then
the API routine happily uses the string.

Now, in other API routines that have a string as an argument
the interface definition is indicated as:
  character*(*) string_name
and the line before that has:
  !DEC$ ATTRIBUTES REFERENCE :: string_name
In this second case it looks like a pointer is not indicated,
rather the string should be passed to the API routine.  Since
the API routine will need a null terminated string we can add
the null termination to the string in the Fortran routine by
using:

  i = LEN_TRIM(string_name) + 1    ! add 1 character for the null
character
  string_name(i:i) = CHAR(0)       ! add the null character to
terminate the string
and then pass string_name(:i) to the API routine

If we put the string_name(:i) variable in the call statement
to the API routine we get a compiler error:
  Error: The type of the actual argument differs from the type of the
dummy argument.

This seems to say that there is a variable type mismatch
between the character variable type for string_name in the
Fortran routine and the LPCSTR string variable that the API
routine is expecting.  The LPCSTR variable type is given in
the help listing for Visual Fortran and is described as a
"pointer to a constant null-terminated string of 8-bit (ANSI)
Windows characters".  That is a little confusing since LPCSTR
wants a "pointer", but a character variable is given in the
interface definition (see particular example below).

Is there a way to pass the string_name character variable
from the Fortran routine to the API routine as the needed
LPCSTR type (string or a type of pointer)?  
We have tried to use a pointer with the LOC() function but
that also does not work (same compiler error).

Specifically in our case we are trying to use the
CryptAcquireContext() API routine to get a handle to a hash
object.  We are getting the compiler error at the third
argument, pszProvider, the CSP name (Cryptographic Service
Provider).  Our call statment to the API routine is:

  lResult = CryptAcquireContext(m_lProvider, NULL,
CRYPTO_PROVIDER_NAME, CRYPTO_PROV_RSA_FULL, CRYPTO_VERIFY_CONTEXT)

Where m_lProvider will be the handle returned by the API
routine and stored as an integer, NULL is a null string
(for a default argument), CRYPTO_PROVIDER_NAME is the string
that we are having the trouble with, it is declared as
character(len=80) :: CRYPTO_PROVIDER_NAME, and
CRYPTO_PROV_RSA_FULL and CRYPTO_VERIFY_CONTEXT are both
integers (flags we set).

The interface statement from ADVAPI32.f90 (in the DF98
Include folder) is:

INTERFACE
FUNCTION CryptAcquireContext( &
        phProv, &
        pszContainer, &
        pszProvider, &
        dwProvType, &
        dwFlags)
USE DFWINTY
  integer(BOOL) :: CryptAcquireContext ! BOOL
    !DEC$ ATTRIBUTES DEFAULT :: CryptAcquireContext
    !DEC$IF DEFINED(_X86_)

CryptAcquireContext
    !DEC$ ELSE
    !DEC$ ATTRIBUTES STDCALL, ALIAS:'CryptAcquireContextA' ::
CryptAcquireContext
    !DEC$ ENDIF
!DEC$ ATTRIBUTES REFERENCE :: phProv
  integer(ULONG) phProv ! HCRYPTPROV* phProv
!DEC$ ATTRIBUTES REFERENCE :: pszContainer
  character*(*) pszContainer ! LPCSTR pszContainer
!DEC$ ATTRIBUTES REFERENCE :: pszProvider
  character*(*) pszProvider ! LPCSTR pszProvider
  integer(DWORD) dwProvType ! DWORD dwProvType
  integer(DWORD) dwFlags ! DWORD dwFlags
 END FUNCTION
END INTERFACE

Here we see the lines declaring pszContainer as a
character*(*) variable to be passed by reference.  I think we
need to get the call statement variable type to agree with the
string by reference type in the API routine.  
How can we do that?

Your help and advice is greatly appreciated!
Regards,

Greg Thorwald
Structural Reliability Technology
1898 South Flatiron Court, Suite 235
Boulder, Colorado  80301
voice:  (303) 415-1475   FAX:  (303) 415-1847



Sat, 08 Nov 2003 07:00:37 GMT  
 passing an LPCSTR or LPCTSTR string to an API routine, CryptAcquireContext()
Hi,

Whether a string is passed to a Win32 API routine as just
'string_name' or as 'loc(string_name)' depends on how the interface
block for that routine defines that string dummy argument.  If the
dummy argument is defined as an integer passed by value (byval as a
result of the stdcall attribute applied to the routine itself) then
'loc(string_name)' is used.  If the dummy argument is defined as an
assumed length character variable  with the reference attribute, then
'string_name' is used to pass the string.  How and why this works is
discussed in detail in the CVF Programmer's Guide, Programming with
Mixed Languages chapter.  

The inconsistency in the way strings are passed in different API
functions is a by product of backward compatibility with MS FPS.  It
seems as though the MS generated interface blocks to API functions
just punted on the Fortran to C language mapping and passed all
pointer variables (including strings and intent(inout) variables) as
integers passed by value - hence the use of loc().  Many of the
Compaq/Digital generated interface blocks provide a more natural
language mapping in most cases (with some notable shortcomings here
and there).  The desire not to break backward compatibility leaves
users without a _consistent_ Fortran to C language mapping.  This
forces users to always check the declaration of the interface block of
each and every API function used to see how to pass things like
strings and out parameters.  Some time ago I believed that a solution
was being evaluated for this issue, but I don't know what its current
status is.

As for your specific function call and error message, it looks like
you are likely passing the third parameter correctly.  But the second
parameter looks suspect.  In module dfwinty (used in module advapi32),
NULL is declared as

integer, parameter :: NULL     = 0

but based on the interface block the second parameter should be an
assumed length character variable.  This is the argument giving you
the
Error: The type of the actual argument differs from the type of the
dummy argument.

Instead, you can use NULL_CHARACTER, like so:

! ...
nullify(NULL_CHARACTER)  ! sure wish this was initialised with null()
lResult = CryptAcquireContext(m_lProvider, NULL_CHARACTER,      &
CRYPTO_PROVIDER_NAME, CRYPTO_PROV_RSA_FULL, CRYPTO_VERIFY_CONTEXT)
! ...

or alternatively you can override the interface block with the %val(),
although this working my depend on what version of CVF you're using -
probably 6.0+ will do.

lResult = CryptAcquireContext(m_lProvider, %val(0),
CRYPTO_PROVIDER_NAME, CRYPTO_PROV_RSA_FULL, CRYPTO_VERIFY_CONTEXT)

hth,
John



Sat, 08 Nov 2003 11:40:51 GMT  
 passing an LPCSTR or LPCTSTR string to an API routine, CryptAcquireContext()
On Mon, 21 May 2001 23:40:51 -0400, John C. Termine

Quote:

>The inconsistency in the way strings are passed in different API
>functions is a by product of backward compatibility with MS FPS.  It
>seems as though the MS generated interface blocks to API functions
>just punted on the Fortran to C language mapping and passed all
>pointer variables (including strings and intent(inout) variables) as
>integers passed by value - hence the use of loc().  Many of the
>Compaq/Digital generated interface blocks provide a more natural
>language mapping in most cases (with some notable shortcomings here
>and there).  The desire not to break backward compatibility leaves
>users without a _consistent_ Fortran to C language mapping.  This
>forces users to always check the declaration of the interface block of
>each and every API function used to see how to pass things like
>strings and out parameters.  Some time ago I believed that a solution
>was being evaluated for this issue, but I don't know what its current
>status is.

A hint as to the status can be seen in the new ALLOW_NULL and
IGNORE_LOC attributes we added in CVF 6.5.  In the next update of CVF,
we will be replacing the current Win32 interfaces with a completely
new set, automatically generated from the current MS .h files.  For
arguments that are "strings", they will be consistently declared as
CHARACTER in the interfaces.  Where appropriate, the new ALLOW_NULL
and/or IGNORE_LOC attributes will be included to provide backward
compatibility with existing sources.  For example, consider the pesky
routine RegCreateKeyEx, whose interface currently looks like this
(ignore the wrapping, please):

integer(4) function  RegCreateKeyEx  (hKey ,lpSubKey ,Reserved
,lpClass ,dwOptions ,samDesired ,lpSecurityAttributes ,phkResult
,lpdwDisposition  )
!DEC$ ATTRIBUTES DEFAULT :: RegCreateKeyEx
!DEC$ IF DEFINED(_X86_)

RegCreateKeyEx  
!DEC$ ELSE
!DEC$ ATTRIBUTES STDCALL, ALIAS :  'RegCreateKeyExA'      ::
RegCreateKeyEx  
!DEC$ ENDIF
!DEC$ ATTRIBUTES REFERENCE :: lpSubKey
!DEC$ ATTRIBUTES REFERENCE :: lpClass
!DEC$ ATTRIBUTES REFERENCE :: lpSecurityAttributes
use dfwinty
integer                     hKey
character*(*)               lpSubKey
integer                     Reserved
character*(*)               lpClass
integer                     dwOptions
integer                     samDesired
type(T_SECURITY_ATTRIBUTES) lpSecurityAttributes
integer                     phkResult
integer                     lpdwDisposition  
end function RegCreateKeyEx

Note that lpSecurityAttributes, phkResult and lpdwDisposition are just
integers (passed by value, implied by the explicit STDCALL attribute.)
If you want to pass an actual variable, you have to pass
LOC(variable), and if you want to omit lpSecurityAttributes, you have
to use the predeclared NULL_SECURITY_ATTRIBUTES.

Here's what it will look like in the future:

INTERFACE
FUNCTION RegCreateKeyEx( &
        hKey, &
        lpSubKey, &
        Reserved, &
        lpClass, &
        dwOptions, &
        samDesired, &
        lpSecurityAttributes, &
        phkResult, &
        lpdwDisposition)
USE DFWINTY
  integer(LONG) :: RegCreateKeyEx ! LONG
    !DEC$ ATTRIBUTES DEFAULT, STDCALL, DECORATE,
ALIAS:'RegCreateKeyExA' :: RegCreateKeyEx
  integer(HANDLE) hKey ! HKEY hKey
!DEC$ ATTRIBUTES REFERENCE, IGNORE_LOC, ALLOW_NULL :: lpSubKey
  character*(*) lpSubKey ! LPCSTR lpSubKey
  integer(DWORD) Reserved ! DWORD Reserved
!DEC$ ATTRIBUTES REFERENCE, IGNORE_LOC, ALLOW_NULL :: lpClass
  character*(*) lpClass ! LPSTR lpClass
  integer(DWORD) dwOptions ! DWORD dwOptions
  integer(ULONG) samDesired ! REGSAM samDesired
!DEC$ ATTRIBUTES REFERENCE, IGNORE_LOC, ALLOW_NULL ::
lpSecurityAttributes
  TYPE (T_SECURITY_ATTRIBUTES) lpSecurityAttributes !
LPSECURITY_ATTRIBUTES lpSecurityAttributes
!DEC$ ATTRIBUTES REFERENCE, IGNORE_LOC :: phkResult
  integer(HANDLE)  phkResult ! PHKEY phkResult
  integer(LPDWORD) lpdwDisposition ! LPDWORD lpdwDisposition
 END FUNCTION
END INTERFACE

The interesting differences are:

1) Explicit specification of KINDs (the KIND values are declared in
DFWINTY.)
2) The last two arguments are now specified as passed by reference, so
no LOC() is needed.  The IGNORE_LOC attribute provides
backwards-compatibility for code that uses LOC.
3) The arguments which can be omitted also have ALLOW_NULL, allowing
use of NULL or NULL() (your choice), rather than NULL_CHARACTER,
NULL_SECURITY_ATTRIBUTES, etc.
4) The DECORATE attribute replaces the conditionalization on platform
- this says "apply this platform's default decoration rules to the
ALIAS specified.

We've been doing extensive testing of these new modules, and found
that there are very few problems with old sources.  Of the few
problems we've encountered, nearly all deal with updated derived type
declarations where MS redefined fields - some code may need minor
changes for such cases.  Of course, we'll document all such changes
we're aware of.

Look for this update in August or September - it will be free to CVF
6.5 users.  (If you're currently at 6.0 or 6.1, I suggest taking
advantage now of the special $149 upgrade price for registered users,
as it will probably end at about the same time.  For details, see our
web site.)



Fortran Engineering
Compaq Computer Corporation, Nashua NH

Compaq Fortran web site: http://www.compaq.com/fortran
Message Board: http://www.compaq.com/fortran/forum



Sun, 09 Nov 2003 05:08:47 GMT  
 
 [ 3 post ] 

 Relevant Pages 

1. Trying to pass strings to Fortan routines

2. Passing a string to a Fortran DLL routine from Pascal

3. LPCSTR

4. API routine CryptEncrypt() returns error 234

5. Lf95: How to call API file mapping routines?

6. Prototyping API: Passing Pointer to A Queue

7. Can routines be passed as parameters?

8. Passing stem variables to external routines

9. Pass stem name to called routine

10. gcc: passing register arguments to an assembly routine

11. Passing pointer to assembly routine

12. Passing arguments to Win32 API functions

 

 
Powered by phpBB® Forum Software