I see in the ACUCOBOL-GT docs that it is possible to call C/C functions from COBOL using the CALL statement.
In Windows, I've managed to do this using pure C code that was compiled with gcc. This was done using the version of gcc that ships with MinGW in release 5.1.1 of the Qt framework.
If I try to call functions in a DLL that was compiled with g or cl.exe (the Visual C compiler), I keep hitting the ON EXCEPTION part of my CALL statement. Obviously I'm missing something.
I'm aware of the name-mangling issue with C compilers, and have tried to work around it by using __declspec(dllimport) and __cdecl in the C function declarations. However, this does not resolve the problem.
Can anyone provide a simple example of both C code and compile/link commands, which would allow C library code to be used from ACUCOBOL? And can this only be done using COM DLLs? (That's the one thing I haven't tried, because I don't have a development environment that supports creating COM DLLs.)
I'm interested in doing this both in Windows and Linux, with the current release of ACUCOBOL-GT.
Thank you in advance for any assistance!
#c#C#Linux#Windows#InteroperatingRather than me trying to come up with an artificial example, could you post a simple C file, your compile and link options, and a COBOL program that fails to call the function? I believe I would be able to then modify the source and/or the COBOL program in such a way that COBOL can call the function.
I see in the ACUCOBOL-GT docs that it is possible to call C/C functions from COBOL using the CALL statement.
In Windows, I've managed to do this using pure C code that was compiled with gcc. This was done using the version of gcc that ships with MinGW in release 5.1.1 of the Qt framework.
If I try to call functions in a DLL that was compiled with g or cl.exe (the Visual C compiler), I keep hitting the ON EXCEPTION part of my CALL statement. Obviously I'm missing something.
I'm aware of the name-mangling issue with C compilers, and have tried to work around it by using __declspec(dllimport) and __cdecl in the C function declarations. However, this does not resolve the problem.
Can anyone provide a simple example of both C code and compile/link commands, which would allow C library code to be used from ACUCOBOL? And can this only be done using COM DLLs? (That's the one thing I haven't tried, because I don't have a development environment that supports creating COM DLLs.)
I'm interested in doing this both in Windows and Linux, with the current release of ACUCOBOL-GT.
Thank you in advance for any assistance!
#c#C#Linux#Windows#InteroperatingSure. First of all I'll show what works. Here is a C file called mydll.c:
#include <string.h>
int multiply_long(long x, long y, long *z)
{
*z = x * y;
return 0;
}
int multiply_double(double *x, double *y, double *z)
{
*z = (*x) * (*y);
return 0;
}
int get_string(char *s, long len)
{
strncpy(s, "Hello, world! This is a string to be copied.", len);
return 0;
}
=====
Here is a COBOL program called dlltest.cbl:
IDENTIFICATION DIVISION.
PROGRAM-ID. DLLTEST.
DATA DIVISION.
WORKING-STORAGE SECTION.
77 XL SIGNED-LONG.
77 YL SIGNED-LONG.
77 ZL SIGNED-LONG.
77 XD DOUBLE.
77 YD DOUBLE.
77 ZD DOUBLE.
77 STR PIC X(80).
77 LEN SIGNED-LONG.
PROCEDURE DIVISION.
CALL "mydll.dll"
MOVE 2 TO XL
MOVE 3 TO YL
CALL "multiply_long"
USING BY VALUE XL, YL
BY REFERENCE ZL
GIVING RETURN-CODE
END-CALL
DISPLAY XL "x" YL "=" ZL
MOVE 1.2 TO XD,
MOVE 3.4 TO YD
* DOUBLE data items cannot be passed BY VALUE.
CALL "multiply_double"
USING BY REFERENCE XD, YD, ZD
GIVING RETURN-CODE
END-CALL
DISPLAY XD "x" YD "=" ZD
MOVE ZEROS TO STR
MOVE 13 TO LEN
CALL "get_string"
USING BY REFERENCE STR
BY VALUE LEN
GIVING RETURN-CODE
END-CALL
DISPLAY STR(1:LEN)
ACCEPT OMITTED
CANCEL "mydll.dll"
GOBACK.
=====
I tested the code shown above in Windows 7 as follows:
ACUCOBOL-GT 8.1.3.1 is already installed.
Install gcc (e.g., the version of gcc that ships in the MinGW flavor of Qt 5.1).
Set the environment variables MINGW and ACU to point to the relevant bin directories.
Open a command prompt, and execute:
%MINGW%\\gcc -c mydll.c
%MINGW%\\gcc -shared -o mydll.dll mydll.o
�U%\\ccbl32 dlltest.cbl
�U%\\wrun32 dlltest
The output is as expected.
=====
I will paste in my C example next.
I see in the ACUCOBOL-GT docs that it is possible to call C/C functions from COBOL using the CALL statement.
In Windows, I've managed to do this using pure C code that was compiled with gcc. This was done using the version of gcc that ships with MinGW in release 5.1.1 of the Qt framework.
If I try to call functions in a DLL that was compiled with g or cl.exe (the Visual C compiler), I keep hitting the ON EXCEPTION part of my CALL statement. Obviously I'm missing something.
I'm aware of the name-mangling issue with C compilers, and have tried to work around it by using __declspec(dllimport) and __cdecl in the C function declarations. However, this does not resolve the problem.
Can anyone provide a simple example of both C code and compile/link commands, which would allow C library code to be used from ACUCOBOL? And can this only be done using COM DLLs? (That's the one thing I haven't tried, because I don't have a development environment that supports creating COM DLLs.)
I'm interested in doing this both in Windows and Linux, with the current release of ACUCOBOL-GT.
Thank you in advance for any assistance!
#c#C#Linux#Windows#InteroperatingThere is no need to compile the C code shown above as C . However, my goal is eventually to write a C wrapper that provides a C interface to a library written in C .
=====
A first simple-minded attempt to compile the C code as C is:
%MINGW%\\g -c -x c mydll.c
%MINGW%\\g -shared -o mydll.dll mydll.o
�U%\\ccbl32 dlltest.cbl
�U%\\wrun32 dlltest
=====
This yields the following error from wrun32:
---------------------------
Error
---------------------------
multiply_long: Program missing or inaccessible
COBOL error at 000025 in dlltest
---------------------------
OK
---------------------------
I see in the ACUCOBOL-GT docs that it is possible to call C/C functions from COBOL using the CALL statement.
In Windows, I've managed to do this using pure C code that was compiled with gcc. This was done using the version of gcc that ships with MinGW in release 5.1.1 of the Qt framework.
If I try to call functions in a DLL that was compiled with g or cl.exe (the Visual C compiler), I keep hitting the ON EXCEPTION part of my CALL statement. Obviously I'm missing something.
I'm aware of the name-mangling issue with C compilers, and have tried to work around it by using __declspec(dllimport) and __cdecl in the C function declarations. However, this does not resolve the problem.
Can anyone provide a simple example of both C code and compile/link commands, which would allow C library code to be used from ACUCOBOL? And can this only be done using COM DLLs? (That's the one thing I haven't tried, because I don't have a development environment that supports creating COM DLLs.)
I'm interested in doing this both in Windows and Linux, with the current release of ACUCOBOL-GT.
Thank you in advance for any assistance!
#c#C#Linux#Windows#InteroperatingA second simple-minded attempt in Visual Studio 2013 RC..
In Visual Studio 2013 RC:
File > New Project > Visual C > Win32 > Win32 Project.
As the project name, enter "mydll".
Click OK > Next, and select DLL as the application type.
Click Finish.
Paste the following code into the stub file mydll.cpp.
By way of example, the implementation of the get_string() function below uses the C string type.
=====
// mydll.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include <string>
#include <cstring>
int multiply_long(long x, long y, long *z)
{
*z = x * y;
return 0;
}
int multiply_double(double *x, double *y, double *z)
{
*z = (*x) * (*y);
return 0;
}
int get_string(char *s, long len)
{
std::string cpp_str = "Hello, world! This is a string to be copied.";
char *c_str = new char[cpp_str.length() 1];
strncpy_s(s, len, c_str, len);
return 0;
}
=====
Click Project > Build to build the DLL.
Copy the DLL to the folder containing the COBOL test program.
Compile and run the COBOL program with:
�U%\\ccbl32 dlltest.cbl
�U%\\wrun32 dlltest
The same error as before occurs in wrun32:
---------------------------
Error
---------------------------
multiply_long: Program missing or inaccessible
COBOL error at 000025 in dlltest
---------------------------
OK
---------------------------
I see in the ACUCOBOL-GT docs that it is possible to call C/C functions from COBOL using the CALL statement.
In Windows, I've managed to do this using pure C code that was compiled with gcc. This was done using the version of gcc that ships with MinGW in release 5.1.1 of the Qt framework.
If I try to call functions in a DLL that was compiled with g or cl.exe (the Visual C compiler), I keep hitting the ON EXCEPTION part of my CALL statement. Obviously I'm missing something.
I'm aware of the name-mangling issue with C compilers, and have tried to work around it by using __declspec(dllimport) and __cdecl in the C function declarations. However, this does not resolve the problem.
Can anyone provide a simple example of both C code and compile/link commands, which would allow C library code to be used from ACUCOBOL? And can this only be done using COM DLLs? (That's the one thing I haven't tried, because I don't have a development environment that supports creating COM DLLs.)
I'm interested in doing this both in Windows and Linux, with the current release of ACUCOBOL-GT.
Thank you in advance for any assistance!
#c#C#Linux#Windows#InteroperatingNext I tried decorating the function signatures with __declspec(dllexport) and __cdecl. The Visual Studio version of the mydll.cpp file then becomes:
// mydll.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include <string>
#include <cstring>
__declspec(dllexport) int __cdecl multiply_long(long x, long y, long *z)
{
*z = x * y;
return 0;
}
__declspec(dllexport) int __cdecl multiply_double(double *x, double *y, double *z)
{
*z = (*x) * (*y);
return 0;
}
__declspec(dllexport) int __cdecl get_string(char *s, long len)
{
std::string cpp_str = "Hello, world! This is a string to be copied.";
char *c_str = new char[cpp_str.length() 1];
strncpy_s(s, len, c_str, len);
return 0;
}
=====
Build the DLL in Visual Studio.
Copy it to the directory containing the COBOL test program.
Execute:
�U%\\ccbl32 dlltest.cbl
�U%\\wrun32 dlltest
The error is the same as before.
Thank you for your help with this!
I see in the ACUCOBOL-GT docs that it is possible to call C/C functions from COBOL using the CALL statement.
In Windows, I've managed to do this using pure C code that was compiled with gcc. This was done using the version of gcc that ships with MinGW in release 5.1.1 of the Qt framework.
If I try to call functions in a DLL that was compiled with g or cl.exe (the Visual C compiler), I keep hitting the ON EXCEPTION part of my CALL statement. Obviously I'm missing something.
I'm aware of the name-mangling issue with C compilers, and have tried to work around it by using __declspec(dllimport) and __cdecl in the C function declarations. However, this does not resolve the problem.
Can anyone provide a simple example of both C code and compile/link commands, which would allow C library code to be used from ACUCOBOL? And can this only be done using COM DLLs? (That's the one thing I haven't tried, because I don't have a development environment that supports creating COM DLLs.)
I'm interested in doing this both in Windows and Linux, with the current release of ACUCOBOL-GT.
Thank you in advance for any assistance!
#c#C#Linux#Windows#InteroperatingGot it. First, I only teseted this with Visual Studio. I am using VS2012, but the version you use should be the same.
Visual Studio comes with a utility called DUMPBIN.EXE, which can show you what symbols are exported from a DLL. Since I didn't use gcc, I don't know what it does, but apparently (as on Linux) it exports all functions. So MYDLL.DLL built from gcc (as C) should have the three functions exported.
When using VS, the __declspec(dllexport) is certainly required. Without it, the functions are not exported, and so not visible. The MYDLL.DLL built with VS (before adding the __declspec(dllexport) shows no functions visible, and so of course the runtime can't find them.
Adding the __declspec(dllexport), rebuilding, and again running dumpbin shows that the function names are mangled:
$ dumpbin /exports mydll.dll
Microsoft (R) COFF/PE Dumper Version 10.00.40219.01
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file mydll.dll
File Type: DLL
Section contains the following exports for MyDll.dll
00000000 characteristics
525ED4A3 time date stamp Wed Oct 16 11:02:11 2013
0.00 version
1 ordinal base
3 number of functions
3 number of names
ordinal hint RVA name
1 0 0001118B ?get_string@@YAHPADJ@Z = @ILT 390(?get_string@@YAHPADJ@Z)
2 1 00011195 ?multiply_double@@YAHPAN00@Z = @ILT 400(?multiply_double@@YAHPAN00@Z)
3 2 00011168 ?multiply_long@@YAHJJPAJ@Z = @ILT 355(?multiply_long@@YAHJJPAJ@Z)
Summary
1000 .data
1000 .idata
3000 .rdata
1000 .reloc
1000 .rsrc
7000 .text
10000 .textbss
The __cdecl addition you made does nothing to the names. That just specifies the calling convention (which is important!, but not yet). Instead, you need to make sure the names are not mangled. The way I found to do this is to surround the majority of the file with extern "C":
extern "C" {
__declspec(dllexport) int multiply_long(long x, long y, long *z)
{
*z = x * y;
return 0;
}
[snip]
return 0;
} // end of function get_string
} // matches extern "C" above
Now when I build the dll and run the COBOL program, I get an assertion failure because the length you pass to get_string() is too small for the string you are trying to copy to the buffer. But the other two functions show the expected results.
So I believe this answers your question.
Note that extern "C"{} should also work with gcc, as this is part of the C standard.
I see in the ACUCOBOL-GT docs that it is possible to call C/C functions from COBOL using the CALL statement.
In Windows, I've managed to do this using pure C code that was compiled with gcc. This was done using the version of gcc that ships with MinGW in release 5.1.1 of the Qt framework.
If I try to call functions in a DLL that was compiled with g or cl.exe (the Visual C compiler), I keep hitting the ON EXCEPTION part of my CALL statement. Obviously I'm missing something.
I'm aware of the name-mangling issue with C compilers, and have tried to work around it by using __declspec(dllimport) and __cdecl in the C function declarations. However, this does not resolve the problem.
Can anyone provide a simple example of both C code and compile/link commands, which would allow C library code to be used from ACUCOBOL? And can this only be done using COM DLLs? (That's the one thing I haven't tried, because I don't have a development environment that supports creating COM DLLs.)
I'm interested in doing this both in Windows and Linux, with the current release of ACUCOBOL-GT.
Thank you in advance for any assistance!
#c#C#Linux#Windows#InteroperatingIt does work with g as well. I had tried using extern "C", but must have made some other error. Your code sample did the trick, which gets me past what had been a total roadblock. Thank you!