Question: problems porting a 32-bit plug-in to 64 bit with Visual Studio

Tridurz

Member
Hi,

I try to convert a 32bit plug-in into a 64bit plug-in.
I'm not really a experienced c++ developer, so I started with a small demo project. I compiled it with the 32bit VCC from Visual Express 2013 and it works fine. The Plug-In DLL is found and can be used in the 32Bit PLSQL Developer.

After that, I tried to compile the plug-in as a 64bit DLL but the PLSQL-Developer is unable to detect the plug-in. I tested the DLL with dumpbin to ensure it is a 64bit DLL.

My Question are:
Has anyone successfully ported 64-bit plug-in with Visual C ++?
What's wrong ?

The Source is really simple. I'm using PLSQL Developer (32bit: Version 11.0.5.1775 / 64bit: PLSQL Version 11.0.5.1790) and Visual Studio Express 2013.

DEMO.H
#include

extern "C"
{
__declspec(dllexport) char* IdentifyPlugIn(int);
__declspec(dllexport) char* CreateMenuItem(int);
__declspec(dllexport) void OnMenuClick(int);
}

DEMO.CPP
#include "Demo.h"

BOOL WINAPI DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { return TRUE; }

char *const Desc = "Plug-In demo 1";
int PlugInID;

char* IdentifyPlugIn(int ID)
{
PlugInID = ID;
return Desc;
}

char* CreateMenuItem(int Index)
{
switch (Index)
{
case 1: return "Demo";
}
return "";
}

void OnMenuClick(int Index)
{
const char* msg = "Test Plug-In";
const char* msgboxtitle = "Plug-In Message";

switch (Index)
{
case 1:
MessageBox(NULL, msg, msgboxtitle, 0);
break;
}
}

 
Last edited:
Norman - check the post from Nicolas on March 1st 2016 in this forum
(I initiated the topic). His reply could be helpful in your case.
BTW PLD 64bit is not ready yet for 64bit C++ Plugins "out of the box".
The scripts in folder PlugInDoc have not been updated to 64bit - they are still 32bit version.

HTH,
 
Norman,

I did encounter the same issue as you did get - whatever I did try, no way to have a 64 bits compiled plugin using Visual Studio to load. I was able to determine out of several test that only plugins compiled with Embarcadero C++ Builder are working for now.

Tested on a similar basic plugin like yours, compiled with both compilers.

Only the "DllMain" is called on the VC++ version, nothing after. Seems it is looking for a signature or a specific address that others compiler do not provide.

For now, our plugin work using a "Relay" - a plugin built on the 30 days trial of the Embarcadero C++ builder - that relay called from the C++ compiled version to PL/SQL Developer - and it work for now.

Andrew and I did notify Marco on that issue already. We are hoping for an update that would work to avoid using the relay in between.

Thanks
 
I am adding here the source code of the "relay" that allow me to run the VC++ 64 bits plugin. You must compile that with Embarcadero C++ Builder as a 64 bits DLL - you may use the 30 days demo for that.
Just update the _libmain function (equivalent for Embarcadero of the DllMain on VC++) to set the name of your DLL into it. In the code the name below is "YourPlugInName.dll.relay" (.relay to avoid PLSQL Developer to try to load it, for now)

Second note, if you need to deploy it you will need the following DLL from Embarcadero (part of the "redist" stuff: borlndmm.dll, cc64230.dll, cc64230mt.dll. drop them in the PL/SQL Developer folder, that work.


//RelayDLLPCH1.h
#ifdef _WIN32
#include
#endif


-----

// RelayDLL.cpp
// Important note about DLL memory management when your DLL uses the
// static version of the RunTime Library:
//
// If your DLL exports any functions that pass String objects (or structs/
// classes containing nested Strings) as parameter or function results,
// you will need to add the library MEMMGR.LIB to both the DLL project and
// any other projects that use the DLL. You will also need to use MEMMGR.LIB
// if any other projects which use the DLL will be performing new or delete
// operations on any non-TObject-derived classes which are exported from the
// DLL. Adding MEMMGR.LIB to your project will change the DLL and its calling
// EXE's to use the BORLNDMM.DLL as their memory manager. In these cases,
// the file BORLNDMM.DLL should be deployed along with your DLL.
//
// To avoid using BORLNDMM.DLL, pass string information using "char *" or
// ShortString parameters.
//
// If your DLL uses the dynamic version of the RTL, you do not need to
// explicitly add MEMMGR.LIB as this will be done implicitly for you

#pragma hdrstop
#pragma argsused

#include

HMODULE hm;

// Pointer to all functions I should be able to call from relayed DLL
typedef void (*RegisterCallbackPtr)(int, void*);
typedef char* (*IdentifyPlugInPtr)(int);
typedef void (*OnCreatePtr)();
typedef void (*OnActivatePtr)();
typedef void (*OnDeactivatePtr)();
typedef void (*OnDestroyPtr)();
typedef BOOL (*CanClosePtr)();
typedef char* (*CreateMenuItemPtr)(int);
typedef void (*OnMenuClickPtr)(int);
typedef void (*OnBrowserChangePtr)();
typedef void (*OnWindowChangePtr)();
typedef void (*OnConnectionChangePtr)();
typedef int (*OnWindowClosePtr)(int, BOOL);
typedef void (*OnWindowCreatePtr)(int);
typedef void (*ConfigurePtr)();
typedef void (*OnPopupPtr)(char *, char *);
typedef void (*OnMainMenuPtr)(char *);
typedef char* (*AboutPtr)();
typedef BOOL (*OnTemplatePtr)(char *, char **);
typedef char* (*PlugInNamePtr)();
typedef char* (*PlugInSubNamePtr)();
typedef char* (*PlugInShortNamePtr)();
typedef char* (*RegisterFileSystemPtr)();
typedef char* (*DirectFileLoadPtr)(char *, char *, int );
typedef BOOL (*DirectFileSavePtr)(char *, char *, int );
typedef char* (*RegisterExportPtr)();
typedef void (*ExportInitPtr)();
typedef void (*ExportFinishedPtr)();
typedef void (*ExportPreparePtr)();
typedef void (*ExportDataPtr)();

// And poiters to each of them.
RegisterCallbackPtr RegistercallbackFct;
IdentifyPlugInPtr IdentifyPlugInFct;
OnCreatePtr OnCreateFct;
OnActivatePtr OnActivateFct;
OnDeactivatePtr OnDeactivateFct;
OnDestroyPtr OnDestroyFct;
CanClosePtr CanCloseFct;
CreateMenuItemPtr CreateMenuItemFct;
OnMenuClickPtr OnMenuClickFct;
OnBrowserChangePtr OnBrowserChangeFct;
OnWindowChangePtr OnWindowChangeFct;
OnConnectionChangePtr OnConnectionChangeFct;
OnWindowClosePtr OnWindowCloseFct;
OnWindowCreatePtr OnWindowCreateFct;
ConfigurePtr ConfigureFct;
OnPopupPtr OnPopupFct;
OnMainMenuPtr OnMainMenuFct;
AboutPtr AboutFct;
OnTemplatePtr OnTemplateFct;
PlugInNamePtr PlugInNameFct;
PlugInSubNamePtr PlugInSubNameFct;
PlugInShortNamePtr PlugInShortNameFct;
RegisterFileSystemPtr RegisterFileSystemFct;
DirectFileLoadPtr DirectFileLoadFct;
DirectFileSavePtr DirectFileSaveFct;
RegisterExportPtr RegisterExportFct;
ExportInitPtr ExportInitFct;
ExportFinishedPtr ExportFinishedFct;
ExportPreparePtr ExportPrepareFct;
ExportDataPtr ExportDataFct;

//Functions to export to PL/SQL Dev
extern "C"
{
__declspec(dllexport) void RegisterCallback(int nIndex, void *pvAddr);
__declspec(dllexport) char* IdentifyPlugIn(int);
__declspec(dllexport) void OnCreate();
__declspec(dllexport) void OnActivate();
__declspec(dllexport) void OnDeactivate();
__declspec(dllexport) void OnDestroy();
__declspec(dllexport) BOOL CanClose();

__declspec(dllexport) char* CreateMenuItem(int);
__declspec(dllexport) void OnMenuClick(int);

__declspec(dllexport) void OnBrowserChange();
__declspec(dllexport) void OnWindowChange();
__declspec(dllexport) void OnConnectionChange();
__declspec(dllexport) int OnWindowClose(int WindowType, BOOL Changed);
__declspec(dllexport) void OnWindowCreate(int WindowType);
__declspec(dllexport) void Configure();

__declspec(dllexport) void OnPopup(char *ObjectType, char *ObjectName);
__declspec(dllexport) void OnMainMenu(char *MenuName);
__declspec(dllexport) char *About();
__declspec(dllexport) BOOL OnTemplate(char *Filename, char **Data);
__declspec(dllexport) char *PlugInName();
__declspec(dllexport) char *PlugInSubName();
__declspec(dllexport) char *PlugInShortName();

__declspec(dllexport) char *RegisterFileSystem();
__declspec(dllexport) char *DirectFileLoad(char *Tag, char *Filename, int WindowType);
__declspec(dllexport) BOOL DirectFileSave(char *Tag, char *Filename, int WindowType);
__declspec(dllexport) char *RegisterExport();
__declspec(dllexport) void ExportInit();
__declspec(dllexport) void ExportFinished();
__declspec(dllexport) void ExportPrepare();
__declspec(dllexport) void ExportData();
}

extern "C" int _libmain(unsigned long reason)
{
if (reason == DLL_PROCESS_ATTACH) {
hm = LoadLibrary("PlugIns\\YourPlugInName.dll.relay");
if(hm == NULL)
{
return 0;
}

//Connect C function for the real DLL to the pointer
RegistercallbackFct = (RegisterCallbackPtr)GetProcAddress(hm, "RegisterCallback");
IdentifyPlugInFct = (IdentifyPlugInPtr)GetProcAddress(hm, "IdentifyPlugIn");
OnCreateFct = (OnCreatePtr)GetProcAddress(hm, "OnCreate");
OnActivateFct = (OnActivatePtr)GetProcAddress(hm, "OnActivate");
OnDeactivateFct = (OnDeactivatePtr)GetProcAddress(hm, "OnDeactivate");
OnDestroyFct = (OnDestroyPtr)GetProcAddress(hm, "OnDestroy");
CanCloseFct = (CanClosePtr)GetProcAddress(hm, "CanClose");
CreateMenuItemFct = (CreateMenuItemPtr)GetProcAddress(hm, "CreateMenuItem");
OnMenuClickFct = (OnMenuClickPtr)GetProcAddress(hm, "OnMenuClick");
OnBrowserChangeFct = (OnBrowserChangePtr)GetProcAddress(hm, "OnBrowserChange");
OnWindowChangeFct = (OnWindowChangePtr)GetProcAddress(hm, "OnWindowChange");
OnConnectionChangeFct = (OnConnectionChangePtr)GetProcAddress(hm, "OnConnectionChange");
OnWindowCloseFct = (OnWindowClosePtr)GetProcAddress(hm, "OnWindowClose");
OnWindowCreateFct = (OnWindowCreatePtr)GetProcAddress(hm, "OnWindowCreate");
ConfigureFct = (ConfigurePtr)GetProcAddress(hm, "Configure");
OnPopupFct = (OnPopupPtr)GetProcAddress(hm, "OnPopup");
OnMainMenuFct = (OnMainMenuPtr)GetProcAddress(hm, "OnMainMenu");
AboutFct = (AboutPtr)GetProcAddress(hm, "About");
OnTemplateFct = (OnTemplatePtr)GetProcAddress(hm, "OnTemplate");
PlugInNameFct = (PlugInNamePtr)GetProcAddress(hm, "PlugInName");
PlugInSubNameFct = (PlugInSubNamePtr)GetProcAddress(hm, "PlugInSubName");
PlugInShortNameFct = (PlugInShortNamePtr)GetProcAddress(hm, "PlugInShortName");
RegisterFileSystemFct = (RegisterFileSystemPtr)GetProcAddress(hm, "RegisterFileSystem");
DirectFileLoadFct = (DirectFileLoadPtr)GetProcAddress(hm, "DirectFileLoad");
DirectFileSaveFct = (DirectFileSavePtr)GetProcAddress(hm, "DirectFileSave");
RegisterExportFct = (RegisterExportPtr)GetProcAddress(hm, "RegisterExport");
ExportInitFct = (ExportInitPtr)GetProcAddress(hm, "ExportInit");
ExportFinishedFct = (ExportFinishedPtr)GetProcAddress(hm, "ExportFinished");
ExportPrepareFct = (ExportPreparePtr)GetProcAddress(hm, "ExportPrepare");
ExportDataFct = (ExportDataPtr)GetProcAddress(hm, "ExportData");
}
if (reason == DLL_PROCESS_DETACH) {
FreeLibrary(hm);
}
return 1;
}

extern "C" {
__declspec(dllexport) void RegisterCallback(int nIndex, void *pvAddr) {
if (RegistercallbackFct == NULL) {
return;
}
return RegistercallbackFct (nIndex, pvAddr);
}

__declspec(dllexport) char* IdentifyPlugIn(int ID) {
if (IdentifyPlugInFct == NULL) {
return "";
}
return IdentifyPlugInFct(ID);
}

__declspec(dllexport) void OnCreate() {

if (OnCreateFct == NULL) {
return;
}
return OnCreateFct();

}

__declspec(dllexport) void OnActivate() {
if (OnActivateFct == NULL) {
return;
}
return OnActivateFct();
}

__declspec(dllexport) void OnDeactivate() {
if (OnDeactivateFct == NULL) {
return;
}
return OnDeactivateFct();
}
__declspec(dllexport) void OnDestroy() {
if (OnDestroyFct == NULL) {
return;
}
return OnDestroyFct();
}
__declspec(dllexport) BOOL CanClose() {
if (CanCloseFct == NULL) {
return TRUE;
}
return CanCloseFct();
}

__declspec(dllexport) char* CreateMenuItem(int ID) {
if (CreateMenuItemFct == NULL) {
return NULL;
}
return CreateMenuItemFct(ID);
}
__declspec(dllexport) void OnMenuClick(int ID) {
if (OnMenuClickFct == NULL) {
return;
}
return OnMenuClickFct(ID);
}

__declspec(dllexport) void OnBrowserChange() {
if (OnBrowserChangeFct == NULL) {
return;
}
return OnBrowserChangeFct();
}
__declspec(dllexport) void OnWindowChange() {
if (OnWindowChangeFct == NULL) {
return;
}
return OnWindowChangeFct();
}
__declspec(dllexport) void OnConnectionChange() {
if (OnConnectionChangeFct == NULL) {
return;
}
return OnConnectionChangeFct();
}
__declspec(dllexport) int OnWindowClose(int WindowType, BOOL Changed) {
if (OnWindowCloseFct == NULL) {
return NULL;
}
return OnWindowCloseFct(WindowType, Changed);
}
__declspec(dllexport) void OnWindowCreate(int WindowType) {
if (OnWindowCreateFct == NULL) {
return;
}
return OnWindowCreateFct(WindowType);
}
__declspec(dllexport) void Configure() {
if (ConfigureFct == NULL) {
return;
}
return ConfigureFct();
}

__declspec(dllexport) void OnPopup(char *ObjectType, char *ObjectName) {
if (OnPopupFct == NULL) {
return;
}
return OnPopupFct(ObjectType, ObjectName);
}
__declspec(dllexport) void OnMainMenu(char *MenuName) {
if (OnMainMenuFct == NULL) {
return;
}
return OnMainMenuFct(MenuName);
}
__declspec(dllexport) char *About() {
if (AboutFct == NULL) {
return NULL;
}
return AboutFct();
}
__declspec(dllexport) BOOL OnTemplate(char *Filename, char **Data) {
if (OnTemplateFct == NULL) {
return TRUE;
}
return OnTemplateFct(Filename, Data);
}
__declspec(dllexport) char *PlugInName() {
if (PlugInName == NULL) {
return NULL;
}
return PlugInNameFct();
}
__declspec(dllexport) char *PlugInSubName() {
if (PlugInSubNameFct == NULL) {
return NULL;
}
return PlugInSubNameFct();
}
__declspec(dllexport) char *PlugInShortName() {
if (PlugInShortNameFct == NULL) {
return NULL;
}
return PlugInShortNameFct();
}

__declspec(dllexport) char *RegisterFileSystem() {
if (RegisterFileSystemFct == NULL) {
return NULL;
}
return RegisterFileSystemFct();
}
__declspec(dllexport) char *DirectFileLoad(char *Tag, char *Filename, int WindowType) {
if (DirectFileLoadFct == NULL) {
return NULL;
}
return DirectFileLoadFct(Tag, Filename, WindowType);
}
__declspec(dllexport) BOOL DirectFileSave(char *Tag, char *Filename, int WindowType) {
if (DirectFileSaveFct == NULL) {
return NULL;
}
return DirectFileSaveFct(Tag, Filename, WindowType);
}
__declspec(dllexport) char *RegisterExport() {
if (RegisterExportFct == NULL) {
return NULL;
}
return RegisterExportFct();
}
__declspec(dllexport) void ExportInit() {
if (ExportInitFct == NULL) {
return;
}
ExportInitFct();
}
__declspec(dllexport) void ExportFinished() {
if (ExportFinishedFct == NULL) {
return;
}
ExportFinishedFct();
}
__declspec(dllexport) void ExportPrepare() {
if (ExportPrepareFct == NULL) {
return;
}
ExportPrepareFct();
}
__declspec(dllexport) void ExportData() {
if (ExportDataFct == NULL) {
return;
}
ExportDataFct();
}

}
 
Last edited:
Hi, I tried that "relay" workaround, but no plugin under "Tools/Configure plugins" appeared.
I have PLSQL Developer build 1790 64bit (latest build)
My steps:
1. Install Embarcadero C++ Builder (huge sw)
2. C++ Builder: New Dynamic link library, C++, no target framework
3. C++ Builder: Rename dll to RelayDLL
4. C++ Builder: Add target platform 64-bit Windows (active)
5. C++ Builder: Put all your code in cpp/h files
6. C++ Builder: change line in code to: hm = LoadLibrary("PlugIns\\Demo2.dll.relay");
7. C++ Builder: make dll (relase) and copy to PlugIns dir
8. Rename Demo2.dll (included in Developer installation as example) to Demo2.dll.relay (in PlugIns dir)
9. Put files: borlndmm.dll, cc64230.dll, cc64230mt.dll into c:\Program Files\PLSQL Developer
from Embarcadero\Studio\17.0\Redist\win64
10. Start Developer: no new plugin found

What did I missed?

PS: I have written my own plugin, 32bit Developer perfectly functional
 
Vorbis
You should be close, but unfortunately, the 30 days are over for me and can't recheck on the software to verify the parameters you did use.

You may check if you are compiling for proper target
and maybe add some "MessageBox" call to check if it run or not - especially in the _libmain to check if the DLL is called (it should react if PL/SQL try to load the DLL, even if it fail), and to test if the LoadLibrary call did work and hm value is no longer null.

Also, the bad bug, but in case of.. make sure your shortcut to run PL/SQL developer run the 64 bits.. it did happen to me that I was testing but running the 32 bits one.. and asking myself why it did not work.

It did take a few attempt for me before it start running.
 
Hi Nicolas, I put as first command in _libmain:
MessageBox(HWND_DESKTOP,"TEST mesydz",NULL,MB_OK);

And after start 64bit Developer, it showed me TWO MessageBoxes with "TEST mesydz" (second after I click OK button).
It's funny, I tried 32bit compilation in 64bit Developer - same result :-) Myabye I will need to try something 32bit compilation in Embarcadero for 32bit Devel. I'll find time for this.
Do you think I can request support from support team?
Thnak you a lot
 
SO at least your DLL is visible... now need to ensure the Visual Studio one properly load.

Strange that it react, a 32 bits DLL should not load in a 64 bits program, and reverse also true.

Not sure the support team will be able to help with this fancy workaround :)
 
Hello Vorbis,

MinGW64 ("Minimalistic GNU for Windows) also works.

Here is the code for the demo sample from the first post to play around.

#include

extern "C"
{
__declspec(dllexport) char* IdentifyPlugIn(int);
__declspec(dllexport) char* CreateMenuItem(int);
__declspec(dllexport) void OnMenuClick(int);
}

#include "relay_demo.h"

HMODULE hm;

// Pointer to all functions I should be able to call from relayed DLL
typedef char* (*IdentifyPlugInPtr)(int);
typedef char* (*CreateMenuItemPtr)(int);
typedef void(*OnMenuClickPtr)(int);

// Pointers to to each of them.
IdentifyPlugInPtr IdentifyPlugInFct;
CreateMenuItemPtr CreateMenuItemFct;
OnMenuClickPtr OnMenuClickFct;

BOOL WINAPI DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
if (ul_reason_for_call == DLL_PROCESS_ATTACH || ul_reason_for_call == 1) {
hm = LoadLibrary("PlugIns\\demo.dl_");
if (hm == NULL)
{
return false;
}

//Connect C function for the real DLL to the pointer
IdentifyPlugInFct = (IdentifyPlugInPtr)GetProcAddress(hm, "IdentifyPlugIn");
CreateMenuItemFct = (CreateMenuItemPtr)GetProcAddress(hm, "CreateMenuItem");
OnMenuClickFct = (OnMenuClickPtr)GetProcAddress(hm, "OnMenuClick");
}

if (ul_reason_for_call == DLL_PROCESS_DETACH || ul_reason_for_call == 0) {
FreeLibrary(hm);
}
return true;
}

extern "C" {

__declspec(dllexport) char* IdentifyPlugIn(int ID) {
if (IdentifyPlugInFct == NULL) {
return "";
}
return IdentifyPlugInFct(ID);
}

__declspec(dllexport) char* CreateMenuItem(int ID) {
if (CreateMenuItemFct == NULL) {
return NULL;
}
return CreateMenuItemFct(ID);
}
__declspec(dllexport) void OnMenuClick(int ID) {
if (OnMenuClickFct == NULL) {
return;
}
return OnMenuClickFct(ID);
}
}

 
Adding a note for Marco -- the issue loading PlugIn compiled from Visual Studio could be related to the size of the address on the 64 bits version?

Using DLL Export Viewer, the Address of the function in the DLL show as 0x000000018001b240 on the VS compiled one (64 bits address) while the addresses on the relay or plugin you provide show a 32 bit address -- 0x00401620 for example.

Maybe it can help.

Note: Tried to use linker paramater /LARGEADDRESSAWARE:NO to avoid 64 bits addresses, but it is refused - this parameter is ignored because of /DLL (LNK4075 warning)
 
Last edited:
I don't use 64 bit PSD, so I can't check this, but I've found a related post.

When I added the x64 platform in VS2010 it set 2 settings that cause the whole issue: Project options > Linker > Advanced > - Randomized Base Address - Data Execution Prevention (DEP)
Disabling those 2 settings fixed it.
 
No luck, plugin still won't load after rebuilding the project with those parameters disabled (I use VS2012 but they are the same).
And addresses still show as a 64 bits addresses

But the comment below the one you did quote is same as what I refer above -- maybe just one object that is not able to handle those 64 bits addresses.
 

Similar threads

Back
Top