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:
with external environment (language c_odbc64):
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 Dütting |
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? answered 28 Mar '12, 12:42 Markus Dütting 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... 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; answered 28 Mar '12, 10:22 Breck Carter 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
|
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.
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.
No, personally I'm still on 32-bit - but big @Breck is not:)
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
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?
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.
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:)