cancel
Showing results for 
Search instead for 
Did you mean: 

Can't load external 64 bit DLL

Former Member
5,325

Has someone successfully created a 64 bit DLL for external procedures?

I had a few serious issues with external environments (instability, slow) and therefore wanted to go back the "old" way of not using it. I don't mean the old interface for external librarys i use extfn_use_new_api. I successfully created a few dll's with Delphi 2006 but as we gradually moved to 64 bit servers (Delphi 2006 is 32 bits only and you can't use 32 bit dll's with a 64 bit server without an external environment) i also wanted to create 64 bit dll's. As i had Visual Studio 2010 lying around i tried my luck and created a very simple test dll compiled for the x64 platform:

#include "stdafx.h"

#include "extfnapi.h"

extern "C" __declspec(dllexport) unsigned int extfn_use_new_api( void )
{
    return( EXTFN_API_VERSION );
}

extern "C" __declspec(dllexport) void lib64test( an_extfn_api *api, void *arg_handle )
{
}

ALTER PROCEDURE "FCT"."Test64"() external name 'lib64test@Test64.dll'

But when i dont use an external environment i get the error message:

Could not load dynamic library 'Test64.dll' (-620)

with external environment (language c_odbc64):

Procedure 'Test64' terminated with unhandled exception 'Test64.dll could not be found' (-91)

I can load 32 bit dll's from the directory, i even copied the dll into the appropriate bin64 directory to no avail.

Accepted Solutions (1)

Accepted Solutions (1)

Former Member

I started the db with dbeng and got the error message that "msvcr100.dll" would be missing. This error message doesn't get shown if you use a service as it can't "communicate" with the desktop. As always the problem sits behind the keyboard. Sorry for all the noise and thanks for the incredibly fast help. Just statically linking the runtime library with /MT and all is good. How should i close this thing now?

VolkerBarth
Contributor
0 Kudos

Feel free to turn your comment into an answer and accept that as "the answer" - if the other ones do not fit as explanation...

IMHO, there's no need to "close" anything here:)

Former Member
0 Kudos

Just seems wrong to answer my own stupid question with a declaration of my own foolishness.

MarkCulp
Participant
0 Kudos

There is no such thing as a stupid question on this forum!

VolkerBarth
Contributor
0 Kudos

...and it's always helpful to get to know what - sometimes unexpected - solution was found.

Besides that: I do learn (or better: get reminded) from your experience that one should try with dbeng12/dbsrv12 as a "normal application" instead of as a service when something doesn't work as expected - simply as services sometimes are less verbose in their error messages/warnings...

Answers (1)

Answers (1)

Breck_Carter
Participant

Quite often the "could not load" message simply means the dll isn't there (or isn't in the right place, same thing from the server's point of view).

I assume you picked the right platform and other properties when building...


Re Cant load external 64 bit DLL

Does your procedure really have no parameters? I've never used ALTER PROCEDURE, only DROP and CREATE, and they all have parameter lists.

I'm fairly certain some (a lot?) of the following #stuff is unnecessary, but that's what happens with legacy code.

Anyway, the following code works with the 64-bit SQL Anywhere 12.0.1 server, and the CREATE PROCEDURE dynamically chooses which DLL to used based on which bit-ness of SQL Anywhere is in use.

#if defined( WIN32 )
   #include <windows.h>
#endif

#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#if defined( _MSC_VER )
   #include <tchar.h>
#endif

#include "extfnapi.h"
#include "Shlobj.h"

#if !defined( _unused )
#define _unused( i )    ( (i) = (i) )
#endif

#if !defined( TRUE )
#define TRUE 1
#endif
#if !defined( FALSE )
#define FALSE 0
#endif

#if defined( WIN32 )
    #define _UINT32_ENTRY   unsigned int FAR __stdcall
    #define _VOID_ENTRY     void FAR __stdcall
#else
    #define _UINT32_ENTRY   unsigned int 
    #define _VOID_ENTRY     void 
#endif

#define int64   __int64
#define uint64  unsigned __int64

#if defined( WIN32 )
int __stdcall LibMain(
    HANDLE inst,
    ULONG reasoncalled,
    LPVOID reserved )
/*********************/
{
    _unused( inst );
    _unused( reasoncalled );
    _unused( reserved );
    return( 1 );
}
#endif

__declspec(dllexport) _UINT32_ENTRY extfn_use_new_api( void )
{
    return( EXTFN_API_VERSION );
}

__declspec(dllexport) _VOID_ENTRY get_first_dsn ( an_extfn_api *api, void *arg_handle ) {

...etcetera

SET @sql = STRING ( 
   'CREATE PROCEDURE rroad_get_first_dsn ( ',
      'IN    dsn_type_code     UNSIGNED INTEGER, ',
      IF @rroad1_dll_name = 'rroad1.dll'
         THEN 'OUT   odbc_hkey         UNSIGNED INTEGER, ' 
         ELSE 'OUT   odbc_hkey         UNSIGNED BIGINT, ' 
      ENDIF,
      'OUT   dsn_index         UNSIGNED INTEGER, ',
      'OUT   odbc_dsn          VARCHAR ( 255 ), ',
      'OUT   odbc_driver       VARCHAR ( 255 ), ',
      'OUT   return_code       UNSIGNED INTEGER, ',
      'OUT   diagnostic_code   UNSIGNED INTEGER, ',
      'OUT   diagnostic_string VARCHAR ( 255 ) ) ',
   'EXTERNAL NAME ''get_first_dsn@', @foxhound_db_folder, '\\\\', @rroad1_dll_name, '''' );

EXECUTE IMMEDIATE @sql;

MCMartin
Participant
0 Kudos

He said that loading 32bit DLLs worked for him

Breck_Carter
Participant
0 Kudos

@Martin... yeah, speed-reading-without-comprehending leaves something to be desired 🙂

Former Member
0 Kudos

This is just a test as simple as i could imagine, because the real function also did'nt work. I want to use zlib compression in our application to compress big documents (up to 5 Mb very compressible rtf text) before saving them in the db. I could use the compress flag of the column i know, but then the problem becomes the network and client memory usage. I just want to be able to decompress the content in the database on ocassion, not only in the client. I can load the same code compiled as 32 bit but not as x64. I also checked your screenshot with my settings and couldn't find a difference. Perhaps i have to use the defines from the example code, but i'm not a big fan of them, makes code very fast really unreadable. But i'm a Delphi porgrammer so that could be the real problem.

VolkerBarth
Contributor

FWIW, if you want to compress data on demand, there are also the builtin COMPRESS()/DECOMPRESS() functions. - Note, they are executed in the server, not on the client, so they won't help to reduce network traffic or the like.

Former Member
0 Kudos

We have customers with version 8 to 12 and i want to reliably decompress in our client application. But that was a good tip nevertheless, i thougt compress/decompress would use a proprietary format, but it seems it would be possible to decompress in a client application, though i didnt't test this.

VolkerBarth
Contributor
0 Kudos

AFAIK, the "zip" algorithm is not necessarily compatible with client-side libraries - the "gzip" seems compatible with Unix tools. I think I remember there are some hints to that in this forum (possibly from Graeme) but couldn't just find them:(

Former Member
0 Kudos

zlib should be able to compress/decompress the "gzip" format. I will try that and report back.