trouble with aaApi_Login(), and how do I find the correct DLL for declaring a function?

I'm learning how to use the ProjectWise API through VBA, and I'm trying to build a basic Hello World program.  So far, I have:

Public Declare Function aaApi_Initialize Lib "DMSCLI.dll" (ByVal ulModule As Long) As Long
Public Declare Function aaApi_GetCurrentUserId Lib "DMSCLI.dll" () As Long
Public Declare Function aaApi_Login Lib "DMSCLI.dll" (ByVal lDsType As Long, lpctstrDSource As String, ByVal lpctstrUser As String, ByVal lpctstrPassword As String, ByVal lpctstrSchema As String) As Boolean

Sub LogIn()

Dim result1 As Boolean
Dim result2 As Boolean
Dim result3 As Long


'Initialize the API
result1 = aaApi_Initialize(AAMODULE_ALL)
'Login to PW using single sign-on
result2 = aaApi_Login(AAAPIDB_UNKNOWN, "XYZABC.my.site.com:PWOPPID_ABC", vbNullString, vbNullString, vbNullString)
'Get ID for current user
result3 = aaApi_GetCurrentUserId()

End Sub

The aaApi_Login() call is returning false, and I don't know why. I want to use aaApi_GetLastErrorID() to inspect the problem, but I don't know which DLL to use for declaring it.

Short of running a dumpbin on every DLL in the ProjectWise\Bin folder and searching through each dump, is there an easier way to find out which DLL should be used to declare a given function? Is this information available somewhere in the SDK that I've overlooked?

Parents
  • Joshua,

    Here are a couple tips and the primary answer to your question.

    1. Although you may find a few posts on calling the ProjectWise APIs from Microsoft VBA, at this time it is not a fully supported path for several reasons.   The recommended path is to create yourself a ProjectWise API native code custom module in C/C++ allowing for providing your external (VBA) apps a simplified interface hiding the complexity of the underlying ProjectWise C/C++ code required to perform a given task.  Unfortunatley we do not have or provide a functional ProjectWise API to VBA type mapping guide and necessary function declarations required.
    2. Microsoft VBA allows a programmer to call functions declared in the Microsoft __stdcall convention when a public export in a .dll.  It is important that the application calling an exported function has the function's owning .dll in a readily available and searched application PATH.  If not, the external application will not be able to locate the .dll referenced and fail.  Always make sure that the application in question is "aware" of the required .dll or use a Microsoft tool like Microsoft Process Monitor (procmon) to find out where Windows is searching for .dlls for a given application.  For example, if you create a ProjectWise native code custom module it requires additional dependencies in the appropriate ..\ProjectWise\bin directory.  Your customization would also need to reside there, or provide early binding (application) pathing to find and load required dependent .dlls.  If you extend your custom module with exports and the __stdcall convention you can then use e.g. MicroStation VBA, Microsoft Excel VBA, etc. - IF you provide a correct working path to the ..\ProjectWise\bin directory and/or your own seperate .dll directory; if you chose not to place your customization in the ProjectWise bin directory.
    3. So, to answer your question you could use a Microsoft Visual Studio command shell and use the Visual Studio dumpbin.exe in conjuction with Microsoft Findstr.exe to provide effective filtering.  For example this keyin:

    dumpbin /EXPORTS *.dll | findstr "following aaApi_GetLastErrorId"

    Provides an abbreviated list (below) showing which .dll you would need to actively reference. 

    C:\Program Files (x86)\Bentley\ProjectWise\bin>dumpbin /EXPORTS *.dll | findstr "following aaApi_GetLastErrorId"
      Section contains the following exports for acledit.dll
      Section contains the following exports for Bentley.Crypto.1.0.dll
      ...

      Section contains the following exports for DMSGEN.dll
            198   C5 0000AF80 aaApi_GetLastErrorId = _aaApi_GetLastErrorId@0
      Section contains the following exports for dmslogapi.dll
      Section contains the following exports for dmsmapiclient.dll
    ...

    Please note the following:

    • All Function calls and searches should be performed in a case-sensitive manner to ensure that correct code is called and executed.  Microsoft VBA's environment does not always make the most strict programmer preferred options the default and therefore you should validate your VBA Project properties and ensure "Require Variable Declaration" use of "Break on All Errors" for development and debugging, and "Break on All Unhandled Errors" for users in production.  I always look at the top of Every source code Module, Class, and Form to make sure "Option Explicit" is set to best ensure valuable time is not wasted troubleshooting well hidden bugs. :)
    • I specifically did not tell Findstr.exe to be case insensitive with a "-i" argument since I want only lines that contain "following" in lowercase.
    • This approach also forces the programmer to know the exact case of the function in question, otherwise no results (or failing calls) will happen.
    • There may be better ways to do this from a command line or GUI tool like Depends.exe, etc.; however this was quick and provided the correct result.

    Feel free to reply to this thread to let us know if this or something else helped resolve the issue.

    HTH,

    Bob



  • Thanks Bob.  I have been using Depends and just looking for them alphabetically based on which .h or fdf the definintion is in.

  • Bob,

    Thanks for your advice on this.  The findstr.exe approach will work fine for my purposes.

    If I understand correctly, you are recommending that I create a class library (DLL) in C++ that makes the ProjectWise API calls, then use the ProjectWise Custom Module Manager to register the DLL, so that I can call these wrapper functions in VBA and keep an abstraction layer between my VBA code and the underlying API calls.  Is this an accurate understanding of what you're suggesting?

    Thanks,

    Joshua

Reply
  • Bob,

    Thanks for your advice on this.  The findstr.exe approach will work fine for my purposes.

    If I understand correctly, you are recommending that I create a class library (DLL) in C++ that makes the ProjectWise API calls, then use the ProjectWise Custom Module Manager to register the DLL, so that I can call these wrapper functions in VBA and keep an abstraction layer between my VBA code and the underlying API calls.  Is this an accurate understanding of what you're suggesting?

    Thanks,

    Joshua

Children
  • Joshua - yes.  Overtime you will see and realize the benefits of taking this approach.  Whether a VBA or .NET project needing to perform ProjectWise or MicroStation API calls this will provide faster and more easily debuggable code and allowing you to create a simpler, reusable, and stable interface for others to use. 



  • Bob

    I few questions to your statements:

    1. Why would it be "faster" to interact with PW through a wrapper DLL rather then directly using the PW dlls?
    2. Custom Module Manager is as far as I see only installed with the SDK. How do you then get your program running at a non-SDK PC?

    Thomas

  • Unknown said:

    1. Why would it be "faster" to interact with PW through a wrapper DLL rather then directly using the PW dlls?

    For your first question:

    1. A wrapper DLL could expose a simple interface.  e.g. PWCheckoutDoc("pwname://...").  If you were required to write, migrate, and verify all the necessary ProjectWise functions, types, and parameter calls across the different runtime boundaries (ensuring no memoryallocated by different runtimes occurs) the underlying native C/C++ code in your wrapper does not need to be exposed to the target language (e.g. VBA or .NET).
    2. Making calls across different runtime API boundaries incurs computational and resource overhead.  The fewer times this needs to occur the faster the application will be.
    3. The target API; VBA for this example; though simpler to program in can hide real (logic or explicit) errors in your code making it more difficult to find and debug hidden problem. See my prior suggestions on VBA options to run with for development vs. production below. Microsoft VBA is an interpreted language that certainly has its own overhead to add vs. calling native code functions in a native code application.  Any mission critical sub-second timing related processes will need the additional control that Native code and/or Assembly language can deliver.

    Unknown said:

    2. Custom Module Manager is as far as I see only installed with the SDK. How do you then get your program running at a non-SDK PC?

    For your second question:

    Please see the attached .pdf I have created on this topic.  Simply in your development environment export out the appropriate bitness ProjectWise custom module entries and deploy to your client registries along with your custom module in the ProjectWise bin directory.

     



  • Hi Bob

    Thank you for your very elaborate answers.

    I do however need to get a full understanding of the implications of your statements on VBA usage.

    Let me give an example

    From a VBA application I want to make a list of documents stored in my PW. Should I:

    1. Make one C++-function in a wrapper DLL taking care of everything including login.
    2. Make more C++-function in a wrapper DLL each taking care of the major steps in the process: Login, Setting up document list (filter, sort), Getting the data, Logout.

    And a side question: Is Visual Studio 2010 Express suitable as IDE? If not what is the minimum Visual Studio edition required.

     

     

    Joshua

    I apologize for hijacking your thread.

     

    Thomas 

  • By the way, you don't need Custom Modules if you are creating a stand alone application. Custom modules are for DLLs that are invoked from ProjectWise as it starts and usually contain menu items to dispay in ProjectWise.  You can make a stand alone app in C++ and then see what make sense to put into a C++ COM dll and what makes sense to put into a .NET program.  A standalone application samlple can be found at C:\Program Files (x86)\bentley\ProjectWise\SDK\samples\vaultlist if you have the SDK installed.

         Most likely you will have Login, Logout, and most of your aaApi_function calls wrapped in the same DLL as they have data that they need to share.  Login creates an HDSOURCE that is needed by Logout is an example.