1

我正在尝试从使用 Dev C++ IDE 用 C 编写的程序调用 OpenCobol 文件处理例程(它们是免费的,我喜欢它们)。

当您将代码编译为模块时,Cobol 环境会生成一个 DLL,因此我希望我可以只使用调用代码的常规方法(见下文)。如果按如下方式编译和运行,我会收到错误消息“libcob:cob_init() 尚未被调用”,但是,在相关位置包含标头和库并取消注释代码中的部分后,我得到“未定义”引用 _imp_cob_init" 消息。

我显然错过了一些简单的东西。任何帮助,将不胜感激。

AdyB

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <windows.h>

/*
#ifdef __cplusplus
extern "C" {
#endif
#include "libcob.h"

#ifdef __cplusplus
}
#endif
*/

typedef void (*pFile)(char*);

pFile filehandler=NULL;
char dllpath[256];

int main(int argc, char *argv[])
{
    HINSTANCE hLib;
    char txt[100]="this is a test";

/*  cob_init(0, NULL);*/

    hLib = LoadLibrary("F:\\source\\filehandler\\bin\\filehandler.dll");
    if (!hLib)
    {
      perror("Error loading dll");
      exit(1);
    }

    GetModuleFileName((HMODULE)hLib, (LPTSTR)dllpath, sizeof(dllpath));
    printf("Opened %s\n\n", dllpath);

    filehandler = (pFile)GetProcAddress((HMODULE)hLib, "filehandler");
    if (!filehandler)
    {
      perror("Can't find dll function");
      exit(1);
    }

    filehandler(txt);

    return 0;
}
4

1 回答 1

2

您已经混合了调用,现在部分使用了 COBOL 运行时库 libcob,部分未使用它。通常您会执行以下操作之一(大多数时候是第三个选项):

  1. 只需将生成的 COBOL dll 用作“普通”dll,不关心任何清理

  2. 使用“干净”的运行时初始化和清理

  3. 使用选项并将 COBOL 模块的加载留给 libcob

选项 1:“最简单的解决方案” - 使用 COBOL 模块,无需清理

删除 C 源代码中对 libcob 的注释。

用 编译你的 COBOL 模块cobc -fimplicit-init filehandler.cob,这样初始化是自动完成的。

注意:这会导致模块加载的额外启动时间最少(多少取决于正在使用的 libcob 版本,但通常不会太多)。

可能的问题:您没有清理 COBOL 部件的选项,在您完成(甚至关闭)模块句柄后它们仍将处于活动状态。

选项 2:“更清洁的解决方案,但仍涉及模块加载的系统特定部分”

编译您的 COBOL 模块,-fimplicit-init并将您的代码更改为

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <windows.h>

#ifdef __cplusplus
extern "C" {
#endif
#include "libcob.h"

#ifdef __cplusplus
}
#endif

typedef void (*pFile)(char*);

pFile filehandler=NULL;
char dllpath[256];

int main(int argc, char *argv[])
{
    HINSTANCE hLib;
    char txt[100]="this is a test";

#if !defined PASS_COMMAND_LINE_TO_COBOL
    cob_init(0, NULL);     /* initialization of COBOL runtime, no command line passed */
#else
    cob_init(argc, argv);  /* initialization of COBOL runtime, complete command line passed */
#endif

    hLib = LoadLibrary("F:\\source\\filehandler\\bin\\filehandler.dll");
    if (!hLib)
    {
      perror("Error loading dll");
      exit(1);
    }

    GetModuleFileName((HMODULE)hLib, (LPTSTR)dllpath, sizeof(dllpath));
    printf("Opened %s\n\n", dllpath);

    filehandler = (pFile)GetProcAddress((HMODULE)hLib, "filehandler");
    if (!filehandler)
    {
      perror("Can't find dll function");
      exit(1);
    }

    filehandler(txt);

#if defined (cob_c8_ptr) /* hack for checking if you use a 2.x+ version, not *really* needed in this case */
    cob_tidy;  /* finalizing of COBOL runtime (OC/GC function) */
#else
    cobtidy;   /* finalizing of COBOL runtime (MF compatibility function name available since OpenCOBOL 1.1 released Feb 2009 [still available (as define) in 2.x+ version]) */
#endif

    return 0;
}

或(如果您真的想在 COBOL 调用后退出)将最后一个代码部分更改为:

    int cob_return_int = filehandler(txt);
    cob_stop_run (cob_return_int);

重要提示:您现在需要同时包含libcob.hC 编译器以了解函数声明链接到 libcob 库(很可能通过添加-lcob到 DevC++ 中的编译器选项(否则您将从 C 链接器获得“未定义引用”消息)。

选项 3:“将所有 COBOL 都留给 libcob 的干净解决方案”

显然,在这种情况下,您也必须链接到 libcob。

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>

#ifdef __cplusplus
extern "C" {
#endif
#include "libcob.h"

#ifdef __cplusplus
}
#endif

int main(int argc, char *argv[])
{
    cob_call_union  filehandler_module;
    int     cob_return_int;
    char txt[100]="this is a test";

    /* initialization of COBOL runtime, complete command line passed */
    cob_init(argc, argv);

    /* search and load a function pointer for program-id "filehandler" in a module called "filehandler" */
    filehandler_module.funcvoid = cob_resolve ("filehandler");
    if (filehandler_module.funcvoid == NULL) {
        /* this will display the error and return with 1, as your old code did */
        cob_call_error ();
        /* if you just want the error text in a local buffer call `cob_resolve_error` instead */
    }

    /* calling the COBOL module "filehandler" and store its return-code in cob_return_int */
    cob_return_int = filehandler_module.funcint(txt);

    /* NOTE: you may call additional COBOL modules (or the same with a different option) here, maybe depending on `cob_return_int` */

    cob_tidy;  /* finalizing the COBOL runtime */

    /* NOTE: more code goes here, likely handling `cob_return_int` */

    return 0;
}

代码中唯一“缺少”的是“filehandler.dll”的路径。libcob 首先尝试当前路径,因此如果您的模块在那里,则无需调整它。

set COB_LIBRARY_PATH=F:\source\filehandler\bin通过应用程序外部指定模块查找路径。

如果你真的想在你的应用程序中硬连线它并且有一个非常新的版本(读作“近乎当前的开发快照”)你可以通过调用来做到这一点cob_setenv("COB_LIBRARY_PATH", "F:\\source\\filehandler\\bin", 1);- 这样做setenv()或者putenv() 可能工作(但这高度依赖于 C 运行时库用于您的程序和 libcob。

如果可能的话,我总是建议(对于“当前”版本的 GnuCOBOL)使用运行时配置文件set COB_RUNTIME_CONFIG=X:\PATH\TO\filehandler.cfg并使用上面概述的环境函数指定其路径。

如果您使用比 GnuCOBOL 2.2rc 更旧的任何东西,我总是建议切换到最新版本的 GnuCOBOL,但这是一个不同的问题......

于 2017-08-28T12:05:35.060 回答