Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: Standalone exe with libxl


This question is answered. Helpful answers available: 0. Correct answers available: 1.


Permlink Replies: 7 - Last Post: Jan 30, 2017 1:05 PM Last Post By: Remy Lebeau (Te...
Bill Franzsen

Posts: 6
Registered: 2/4/13
Standalone exe with libxl  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 25, 2017 3:24 PM
Hi,

Project completed and ready to export, except I'd like to avoid having to deploy with libxl.dll (or, for later, any other 'external' dll).

Have unchecked the two standard runtime settings so the only dll I still need to include is the libxl.dll.

Is there anyway of building a completely standalone exe?

Using C++ Builder XE8 with a vcl project.

Cheers

Bill
Arkady Semylio

Posts: 87
Registered: 9/18/15
Re: Standalone exe with libxl
Helpful
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 25, 2017 3:35 PM   in response to: Bill Franzsen in response to: Bill Franzsen
Bill Franzsen wrote:
Hi,

Is there anyway of building a completely standalone exe?

Hi,

do you have a static version of that library (compatible with Embarcadero compilers)?
If you only have the DLL's import library, the DLL itself will be always required.

Bye bye
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Standalone exe with libxl
Helpful
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 25, 2017 3:45 PM   in response to: Bill Franzsen in response to: Bill Franzsen
Bill wrote:

Have unchecked the two standard runtime settings so the only dll
I still need to include is the libxl.dll.

Those options only apply to RTL/VCL/FMX runtime packages (BPL files), not
standard DLLs.

Is there anyway of building a completely standalone exe?

Not when a DLL is involved, no. By design, a DLL is an external file and
must be deployed with the app.

What you are asking for requires libxl to be compiled as a C++Builder compatible
static library instead of as a DLL. That library can then be compiled directly
into the EXE's code.

If libxl does not provide a C++Builder compatible static library, and if
you have the source code for libxl, then you can try creating your own static
library project to compile the source code yourself. But note that most
3rd party open source projects (especially onces that start with 'lib' in
their names) don't usually support C++Builder's compilers officially (if
they ever did, they likely dropped support years ago), so you might need
to make adjustments to the source code, installation procedures, etc to make
them work in C++Builder.

Otherwise, if obtaining/compiling a static version of libxl is not an option,
your only remaining option is to use an .rc file to store the actual DLL
itself in the EXE's resources (bloating the EXE file size) and then your
code can extract that resource to a temp file at runtime and load it into
memory using the Win32 API LoadLibrary() function, either manually or by
using the C++Builder linker's Delay-Load feature.

--
Remy Lebeau (TeamB)
Bill Franzsen

Posts: 6
Registered: 2/4/13
Re: Standalone exe with libxl  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 25, 2017 4:38 PM   in response to: Bill Franzsen in response to: Bill Franzsen
Thanks for the info. Looks like I'll have to stick with the dll. Don't have a static version and no time to learn about the .rc solution from Remy. Maybe for my next project.

Cheers

Bill

Bill Franzsen wrote:
Hi,

Project completed and ready to export, except I'd like to avoid having to deploy with libxl.dll (or, for later, any other 'external' dll).

Have unchecked the two standard runtime settings so the only dll I still need to include is the libxl.dll.

Is there anyway of building a completely standalone exe?

Using C++ Builder XE8 with a vcl project.

Cheers

Bill
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Standalone exe with libxl  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 25, 2017 6:10 PM   in response to: Bill Franzsen in response to: Bill Franzsen
Bill rote:

no time to learn about the .rc solution from Remy.

It is really not that difficult:

http://docwiki.embarcadero.com/RADStudio/en/Resource_Files_Support

Create an .rc file (or let the IDE do it for you) that refers to the DLL, eg:

LIBXLDLL RCDATA "libxl.dll"


Add the .rc file to the project (if it is not already), and then the DLL
will get compiled into the EXE's resources. You can then use a TResourceStream
at runtime to access the resource data and save it to a temp file, eg:

#include <memory>
 
// or std::unique_ptr in C++11 and later
std::auto_ptr<TResourceStream> Stream(new TResourceStream((unsigned)HInstance, 
_D("LIBXLDLL"), RT_RCDATA));
Stream->SaveToFile("C:\\path to\\libxl.dll");


To prevent the app from failing at startup when the DLLL is missing, make
sure the project is not static linking to the DLL's import lib, as you will
need to load the DLL dynamically with LoadLibrary() and access its exports
with GetProcAddress().

Or, you can static link to the DLL's import file, you just have to mark the
DLL as delay-load in the Project Options so the EXE will handle the LoadLibrary()
and GetProcAddress() calls silently for you. The EXE will not try to load
and access the DLL until the first time any of its exports are actually used.
You can then use a delay-load hook (http://docwiki.embarcadero.com/RADStudio/Berlin/en/PfnDliNotifyHook,_pfnDliFailureHook)
to extract the resource to file only when it is actually needed, eg:

#include <delayimp.h>
#include <shlwapi.h>
#include <memory>
 
FARPROC WINAPI MyDelayLoadHook(dliNotification dliNotify, DelayLoadInfo *pdli)
{
    if ((dliNotify == dliFailLoadLibrary) && (strcmpi(pdli->szDll, "libxl.dll") 
== 0))
    {
        // or std::unique_ptr in C++11 and later
        std::auto_ptr<TResourceStream> Stream(new TResourceStream((unsigned)HInstance, 
"LIBXLDLL", RT_RCDATA));
 
        TCHAR szFileName[MAX_PATH] = {0};
        GetTempPath(MAX_PATH, szFileName);
        PathAppend(szFileName, TEXT("libxl.dll"));
 
        Stream->SaveToFile(szFileName);
 
        return (FARPROC) LoadLibrary(szFileName);
    }
 
    return NULL;
}
 
__fastcall TMainForm::TMainForm(TComponent *Owner)
    : TForm(Owner)
{
    __pfnDliFailureHook = &MyDelayLoadHook;
}


--
Remy Lebeau (TeamB)
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Standalone exe with libxl  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 26, 2017 11:55 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy wrote:

You can then use a delay-load hook
(http://docwiki.embarcadero.com/RADStudio/Berlin/en/PfnDliNotifyHook,_pfnDliFailureHook)
to extract the resource to file only when it is actually needed, eg:

Alternatively, using the dliNotePreLoadLibrary notification instead of the
dliFailLoadLibrary notification:

#include <delayimp.h>
#include <shlwapi.h>
#include <memory>
 
FARPROC WINAPI MyDelayLoadHook(dliNotification dliNotify, DelayLoadInfo *pdli)
{
    if ((dliNotify == dliNotePreLoadLibrary) && (strcmpi(pdli->szDll, "libxl.dll") 
== 0))
    {
        // or std::unique_ptr in C++11 and later
        std::auto_ptr<TResourceStream> Stream(new TResourceStream((unsigned)HInstance, 
"LIBXLDLL", RT_RCDATA));
 
        TCHAR szFileName[MAX_PATH] = {0};
        GetTempPath(MAX_PATH, szFileName);
        PathAppend(szFileName, TEXT("libxl.dll"));
        Stream->SaveToFile(szFileName);
 
        return (FARPROC) LoadLibrary(szFileName);
    }
    return NULL;
}
 
__fastcall TMainForm::TMainForm(TComponent *Owner)
    : TForm(Owner)
{
    __pfnDliNotifyHook = &MyDelayLoadHook;
}


--
Remy Lebeau (TeamB)
Bill Franzsen

Posts: 6
Registered: 2/4/13
Re: Standalone exe with libxl  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 30, 2017 12:28 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Hi Remy,

You're right, that seems easy enough.

Tried it and it worked perfectly with the first suggestion.

Is there a way to ensure the libxl.dll file gets deleted on exit?

Cheers

Bill

Remy Lebeau (TeamB) wrote:
Bill rote:

no time to learn about the .rc solution from Remy.

It is really not that difficult:

http://docwiki.embarcadero.com/RADStudio/en/Resource_Files_Support

Create an .rc file (or let the IDE do it for you) that refers to the DLL, eg:

LIBXLDLL RCDATA "libxl.dll"


Add the .rc file to the project (if it is not already), and then the DLL
will get compiled into the EXE's resources. You can then use a TResourceStream
at runtime to access the resource data and save it to a temp file, eg:

#include <memory>
 
// or std::unique_ptr in C++11 and later
std::auto_ptr<TResourceStream> Stream(new TResourceStream((unsigned)HInstance, 
_D("LIBXLDLL"), RT_RCDATA));
Stream->SaveToFile("C:\\path to\\libxl.dll");


To prevent the app from failing at startup when the DLLL is missing, make
sure the project is not static linking to the DLL's import lib, as you will
need to load the DLL dynamically with LoadLibrary() and access its exports
with GetProcAddress().

Or, you can static link to the DLL's import file, you just have to mark the
DLL as delay-load in the Project Options so the EXE will handle the LoadLibrary()
and GetProcAddress() calls silently for you. The EXE will not try to load
and access the DLL until the first time any of its exports are actually used.
You can then use a delay-load hook (http://docwiki.embarcadero.com/RADStudio/Berlin/en/PfnDliNotifyHook,_pfnDliFailureHook)
to extract the resource to file only when it is actually needed, eg:

#include <delayimp.h>
#include <shlwapi.h>
#include <memory>
 
FARPROC WINAPI MyDelayLoadHook(dliNotification dliNotify, DelayLoadInfo *pdli)
{
    if ((dliNotify == dliFailLoadLibrary) && (strcmpi(pdli->szDll, "libxl.dll") 
== 0))
    {
        // or std::unique_ptr in C++11 and later
        std::auto_ptr<TResourceStream> Stream(new TResourceStream((unsigned)HInstance, 
"LIBXLDLL", RT_RCDATA));
 
        TCHAR szFileName[MAX_PATH] = {0};
        GetTempPath(MAX_PATH, szFileName);
        PathAppend(szFileName, TEXT("libxl.dll"));
 
        Stream->SaveToFile(szFileName);
 
        return (FARPROC) LoadLibrary(szFileName);
    }
 
    return NULL;
}
 
__fastcall TMainForm::TMainForm(TComponent *Owner)
    : TForm(Owner)
{
    __pfnDliFailureHook = &MyDelayLoadHook;
}


--
Remy Lebeau (TeamB)
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Standalone exe with libxl  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 30, 2017 1:05 PM   in response to: Bill Franzsen in response to: Bill Franzsen
Bill wrote:

Is there a way to ensure the libxl.dll file gets deleted on exit?

Typically, you would have to delete it manually when you are done using it.

The usual way to "automatically" delete a file is to open the file with CreateFile()
with the FILE_FLAG_DELETE_ON_CLOSE flag enabled. However, you can't easily
mix that with LoadLibrary(), either explicitly or via delay-load (due to
how LoadLibrary() works internally, that it accesses the file using flags
that are not compatible with the flags needed to make FILE_FLAG_DELETE_ON_CLOSE
work).

However, you might be able to call DeleteFile() after LoadLibrary() is called
(while the file is still open), and the deletion should get delayed until
all handles to the file have been closed.

--
Remy Lebeau (TeamB)
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02