Announcement

Collapse
No announcement yet.

Struggling to convert MSDN C++ to PB

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Struggling to convert MSDN C++ to PB

    I am having a problem converting some C++, from MSDN, into PB. I have tried umpteen PB interpretations to no avail.

    The real problem is that I do not fully understand what the MSDN code is doing.

    Here is the code from MSDN along with a structure definition and what I have found in PB's docs.

    The code requires Win Vista or later and PB compilers 6 or 10.

    Code:
    C++
     
    #include <windows.h>
     
    #ifndef NT_SUCCESS
    #define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
    #endif
     
    void EnumProviders1()
    {
        NTSTATUS status;
        ULONG cbBuffer = 0;
        PCRYPT_PROVIDERS pBuffer = NULL;
     
        /*
        Get the providers, letting the BCryptEnumRegisteredProviders
        function allocate the memory.
        */
        status = BCryptEnumRegisteredProviders(&cbBuffer, &pBuffer);
     
        if (NT_SUCCESS(status))
        {
            if (pBuffer != NULL)
            {
                // Enumerate the providers.
                for (ULONG i = 0; i < pBuffer->cProviders; i++)
                {
                    printf("%S\n", pBuffer->rgpszProviders[i]);
                }
            }
        }
        else
        {
            printf("BCryptEnumRegisteredProviders failed with error "
                "code 0x%08x\n", status);
        }
     
        if (NULL != pBuffer)
        {
            /*
            Free the memory allocated by the
            BCryptEnumRegisteredProviders function.
            */
            BCryptFreeBuffer(pBuffer);
        }
    }
     
    ----------------------------------------------------------------
     
    C++
     
    typedef struct _CRYPT_PROVIDERS {
      ULONG cProviders;
      PWSTR *rgpszProviders;
    } CRYPT_PROVIDERS, *PCRYPT_PROVIDERS;
     
    Members
     
    cProviders
       Contains the number of elements in the rgpszProviders array.
     
    rgpszProviders
       An array of null-terminated Unicode strings that contains the names of the registered providers.
     
    ----------------------------------------------------------------
     
    From PB's BCrypt.inc with compilers 6 and 10.
     
    DECLARE FUNCTION BCryptEnumRegisteredProviders LIB "BCrypt.dll" _
        ALIAS "BCryptEnumRegisteredProviders" (pcbBuffer AS DWORD, _
        ppBuffer AS ANY) AS LONG
     
    TYPE CRYPT_PROVIDERS
        cProviders     AS DWORD
        rgpszProviders AS DWORD
    END TYPE
     
    ----------------------------------------------------------------
    This is what MSDN say:

    You use the BCryptEnumRegisteredProviders function to enumerate the registered providers. The BCryptEnumRegisteredProviders function can be called in one of two ways:

    1. The first is to have the BCryptEnumRegisteredProviders function allocate the memory. This is accomplished by passing the address of a NULL pointer for the ppBuffer parameter. This code will allocate the memory required for the CRYPT_PROVIDERS structure and the associated strings. When the BCryptEnumRegisteredProviders function is used in this manner, you must free the memory when it is no longer needed by passing ppBuffer to the BCryptFreeBuffer function.
    The opening code is for the first method - that is, the buffer will allocated for us.

    The first issue which I do not understand is 'PCRYPT_PROVIDERS pBuffer = NULL;'. I understand the need but do not know how to accomplish it.

    The second issue is that the assignment given to the buffer which BCryptEnumRegisteredProviders will allocate for us is the same as the assignment used for the CRYPT_PROVIDERS structure.

    It seems to me that we do not have a structure on the one hand and a separate buffer on the other but a structure base which gets redefined, the first Dword being cProviders, the number of providers, and then a 'bunch' of rgpszProviders each one pointing to the individual providers.

    Whatever interpretation I have used I always get cbBuffer = 334 but I have had many values for cProviders ranging from 4 to 400,000 when I should be getting about 33.

    Don't laugh becuase I have been at this a couple of days. It is an aspect that I have never seen before and although always a struggle for me to convert MSDN's C++ to PB I usually get there in the end.

    Can anyone shed any light on what the MSDN code is actually doing?

  • #2
    Something like this:

    Code:
    #COMPILE EXE
    #DIM ALL
    #INCLUDE "win32api.inc"
    #INCLUDE "bcrypt.inc"
    
    FUNCTION PBMAIN () AS LONG
    
       LOCAL nstatus AS LONG
       LOCAL cbBuffer AS DWORD
       LOCAL pBuffer AS CRYPT_PROVIDERS PTR
       LOCAL prgpszProviders AS WSTRINGZ PTR
       LOCAL i AS LONG
       
       nstatus = BCryptEnumRegisteredProviders(cbBuffer, pBuffer)
       IF nstatus = 0 THEN
          IF pBuffer THEN
             ' // Enumerate the providers.
             prgpszProviders = @pBuffer.rgpszProviders
             FOR i = 0 TO @pBuffer.cProviders - 1
                ? @@prgpszProviders[i]
             NEXT
          END IF
       ELSE
          ? "BCryptEnumRegisteredProviders failed with error &H" & HEX$(nstatus)
       END IF
    
       IF pBuffer THEN
          ' Free the memory allocated by the BCryptEnumRegisteredProviders function.
          BCryptFreeBuffer(BYVAL pBuffer)
       END IF
       
       WAITKEY$
    
    END FUNCTION
    Forum: http://www.jose.it-berater.org/smfforum/index.php

    Comment


    • #3
      Thanks, José. One of my interpretations is knocking on the door of your code but I hadn't gone deep enough.

      We are not quite there yet. This is what I am getting.

      Microsoft Primitive Provider
      Microsoft Primitive Provider
      Microsoft Primitive Provider
      Microsoft Primitive Provider

      unless that is all we will get but it is not telling us anything that cProviders = 4 is telling us.

      Comment


      • #4
        Pointers to pointers are always a bit confussing. This works:

        Code:
        #COMPILE EXE
        #DIM ALL
        #INCLUDE "win32api.inc"
        #INCLUDE "bcrypt.inc"
        
        FUNCTION PBMAIN () AS LONG
        
           LOCAL nstatus AS LONG
           LOCAL cbBuffer AS DWORD
           LOCAL pBuffer AS CRYPT_PROVIDERS PTR
           DIM   rgpszProviders(0) AS WSTRINGZ PTR
           LOCAL i AS LONG
           
           nstatus = BCryptEnumRegisteredProviders(cbBuffer, pBuffer)
           IF nstatus = 0 THEN
              IF pBuffer THEN
                 ' // Enumerate the providers.
                 REDIM rgpszProviders(@pBuffer.cProviders - 1) AT @pBuffer.rgpszProviders
                 FOR i = 0 TO @pBuffer.cProviders - 1
                    ? @rgpszProviders(i)
                 NEXT
              END IF
           ELSE
              ? "BCryptEnumRegisteredProviders failed with error &H" & HEX$(nstatus)
           END IF
        
           IF pBuffer THEN
              ' Free the memory allocated by the BCryptEnumRegisteredProviders function.
              BCryptFreeBuffer(BYVAL pBuffer)
           END IF
           
           WAITKEY$
        
        END FUNCTION
        Forum: http://www.jose.it-berater.org/smfforum/index.php

        Comment


        • #5
          José, with a bit of redundant line removal I have managed to get both your routines onto one sheet of A4. I use two monitors and a file of useful snippets which I use as my third monitor.
          Pointers to pointers are always a bit confusing.
          It doesn't help when MSDN refers to rgpszProviders as "An array of null-terminated Unicode strings that contains the names of the registered providers." when, in fact, it is a pointer to an array of pointers with the array of pointers being needed because the strings are dynamic and not using contiguous memory as fixed length strings would.
          but it is not telling us anything that cProviders = 4 is telling us.
          Actually, it does - it tells us that Intel are not one of them. I was hoping to see Intel there.

          Thanks, again.

          Comment


          • #6
            Originally posted by David Roberts View Post

            The first issue which I do not understand is 'PCRYPT_PROVIDERS pBuffer = NULL;'. I understand the need but do not know how to accomplish it.
            NULL usually means zero in regard to pointers. It is usually, but not always, defined as zero
            in the standard libraries. You should use NULL when using C or C++. In PB, you can use zero.
            A pointer value of zero means that there is no memory associated with the pointer.
            This is generally used to validate pointer data. If a NULL pointer is returned, it may
            be assumed that there is no valid data to be processed.
            C or C++ routines returning a pointer will return a NULL pointer if the function fails,
            or if there is no data available to be returned by the called function.

            Note: there is no instance of which I am aware in which NULL does not equal zero,
            but there is no reason some C or C++ implementation could not use something different.
            I haven't checked the new standard, but the old one does not guarantee NULL = 0.
            Last edited by Kurt Kuzba; 30 Jan 2013, 02:25 AM.
            The world is strange and wonderful.*
            I reserve the right to be horrifically wrong.
            Please maintain a safe following distance.
            *wonderful sold separately.

            Comment


            • #7
              Code:
              %NULL = 0&
              I think that may be defined in one or more of the PB-provided Windows' headers.

              I use %NULL for parameters in calls in which that parameter is not used, reserving zero for use when zero actually means something, e.g. "row zero" of a list control.

              (For DDT-ers, Windows numbers rows in list controls (listbox, combobox, listview) starting with row zero).



              MCM
              Michael Mattias
              Tal Systems (retired)
              Port Washington WI USA
              [email protected]
              http://www.talsystems.com

              Comment


              • #8
                The first issue which I do not understand is 'PCRYPT_PROVIDERS pBuffer = NULL;'. I understand the need but do not know how to accomplish it.
                That is not saying that I do not understand what NULL means.

                For anyone who is not that au fait with C or C++ then it will not be obvious that

                C++: PCRYPT_PROVIDERS pBuffer = NULL; ==> PB: LOCAL pBuffer AS CRYPT_PROVIDERS PTR

                We have then, in general, C++: Type name = NULL; ==> PB: LOCAL name AS Type PTR

                I should imagine then that the following is true:

                C++: ULONG x = NULL; ==> PB: LOCAL x AS DWORD PTR

                providing further evidence, not that I needed any, that C and C++ uses 'Enigmatic or incomprehensible symbols or writing.' aka hieroglyphics.

                Comment


                • #9
                  No.

                  ULONG x = NULL ==> PB: LOCAL x AS DWORD

                  PULONG x = NULL ==> PB: LOCAL x AS DWORD PTR

                  In the C++ headers, ULONG is defined as unsigned long, i.e. a DWORD, and PULONG as a pointer to ULONG.

                  C++ headers use a ton of defines.

                  The = NULL is used because C++, contrarily to PB, doesn't initialize variables to a default value.
                  Last edited by José Roca; 30 Jan 2013, 02:52 PM.
                  Forum: http://www.jose.it-berater.org/smfforum/index.php

                  Comment


                  • #10
                    should imagine then that the following is true:

                    C++: ULONG x = NULL; ==> PB: LOCAL x AS DWORD PTR
                    You could make that work, provided you respect it in assignment, DECLAREs and use at the point of calls.

                    You could also make DWORD (not DWORD PTR) work, provided you respect it in assignment, DECLAREs and use at the point of calls.

                    You could also accomplish whatever the code you are replacing does without even using an 'X' variable.

                    If you are going to be replacing code written in other languages, there is simply no substitute for thoroughly understanding the application logic and knowing something of the source language and a lot of the destination language.

                    MCM
                    Michael Mattias
                    Tal Systems (retired)
                    Port Washington WI USA
                    [email protected]
                    http://www.talsystems.com

                    Comment


                    • #11
                      For anyone who is not that au fait with C or C++ then it will not be obvious that

                      C++: PCRYPT_PROVIDERS pBuffer = NULL; ==> PB: LOCAL pBuffer AS CRYPT_PROVIDERS PTR
                      It is as if you do:

                      MACRO PCRYPT_PROVIDERS = CRYPT_PROVIDERS PTR
                      LOCAL pBuffer AS PCRYPT_PROVIDERS
                      pBuffer = 0 ' unneeded because PB automatically initializes it as 0.
                      Forum: http://www.jose.it-berater.org/smfforum/index.php

                      Comment


                      • #12
                        Ah, I did not spot the 'P' in 'PCRYPT_PROVIDERS'

                        In general then we have

                        C++: Type name = NULL; ==> PB: LOCAL name AS Type
                        C++: PType name = NULL; ==> PB: LOCAL name AS Type PTR

                        In 1000 years time when a piece of PB is dug up and no manuals have survived a debate about DWORD PTR would swiftly progress to DWORD POINTER and the debate would terminate. On the other hand, when a piece of C is dug up and no manuals have survived a debate about PULONG may well have to adjourn for lunch. The moral of this story is that if you are an atheist, like me, then you should write your code in PowerBASIC; as if you needed telling.

                        Comment


                        • #13
                          In post #5 I showed the output of José's post #2. The reason why we get 'Microsoft Primitive Provider' four times is because we are using pointer indexing with no array and get the first entry in the buffer at @pBuffer.rgpszProviders repeated.

                          Added: The above is not true. At the moment I am not sure why it does not work.

                          With José's post #4 we are mapping the buffer at @pBuffer.rgpszProviders into the array rgpszProviders(@pBuffer.cProviders - 1) and the result is:

                          Microsoft Primitive Provider
                          Microsoft Smart Card Key Storage Provider
                          Microsoft Software Key Storage Provider
                          Microsoft SSL Protocol Provider

                          which is correct.
                          José, with a bit of redundant line removal I have managed to get both your routines onto one sheet of A4.
                          I now have landscape A5.
                          Last edited by David Roberts; 31 Jan 2013, 07:51 AM.

                          Comment


                          • #14
                            With José's post #2 prgpszProviders should be a DWORD PTR and not a WSTRINGZ PTR.

                            Here is a rewrite which does work.

                            Code:
                            #Compile Exe
                            #Dim All
                            #Include "win32api.inc"
                            #Include "bcrypt.inc"
                            
                            Function PBMain () As Long
                            
                               Local nstatus As Long
                               Local cbBuffer As Dword
                               Local pBuffer As CRYPT_PROVIDERS Ptr
                               Local prgpszProviders As Dword Ptr
                               Local wprgpszProviders As WStringZ Ptr
                               Local i As Long
                               
                               nstatus = BCryptEnumRegisteredProviders(cbBuffer, pBuffer)
                               If nstatus = 0 Then
                                  If pBuffer Then
                                     ' // Enumerate the providers.
                                     prgpszProviders = @pBuffer.rgpszProviders
                                     For i = 0 To @pBuffer.cProviders - 1
                                        wprgpszProviders = @prgpszProviders[i]
                                        ? @wprgpszProviders
                                     Next
                                  End If
                               Else
                                  ? "BCryptEnumRegisteredProviders failed with error &H" & Hex$(nstatus)
                               End If
                            
                               If pBuffer Then
                                  ' Free the Memory allocated by the BCryptEnumRegisteredProviders Function.
                                  BCryptFreeBuffer(ByVal pBuffer)
                               End If
                               
                               WaitKey$
                            
                            End Function
                            José's post #4 is very clever and worth looking at by quite a few of us here.

                            Comment

                            Working...
                            X