Delphi Library Memory Manager Strange - c++

I got an error from DLL that compiled from Delphi using in c++ run in multithread
Delphi (Architect 10.3 Version 26.0.32429.4364) Library Code
library Project1;
uses
System.SysUtils,
System.Classes;
{$R *.res}
procedure __test(size: integer); cdecl;
var
data : AnsiString;
begin
SetLength(data, size);
end;
exports
__test;
begin
end.
C++ (Viausl Studio 2019) Load Library And Using Multithread
// ConsoleApplication1.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <iostream>
#include <Windows.h>
#include <thread>
typedef void(__cdecl *functest)(int);
HINSTANCE hInst = nullptr;
functest test;
void thread_loop() {
while (1) {
test(10);
}
}
int main()
{
hInst = LoadLibraryA("Project1.dll");
if (!hInst) {
return 0;
}
test = (functest)GetProcAddress(hInst, "__test");
if (!test) {
return 0;
}
std::thread t1(thread_loop);
std::thread t2(thread_loop);
return 1;
I got an exception but it should not get any exception because that is procedure variable which was not shared

Set IsMultiThread to True in your Delphi DLL's main block. Delphi's default memory manager assumes single-threaded mode by default.
begin
IsMultiThread := True;
end.

Related

Access violation when invoking a C++ DLL from Delphi

I write a Unicode DLL in Visual C++ 6.0. Then try to invoke the DLL function from Delphi XE3.
When I debug in Delphi, when step over the line to invoke the DLL function, I will always get an Access violation exception.
However, when I debug in Visual C++, I can see all parameters passed from Delphi are correct and I can step over all codelines without any exceptions.
If running outside the debugger, then I will not see any "access violation exceptions.
I try many methods but still cannot figure out how to eliminate the exception when debuggin in Delphi.
Below is the code in Visual C++ 6.0 part:
TestDLL.cpp:
extern "C" VOID WINAPI Test(CONST MESSAGEPROC lpMessageProc, LPVOID lParam)
{
if (lpMessageProc != NULL)
(*lpMessageProc)(1500, (const LPVOID)(LPCTSTR)CString((LPCSTR)IDS_MYTEST), lParam);
/*
if (lpMessageProc != NULL)
(*lpMessageProc)(1500, (const LPVOID)(LPCTSTR)CString(_T("Test")), lParam);*/
}
TestDLL.h:
// TestDLL.h : main header file for the TESTDLL DLL
//
#if !defined(AFX_TESTDLL_H__38054A53_5CEE_4ABF_9BA8_BCE427FCB8E1__INCLUDED_)
#define AFX_TESTDLL_H__38054A53_5CEE_4ABF_9BA8_BCE427FCB8E1__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file for PCH
#endif
#include "resource.h" // main symbols
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef BOOL (CALLBACK* MESSAGEPROC)(CONST DWORD dwMessageId, CONST LPVOID lp, LPVOID lParam);
VOID WINAPI Test(CONST MESSAGEPROC lpMessageProc, LPVOID lParam);
#ifdef __cplusplus
}
#endif
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_TESTDLL_H__38054A53_5CEE_4ABF_9BA8_BCE427FCB8E1__INCLUDED_)
Below is the codes in Delphi XE3 part:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
public
{ Public declarations }
end;
PForm1 = ^TForm1;
TMessageProc = function (const dwMessageId: DWORD; const lp: Pointer; lParam: Pointer): BOOL; stdcall;
{$EXTERNALSYM TMessageProc}
var
Form1: TForm1;
procedure Test(const lpMessageProc: TMessageProc; lParam: Pointer); stdcall;
implementation
{$R *.dfm}
procedure Test; external 'TestDLL.dll' index 2;
function MessageProc(const dwMessageId: DWORD; const lp: Pointer; lParam: Pointer): BOOL; stdcall;
begin
Result := True;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Test(MessageProc, #Self); // <---- This code line will cause "access violation
end;
I belive the problem occurs in DLL test function, when it try to load string from resource using CString((LPCSTR)IDS_MYTEST). If I change the code to CString(_T("Test")), then problem disappears.
Thanks
As you surmised, this statement will not work:
CString((LPCSTR)IDS_MYTEST)
Although this constructor of CString does allow you to pass it a resource ID, it will try to find the resource in the calling process's (ie, the Delphi EXE's) resources, not in the DLL's resources. You need to use the HINSTANCE of the DLL, as provided by the DLL's DllMain(), when loading strings from the DLL's resources. You can use the CString::LoadString() method for that, eg:
HINSTANCE hInst;
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
hInst = hinstDLL;
return TRUE;
}
extern "C" VOID WINAPI Test(CONST MESSAGEPROC lpMessageProc, LPVOID lParam)
{
if (lpMessageProc != NULL)
{
CString str;
str.LoadString(hInst, IDS_MYTEST);
(*lpMessageProc)(1500, (LPCTSTR)str, lParam);
}
}
I finally figure out this is a bug of MFC codes(VC6.0 version).
I don't know if I can post MFC source codes so I will just paste the function headers and related parts only.
In Microsoft Visual Studio\VC98\MFC\SRC\STRCORE.CPP, we can see the following 3 functions:
//////////////////////////////////////////////////////////////////////////////
// More sophisticated construction
CString::CString(LPCTSTR lpsz) // Function 1
{
Init();
if (lpsz != NULL && HIWORD(lpsz) == NULL)
{
UINT nID = LOWORD((DWORD)lpsz);
if (!LoadString(nID))
TRACE1("Warning: implicit LoadString(%u) failed\n", nID);
}
else
{
// Construct string normally
}
}
/////////////////////////////////////////////////////////////////////////////
// Special conversion constructors
#ifdef _UNICODE
CString::CString(LPCSTR lpsz) // Function 2
{
// Construct string normally
}
#else //_UNICODE
CString::CString(LPCWSTR lpsz) // Function 3
{
// Construct string normally
}
#endif //!_UNICODE
As we can see in the above code snippet, only function 1 contains codes that will take special process on lpsz and check if it is a string resource ID, if yes, then load the string from the resource. Both function 2 & 3 have no such special processes.
When we create a project in VS6, the default settings for a project is _MBCS, in such a case, function 1 will become
CString::CString(LPCSTR lpsz)
so CString((LPCSTR)nResID) will actually invoke function 1 and load string resource properly.
Function 2 will be disabled since _UNICODE is not defined. And function 3 works with wide char strings.
Therefore, for _MBCS project, everything works perfectly and consistently with the MSDN document.
However, when I change _MBCS to _UNICODE, function 1 will become
CString::CString(LPCWSTR lpsz)
Fucntion 2 will be enabled and function 3 will be disabled.
So CString((LPCSTR)nResID) will actually invoke function 2, which does NOT have special process to load string resource, which makes the problem.
There are two solutions for this problem:
Always use CString((LPCTSTR)nResID) instead of CString((LPCSTR)nResID) to load a string from resource. However, this usage is inconsistent with MSDN document so we have to call it as an undocumented usage.
Always use LoadString to load a string resource.
Though solution 1 is a little simpler, it is an undocumented usage so I finally opt solution 2 to solve my problem.
Many thanks to all your helps in solving this issue.

Error using library functions of cygwin compiled dll in visual studio

I am trying to call cygwin compiled dll in wisual studio environment.
If I compile dll which have function without any library (just return any number),
it works ok, but if I call for example stdio.h, and function with writing file, or just printf function, does not work ( in case of printf function has exited with code 1536).
#include <stdio.h>
int myfunc()
{
char* strtxt = "test";
FILE *hF = fopen( "Newlogtst.txt", "w" );
if(hF == 0)
{
return 5;
}
fputs( (const char*)strtxt, hF );
fclose(hF);
return 1;
}
int tst()
{
return 25;
}
function tst works ok, function myfunc make empty file Newlogtst.txt and shows exception .
`
Exception thrown at 0x6113333A (cygwin1.dll) in CygwinDlltest.exe:
0xC0000005: Access violation reading location 0x004E0059.
If there is a handler for this exception, the program may be safely
continued.
`
in visual studio I am using this code
#include <windows.h>
typedef int (*PFN_HELLO)();
typedef void (*PFN_CYGWIN_DLL_INIT)();
int main()
{
PFN_HELLO func;
HMODULE hLib, h = LoadLibrary(TEXT("C:\\cygwin\\bin\\cygwin1.dll"));
PFN_CYGWIN_DLL_INIT init = (PFN_CYGWIN_DLL_INIT) GetProcAddress(h,"cygwin_dll_init");
init();
hLib = LoadLibrary (TEXT("C:\\Cygwin\\home\\azatyan\\TestDynamicLink\\mydll.dll"));
func = (PFN_HELLO) GetProcAddress (hLib, "myfunc");
return func();
}
please help what should I do to use library functions.
You don't check the returncode of GetProcAddress().
If you compile it in C++, the names are mangled differently, (which is why GetprocAddress() will return NULL btw.) because they are different compilers.
If you are just using basic functions like in your example, you should declare them as extern "C" so that they wont get mangled. Also make sure that the __declspec export statement are used correctly when compiling the DLL.

Calling a function from a FORTRAN DLL using C++ code

I want to load a fortran dll in C++ code and call a function in the fortran dll.
Following is the code
SUBROUTINE SUB1()
PRINT *, 'I am a function '
END
After creation of the foo.dll [fotran dll ] this is the folowing C++ code in visual studio 2012 that I have written to load the fortran dll .
and call the function SUB1 in the fortran code
#include <iostream>
#include <fstream>
#include <Windows.h>
using namespace std;
extern "C" void SUB1();
typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO);
int main(void)
{
LoadLibrary(L"foo.dll");
PGNSI pGNSI = (PGNSI) GetProcAddress(GetModuleHandle(TEXT("foo.dll")),"SUB1");
return 0;
}
While running the I am getting the following error:
The program can't start because libgcc_s_dw2-1.dll is missing from your computer.
Try reinstalling the program to fix this problem.
Is this the correct way of calling the dll from C++ ?
I am very new to this fortran dll . Please help me regarding this.
First of all you need to export the function like this...
!fortcall.f90
subroutine Dll1() BIND(C,NAME="Dll1")
implicit none
!DEC$ ATTRIBUTES DLLEXPORT :: Dll1
PRINT *, 'I am a function'
return
end !subroutine Dll1
Create the dll using following command
gfortran.exe -c fortcall.f90
gfortran.exe -shared -static -o foo.dll fortcall.o
After that, place the libgcc_s_dw2-1.dll, libgfortran-3.dll and libquadmath-0.dll in the application path of VS. OR you can add the PATH to environment.
After that, you can call the FORTRAN exposed function from VS like below...
#include <iostream>
#include <Windows.h>
using namespace std;
extern "C" void Dll1();
typedef void(* LPFNDLLFUNC1)();
int main(void)
{
HINSTANCE hDLL;
LPFNDLLFUNC1 lpfnDllFunc1; // Function pointer
hDLL = LoadLibrary(L"foo.dll");
if (hDLL != NULL)
{
lpfnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(hDLL,"Dll1");
if (!lpfnDllFunc1)
{
// handle the error
FreeLibrary(hDLL);
return -1;
}
else
{
// call the function
lpfnDllFunc1();
}
}
return 0;
}

Calling Win32 DLL from C++

I am new to the DLL world. I have been given a Win32 DLL which has a lot of functions. Need to call these DLL functions from C++
I want to call CreateNewScanner which creates a new scanner object and get the results in C++.
Function mentioned in the DLL is:
BOOL CreateNewScanner(NewScanner *newScan);
and NewScanner is a struct, as below,
// Structure NewScanner is defined in "common.h" .
typedef struct{
BYTE host_no; // <- host_no =0
LONG time; // <- command timeout (in seconds)
BYTE status; // -> Host adapter status
HANDLE obj; // -> Object handle for the scanner
}NewScanner;
How will I call this function? Started with C++ and here is what I managed,
#include <iostream>
#include <windows.h>
using namespace std;
int main(){
HINSTANCE hInstance;
if(!(hInstance=LoadLibrary("WinScanner.dll"))){
cout << "could not load library" << endl;
}
/* get pointer to the function in the dll*/
FARPROC handle = GetProcAddress(HMODULE(hInstance), "CreateNewScanner");
if(!handle){
// Handle the error
FreeLibrary(hInstance);
return "-1";
}else{
// Call the function
//How to call here??
}
}
First of all, return "-1" is no good. You are expected to return an integer. So you surely mean return -1.
Now to the question. Instead of declaring the function pointer as FARPROC, it's easier to declare it as a function pointer type.
typedef BOOL (*CreateNewScannerProc)(NewScanner*);
Then call GetProcAddress like this:
HMODULE hlib = LoadLibrary(...);
// LoadLibrary returns HMODULE and not HINSTANCE
// check hlib for NULL
CreateNewScannerProc CreateNewScanner =
(CreateNewScannerProc) GetProcAddress(hlib, "CreateNewScanner");
if (CreateNewScanner == NULL)
// handle error
// now we can call the function
NewScanner newScan;
BOOL retval = CreateNewScanner(&newScan);
Having said all of that, usually a library will come with a header file (yours clearly does so you should include it) and a .lib file for load-time linking. Make sure that you pass the .lib file to your linker and you can simply do this:
#include "NameOfTheHeaderFileGoesHere.h"
....
NewScanner newScan;
BOOL retval = CreateNewScanner(&newScan);
No need to mess around with LoadLibrary, GetProcAddress and so on.
If you want to follow the LoadLibrary/GetProcAddress/FreeLibrary approach, consider the following "code path" (note that if you have the DLL public header file and the corresponding .lib file, just #include the public DLL header, and link with the .lib file, and just use the function whose prototype is defined in the DLL header as you would do with an ordinary C function called from C++ code).
Define a typedef for a pointer to the function exported from the DLL.
Note that the calling convention is specified (usually, Win32 DLLs with pure-C interfaces use __stdcall calling convention):
//
// Prototype of the DLL function, with *calling convention* specified
// (usually it's __stdcall for DLL with pure-C interface).
//
typedef BOOL (__stdcall *CreateNewScannerPtr)(NewScanner *);
Then you try loading the DLL using LoadLibrary:
//
// Try loading the DLL.
//
HMODULE hDll = LoadLibrary(L"WinScanner.dll"); // <--- Note the use of L"..." for Unicode
if (! hDll)
{
.... error
}
Note that the file name of the DLL is a Unicode string (note the L"..." decoration). In general, you should use Unicode in modern C++/Win32 code.
Then you can try getting the function pointer using GetProcAddress:
//
// Try getting the pointer to CreateNewScanner DLL function.
//
auto pCreateNewScanner = reinterpret_cast<CreateNewScannerPtr>
(
GetProcAddress
(
hDll, // DLL handle
"CreateNewScanner" // Function name
)
);
if (! pCreateNewScanner)
{
.... error
// Release the DLL
FreeLibrary(hDll);
// Avoid dangling references
hDll = nullptr;
}
Note that since you are using C++, it's better using C++-style casts (like reinterpret_cast<> in this case), instead of old C-style casts.
Moreover, since the type of the function pointer is specified in reinterpret_cast, it's useless to repeat it at the beginning of the statement, so the new C++11's keyword auto can be used.
You can use the returned function pointer to call the DLL function:
BOOL retCode = pCreateNewScanner( .... );
// Note: some other common prefix used in this case is "pfn"
// as "pointer to function" (e.g. pfnCreateNewScanner).
Once you have finished using the DLL, you can release it, calling FreeLibrary:
//
// Release the DLL
//
FreeLibrary(hDll);
hDll = nullptr;
In addition, note that you can use the C++ RAII pattern, and define a class with a destructor that automatically frees the DLL (this simplifies the code that manages the library loading/releasing parts).
e.g.
class RaiiDll
{
public:
// Load the DLL.
explicit RaiiDll(const std::wstring& filename) // may also provide an overload
// with (const wchar_t*)
{
m_hDll = ::LoadLibrary(filename.c_str());
if (! m_hDll)
{
// Error
throw std::runtime_error("Can't load the DLL - LoadLibrary() failed.");
// .... or use some other exception...
}
}
// Safely and automatically release the DLL.
~RaiiDll()
{
if (m_hDll)
{
::FreeLibrary(m_hDll);
m_hDll = nullptr;
}
}
// Get DLL module handle.
HMODULE Get() const
{
return m_hDll;
}
private:
HMODULE m_hDll; // DLL instance handle
//
// Ban copy (if compiler supports new C++11 =delete, use it)
//
private:
RaiiDll( RaiiDll & );
RaiiDll & operator=( RaiiDll & );
};
Then, in some code block, you can have:
{
// Load the library (throws on error).
RaiiDll scannerDll(L"WinScanner.dll");
// Get DLL function pointer
auto pCreateNewScanner = reinterpret_cast<CreateNewScannerPtr>(
GetProcAddress(scannerDll.Get(), "CreateNewScanner"));
if (! pCreateNewScanner)
{
.... error.
}
.... use the function
} // <--- DLL automatically released thanks to RaiiDll destructor!!!
Note how code is simplified thanks to automatic invocation of RaiiDll destrutor (and so of FreeLibrary), also in the error path case.

Delphi: Calling a function from a vc++ dll that exports a interface / class

i have some trouble accessing a dll written in vc++ that exports an interface. First i tried to use classes, but after some google-search i came to the solution, that this i not possible. I just want to make sure, that the plugin interface can accessed, by using other languages like c++.
Delphi Interface
IPlugIn = interface
function GetName: WideString; stdcall;
end;
Delphi Plugin call
procedure TForm1.Button5Click(Sender: TObject);
var
hLib: Cardinal;
MLoadPlugIn: TLoadPlugIn;
PlugIn: IPlugIn;
begin
hLib := LoadLibrary('PluginB.dll');
try
if not(hLib = 0) then
begin
#MLoadPlugIn := GetProcAddress(hLib, 'LoadPlugIn');
if not(#MLoadPlugIn = nil) then
begin
if MLoadPlugIn(PlugIn) then
try
ShowMessage(PlugIn.GetName); // here i get the access-violation using the vc++ plugin
finally // i get the return value but the instance is not created
PlugIn := nil;
end;
end
else
raise Exception.Create('');
end;
finally
FreeLibrary(hLib);
end;
end;
Delphi plugin dll
TMyPlugin = class(TInterfacedObject, IPlugIn)
public
function GetName: WideString; stdcall;
end;
function TMyPlugin.GetName;
begin
result := 'TMyPlugin';
end;
function LoadPlugIn(var PlugIn: IPlugIn): Boolean; stdcall;
begin
try
PlugIn := TMyPlugin.Create;
result := True;
except
result := False;
end;
end;
exports
LoadPlugIn;
vc++ plugin dll
// IPlugIn
__interface //__declspec(uuid("E44BB34F-D13F-42D7-9479-4C79AF5C0D1B"))
IPlugIn : public IUnknown
{
void _stdcall GetName(BSTR* result);
};
// TMyPlugIn header
class TMyPlugIn : public IPlugIn
{
public:
// Constructor
TMyPlugIn() : m_cRef(1) {}
// Destructor
~TMyPlugIn() {}
// Needed to implement IUnknown used by COM to acces your component
HRESULT _stdcall QueryInterface(const IID& iid, void** ppv);
ULONG _stdcall AddRef();
ULONG _stdcall Release();
void _stdcall GetName(BSTR* result);
private:
long m_cRef ;
};
// TMyPlugIn cpp
HRESULT _stdcall TMyPlugIn::QueryInterface(const IID& iid, void** ppv)
{
if (iid == IID_IUnknown)
{
*ppv = static_cast<IPlugIn*>(this) ;
}
else if (iid == IID_IPlugIn)
{
*ppv = static_cast<IPlugIn*>(this) ;
}
else
{
*ppv = NULL ;
return E_NOINTERFACE ;
}
reinterpret_cast<IUnknown*>(*ppv)->AddRef() ;
return S_OK ;
}
ULONG _stdcall TMyPlugIn::AddRef()
{
return InterlockedIncrement(&m_cRef) ;
}
ULONG _stdcall TMyPlugIn::Release()
{
if (InterlockedDecrement(&m_cRef) == 0)
{
delete this ;
return 0 ;
}
return m_cRef ;
}
void _stdcall TMyPlugIn::GetName(BSTR* result)
{
string s1 = "PluginName";
*result = A2WBSTR(s1.c_str());
}
// the export function from the cpp plugin
extern "C" bool __declspec(dllexport) __stdcall LoadPlugIn(IPlugIn* PlugIn);
bool __declspec(dllexport) __stdcall LoadPlugIn(IPlugIn* PlugIn)
{
PlugIn = new TMyPlugIn;
return TRUE;
}
You get the access violation because this code
extern "C" bool __declspec(dllexport) __stdcall LoadPlugIn(IPlugIn* PlugIn);
bool __declspec(dllexport) __stdcall LoadPlugIn(IPlugIn* PlugIn)
{
PlugIn = new TMyPlugIn;
return TRUE;
}
creates an instance of your plugin class and writes the address to the stack, where it quickly will be forgotten. Back in the Delphi program the original plugin interface variable is still nil, so calling a method on it crashes. You need to mimic what QueryInterface() does, like so:
extern "C" bool __declspec(dllexport) __stdcall LoadPlugIn(IPlugIn** PlugIn);
bool __declspec(dllexport) __stdcall LoadPlugIn(IPlugIn** PlugIn)
{
*PlugIn = new TMyPlugIn;
return TRUE;
}
This passes the address of the interface variable, and the address of the plugin instance will be written to the variable.
In addition to what mghie has said, you also have a problem with mismatched definitions between Delphi and C++
Your C++ signature for GetName is:
void _stdcall GetName(BSTR* result);
Your Delphi signature is:
function GetName: WideString; stdcall;
There are (at least) 2 possible ways to fix this.
1) If you want the Delphi code to work as a function, then make it safecall and adjust the C++ to match:
Delphi:
function GetName: WideString; safecall;
C++:
HRESULT _stdcall GetName(BSTR* result);
or
2) fix the Delphi to match the existing C++ defn:
procedure GetName( var name: WideString );
I (personally) would probably go the safecall route, as I think it is much cleaner on the Delphi side...
In general, you should not export interfaces (and for that matter: objects should really not be exported) across DLL boundaries because you do not know which memory manager, run-time library and object model will be on either side.
See also this thread about exceptions in DLL's (exceptions are objects).
Since the Delphi interface model is binary compatible with the COM interface model, and Visual C++ can export COM objects, you should go the COM way (was Adelf also suggested).
--jeroen
All Delphi classes parent - TObject class from VCL.
If you use Borland C++ Builder(VCL library) - you can write plugin to Delphi with this way.
For another cases.. you should read about COM.