clang [bcc32c Warning] redeclaration should not add 'dllexport' attribute - clang

I am creating a DLL and exporting a SimpleMAPI DLL function and one of the functions signature is as following:
extern "C" ULONG __declspec(dllexport) WINAPI MAPISendMail(LHANDLE lhSession, ULONG_PTR ulUIParam, lpMapiMessage lpMessage, FLAGS flFlags, ULONG ulReserved);
I am using C++ Builder, using clang compiler. Compiler issues warning:
[bcc32c Warning]: redeclaration of 'MAPISendMail' should not add 'dllexport' attribute mapi.h(262): previous declaration is here
It compiles and works, but I am bothered by this warning. Can it be avoided?

As #RemyLebeau pointed out, the warnings happened because I included <mapi.h> header.
If MAPI DLL is being created (creating your own DLL that other programs will use or exporting MAPI functions), so if one is implementing MAPI support in their own program, then the required structures and #define are copied from the original mapi.h file into a custom header file which is then included. #define such as FLAGS or MapiMessage struct.
If MAPI is being used (so using calling MAPI functions from other DLL, or other programs) then <mapi.h> is included.
So after creating a custom mapidefs.h file which only contained required structures and #define, the problem is now solved.
There is also this example on StackOverflow as well.

Related

How to fix Unresolved external from FILE2.0?

I have some HDF5 C code that I am trying to port to C++Builder. I am getting this error at build time:
[ilink64 Error] Error: Unresolved external 'H5check_version' referenced from D:\DELPHITOOLS\PASHDF\C\WIN64\DEBUG\FILE2.O
H5check_version is included in H5public.h as a macro.
Why does C++Builder not find this?
H5check_version is included in H5public.h as a macro.
If that were true, you would not be getting a linker error, since macros are handled only during the preprocessor stage.
Somewhere in your project, the compiler is seeing a declaration of H5check_version as a function, and your file2 unit is calling it as a function, but the linker can't find the implementation of that function, hence the error.
Your project needs to contain a reference to the appropriate .lib file that either implements the actual function (static linking) or tells the linker which DLL the function is exported from (dynamic linking).
C/C++ is case sensitive, so H5check_version is different from H5Check_version.
AFAIK pascal is not case sensitive at all.
Regards

OmniThreadLibrary C++ builder Build issues

I'v been trying to get OmniThreadLibrary to run in builder, i've built it with all the c++ required files it builds ok but when i use it in an c++ builder app i get a bunch of error messages that look like the following
[bcc32 Error] DSiWin32.hpp(385): E2040 Declaration terminated incorrectly
one points at this line of code in the generated hpp file
static const System::Int8 CSIDL_ADMINTOOLS = System::Int8(0x30);
has anyone had this working in C++ builder or know the best way to resolve these issues
I'm using c++ builder settle and OmniThreadLibrary version 3.06
The Win32 API (and Delphi, for that matter) already declares CSIDL_ADMINTOOLS, Omni should not be declaring it at all. It should be using Delphi's Shlobj unit instead.
The Win32 API declares CSIDL_ADMINTOOLS using a #define statement:
#define CSIDL_ADMINTOOLS 0x0030
So the declaration in Omni's .hpp is getting modified by the C++ preprocessor to this:
static const System::Int8 0x0030 = System::Int8(0x30);
Thus the "Declaration terminated incorrectly" compiler error.
When Delphi code declares something that already exists in C++, it needs to be declared as either {$EXTERNALSYM} or {$NODECLARE} to avoid duplicate declarations, and then optionally use {$HPPEMIT} to output a relevant #include statement in a generated .hpp file. Delphi's units already do that for its Win32 declarations.
If Omni is not already doing that (and the error would suggest it is not) then it needs to be updated accordingly.

JEDI JCL runtime compiler error E2040 when using JclWin32.hpp

I have installed the current stable JEDI Code library in C++ Builder XE3 on Windows 7 x32. It works fine, but only as long as I don't include files like JclFileUtils.hpp which are including JclWin32.hpp. Then I get always the compiler error E2040: "Declaration terminated incorrectly" (in file JclWin32.hpp, line 682, second line in the following code snippet):
#define NetApi32 L"netapi32.dll"
static const System::Int8 CSIDL_PROGRAM_FILESX86 = System::Int8(0x2a);
#define RT_MANIFEST (System::WideChar *)(0x18)
I neither have an idea were this error comes from, nor could I found any hints to this. What could be the cause? Thanks in advance.
I got help and the solution for this problem. Just replace the static const declaration:
static const System::Int8 CSIDL_PROGRAM_FILESX86 = System::Int8(0x2a);
with this macro definition:
#define CSIDL_PROGRAM_FILESX86 0x2a
This is a bug in JclWin32.pas.
In C/C++, the Win32 API declares CSIDL values in Microsoft's shlobj.h header using preprocessor #define statements, eg:
#define CSIDL_PROGRAM_FILESX86 0x002a
After the preprocessor is run and performs #define symbol replacements, the compiler ends up seeing the following invalid declaration in JclWin32.hpp:
static const System::Int8 0x002a = System::Int8(0x2a);
JCL should not be re-declaring CSIDL_PROGRAM_FILESX86 (or any other CSIDL value) at all. It should be either:
using Delphi's own Winapi.ShlObj unit, which already declares CSIDL values.
if not using the Winapi.ShlObj unit, then it should at least be declaring its manual CSIDL values as {$EXTERNALSYM} so they do not appear in the generated JclWin32.hpp file. If needed, JCL can include an {$HPPEMIT '#include <shlobj.h>'} statement to pull in the existing Win32 API declarations for C/C++ projects to use.

How does CLR match the exported names during P/Invoke?

I work on a project that requires .Net interoperability with unmanaged code. I started to work with .Net a couple of weeks ago, though I have a lot of experience with C/C++, and I am surprised how CLR deals with P/Invoke. Here are the details. My colleague wrote this function
__declspec(dllexport) int __stdcall ReadIPWSensor(unsigned int deviceClassId, void *buffer) {...}
and I had to call it from C# module. I imported the function as
[DllImport("ipw", CallingConvention = CallingConvention.StdCall)]
extern static int ReadIPWSensor(uint deviceClassId, IntPtr buffer);
just to find out an exception (System.EntryPointNotFoundException, Unable to find an entry point named 'ReadIPWSensor' in DLL 'ipw'). I used DependencyWalker tool and found that the function was exported as ?ReadIPWSensor##YGHIPAX#Z (my colleague forgot to export it in the DEF file). Just for the quick test (the unmanaged DLL compiles very slowly) I changed my import definition to:
[DllImport("ipw", EntryPoint = "#22", CallingConvention = CallingConvention.StdCall)]
extern static int ReadIPWSensor(uint deviceClassId, IntPtr buffer);
as the ordinal was 22. The test passed successfully with the new import definition.
My first question is: What are the good practices when dealing the mangled function exports? Is it a good practice to use the export ordinals?
In my case I had access to the C++ source code and the DEF file so I added the export and changed back the import definition to
[DllImport("ipw", CallingConvention = CallingConvention.StdCall)]
extern static int ReadIPWSensor(uint deviceClassId, IntPtr buffer);
I knew there is another function we already use in our project and wanted to compare my code with the existing one. The function is defined as
extern "C" __declspec(dllexport) int __stdcall LoadIPWData(void
*buffer)
and is imported as
[DllImport("ipw", CallingConvention = CallingConvention.StdCall)]
extern static int LoadIPWData(IntPtr buffer);
To my surprise DependencyWalker tool shows that the function is exported as _LoadIPWData#4 (my coworker forgot to export it in the DEF file again). However with this function there is no System.EntryPointNotFoundException error. Obviously, the CLR somehow managed to resolve the right name. It seems there is some sort of fallback mechanism that allows CLR to find the right function. I can easily imagine the it sums the sizes of the parameters and is looking for "function_name#the_sum_of_all_parameter_sizes" though it seems quite simplistic.
My second question is: How does CLR match the exported function names during P/Invoke?
In this scenario I think CLR is so clever that it actually hides a bug - LoadIPWData function should be accessible by its name from other unmanaged modules. Maybe I am a bit of paranoid but I prefer to know how actually CLR works. Unfortunately all my google searches on that topic were fruitless.
The pinvoke marshaller has built-in knowledge of a few common DLL export naming schemes. It knows that __cdecl functions often have a leading underscore and that __stdcall in 32-bit mode is commonly decorated with a leading underscore and a trailing #x where x is the size in bytes of the arguments passed on the stack. It also knows that winapi functions are exported with a trailing extra A or W, a naming scheme to distinguish functions that accept strings and for which there's both an ansi and a Unicode version. The corresponding [DllImport] property is CharSet. It just tries them all until it finds a match.
It doesn't know anything about C++ compiler name decoration rules (aka mangling) so that's why you have to use extern "C" to suppress that by hand.

Variants recursively uses itself?

I'm trying to build a debug version of rtl140.bpl to make debugging apps with runtime packages easier. I built the DPK and ran DCC32 on it, and it gets a ways in, then dies.
C:\Program Files (x86)\Embarcadero\RAD Studio\7.0\source\Win32\rtl\sys\Variants.pas(1072) Fatal: F2092 Program or unit 'Variants' recursively uses itself
But looking at Variants.pas, I can't see how. It only uses SysUtils and Types in the interface section, and neither of those use Variants, or use anything that uses Variants.
Does anyone have any idea why this is breaking?
This is one of the main reasons why we (the RAD Studio team) do not recommend rebuilding the core rtl package. It needs to be done very carefully and the units need to be listed in the contains section in a specific order.
Variants is a bit of a "bastard" unit. The compiler has specific knowledge of it such that when it sees the use of the Variant type, it will automatically add Variants to the uses list in order to ensure the actual RTL support for the Variant type is present. System.pas defers most all variant operations to the Variants unit, but since System cannot use any other units other than SysInit (which is also a very special unit), the compiler has to get involved.
At this time, I don't have any specific suggestions to make this work, other than try to rearrange the contains list in the .dpk and try again. Here's the contains list from the rtl.dpk that we used to build that package:
Variants in 'sys\Variants.pas',
VarUtils in 'sys\VarUtils.pas',
SysConst in 'sys\SysConst.pas',
SysUtils in 'sys\SysUtils.pas',
SyncObjs in 'common\SyncObjs.pas',
Types in 'sys\Types.pas',
VCLCom in 'common\VCLCom.pas',
ComConst in 'common\ComConst.pas',
ComObj in 'common\ComObj.pas',
ComObjWrapper in 'common\ComObjWrapper.pas',
RTLConsts in 'common\RTLConsts.pas',
Contnrs in 'common\Contnrs.pas',
ConvUtils in 'common\ConvUtils.pas',
DateUtils in 'common\DateUtils.pas',
IniFiles in 'common\IniFiles.pas',
Masks in 'common\Masks.pas',
Math in 'common\Math.pas',
Registry in 'common\Registry.pas',
StdConvs in 'common\StdConvs.pas',
StdVCL in 'common\StdVCL.pas',
StrUtils in 'common\StrUtils.pas',
TypInfo in 'common\TypInfo.pas',
VarConv in 'common\VarConv.pas',
VarCmplx in 'common\VarCmplx.pas',
Classes in 'common\Classes.pas',
MaskUtils in 'common\MaskUtils.pas',
HelpIntfs in 'common\HelpIntfs.pas',
ScktComp in 'common\ScktComp.pas',
AccCtrl in 'win\AccCtrl.pas',
AclAPI in 'win\AclAPI.pas',
ActiveX in 'win\ActiveX.pas',
ComSvcs in 'win\ComSvcs.pas',
ADOInt in 'win\ADOInt.pas',
AspTlb in 'win\AspTlb.pas',
COMAdmin in 'win\COMAdmin.pas',
CommCtrl in 'win\CommCtrl.pas',
CommDlg in 'win\CommDlg.pas',
Cpl in 'win\Cpl.pas',
DDEml in 'win\DDEml.pas',
Dlgs in 'win\Dlgs.pas',
DwmApi in 'win\DwmApi.pas',
FlatSB in 'win\FlatSB.pas',
ImageHlp in 'win\ImageHlp.pas',
Imm in 'win\Imm.pas',
Isapi in 'win\Isapi.pas',
Isapi2 in 'win\Isapi2.pas',
LZExpand in 'win\LZExpand.pas',
Mapi in 'win\Mapi.pas',
Messages in 'win\Messages.pas',
MMSystem in 'win\MMSystem.pas',
msxml in 'win\msxml.pas',
Mtx in 'win\Mtx.pas',
MultiMon in 'win\MultiMon.pas',
Nb30 in 'win\Nb30.pas',
Ns30Fix in 'win\Ns30Fix.pas',
Ns35Fix in 'win\Ns35Fix.pas',
Ns36Fix in 'win\Ns36Fix.pas',
Nsapi in 'win\Nsapi.pas',
ObjComAuto in 'common\ObjComAuto.pas',
ObjAuto in 'common\ObjAuto.pas',
OleDB in 'win\OleDB.pas',
OleDlg in 'win\OleDlg.pas',
OpenGL in 'win\OpenGL.pas',
oleacc in 'win\oleacc.pas',
Penwin in 'win\Penwin.pas',
PsAPI in 'win\PsAPI.pas',
RegStr in 'win\RegStr.pas',
RichEdit in 'win\RichEdit.pas',
ShellAPI in 'win\ShellAPI.pas',
SHFolder in 'win\SHFolder.pas',
ShlObj in 'win\ShlObj.pas',
ShLwApi in 'win\ShLwApi.pas',
StrHlpr in 'sys\StrHlpr.pas',
TlHelp32 in 'win\TlHelp32.pas',
UrlMon in 'win\UrlMon.pas',
UxTheme in 'win\UxTheme.pas',
VarHlpr in 'sys\VarHlpr.pas',
WideStrings in 'common\WideStrings.pas',
WideStrUtils in 'common\WideStrUtils.pas',
windows in 'win\windows.pas',
winInet in 'win\winInet.pas',
Winsafer in 'win\Winsafer.pas',
WinSock in 'win\WinSock.pas',
winSpool in 'win\winSpool.pas',
winSvc in 'win\winSvc.pas',
CorError in 'win\CorError.pas',
CorHdr in 'win\CorHdr.pas',
Cor in 'win\Cor.pas',
DXTypes in 'win\DXTypes.pas',
DXFile in 'win\DXFile.pas',
DxDiag in 'win\DxDiag.pas',
D3DX8 in 'win\D3DX8.pas',
D3DX9 in 'win\D3DX9.pas',
Direct3D in 'win\Direct3D.pas',
Direct3D8 in 'win\Direct3D8.pas',
DX7toDX8 in 'win\DX7toDX8.pas',
Direct3D9 in 'win\Direct3D9.pas',
DirectDraw in 'win\DirectDraw.pas',
DirectShow9 in 'win\DirectShow9.pas',
DirectInput in 'win\DirectInput.pas',
DirectSound in 'win\DirectSound.pas',
DirectPlay8 in 'win\DirectPlay8.pas',
DirectMusic in 'win\DirectMusic.pas',
WMF9 in 'win\WMF9.pas',
ZLibConst in 'common\ZLibConst.pas',
ZLib in 'common\ZLib.pas',
Character in 'common\Character.pas',
Generics.Defaults in 'common\Generics.Defaults.pas',
Generics.Collections in 'common\Generics.Collections.pas',
Rtti in 'common\Rtti.pas',
TimeSpan in 'common\TimeSpan.pas',
Diagnostics in 'common\Diagnostics.pas',
AnsiStrings in 'common\AnsiStrings.pas',
TpcShrd in 'win\TpcShrd.pas',
RtsCom in 'win\RtsCom.pas',
MsInkAut in 'win\MsInkAut.pas',
MsInkAut15 in 'win\MsInkAut15.pas',
Manipulations in 'win\Manipulations.pas',
IOUtils in 'common\IOUtils.pas',
D2D1 in 'win\D2D1.pas',
DxgiFormat in 'win\DxgiFormat.pas',
Wincodec in 'win\Wincodec.pas',
KnownFolders in 'win\KnownFolders.pas',
ObjectArray in 'win\ObjectArray.pas',
PropSys in 'win\PropSys.pas',
PropKey in 'win\PropKey.pas',
StructuredQuery in 'win\StructuredQuery.pas',
StructuredQueryCondition in 'win\StructuredQueryCondition.pas';
Program or unit 'Variants' recursively uses itself
is often caused by having the path to source/win32/rtl/sys in the Library search path of the project you are trying to build.
Goto (Delpi_Path)\source\Win32\rtl\sys, and then rename "Variants.pas" to anything, e.g "Variants.sav", then all are OK.
It's because Delphi can't find "Variants.pas" anywhere now, but it still can find a compiled dcu file named "Variants.dcu" somewhere, so that's it.
P.S. If Delphi can't find the dcu too, you should manually serch for "Variants.dcu", and then add the path in the "Tools -> Options" menu.

Resources