Using sqlite3_load_extension with a windows DLL - c++

Can anyone tell me where I'm going wrong here?
I'm using C++ bulder 10.2 (clang compiler). From IDE menu I've selected File|New|Dynamic Link Library and chosen compile as C with no dependencies. I've then added sqliteFcts.c and made the sqliteFcts.dll library. It all compiles fine.
Contents of sqliteFcts.c.
#include <sqlite3ext.h>
SQLITE_EXTENSION_INIT1
#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_sqliteFcts_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
return rc;
}
// My code is above. Code below was created by the IDE
#pragma argsused
int _libmain(unsigned long reason)
{
return 1;
}
From my own app I try to use the dll with the following code
int rc;
sqlite3_db_config(db,SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION,1,&rc);
rc=sqlite3_load_extension(db,"C:/temp/sqliteFcts.dll",0,&buf);
I get the error message "The specified procedure could not be found". From what I've read windows expects _libmain to be the Entry Point but sqlite expects sqlite3_sqliteFcts_init to b e the Entry Point and I've no idea how to resolve that or if that is even the problem.

I finally got it working but with a loose end.
Firstly in this line
rc=sqlite3_load_extension(db,"C:/temp/sqliteFcts.dll",0,&buf);
I supplied a null for the 3rd parameter (the entry point) thinking sqlite would resolve this however sqlite would've supplied sqlite3_sqlitefcts_init (note lower case f) as the entry point so, inevitably, the function wouldn't be found. The line should read
rc=sqlite3_load_extension(db,"C:/temp/sqliteFcts.dll","sqlite3_sqliteFcts_init",&buf);
That said, it still didn't work. After advice I received on the sqlite forum I downloaded Dependency Walker and found the function listed as _sqlite3_sqliteFcts_init (note opening underscore) although I've no idea why. Anyway, I changed the above line to
rc=sqlite3_load_extension(db,"C:/temp/sqliteFcts.dll","_sqlite3_sqliteFcts_init",&buf);
and it worked. That was for a 32 bit implementation. I later discovered that when it was compiled as a 64 bit app the opening underscore wasn't required. If anyone can throw any light on this quirk I'd be grateful.

Related

strncasecmp and strcasecmp has not been declared

I'm trying to compile Assimp with MinGW in Code::Blocks, but I get the following errors.
\assimp-3.3.1\assimp-3.3.1\code\StringComparison.h||In function 'int Assimp::ASSIMP_stricmp(const char*, const char*)':|
\assimp-3.3.1\assimp-3.3.1\code\StringComparison.h|144|error: '::strcasecmp' has not been declared|
\assimp-3.3.1\assimp-3.3.1\code\StringComparison.h||In function 'int Assimp::ASSIMP_strincmp(const char*, const char*, unsigned int)':|
\assimp-3.3.1\assimp-3.3.1\code\StringComparison.h|193|error: '::strncasecmp' has not been declared|
While searching I've found out that the two functions in question (strcasecmp and strncasecmp) are in fact declared in string.h which is included in the header of StringComparison.h. I've also managed to get strings.h, the file which they originally belong to, but including that didn't solved the issue either.
While searching this site I've found out that I'm not the only one struggling with this issue. Another solution I've found suggested to use define statements, because the functions might have a slightly different name, but that didn't helped either.
I just encountered this exact same problem, and this question came up during a Google search for the solution, so I'll document my dodgy solution here:
In the end I got it going just by making multiple small edits to the Assimp source code. Solving the string problem isn't enough to get it to work because it just fails later in the build. I'll list the edits I made below. I recommend making them one at a time and then rebuilding, just in case for whatever reason with your setup some of them aren't required. Note that you can't do model exporting with this solution because of the last edit (to Exporter.cpp) if you really need that you'll have to figure out another way to fix the link errors.
It's not a clean solution and it will probably be superceded by a future version of Assimp, at which point I will just delete it. This is for assimp-3.3.1, built with MinGW:
In StringComparison.h, edit the ASSIMP_stricmp function, commenting out everything except the else clause of the #ifdef:
/*#if (defined _MSC_VER)
return ::_stricmp(s1,s2);
#elif defined( __GNUC__ )
return ::strcasecmp(s1,s2);
#else*/
char c1, c2;
do {
c1 = tolower(*s1++);
c2 = tolower(*s2++);
}
while ( c1 && (c1 == c2) );
return c1 - c2;
//#endif
Do a similar thing in ASSIMP_strincmp.
Next, it throws up an error about ::_fullpath in DefaultIOSystem.cpp. My "fix" for this was just to use comment out everything other the fallback option in this function:
ai_assert(in && _out);
// char* ret;
//#if defined( _MSC_VER ) || defined( __MINGW32__ )
// ret = ::_fullpath( _out, in, PATHLIMIT );
//#else
// use realpath
// ret = realpath(in, _out);
//#endif
// if(!ret) {
// preserve the input path, maybe someone else is able to fix
// the path before it is accessed (e.g. our file system filter)
// DefaultLogger::get()->warn("Invalid path: "+std::string(in));
strcpy(_out,in);
// }
It also complains about snprintf being undefined. Edit StringUtils.h to change the following #define to add an underscore before snprintf:
# define ai_snprintf _snprintf
There's also an error about ::atof not being defined. You can fix this by adding
#include <cstdlib>
to StringUtils.h
This should get it building but there will be a link error in Exporter.cpp (this might be due to my specific CMake setttings because I disabled almost all model formats). I fixed it by commenting out the definition of gExporters and replacing it with this:
Exporter::ExportFormatEntry* gExporters = 0;
After this it built and ran fine. The library files are placed in the code folder. Place libassimp.dll.a in your lib build path and libassimp.dll in the path of your executable.
Of course, you can also get it going by using VisualStudio instead (I didn't because I couldn't be bothered installing it) or by building on Linux (I did this previously and it built fine first go, but I needed to do a Windows port).
I had some problems too but hopefully I was able to solve them. I know this is probably too late to help in particular but I hope someone on the Internet will find this useful. I compile using Code::Blocks 16.01 using gcc 5.3.0.
::strncasecmp not declared in this scope:
You have to include and remove the "::"
::_fullpath not declared in this scope:
I never had to perform the operation of finding a full path, so this one is the one I am the least sure of. But anyway, since I couldn't simply remove everything, I had to find the alternative. That is, using "GetFullPathName".
So, as suggested by MSDN, I included , , , .
I also replace the line :
ret = _fullpath( _out, in, PATHLIMIT );
by
ret = (char*)GetFullPathName(in, PATHLIMIT, _out, NULL);
Should work fine, full path is obtained and error checking is kept too.
vsnprintf not declared in this scope
Just add an underscore _ in front of the function name.
to_string is not a member of std::
I would have that this is the usual bug from using MinGW, but actually, Assimp contains a built-in alternative to std::to_string. You just have to remove the std:: part and it should roll.
Make sure to include in the files in which just removing std:: doesn't work.
test\CMakeFiles\gtest.dir\build.make|109|recipe for target 'test/gtest/src/gtest-stamp/gtest-build' failed| ?
It doesn't matter, you already have your working .dll in the "code" folder ;)
I was using Cygwin and encounter the same error, using strncmp and strcmp worked, guessing it is something to do with the libraries (ANSI C++) currently implemented for Cygwin or being used by your project. Not sure though, just wanted it to work for the moment...

Visual Studio 2013 Floating Point Support fix?

I have a DLL, which is commercial software, so therefore I cannot show the code here...
I get the error "6002" -floating point support not loaded, but only on some applications.
This dll is hooked to several applications, without problems.
I tried everything that I found on Google, like reinstalling VC++, clean PC, registry, everything.
So my conclusion is that either there is another dll compiled in another version of Visual Studio (2010) and it`s somehow conflicting with my dll ?!
Or, I have some memory leak, which I cannot find.
I use the following functions in my DLL which (I think) is the issue:
sscanf(); // DISABLED IT FOR TEST, BUT STILL GET ERROR
fprintf_s();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DisableThreadLibraryCalls(hModule);
DetourRestoreAfterWith();
_beginthreadex();
strtoul();
Example function I use for logging:
void ##SOFTWARE-CLASS##::write_log(char *text)
{
FILE *write_log;
char dateStr [9];
char timeStr [9];
_strdate( dateStr);
_strtime( timeStr );
write_log = fopen("##SOFTWARE-FILE##","a+");
fprintf_s(write_log,"[%s %s] %s \n", dateStr, timeStr, text);
fclose(write_log);
}
Nothing else is used that may cause floating errors...
The dll is hooked properly, I have no warnings, and no errors.
I must mention, that I have created an empty DLL, with a MessageBox, at the first run, I was getting the same error, but after switching to /fp:strict, the error disappeared. So I did the same thing to my project, but the error is still there. I even recoded the whole project, just to see if it fixes the problem, but no.
Please give me advice on how can I solve this problem, as this is the third day that I am testing...
From MSDN : R6002 the document says that a program will only load floating point support if needed. What this means, is that the detoured code is being injected into binaries which did not initialize the floating point subsystem. The solution would be to relink your commercial product without requiring the floating point code, or to relink with an alternative floating point library.
You could try and detect the missing initialization and perform it yourself, but that would have a larger impact on the injected system, and possibly create instabilities.
Use a debugger with the failing executable, and you should be able to get a call stack which identifies where the failure occurs.

Assigning value to float data type crashes program

I'm losing my mind here. Please someone help me understand what is going on.
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <windows.h>
int main(int argc, char *argv[])
{
float test;
printf("You see me\n");
test = 3;
printf("Wont get here\n");
return(0);
}
You see me is printed out then the app crashes before the Wont get here is printed.
Important to note that this compiles and runs fine on my system, but when this exe is transferred to a 32 bit, Windows XP machine it crashes.
Ints, Bools, char data formats work fine, but when I try to use floats/doubles the app just crashes with no error.
Am I not compiling this correctly in Visual Studio Express 2013 in some way that anyone can think of? Should I check myself into the local loony ward?
Okay found the issue with the help of a colleague.
The windows machine has an older processor, Geode Integrated Processor.
Found the answer here: http://msdn.microsoft.com/en-us/library/7t5yh4fd.aspx
Open the Property Pages dialog box for the project.
Select the C/C++ folder.
Select the Code Generation property page.
Modify the Enable Enhanced Instruction Set property.
In my case I needed to change this to /arch:IA32. Bam! Works! Thank you all for the brainstorming session.

swprintf fails with unicode characters in xcode, but works in visual studio

While trying to convert some existing code to support unicode characters this problem popped up. If i try to pass a unicode character (in this case im using the euro symbol) into any of the *wprintf functions it will fail, but seemingly only in xcode. The same code works fine in visual studio and I was even able to get a friend to test it successfully with gcc on linux. Here is the offending code:
wchar_t _teststring[10] = L"";
int _iRetVal = swprintf(_teststring, 10, L"A¥€");
wprintf(L"return: %d\n", _iRetVal);
// print values stored in string to check if anything got corrupted
for (int i=0; i<wcslen(_teststring); ++i) {
wprintf(L"%d: (%d)\n", i, _teststring[i]);
}
In xcode the call to swprintf will return -1, while in visual studio it will succeed and proceed to print out the correct values for each of the 3 chars (65, 165, 8364).
I have googled long and hard for solutions, one suggestion that has appeared a number of times is using a call such as:
setlocale(LC_CTYPE, "UTF-8");
I have tried various combinations of arguments with this function with no success, upon further investigation it appears to be returning null if i try to set the locale to any value other than the default "C".
I'm at a loss as to what else i can try to solve this problem, and the fact it works in other compilers/platforms just makes it all the more frustrating. Any help would be much appreciated!
EDIT:
Just thought i would add that when the swprintf call fails it sets an error code (92) which is defined as:
#define EILSEQ 92 /* Illegal byte sequence */
It should work if you fetch the locale from the environment:
#include <stdio.h>
#include <wchar.h>
#include <locale.h>
int main(void) {
setlocale(LC_ALL, "");
wchar_t _teststring[10] = L"";
int _iRetVal = swprintf(_teststring, 10, L"A¥€");
wprintf(L"return: %d\n", _iRetVal);
// print values stored in string to check if anything got corrupted
for (int i=0; i<wcslen(_teststring); ++i) {
wprintf(L"%d: (%d)\n", i, _teststring[i]);
}
}
On my OS X 10.6, this works as expected with GCC 4.2.1, but when compiled with CLang 1.6, it places the UTF-8 bytes in the result string.
I could also compile this with Xcode (using the standard C++ console application template), but because graphical applications on OS X don't have the required locale environment variables, it doesn't work in Xcode's console. On the other hand, it always works in the Terminal application.
You could also set the locale to en_US.UTF-8 (setlocale(LC_ALL, "en_US.UTF-8")), but that is non-portable. Depending on your goal there may be better alternatives to wsprintf.
If you are using Xcode 4+ make sure you have set an appropriate encoding for your files that contain your strings. You can find the encoding settings on a right pane under "Text Settings" group.
Microsoft had a plan to be compatible with other compilers starting from VS 2015 but finally it never happened because of problems with legacy code, see link.
Fortunately you can still enable ISO C (C99) standard in VS 2015 by adding _CRT_STDIO_ISO_WIDE_SPECIFIERS preprocessor macro. It is recommended while writing portable code.
I found that using "%S" (upper case) in the formatting string works.
"%s" is for 8-bit characters, and "%S" is for 16-bit or 32-bit characters.
See: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html
I'm using Qt Creator 4.11, which uses Clang 10.

Installer::OpenDatabase() produces a type error with msiOpenDatabaseModeTransact

The following code produces an error hr=0x80020005 (wrong type).
#import <msi.dll>
using namespace WindowsInstaller;
main()
{
::CoInitialize(NULL);
InstallerPtr pInstaller("WindowsInstaller.Installer");
DatabasePtr pDB = pInstaller->OpenDatabase(
"c:\\foo\\bar.msi",
msiOpenDatabaseModeTransact);
}
I think the reason is that behind the scene, there is MsiOpenDatabase(), which
take a LPCTSTR as second argument.
This second argument can be MSIDBOPEN_TRANSACT whose definition is
#define MSIDBOPEN_TRANSACT (LPCTSTR)1
I do not know if it is possible to give a variant with the good inner type as second argument. The _variant_t constructor does many checks, so I can't disguise an int into
a char* so easily.
Has anyone tried to use this method in C++?
Edit:
My version of msi.dll is 3.1.4000.2805, my system is XP SP 2, and the code is supposed to run on any machine with XP or Vista.
urls to MSDN articles are welcome.
On the same machine, the call to the low-level equivalent:
MsiOpenDatabase("c:\\foo\\bar.msi", MSIDBOPEN_TRANSACT);
works perfectly.
I finally got the answer on msdn forums
DatabasePtr pDB = pInstaller->OpenDatabase(
"c:\\foo\\bar.msi",
(long)msiOpenDatabaseModeTransact);
MSDN says OpenDatabase is available from MSI version 4.0 onwards, transactions in general from MSI 4.5 onwards. Just a hunch, but could it be that your MSI is outdated? I once had some mysterious trouble with an outdated MSI version.