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.

asked 28 Mar '12, 08:38

Markus%20D%C3%BCtting's gravatar image

Markus Dütting
53641220
accept rate: 30%

Have you tried to debug the DLL from the VS IDE (with the dbeng12/dbsrv12 process as debuggee)?

That could help to find out whether the DLL can be loaded or not.

This answer may also help on how to debug such a DLL, e.g. by trying to call a non-existing function from that DLL. It deals with external environments but should work with internal calls, too, I guess.

(28 Mar '12, 09:59) Volker Barth

Up until now, i did'nt test this. As the error message led me in a different direction. But i wil try this asap. The error could be even in the calling of extfn_use_new_api from the engine.

Do you have experience with 64 bit dll's? I'm unsure if anyone ever used them.

(28 Mar '12, 10:16) Markus Dütting
Replies hidden

No, personally I'm still on 32-bit - but big @Breck is not:)

(28 Mar '12, 10:26) Volker Barth

Yes, Foxhound uses both 32 and 64-bit DLLs depending on which bit-ness of SQL Anywhere 12.0.1 is in use. I agree that the external environment sucks big wampum, and yes, I had enormous difficulties with datatypes. Some discussions...

http://sqlanywhere.blogspot.ca/2011/02/loading-32-bit-versus-64-bit-dlls.html

http://sqlanywhere.blogspot.ca/2011/02/loading-32-bit-versus-64-bit-dlls_16.html

http://sqlanywhere-forum.sap.com/questions/6215/should-i-use-dt_unsbigint-for-hkey-values-returned-from-a-64-bit-external-procedure-call

(28 Mar '12, 10:30) Breck Carter

Start by using procmon (http://technet.microsoft.com/en-us/sysinternals/bb896645) to determine whether the server finds the DLL & attempts to load it. If so, does the OS report an error during the load?

(28 Mar '12, 11:42) John Smirnios

Very nice. On my development machine it works flawless. On our DB server, where i do all my testing but don't have Visual Studio, it doesn't work and i triple checked that it is actually running the 64 bit variant. It's even the same build number on both machines 11.0.1.2606. I also tried an absolute path like in Brecks example and checked the permissions (would be strange as i can load 32 bit dll's from the same directory). I simply have no clue, what's happening.

(28 Mar '12, 12:01) Markus Dütting
Replies hidden

FWIW, you may be able to use Visual Studio's remote debugging feature to debug programs running on your production servers from your local machine - it needs just the remote debugging tools on the servers and works fine IMHO:)

(29 Mar '12, 03:00) Volker Barth
showing 4 of 7 show all flat view

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?

permanent link

answered 28 Mar '12, 12:42

Markus%20D%C3%BCtting's gravatar image

Markus Dütting
53641220
accept rate: 30%

edited 03 Apr '12, 12:15

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:)

(28 Mar '12, 12:56) Volker Barth
Replies hidden

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

(28 Mar '12, 13:10) Markus Dütting

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

(28 Mar '12, 13:49) Mark Culp

...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...

(28 Mar '12, 15:49) Volker Barth

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...

alt text

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;

permanent link

answered 28 Mar '12, 10:22

Breck%20Carter's gravatar image

Breck Carter
27.3k424585836
accept rate: 21%

edited 28 Mar '12, 10:41

He said that loading 32bit DLLs worked for him

(28 Mar '12, 10:31) Martin
Replies hidden

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

(28 Mar '12, 10:44) Breck Carter

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.

(28 Mar '12, 11:11) Markus Dütting
Replies hidden
1

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.

(28 Mar '12, 11:19) Volker Barth
Comment Text Removed

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.

(28 Mar '12, 12:12) Markus Dütting

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:(

(28 Mar '12, 13:04) Volker Barth

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

(28 Mar '12, 13:40) Markus Dütting
showing 2 of 7 show all flat view
Your answer
toggle preview

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Markdown Basics

  • *italic* or _italic_
  • **bold** or __bold__
  • link:[text](http://url.com/ "title")
  • image?![alt text](/path/img.jpg "title")
  • numbered list: 1. Foo 2. Bar
  • to add a line break simply add two spaces to where you would like the new line to be.
  • basic HTML tags are also supported

Question tags:

×22
×8

question asked: 28 Mar '12, 08:38

question was seen: 2,478 times

last updated: 03 Apr '12, 12:15