I have a large project consisting of one exe (C++) and several dlls (C++) and bpl (delphi ). My target architecture is x64. I ran into a problem in bpl - package. When I tried to debug it, I saw that the breakpoints do not work:
I made a minimal reproducible example. I made three clean projects (exe c++, exe delphi, bpl delphi) and wrote the code for them:
exe c++:
#include <vcl.h>
#include "Unit2.hpp"
#pragma comment(lib, "Package1")
int WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
{
TComponent* cmp = nullptr;
Unit2::TForm2* frm = new Unit2::TForm2(cmp);
frm->Button1Click(nullptr);
return 0;
}
exe delphi:
unit Unit4;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Unit2;
type
TForm4 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form4: TForm4;
implementation
{$R *.dfm}
procedure TForm4.FormCreate(Sender: TObject);
var
frm: TForm2;
begin
frm := TForm2.Create(nil);
frm.Button1Click(nil);
end;
end.
bpl delphi:
unit Unit2;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm2 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
{$R *.dfm}
procedure TForm2.Button1Click(Sender: TObject);
var
i: integer;
begin
i := 678;
end;
end.
I tested 4 debug combinations:
exe (C++ x86) and bpl(delphi x86) - debug working
exe (delphi x86) and bpl(delphi x86) - debug working
exe (delphi x64) and bpl(delphi x64) - debug working
exe (C++ x64) and bpl(delphi x64) - debug not working
Why doesn't the combination exe (C++ x64) and bpl(delphi x64) allow me to debug bpl? I don't know how to defeat my problem.
bpl project debug settings:
OS: Windows 10 x64
IDE: Embarcadero RAD Studio 11.2
Related
I currently come across with an issue getting my application, App, (written and built under Eclipse RCP), to work on 32bit Windows 10 environment.
Here’s the background, I recently implemented a Windows Shutdown Blocker capability using JNI by embedding that capability in a c++ native code. As a result I generated 2 versions of the dll (using Cygwin – mingw32 capabilities - https://www3.ntu.edu.sg/home/ehchua/programming/howto/Cygwin_HowTo.html) one for 64 bit (same as my dev pc) and one for 32 bit. Then bundle them up in OSGi Bundle native-code. Finally the application is then packaged up and built into a .exe that can be deployed to client machines. Some clients use 32bit Windows so I have to cater for it.
In order to test this, I setup a vm using my pc’s Hyper-V function with Windows 10 32bit OS installed (a Windows evaluation license). Deployed my app in there and tried initiate activities that kicks off the Windows Shutdown Blocker capabilities I’ve produced.
Then I get the following error in the logs (I don’t get this issue in my 64bit Windows host environment and it’s working perfectly):
!SESSION 2020-01-21 16:48:42.604 -----------------------------------------------
eclipse.buildId=unknown
java.version=1.8.0_60
java.vendor=Oracle Corporation
BootLoader constants: OS=win32, ARCH=x86, WS=win32, NL=en _AU
Framework arguments: --startup plugins/org.eclipse.equinox.launcher_1.4.0.v20161219-1356.jar
Command-line arguments: -os win32 -ws win32 -arch x86 --startup plugins/org.eclipse.equinox.launcher_1.4.0.v20161219-1356.jar -user #user.home -data #user.home/App/202001201633
!ENTRY org.eclipse.ui 2 0 2020-01-21 16:50:10.579
!MESSAGE Save All Failed
!STACK 0
java.lang.UnsatisfiedLinkError: C:\Users\Dale\App\202001201633\configuration\org.eclipse.osgi\11\0\.cp\lib\shutdown\windows-i686\ShutdownBlocker.dll: Can't find dependent libraries
at java.lang.ClassLoader$NativeLibrary.load(Native Method)
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1938)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1834)
at java.lang.Runtime.loadLibrary0(Runtime.java:870)
at java.lang.System.loadLibrary(System.java:1122)
…
The end-to-end process on how I generated the .dll file goes like this:
Download and install Cygwin including the g++ compilers (32bit and 64bit)
Open Windows command prompt
Generate .h file from JNI class:
javac -h . ShutdownBlocker.java
This is the Java file
public class ShutdownBlocker {
private static boolean nativeLibLoaded;
public static void loadLibrary() {
if(!nativeLibLoaded) {
System.loadLibrary("ShutdownBlocker");
nativeLibLoaded=true;
}
}
public static native void shutdownBlockReasonCreate(String title, String reasonText);
public static native void shutdownBlockReasonDestroy(String title);
}
This is the .h file
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_app_service_util_shutdown_ShutdownBlocker */
#ifndef _Included_com_app_service_util_shutdown_ShutdownBlocker
#define _Included_com_app_service_util_shutdown_ShutdownBlocker
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_app_service_util_shutdown_ShutdownBlocker
* Method: shutdownBlockReasonCreate
* Signature: (Ljava/lang/String;Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_com_app_service_util_shutdown_ShutdownBlocker_shutdownBlockReasonCreate
(JNIEnv *, jclass, jstring, jstring);
/*
* Class: com_app_service_util_shutdown_ShutdownBlocker
* Method: shutdownBlockReasonDestroy
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_com_app_service_util_shutdown_ShutdownBlocker_shutdownBlockReasonDestroy
(JNIEnv *, jclass, jstring);
#ifdef __cplusplus
}
#endif
#endif
Create a .cpp file, i.e. ShutdownBlocker.cpp
#include <jni.h>
#include <iostream>
#include "com_app_service_util_shutdown_ShutdownBlocker.h"
#include <windows.h>
#include <commctrl.h>
using namespace std;
namespace {
LPCWSTR SHUTDOWN_REASON = L"Application is still saving ...";
LRESULT CALLBACK AppWndProc(
_In_ HWND hWnd,
_In_ UINT message,
_In_ WPARAM wParam,
_In_ LPARAM lParam,
_In_ UINT_PTR uIdSubclass,
_In_ DWORD_PTR dwRefData
) {
// Callback function required to process some of the key OS messages in order to stall shutdown
switch (message) {
case WM_QUERYENDSESSION:
PostMessage(hWnd, WM_CLOSE, 0, 0);
return 0;
case WM_ENDSESSION:
PostMessage(hWnd, WM_CLOSE, 0, 0);
return 0;
case WM_NCDESTROY:
RemoveWindowSubclass(hWnd, AppWndProc, uIdSubclass);
break;
}
return DefSubclassProc(hWnd, message, wParam, lParam);
}
}
JNIEXPORT void JNICALL Java_com_app_service_util_shutdown_ShutdownBlocker_shutdownBlockReasonCreate(JNIEnv *env, jclass cls, jstring title, jstring reasonText) {
SHUTDOWN_REASON = (LPCWSTR) env->GetStringChars(reasonText, NULL);
// Parse reasonText string passed in from Java code and retrieve handle to the App window with it
const jchar *str = env->GetStringChars(title, NULL);
HWND hWnd = FindWindowW(NULL, (LPCWSTR)str);
env->ReleaseStringChars(title, str);
if (hWnd == NULL) {
return;
}
ShutdownBlockReasonCreate(hWnd, SHUTDOWN_REASON);
// Obtain control of the window by subclassing its procedure
SetWindowSubclass(hWnd, &AppWndProc, 1, 0);
return;
}
JNIEXPORT void JNICALL Java_com_app_service_util_shutdown_ShutdownBlocker_shutdownBlockReasonDestroy(JNIEnv *env, jclass cls, jstring title) {
// Parse reasonText string passed in from Java code and retrieve handle to the App window with it
const jchar *str = env->GetStringChars(title, NULL);
HWND hWnd = FindWindowW(NULL, (LPCWSTR)str);
env->ReleaseStringChars(title, str);
if (hWnd == NULL) {
return;
}
// Release control of the window procedure
RemoveWindowSubclass(hWnd, &AppWndProc, 1);
ShutdownBlockReasonDestroy(hWnd);
return;
}
Open Cygwin
Run following command to generate ShutdownBlocker.dll file for each Windows OS architecture
For 64bit windows
x86_64-w64-mingw32-g++ -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/win32" -Wl,"C:\Windows\System32\comctl32.dll" -shared -o ShutdownBlocker.dll /cygdrive/c/dale/eclipse-rcp-workspace/App/development/shutdown/ShutdownBlocker.cpp
For 32bit windows
i686-w64-mingw32-g++ -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/win32" -Wl,--enable-stdcall-fixup "C:\Windows\SysWOW64\comctl32.dll" -shared -o ShutdownBlocker.dll /cygdrive/c/dale/eclipse-rcp-workspace/App/development/shutdown/ShutdownBlocker.cpp
Copy the dll files to appropriate location in order for OSGi Bundle to reference
Update OSGi reference
Update build.properties
Update MANIFEST.MF. Pasting relevant section here:
Bundle-NativeCode: lib/shutdown/windows-amd64/ShutdownBlocker.dll;
processor=x86_64,
lib/shutdown/windows-i686/ShutdownBlocker.dll;
processor=x86, *
Save -> Refresh -> Clean -> commit change
Using build tools to generate the setup.exe executable one (which bundles with Java runtime) for each OS architecture
Deploy and run setup32bit.exe in my 32 bit Windows VM (as mentioned above)
Run the App to kick-off the Shutdown Blocker capability
Then I get the above error which prevents the initiation of Shutdown Blocker capability
My approach to fix it (in vain):
I tried to use a DLL Dependency Walker as recommended in this post JNI dependent libraries. Ran it and found it throwing a lot of error on dependencies (which I don’t find it very helpful, because I did the same on a random c:\windows\system32 dll file which gives me similar outcome)
Or maybe I’m not using this tool correctly, here’s how I run it:
C:\Users\Dale >depends.exe ShutdownBlocker.dll
Then I found another post that suggests using a Cygwin capability called “objdump” (https://linux-tips.com/t/how-can-i-find-library-dependencies-of-a-windows-dll/328) I ran it and I got this:
$ objdump -p ShutdownBlocker.dll | grep DLL
DLL
vma: Hint Time Forward DLL First
DLL Name: KERNEL32.dll
DLL Name: msvcrt.dll
DLL Name: USER32.dll
DLL Name: libstdc++-6.dll
DLL Name: COMCTL32.dll
Seems promising and I found “libstdc++-6.dll” is the only dll missing on the new 32bit vm. So I copied this .dll file into a directory and updated PATH variable.
Running the App again but the change made no difference (same error)
In which case, how do I know which library it has trouble finding? Or anything I did wrong here?
Thanks in advance for anyone who can shed some light on this issue. And really appreciated your time on this!
Updated DLL Dependency Walker Image
Updated DLL Dependency Walker Image
Think I found a resolution to the issue of finding dependency dll for my ShutdownBlocker.dll. As you can see in the above image all looks fine now. It turned out by moving all the dependent libraries such as libstdc++-6.dll, libgcc_s_sjlj-1.dll and libwinpthread-1.dll to the same directory as ShutdownBlocker.dll solve the problem. Adding these dlls into PATH seemed to fix the error I had. But now I'm getting a different error:
!ENTRY org.eclipse.ui 4 0 2020-01-22 16:57:22.218
!MESSAGE Unhandled event loop exception
!STACK 0
java.lang.UnsatisfiedLinkError: com.app.service.util.shutdown.ShutdownBlocker.shutdownBlockReasonCreate(Ljava/lang/String;Ljava/lang/String;)V
(not sure if I can still discuss this issue here or I need to create a new question?)
I have created a C++ DLL in Visual Studio 2017 using the following sources:
Header: stdfax.h
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files
#include <windows.h>
// reference additional headers your program requires here
Header: targetver.h
#pragma once
// Including SDKDDKVer.h defines the highest available Windows platform.
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
#include <SDKDDKVer.h>
Source: stdafx.cpp
#include "stdafx.h"
Source: dll.cpp
// dll.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
Source: dllmain.cpp
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Source: Source.cpp <- this is where I intend to add my source file
#include "stdafx.h"
#define EXPORTING_DLL
int HelloWorld(int A) {
return (2 * A);
}
Definition: Source.def <- Intentend to be able to consume this DLL from VB .NET
LIBRARY dll
DESCRIPTION 'A C++ dll tat can be called from VB'
EXPORTS
HelloWorld
Now I try to consume this DLL using a VB.NET project in the same solution:
Imports System.Runtime.InteropServices
Public Class Form1
<DllImport("dll.dll", CallingConvention:=CallingConvention.Cdecl)>
Private Shared Function HelloWorld(ByVal x As Int64) As Int64
End Function
Private Declare Function HelloWorld Lib "dll.dll" (int) As Integer
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim j
j = HelloWorld(CInt(TextBox1.Text))
TextBox2.Text = j
End Sub
End Class
But I get:
System.DllNotFoundException: 'Unable to load DLL 'dll.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)'
EDIT: Following Vincent's comment about the possibility of this being a duplicate of Trouble adding my Visual-C++ DLL to my VB.NET windows forms GUI app I have checked that link and it does effectively tells how to add a DLL to a VB project. In that sense it is a duplicate, however, I have fixed that I find now the following error while trying to access the DLL:
System.BadImageFormatException: 'An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)'
I have also, following the side comment, modified my source file containing the function that needs to be exported to:
Source: Source.cpp <- this is where I intend to add my source file
#include "stdafx.h"
#define EXPORTING_DLL
extern "C" int HelloWorld(int A) {
return (2 * A);
}
I think that fixing that last issue, the question could be useful to others as it is a simple but documented "HelloWorld" example on how to build a DLL in C++ and consume it in VB.NET.
Just to showcase problem I have written a simple DLL x64 of "Hello world" changed its property to CLR and Calling its Function from an Exe which is also x64 and property Changed to CLR.
But My exe prints the Output "Hello World" and crashes every time and gives FAULT Module Name KERNELBASE.dll.
When I change Property of both to NO CLR it works perfectly fine. This happens only for x64 application not observed in x86 program.
I am using Visual Studio 2017 on Windows Server 2012.
It will be very helpful if someone can guide me to correct direction.
Details of App Crash
Problem Event Name: APPCRASH
Application Name: consuming_using_clr.exe
Application Version: 0.0.0.0
Application Timestamp: 5b42fff3
Fault Module Name: KERNELBASE.dll
Fault Module Version: 6.3.9600.17055
Fault Module Timestamp: 532954fb
Exception Code: c0020001
Exception Offset: 0000000000005bf8
OS Version: 6.3.9600.2.0.0.16.7
Locale ID: 1033
Additional Information 1: 8e72
Additional Information 2: 8e72455f15a8480830570fcb3c4abf60
Additional Information 3: f8d5
Additional Information 4: f8d519c5149c6c561af747d4db7e910a
DLL dot.h file
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the DLLWINDOWSDESKTOPWIZARD_EXPORTS
// symbol defined on the command line. This symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// DLLWINDOWSDESKTOPWIZARD_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef DLLWINDOWSDESKTOPWIZARD_EXPORTS
#define DLLWINDOWSDESKTOPWIZARD_API __declspec(dllexport)
#else
#define DLLWINDOWSDESKTOPWIZARD_API __declspec(dllimport)
#endif
#using<System.dll>
#include<iostream>
using namespace System;
using namespace std;
// This class is exported from the Dll_windows_desktop_wizard.dll
class DLLWINDOWSDESKTOPWIZARD_API CDllwindowsdesktopwizard
{
public:
CDllwindowsdesktopwizard(void);
~CDllwindowsdesktopwizard(void);
void helloworld();
};
*DLL DOT CPP File *
// Dll_windows_desktop_wizard.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "Dll_windows_desktop_wizard.h"
// This is the constructor of a class that has been exported.
// see Dll_windows_desktop_wizard.h for the class definition
CDllwindowsdesktopwizard::CDllwindowsdesktopwizard(void)
{
}
CDllwindowsdesktopwizard::~CDllwindowsdesktopwizard(void)
{
}
void CDllwindowsdesktopwizard::helloworld()
{
Console::WriteLine("Hello World");
}
EXE Calling DLL Function
#include<iostream>
#include "Dll_windows_desktop_wizard.h"
using namespace System;
int main()
{
CDllwindowsdesktopwizard lv_obj;
lv_obj.helloworld();
return 0;
}
dllMain.cpp
#include "stdafx.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Finally I got it.Came across this link https://msdn.microsoft.com/en-us/library/ccthbfk8.aspx as i was trying to remove the warning from my exe warning was
"warning:Calling managed 'DllMain': Managed code may not be run under loader lock,including the DLL entrypoint and calls reached from the DLL entrypoint"
I have a C++ Visual Studio 2015 project consisting of
1 Windows API executable, 1 windows console executable, and 1 dll shared by both executables.
I have a #define USEWINDOWS in the Windows API main.cpp file
I don't have this defined in the console app
In the DLL, I would like to do an #ifdef USEWINDOWS statement, but the scope of the #define seems to be only valid to the Win32 executable, not in the dll.
How can I extend this #define to the DLL without having it affect the undefined USEWINDOWS in the console app?
Thanks
The DLL is shared by both executables, hence there is only one implementation available and therefore you can't use implementation specific compilation flags.
You'll need a runtime flag, i.e. some API parameter which tells the DLL code that it is OK to use "windows stuff". E.g.
api.h
void someAPI(...., bool useWindows);
dll.c
#include "api.h"
void someAPI(...., bool useWindows) {
...
if (useWindows) {
// do "windows stuff" here
}
...
}
app.c
#include "api.h"
...
someAPI(...., true);
console.c
#include "api.h"
...
someAPI(...., false);
(not tested by compilation, but you should get the drift...)
My question is if I can use MFC and ATL libraries that come with PSDK Windows Server 2003 R2, without Visual Studio. I mean only at the command prompt with BCC32.exe or CL.exe?
I have found MFC and ATL libraries in the PSDK Windows Server 2003 R2 but I does not know if these libraries can be used without Visual Stuio IDE! What I need to do before using MFC and ATL at the command prompt?
Thanks!
If you have all the headers, and either the source code or compiled version of the rest, then yes it can be used without Visual Studio. Visual Studio is just an IDE that invokes the compiler etc. for you. With command line tools you do that job yourself.
Here's a minimal MFC program that you can try out:
#define WINVER 0x0500 // Windows 2000 and up.
#include <afxwin.h> // MFC core and standard components
typedef CFrameWnd MainWindow;
class App
: public CWinApp
{
private:
bool createTheMainWindow()
{
static char const title[] = "A general top level MFC window";
MainWindow* const pWnd =
new MainWindow;
if( !pWnd ) { return false; } // Pre-standard 'new' in MFC...
m_pMainWnd = pWnd;
pWnd->Create( NULL, title );
return true;
}
public:
virtual BOOL InitInstance()
{
CWinApp::InitInstance();
if( !createTheMainWindow() ) { return false; }
m_pMainWnd->ShowWindow( SW_SHOW );
m_pMainWnd->UpdateWindow();
return true;
}
};
App theApp;
Cheers & hth.,
No you can't, since some functionality relies on the Visual Studio compiler specific behavior. For example the way trampolines are used to map window handles to objects.
I'm assuming that you by "can be used without Visual Stuio IDE" you actually mean "with another compiler", since you mention the Borland compiler. Of course you can write C++ in a text editor and compile those files from the command line, not using the IDE, but what you want is using another compiler, right? (the IDE and the compiler are related but not the same).