I'm trying to call an OpenCobol file handling routine from a program written in C using the Dev C++ IDE (they're free and I like them).
The Cobol environment generates a DLL when you compile the code as a module so I was hoping that I could just use the normal methods of calling the code (see below). If compiled and run as below I get the error message "libcob: cob_init() has not been called", however, after including the header and the library in the relevant places and uncommenting the sections in the code I'm getting an "undefined reference to _imp_cob_init" message.
I'm obviously missing something simple. Any help would be appreciated.
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;
}
You've mixed the calls and now have partially use of the COBOL runtime library libcob and partially not using it. Normally you do one of the following (most times the third option):
just use the generated COBOL dll as "normal" dll and don't care about any cleanup
use a "clean" runtime initialization and cleanup
use option and leave loading of COBOL modules to libcob
Option 1: "simplest solution" - use COBOL module, no cleanup
Remove the comments for libcob in your C source.
Compile your COBOL module with
cobc -fimplicit-init filehandler.cob
, this way the initialization is done automatically.Note: This leads to a minimal additional startup time for the module load (how much depends on the version of libcob in use, but it isn't much in general).
Possible issue: You don't have an option to cleanup the COBOL parts, they will be still active after you finished (and even closed) the module handle.
Option 2: "cleaner solution but still involving system specific parts for module load"
Compile your COBOL module without
-fimplicit-init
and change your code toor (if you really want to exit after the COBOL call) changing the last code part to:
Important: You now need both including
libcob.h
for the C compiler to know the function declarations and link to the libcob library (most likely by adding-lcob
to compiler options in DevC++ (otherwise you'll get the "undefined reference" message from the C linker).Option 3: "clean solution leaving everything COBOL to libcob"
Obviously you have to link against libcob in this case, too.
The only thing that is "missing" in the code is the path to "filehandler.dll". libcob tries the current path first, so if your module is there you don't need to tweak it.
Specify the module lookup path via
set COB_LIBRARY_PATH=F:\source\filehandler\bin
outside of your application.If you really want to hardwire it in your application and have a very recent version (read as "nearly current development snapshot") you can do so by calling
cob_setenv("COB_LIBRARY_PATH", "F:\\source\\filehandler\\bin", 1);
- doing so withsetenv()
orputenv()
may work (but this is highly dependent on the C runtime library used for your program and for libcob.If possible I'd allways suggest (for a "current" version of GnuCOBOL) to use a runtime configuration file and specify its path with
set COB_RUNTIME_CONFIG=X:\PATH\TO\filehandler.cfg
or the environment functions outlined above.And I'd always suggest to switch to a recent version of GnuCOBOL if you use anything older than GnuCOBOL 2.2rc, but this is a different issue...