Question

Is it possible to execute C++ code from within Progress ABL?

Specifically, I am looking to use the function SHGetKnownFolderPath (documentation here) to determine the location of the "Documents" folder on a Windows 7 machine that has the documents folder redirected to another location.

Or, is there an alternative way to determine this information without resorting to checking a registry key?

Was it helpful?

Solution

You can call external shared libraries and DLLs.

http://documentation.progress.com/output/OpenEdge113/pdfs/dvpin/dvpin.pdf

Section 3 "External Interfaces" is what you are looking for.

This http://dbappraise.com/ppt/shlib.pptx might also be helpful.

C++ is often problematic due to the way it names things. You might be better off building a "shim" using plain old C to bridge between OpenEdge and C++

Callling Windows system functions is usually easy though. Something like:

procedure SHGetKnownFolderPath external "pathToLibrary":
  define parameter a as someType.
  define parameter b as someType.
  define return parameter x as someType.
end.

OTHER TIPS

Check the "Programming Interfaces" document, "External Program Interfaces" section.

Also, some versions of ABL also support direct .NET calls as an option.

I was able to get this working in 10.2B after consulting some sources:

The difficult part for SHGetKnownFolderPath is the rfid parameter which needs to be passed by reference. C# has the annotation [System.Runtime.InteropServices.MarshalAs(UnmanagedType.LPStruct)] or the ref keyword. I couldn't figure out how to pass a reference of System.Guid due to Progress OpenEdge's limitations of external procedure parameter datatypes, so I performed a bytewise copy of a .NET Guid and passed that via MEMPTR. I apologize for leaning so heavily on .NET here.

Here is a working example that gets the provided known folder GUID, plus usage to get the Documents folder:

PROCEDURE SHGetKnownFolderPath EXTERNAL "shell32.dll":
  DEFINE INPUT PARAMETER rfid AS MEMPTR.
  DEFINE INPUT PARAMETER dwFlags AS UNSIGNED-LONG.
  DEFINE INPUT PARAMETER hToken AS LONG.
  DEFINE OUTPUT PARAMETER ppszPath AS LONG.
  DEFINE RETURN PARAMETER result AS LONG.
END PROCEDURE.

FUNCTION prepareGuidPointer RETURNS MEMPTR(
  pGuid AS System.Guid):
  
  DEFINE VARIABLE lGuidBytes AS INTEGER EXTENT.
  ASSIGN lGuidBytes = pGuid:ToByteArray().
  
  DEFINE VARIABLE lGuidPointer AS MEMPTR NO-UNDO.
  SET-SIZE(lGuidPointer) = EXTENT(lGuidBytes).
  
  DEFINE VARIABLE ii AS INTEGER NO-UNDO.
  DO ii = 1 TO EXTENT(lGuidBytes):
    PUT-BYTE(lGuidPointer, ii) = lGuidBytes[ii].
  END.

  RETURN lGuidPointer.
END FUNCTION.

FUNCTION deallocatePointer RETURNS INT64(
  pPointer AS MEMPTR):
  SET-SIZE(pPointer) = 0.
  RETURN GET-SIZE(pPointer).
END FUNCTION.

FUNCTION GetKnownFolderPath RETURNS CHARACTER(
  pGuidString AS CHARACTER):

  DEFINE VARIABLE lDontVerifyFolderFlag AS INT64 NO-UNDO
    INITIAL 16384. /* 0x4000 */
  DEFINE VARIABLE lUseDefaultUser AS INTEGER NO-UNDO
    INITIAL 0.

  DEFINE VARIABLE lGuidPointer AS MEMPTR NO-UNDO.
  ASSIGN lGuidPointer = prepareGuidPointer( NEW System.Guid(pGuidString) ).
  
  DEFINE VARIABLE lResult AS INTEGER NO-UNDO.
  DEFINE VARIABLE lPathResponse AS INTEGER NO-UNDO.
  
  RUN SHGetKnownFolderPath(
    INPUT lGuidPointer,
    INPUT lDontVerifyFolderFlag,
    INPUT lUseDefaultUser,
    OUTPUT lPathResponse,
    OUTPUT lResult).
  
  deallocatePointer(lGuidPointer).
  
  IF lResult GE 0 THEN
  DO:
    DEFINE VARIABLE lStringPath AS CHARACTER NO-UNDO.
    DEFINE VARIABLE lPathPointer AS System.IntPtr NO-UNDO.
    ASSIGN lPathPointer = NEW System.IntPtr(lPathResponse).
    ASSIGN lStringPath =
      System.Runtime.InteropServices.Marshal:PtrToStringUni(lPathPointer).
    System.Runtime.InteropServices.Marshal:FreeCoTaskMem(lPathPointer).

    RETURN lStringPath.
  END.
  ELSE
    UNDO, THROW NEW System.Runtime.InteropServices.ExternalException(
      "Unable to retrieve the known folder path. It may not be available on this system.",
      lResult).

END FUNCTION.

DEFINE VARIABLE lDocumentsGuidString AS CHARACTER NO-UNDO
  INITIAL "~{FDD39AD0-238F-46AF-ADB4-6C85480369C7}".

MESSAGE GetKnownFolderPath(lDocumentsGuidString)
  VIEW-AS ALERT-BOX.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top