【发布时间】:2014-05-10 19:06:07
【问题描述】:
是否可以从 Progress ABL 中执行 C++ 代码?
具体来说,我希望使用函数 SHGetKnownFolderPath (documentation here) 来确定 Windows 7 计算机上“Documents”文件夹的位置,该计算机已将文档文件夹重定向到另一个位置。
或者,是否有其他方法可以在不检查注册表项的情况下确定此信息?
【问题讨论】:
标签: c++ progress-4gl openedge
是否可以从 Progress ABL 中执行 C++ 代码?
具体来说,我希望使用函数 SHGetKnownFolderPath (documentation here) 来确定 Windows 7 计算机上“Documents”文件夹的位置,该计算机已将文档文件夹重定向到另一个位置。
或者,是否有其他方法可以在不检查注册表项的情况下确定此信息?
【问题讨论】:
标签: c++ progress-4gl openedge
您可以调用外部共享库和 DLL。
http://documentation.progress.com/output/OpenEdge113/pdfs/dvpin/dvpin.pdf
第 3 节“外部接口”是您要查找的内容。
这个http://dbappraise.com/ppt/shlib.pptx 也可能有帮助。
C++ 经常因为它命名事物的方式而存在问题。您最好使用普通的旧 C 构建一个“shim”来桥接 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 中使用它:
SHGetKnownFolderPath 的难点在于rfid 参数,需要通过引用传递。 C# 具有注释 [System.Runtime.InteropServices.MarshalAs(UnmanagedType.LPStruct)] 或 ref 关键字。由于 Progress OpenEdge 对外部过程参数数据类型的限制,我无法弄清楚如何传递 System.Guid 的引用,因此我执行了 .NET Guid 的按字节复制并通过 MEMPTR 传递。我很抱歉在这里如此依赖 .NET。
这是一个获取提供的已知文件夹 GUID 的工作示例,以及获取 Documents 文件夹的用法:
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.
【讨论】: