我可以从Progress OpenEdge ABL调用C++代码吗?

Can I call C++ code from Progress OpenEdge ABL?

本文关键字:C++ 代码 调用 ABL Progress OpenEdge 我可以      更新时间:2023-10-16

是否可以从Progress ABL中执行C++代码?

具体来说,我希望使用函数SHGetKnownFolderPath(此处的文档)来确定Windows 7计算机上"文档"文件夹的位置,该计算机将文档文件夹重定向到另一个位置。

或者,是否有另一种方法可以在不检查注册表项的情况下确定此信息?

可以调用外部共享库和 DLL。

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

第 3 节"外部接口"是您要查找的内容。

此 http://dbappraise.com/ppt/shlib.pptx 也可能有所帮助。

C++由于命名事物的方式,经常有问题。 你最好使用普通的旧C来构建一个"填充程序",以便在OpenEdge和C++之间架起桥梁

不过,调用Windows系统函数通常很容易。 像这样:

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

查看"编程接口"文档"外部程序接口"部分。

此外,某些版本的 ABL 还支持直接 .NET 调用作为选项。

在咨询了一些来源后,我能够在 10.2B 中使用它:

  • C# 解决方案,例如:https://stackoverflow.com/a/21953690/763102
  • Win32 OpenEdge 示例,用于翻译示例:http://www.oehive.org/book/export/html/385.html

SHGetKnownFolderPath的困难部分是需要通过引用传递的rfid参数。C# 具有批注[System.Runtime.InteropServices.MarshalAs(UnmanagedType.LPStruct)]ref 关键字。由于 Progress OpenEdge 对外部过程参数数据类型的限制,我无法弄清楚如何传递 System.Guid 的引用,所以我执行了 .NET Guid的字节副本并通过 MEMPTR 传递了它。对于在这里如此依赖 .NET,我深表歉意。

下面是一个工作示例,它获取提供的已知文件夹 GUID,以及获取文档文件夹的用法:

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.