Ever since the "disatrous" Adobe Encore (CS4 and 5 does not matter)'s way of storing the installation directory details in Sqlite database file and some uninstall string in the registry, I would like to create dll to get the install directory from Sqlite database as per recommended by the Inno Setup (I can only use that to create some language pack installer for now.) users (http://news.jrsoftware.org/read/article.php?id=24706&group=jrsoftware.innosetup.code#24706).

Hence, I have written a dll in VB.NET as I am only familiar with that (I do not have any experience in C++, so sorry for that) and only to realized that Inno Setup can only call native dlls (Code for VB.NET is here): http://www.daniweb.com/forums/thread310549.html

So the problem is, I would like to create a C++ Native DLL and such that, I have the following prototype in my code (main.h):

#ifndef __MAIN_H__
#define __MAIN_H__

#include <windows.h>
#include <string>
#include <sstream>
/*  To use this exported function of dll, include this header
 *  in your project.
 */
    #define DLL_EXPORT __declspec(dllexport)


#ifdef __cplusplus
extern "C"
{
#endif
[B]string[/B] DLL_EXPORT GetDirectory([B]string[/B] SubDomain);

#ifdef __cplusplus
}
#endif

#endif // __MAIN_H__

And in main.cpp

#include "main.h"
#include "cppSQLite3.h"
#include <iostream>
#include <string>

// a sample exported function
[B]string[/B] DLL_EXPORT GetDirectory([B]string[/B] Subdomain)
{
        //Write a function to get the installation directory.
  [I]  return 0;[/I]
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    switch (fdwReason)
    {
        case DLL_PROCESS_ATTACH:
            // attach to process
            // return FALSE to fail DLL load
            break;

        case DLL_PROCESS_DETACH:
            // detach from process
            break;

        case DLL_THREAD_ATTACH:
            // attach to thread
            break;

        case DLL_THREAD_DETACH:
            // detach from thread
            break;
    }
    return TRUE; // succesful
}

I have the CppSQLite from http://www.codeproject.com/KB/database/CppSQLite.aspx and I have no complication error when I changed the bold part into int
and hence the italics return 0; as I do not have an idea to declare a string variable.

For now, I am not asking on how to connect Sqlite connection but as why cant I put string as a type but can only have int / char? How should I do such that it accepts a receiving and returning string values (Receiving the target value / column to be searched, such as: {27B54140-8302-4B5D-83DD-AEE4B18BC7A4} while returning the installation path before researching on Sql issue.

Thanks a lot.

Recommended Answers

All 27 Replies

What you want is a character array char buffer[255]; That declares an array of 255 characters. c++ also has a std::string class, but you can not use that with SqLite database.

You have to be careful about allocating new memory in a DLL. Memory allocated in a dll with new or malloc() must also be destroyed in that same dll. (std::string allocates memory like that) So you would need to declare that function like this: char* DLL_EXPORT GetDirectory(const char* Subdomain, char* returnbuf) where returnbuf (or whatever you want to call it) is a character array allocated by the calling function and used by GetDirectory() to store the string it needs to return. The return value of that function is just returnbuf, or NULL if an error occurs. You could also make the return value just a bool, indicating either success or failure.

What you want is a character array char buffer[255]; That declares an array of 255 characters. c++ also has a std::string class, but you can not use that with SqLite database.

You have to be careful about allocating new memory in a DLL. Memory allocated in a dll with new or malloc() must also be destroyed in that same dll. (std::string allocates memory like that) So you would need to declare that function like this: char* DLL_EXPORT GetDirectory(const char* Subdomain, char* returnbuf) where returnbuf (or whatever you want to call it) is a character array allocated by the calling function and used by GetDirectory() to store the string it needs to return. The return value of that function is just returnbuf, or NULL if an error occurs. You could also make the return value just a bool, indicating either success or failure.

Thanks for the tip, but I would like to know how to get program files (32bit one even on 64bit OS) directory on C++. Thanks a lot as that will be used for the database directory as well (If it is possible, avoid the need of passing parameters as it is on a fixed location, at Program Files\Common Files\Adobe\Adobe PCD\pcd.db. The Program Files is indeed a (x86) one for 64bit OS case.

By the way, I still dont get the part on

, char* returnbuf

, as it sounded requiring 2 parameters (Correct me if I am mistaken, my apologies) which is not supposed to be the case (Or should I declare in somewhere else??).

Futhermore, I wonder this code:

char* DLL_EXPORT GetDirectory(const char* Subdomain,char* returnbuf)
{


        //Write a function to get the installation directory.
    return returnbuf;
}

on ".cpp" file, but I did not find a place to declare

char buffer[255];

Correction: I mean if I put the following code, it warns on warning: address of local variable 'buffer' returned.

char* DLL_EXPORT GetDirectory(const char* Subdomain,char* returnbuf)
{
char buffer[255];

        //Write a function to get the installation directory.
    return buffer;
}

The warning seems accurate. I don't think you can simply return an array because what you are doing is (as the warning states) returning the address of buffer. You should perhaps try returning an array pointer?

The warning seems accurate. I don't think you can simply return an array because what you are doing is (as the warning states) returning the address of buffer. You should perhaps try returning an array pointer?

I see, as I

return returnbuf

from the function will have no issues at all, except I was confused on the declaring of a 255 char long array.

The warning seems accurate. I don't think you can simply return an array because what you are doing is (as the warning states) returning the address of buffer. You should perhaps try returning an array pointer?

They are already returning a pointer, that's why there is an issue. You can't return a pointer to a local variable, which "buffer" is. This doesn't work because the local object/variable gets destroyed when it goes out of scope at the end of the function. Because the object gets destroyed, the returned pointer is a "dangling pointer", which can be extremely dangerous.

Hence, the reason AD suggested simply returning a bool and using a pointer parameter (char *returnbuf) to get the necessary value back from the function.

They are already returning a pointer, that's why there is an issue. You can't return a pointer to a local variable, which "buffer" is. This doesn't work because the local object/variable gets destroyed when it goes out of scope at the end of the function. Because the object gets destroyed, the returned pointer is a "dangling pointer", which can be extremely dangerous.

Hence, the reason AD suggested simply returning a bool and using a pointer parameter (char *returnbuf) to get the necessary value back from the function.

I see, thanks for the clarification on the warning issues, but I would also like to know how to get 32bit Program Files in C++ in order to establish a connection string as well. Thanks a lot.

This is what I suggested

char* DLL_EXPORT GetDirectory(char* returnbuf)
{
    char buf[255] = {0};
    ExpandEnvironmentStrings("%CommonProgramFiles%", buf, sizeof(buf));
    strcat(buf,"\\Adobe\\Adobe PCD\\pcd.db";

        //Write a function to get the installation directory.
    return returnbuf;
}

Now, in some applcation program

char buffer[255];
char* ptr = GetDirectory(buffer);

if( ptr == NULL)
{
   // error
}

Hi everyone, especially thanks to AD, I hope this would be the last question pertaining to this thread, but when I do this code:

char* DLL_EXPORT GetDirectory(const char* Subdomain,const char* PCD,char* returnbuf)
{
        //Write a function to get the installation directory.
    try
    {
       CppSQLite3DB db;
       db.open(PCD);
       returnbuf = db.execScalar("select value From domain_data where SubDomain = '" & Subdomain &"' And key = 'AMTConfigPath';");
       db.close();
    return returnbuf;
    }
    catch (CppSQLite3Exception& e)
    {
      return NULL;
    }
}

The code::blocks showed this error message:
error: invalid operands of types 'const char [50]' and 'const char*' to binary 'operator&'
And by the way, I have decided that since I am a novice or rather, no experience in C++, I would rather add another parameter and it is up to my installer to input this directory instead might be an easier option, and hence I have added a new parameter named as PCD.

Any ideas on what I have done wrong and what should be done in order to have the char array to get the return value from Sqlite? Thanks a lot! (By the way, the query string is correct, as in extracted from the previous VB.NET code.)

line 8: This is not vb, -- its c++ and you can not concantinate strings like that

std::string command;
command = "select value From domain_data where SubDomain = '";
command += Subdomain;
command += "' And key = 'AMTConfigPath';";
returnbuf = db.execScalar(command.c_str());

line 8: This is not vb, -- its c++ and you can not concantinate strings like that

std::string command;
command = "select value From domain_data where SubDomain = '";
command += Subdomain;
command += "' And key = 'AMTConfigPath';";
returnbuf = db.execScalar(command.c_str());

Thanks for the clarification, however when I changed the code to (The entire function is shown):

char* DLL_EXPORT GetDirectory(const char* Subdomain,const char* PCD,char* returnbuf)
{
        //Write a function to get the installation directory.
    try
    {
       CppSQLite3DB db;
       db.open(PCD);
      [B]std::string command;
    command = "select value From domain_data where SubDomain = '";
    command += Subdomain;
    command += "' And key = 'AMTConfigPath';";
    returnbuf = db.execScalar(command.c_str());
[/B]       db.close();
    return returnbuf;
    }
    catch (CppSQLite3Exception& e)
    {
      return NULL;
    }
}

It give me this new error:
error: invalid conversion from 'int' to 'char*'|

Problem is, I did not see any integer being declared, so what had went wrong for now?

Thanks a lot...

On which line did that error occur? Your compiler should have told you.

Is Subdomain an integer? I thought it was a string or chracter array.

Did you include <string> header file?

On which line did that error occur? Your compiler should have told you.

Is Subdomain an integer? I thought it was a string or chracter array.

Did you include <string> header file?

Subdomain is not an integer as it must have a {,},- as well as alphabets from A to F (Hex value).

My project did not find any "int" keyword.

Also, the compiler says this error on the line

returnbuf = db.execScalar(command.c_str());

while I have these declarations

#include "main.h"
#include "cppSQLite3.h"
#include <iostream>
#include <string>

And the entire function for this

// a sample exported function
char* DLL_EXPORT GetDirectory(const char* Subdomain,const char* PCD,char* returnbuf)
{
        //Write a function to get the installation directory.
    try
    {
       CppSQLite3DB db;
       db.open(PCD);
      std::string command;
    command = "select value From domain_data where SubDomain = '";
    command += Subdomain;
    command += "' And key = 'AMTConfigPath';";
   [I] returnbuf = db.execScalar(command.c_str());[/I] //Error occurred here
       db.close();
    return returnbuf;
    }
    catch (CppSQLite3Exception& e)
    {
      return NULL;
    }
}

Hence, the entire cpp file goes

#include "main.h"
#include "cppSQLite3.h"
#include <iostream>
#include <string>

// a sample exported function
char* DLL_EXPORT GetDirectory(const char* Subdomain,const char* PCD,char* returnbuf)
{
        //Write a function to get the installation directory.
    try
    {
       CppSQLite3DB db;
       db.open(PCD);
      std::string command;
    command = "select value From domain_data where SubDomain = '";
    command += Subdomain;
    command += "' And key = 'AMTConfigPath';";
   [I] returnbuf = db.execScalar(command.c_str());[/I] //Error occurred here
       db.close();
    return returnbuf;
    }
    catch (CppSQLite3Exception& e)
    {
      return NULL;
    }
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    switch (fdwReason)
    {
        case DLL_PROCESS_ATTACH:
            // attach to process
            // return FALSE to fail DLL load
            break;

        case DLL_PROCESS_DETACH:
            // detach from process
            break;

        case DLL_THREAD_ATTACH:
            // attach to thread
            break;

        case DLL_THREAD_DETACH:
            // detach from thread
            break;
    }
    return TRUE; // succesful
}

In case the issue has to do with the h file, heres the h file

#ifndef __MAIN_H__
#define __MAIN_H__

#include <windows.h>
#include <string>
#include <sstream>
/*  To use this exported function of dll, include this header
 *  in your project.
 */
    #define DLL_EXPORT __declspec(dllexport)


#ifdef __cplusplus
extern "C"
{
#endif
char* DLL_EXPORT GetDirectory(const char* Subdomain,const char* PCD);

#ifdef __cplusplus
}
#endif

#endif // __MAIN_H__

You declared the third parameter as const char*. That's why the compiler complained about that assignment.

the function prototype in the header file is wrong. GetDirectory() has three parameters, not two. The last parameter can NOT be const.

The assignment is wrong anyway. returnbuf is where you have to copy the data.

strcpy(returnbuf,db.execScalar(command.c_str()));

In the main application program

char iobuf[255] = {0};
char* return = GetDirectory("something here", "something here", ibuf);

I still got error:
.cpp file:

char* DLL_EXPORT GetDirectory(const char* Subdomain,const char* PCD,char * returnbuf)
{
        //Write a function to get the installation directory.
    try
    {
       CppSQLite3DB db;
       db.open(PCD);
      std::string command;
    command = "select value From domain_data where SubDomain = '";
    command += Subdomain;
    command += "' And key = 'AMTConfigPath';";
[I] strcpy(returnbuf,db.execScalar(command.c_str()));[/I]
       db.close();
    return returnbuf;
    }
    catch (CppSQLite3Exception& e)
    {
      return NULL;
    }
}

.h file:

#ifndef __MAIN_H__
#define __MAIN_H__

#include <windows.h>
#include <string>
#include <sstream>
/*  To use this exported function of dll, include this header
 *  in your project.
 */
    #define DLL_EXPORT __declspec(dllexport)


#ifdef __cplusplus
extern "C"
{
#endif
char* DLL_EXPORT GetDirectory(const char* Subdomain,const char* PCD, [I]char* iobuf[/I]);

#ifdef __cplusplus
}
#endif

#endif // __MAIN_H__

The italics are ones that are edited to.

By the way, is there any thing to do with the dependent (CppSqlite3) where I just simply CppSQLite3.cpp, CppSQLite3.h, sqlite3.def,sqlite3.h,sqlite3.lib on to the project directory?

This time round, the error is:
error: invalid conversion from 'int' to 'const char*'|

And
error: initializing argument 2 of 'char* strcpy(char*, const char*)'|

Both are the line of

strcpy(returnbuf,db.execScalar(command.c_str()));

If I commented that out, the error becomes:

obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_close'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_free_table'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_column_count'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_column_count'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_free'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_vmprintf'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_free'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_free'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_free'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_mprintf'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_mprintf'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_mprintf'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_prepare'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_get_table'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_step'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_finalize'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_errmsg'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_exec'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_changes'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_open'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_errmsg'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_finalize'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_errmsg'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_reset'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_errmsg'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_bind_null'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_bind_blob'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_bind_double'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_bind_int'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_bind_text'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_step'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_reset'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_errmsg'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_step'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_reset'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_errmsg'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_changes'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_reset'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_errmsg'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_finalize'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_errmsg'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_step'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_finalize'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_errmsg'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_column_type'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_column_decltype'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_column_name'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_column_name'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_column_bytes'|
obj\Release\CppSQLite3.o:CppSQLite3.cpp|| undefined reference to `sqlite3_column_blob'|
||More errors follow but not being shown.|
||Edit the max errors limit in compiler options...|
||=== Build finished: 50 errors, 0 warnings ===|


Whats going wrong??

Look at that CppSqlIite project and header file. execScalar() returns an int, not a string. Therefore strcpy() will not work. Read this and find out how to get the result set after the query. (that's the same link you posted in your original thread starter post.)

And you need to add SqLite3.cpp to your program's project because it has to be compiled along with your program. You could make it a library if you want to, but that isn't necessary if you are using it for only this project.

Look at that CppSqlIite project and header file. execScalar() returns an int, not a string. Therefore strcpy() will not work. Read this and find out how to get the result set after the query. (that's the same link you posted in your original thread starter post.)

And you need to add SqLite3.cpp to your program's project because it has to be compiled along with your program. You could make it a library if you want to, but that isn't necessary if you are using it for only this project.

I see, thanks of the clarification, but when I changed to

// a sample exported function
char* DLL_EXPORT GetDirectory(const char* Subdomain,const char* PCD, char * returnbuf)
{
        //Write a function to get the installation directory.
    try
    {
       CppSQLite3DB db;
         std::string command;
    command = "select value From domain_data where SubDomain = '";
    command += Subdomain;
    command += "' And key = 'AMTConfigPath';";
    db.open(PCD);
     [I]  CppSQLite3Query q = db.execQuery(command.c_str());[/I] //Instead of using execScalar, I used execQuery instead. It has to be char* form and hence command was converted from string to char again.
       db.close();
  [I][U]returnbuf = q.fieldValue(0);[/U][/I]//Somehow referenced from the site as most of the source are showing cout and I am not sure whats that. (Was that kind of print screen thing, displaying the output?)
    return returnbuf;
    }
    catch (CppSQLite3Exception& e)
    {
      return NULL;
    }
}

Problem is by using italics + underlined code, it showed error: invalid conversion from 'const char*' to 'char*'|, but even if I tried the "illogical way" of

q.fieldValue(0) = returnbuf;

It showed an error of: error: lvalue required as left operand of assignment|

I read somewhere on the internet that

char* src;
const char* dest ;
 [U][B]dest = src;[/B][/U] //Correct
[B][U]src = dest;[/U][/B] //Wrong

and hence the idea of "illogical way"

So maybe now the issue is how to assign the returned value onto returnbuf as I do not know how to use the cout thing to suit in this project.

Thanks a lot.

And yes, I did downloaded sqlite-amalgamation-3_7_2 and extracted sqlite3.c, sqlite3.h, sqlite3ext.h, shell.c, sqlite3.def.

>>//Somehow referenced from the site as most of the source are showing cout and I am not sure whats that. (

No wonder you are having so much trouble, you have not the slightest idea of what you are doing. Anyone with a week's worth of c++ training would know what cout is.

>>returnbuf = q.fieldValue(0);//
Wrong. wrong. wrong.

char* p = q..fieldValue(0);
if( p != NULL)
   strcpy(returnbuf,p);

>>//Somehow referenced from the site as most of the source are showing cout and I am not sure whats that. (

No wonder you are having so much trouble, you have not the slightest idea of what you are doing. Anyone with a week's worth of c++ training would know what cout is.

>>returnbuf = q.fieldValue(0);//
Wrong. wrong. wrong.

char* p = q..fieldValue(0);
if( p != NULL)
   strcpy(returnbuf,p);

Oddly, only when I have this function, it allows me to compile

char* DLL_EXPORT GetDirectory(const char* Subdomain,const char* PCD,char * returnbuf)
{
        //Write a function to get the installation directory.
    try
    {
       CppSQLite3DB db;
         std::string command;
    command = "select value From domain_data where SubDomain = '";
    command += Subdomain;
    command += "' And key = 'AMTConfigPath';";
    db.open(PCD);
       CppSQLite3Query q = db.execQuery(command.c_str());
       db.close();
[B]const[/B] char* p = q.fieldValue(0); //Without the one in bold, error message: [I]error: invalid conversion from 'const char*' to 'char*'[/I] is thrown.
if( p != NULL)
   strcpy(returnbuf,p);
    return returnbuf;
    }
    catch (CppSQLite3Exception& e)
    {
      return NULL;
    }
}

I know the double dot looks a typo, on top of that there is no more issues except that for some reason, while it has successfully compiled, it seemed to be throwing errors during runtime (Failed to get correct directory) Could this be the above code is wrong or something to do with my main application code, which is not intended to write in C++ but to be deployed in an installer. (Details of it would be out of scope, I know)

What is being passed in as the parameters to that function?

One ways to debug it is to put that function in a simple c++ console program and run it without the DLL. Once you have the function working correctly you can put it into a DLL and call it from the installer.

What is being passed in as the parameters to that function?

One ways to debug it is to put that function in a simple c++ console program and run it without the DLL. Once you have the function working correctly you can put it into a DLL and call it from the installer.

3 parameters (I tested from both installer, which is using pascal script --- inno setup and again, VB.net)

For VB.net test app one, the code involved is:

//'During load time
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
              Try
            Dim InstallPath As Char() = Nothing
            Dim Subdomain As Char() = "{A334FDED-DCCA-481E-B226-F902CCC419D2}"
            Dim Path As Char() = "C:\Program Files (x86)\Common Files\Adobe\Adobe PCD\pcd.db"
            InstallPath = GetDirectory(Subdomain, Path, InstallPath)
            MessageBox.Show(InstallPath)
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
        
        Application.Exit()
    End Sub
 <DllImport("GetPCD.DLL", CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function GetDirectory(ByVal SubDomain As Char(), ByVal PCD As Char(), ByVal returnbuf As Char()) _
    As Char()
        ' Leave the body of the function empty.
    End Function

There is no missing file issues but rather some odd messages like: Unable to marshal "return value": Invalid managed, unmanaged type combination.

For Pascal script, the code involved was: (Note that green part are non-essenital codes pertaining to this issue, and that are proven to be working codes while the red ones might be problematic / the code involved is related to this question.

//"Public variable" location
const MB_ICONINFORMATION = $40;
var
function GetDirectory(SubDomain: String;PCD:String;returnbuf: array of string): String;
external 'GetDirectory@files:GetPCD.dll stdcall setuponly';
var
Install: String; //I need this to be "public" so that later I could use it to be assigned as default installation location.
returnbuf : array of char;
//Function to be loaded first before the installer has completed its setup:
function InitializeSetup(): Boolean;
var
//For check if installed the main application
Result1 : Boolean;
//For check if the main application is running
HasRun:HWND;
//Something to do with getting uninstaller details (Check if installed)
ResultCode: Integer;
uicmd: String;
begin
//If the patch is installed, Setup would become uninstaller for a particular language pack. (I give a slightly different name on different languages such as Adobe Encore CS5 "Italiano" language pack and Adobe Encore CS5 "Deutsch" language pack [without quotes])
	if RegQueryStringValue(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' + ExpandConstant('{cm:AppName}') + '_is1', 'UninstallString', uicmd) then
	begin //Code to show uninstaller instead of setup
	Result:=false;
	Exec(RemoveQuotes(uicmd), '', '', SW_SHOW, ewWaitUntilTerminated, ResultCode);
	end else begin
	//Check if main application is installed
	Install := GetDirectory('{A334FDED-DCCA-481E-B226-F902CCC419D2}',ExpandConstant('{pf32}') + '\Common Files\Adobe\Adobe PCD\pcd.db',returnbuf); //Check testing new dll
	Install:= ExtractFileDir(Install); //Get AMT folder, we do not want the Application.xml file. (The returned value from the dll is always to be "C:\Program Files (x86)\Adobe\Adobe Encore CS5\AMT\Application.XML" in most default case and the AMT folder structure is fixed by Adobe.)
	Install:= ExtractFileDir(Install); //Get the real installation directory. (As the language specific files for this application are located at "this location"\Required\<language code>, and acceptables one are de_DE,it_IT,en_US,ko_KR,ja_JP,es_ES & fr_FR which exists only the user has installed on the specific language. I had basically extracted all of these and hence this installer so that users just use this installer instead of reinstalling the application.)
		if Install = '' then
		begin
		//Main application is not installed -- Auto exit with a prompt
		Result1 := MsgBox(ExpandConstant('{cm:ENmissing}'),
		mbError, MB_OK) = idYes;
		Result:=false;
		end else begin
		//Check if the main application is running or not
		//(Due to application can have dynamic Window Title, Window Class is used instead.)
		HasRun := FindWindowByClassName('EncoreMainFrame');
			while HasRun<>0 do
			begin
				if MsgBox(ExpandConstant('{cm:ENRunningB4Install}'), mbConfirmation, MB_YESNO) = idNO then
				begin
				Result := false;
				HasRun := 0;
				end else begin
				HasRun := FindWindowByClassName('EncoreMainFrame');
				end;
			end;
		Result:=true;//After validation, it can now be started
		end;
	end;
end;

I would like to write a test console C++ app, but I am sorry to say that I do not know how to port the code and declare the correct const or not char array and call another function outside the "int main" thing.

c++ program. Just because a function parameter uses cons doesn't mean the calling function has to declare it as const. All const keyword says is that the function is not going to change its value.

In the VB program you posted you need to allocate memory for InstallPath because the C DLL program is going to try to copy a string to that variable. In the code below I just set the size of that variable to 255 characters, because under MS-Windows that's the longest possible path.

#include <iostream>

char* __dllspec(__dllimport) GetDirectory(const char* Subdomain,const char* PCD,char * returnbuf);

int main()
{
   char InstallPath[255] = {0};
   char Subdomain[] "{A334FDED-DCCA-481E-B226-F902CCC419D2}"
   char Path[] = "C:\Program Files (x86)\Common Files\Adobe\Adobe PCD\pcd.db"
   char* p = GetDirectory(Subdomain, Path, InstallPath);
   if( p != NULL)
      cout << InstallPath << '\n';
   else
      cout << "GetDirectory() failed\n";
}

c++ program. Just because a function parameter uses cons doesn't mean the calling function has to declare it as const. All const keyword says is that the function is not going to change its value.

In the VB program you posted you need to allocate memory for InstallPath because the C DLL program is going to try to copy a string to that variable. In the code below I just set the size of that variable to 255 characters, because under MS-Windows that's the longest possible path.

#include <iostream>

char* __dllspec(__dllimport) GetDirectory(const char* Subdomain,const char* PCD,char * returnbuf);

int main()
{
   char InstallPath[255] = {0};
   char Subdomain[] "{A334FDED-DCCA-481E-B226-F902CCC419D2}"
   char Path[] = "C:\Program Files (x86)\Common Files\Adobe\Adobe PCD\pcd.db"
   char* p = GetDirectory(Subdomain, Path, InstallPath);
   if( p != NULL)
      cout << InstallPath << '\n';
   else
      cout << "GetDirectory() failed\n";
}

Nope, it still dont work
For a console program, if a wrote

#include <iostream>
#include "cppSQLite3.h"
#include <string>
int main()
{
   char InstallPath[255] = {0};
   char Subdomain[] "{A334FDED-DCCA-481E-B226-F902CCC419D2}"
   char Path[] = "C:\Program Files (x86)\Common Files\Adobe\Adobe PCD\pcd.db"
   char* p = GetDirectory(Subdomain, Path, InstallPath);
   if( p != NULL)
      cout << InstallPath << '\n';
   else
      cout << "GetDirectory() failed\n";
}
char* GetDirectory(const char* Subdomain,const char* PCD,char * returnbuf)
{
        //Write a function to get the installation directory.
    try
    {
       CppSQLite3DB db;
         std::string command;
    command = "select value From domain_data where SubDomain = '";
    command += Subdomain;
    command += "' And key = 'AMTConfigPath';";
    db.open(PCD);
       CppSQLite3Query q = db.execQuery(command.c_str());
       db.close();
const char* p = q.fieldValue(0); //Without the one in bold, error message: error: invalid conversion from 'const char*' to 'char*' is thrown.
if( p != NULL)
   strcpy(returnbuf,p);
    return returnbuf;
    }
    catch (CppSQLite3Exception& e)
    {
      return NULL;
    }
}

The errors are (All on the main.cpp):
|7|error: expected initializer before string constant|
|10|error: 'p' was not declared in this scope|
|11|error: 'cout' was not declared in this scope|
|13|error: 'cout' was not declared in this scope|
||=== Build finished: 4 errors, 0 warnings ===|

If I wrote as:

#include <iostream>



char* __dllspec(__dllimport) GetDirectory(const char* Subdomain,const char* PCD,char * returnbuf);



int main()

{

char InstallPath[255] = {0};

char Subdomain[] "{A334FDED-DCCA-481E-B226-F902CCC419D2}"

char Path[] = "C:\Program Files (x86)\Common Files\Adobe\Adobe PCD\pcd.db"

char* p = GetDirectory(Subdomain, Path, InstallPath);

if( p != NULL)

cout << InstallPath << '\n';

else

cout << "GetDirectory() failed\n";

}

The errors are (All on the main.cpp):
|6|error: '__dllimport' was not declared in this scope|
|6|error: expected ',' or ';' before 'GetDirectory'|
|16|error: expected initializer before string constant|
|22|error: 'p' was not declared in this scope|
|24|error: 'cout' was not declared in this scope|
|28|error: 'cout' was not declared in this scope|
||=== Build finished: 6 errors, 0 warnings ===|

By the way, I have copied the generated dll file and the CppSqlite3 project file.

Please help, thanks a lot for the continuous effort.

You have a lot of syntax errors in your program. Here's the correctins. I added another parameter to that function -- the size of returnbuf. I didn't test it out because I don't have a copy of that database.

#include <iostream>
#include "cppSQLite3.h"
#include <string>
#include <string.h>

using std::string;
using std::cout;
using std::cin;

char* GetDirectory(const char* Subdomain,const char* PCD,char * returnbuf,int bufsize);

int main()
{
    char InstallPath[255] = {0};
   char Subdomain[] = "{A334FDED-DCCA-481E-B226-F902CCC419D2}";
   char Path[] = "C:\\Program Files (x86)\\Common Files\\Adobe\\Adobe PCD\\pcd.db";
   char* p = GetDirectory(Subdomain, Path, InstallPath, sizeof(InstallPath));
   if( p != NULL)
      cout << InstallPath << '\n';
   else
      cout << "GetDirectory() failed\n";
}
char* GetDirectory(const char* Subdomain,const char* PCD,char * returnbuf,int bufsize)
{
        //Write a function to get the installation directory.
    try
    {
       CppSQLite3DB db;
         std::string command;
    command = "select value From domain_data where SubDomain = '";
    command += Subdomain;
    command += "' And key = 'AMTConfigPath';";
    db.open(PCD);
       CppSQLite3Query q = db.execQuery(command.c_str());
       db.close();
const char* p = q.fieldValue(0); //Without the one in bold, error message: error: invalid conversion from 'const char*' to 'char*' is thrown.
if( p != NULL)
   strcpy_s(returnbuf,bufsize,p);
    return returnbuf;
    }
    catch (CppSQLite3Exception& e)
    {
      return NULL;
    }
}

You have a lot of syntax errors in your program. Here's the correctins. I added another parameter to that function -- the size of returnbuf. I didn't test it out because I don't have a copy of that database.

#include <iostream>
#include "cppSQLite3.h"
#include <string>
#include <string.h>

using std::string;
using std::cout;
using std::cin;

char* GetDirectory(const char* Subdomain,const char* PCD,char * returnbuf,int bufsize);

int main()
{
    char InstallPath[255] = {0};
   char Subdomain[] = "{A334FDED-DCCA-481E-B226-F902CCC419D2}";
   char Path[] = "C:\\Program Files (x86)\\Common Files\\Adobe\\Adobe PCD\\pcd.db";
   char* p = GetDirectory(Subdomain, Path, InstallPath, sizeof(InstallPath));
   if( p != NULL)
      cout << InstallPath << '\n';
   else
      cout << "GetDirectory() failed\n";
}
char* GetDirectory(const char* Subdomain,const char* PCD,char * returnbuf,int bufsize)
{
        //Write a function to get the installation directory.
    try
    {
       CppSQLite3DB db;
         std::string command;
    command = "select value From domain_data where SubDomain = '";
    command += Subdomain;
    command += "' And key = 'AMTConfigPath';";
    db.open(PCD);
       CppSQLite3Query q = db.execQuery(command.c_str());
       db.close();
const char* p = q.fieldValue(0); //Without the one in bold, error message: error: invalid conversion from 'const char*' to 'char*' is thrown.
if( p != NULL)
   strcpy_s(returnbuf,bufsize,p);
    return returnbuf;
    }
    catch (CppSQLite3Exception& e)
    {
      return NULL;
    }
}

Hi, thanks for making the tips clearer, but if I use

strcpy_s(returnbuf,bufsize,p);

, I get these errors (All in the main.cpp):
38|error: 'strcpy_s' was not declared in this scope|

And if I changed to:

strcpy(returnbuf,bufsize,p);

, I get these errors (All in the main.cpp):
|In function 'char* GetDirectory(const char*, const char*, char*, int)': |
38|error: invalid conversion from 'int' to 'const char*'|
c:\program files (x86)\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\..\..\..\..\include\string.h|45|error: too many arguments to function 'char* strcpy(char*, const char*)'|
38|error: at this point in file|
||=== Build finished: 3 errors, 0 warnings ===|

And users can have the copy of the database if they installed any of the Adobe Creative Suite products, at least from CS4 onwards, alternatively the database is attached in the attachment.

1) Did you copy/paste the program I gave you into your console application?

On Windows 7 (and probably Windows Vista too) you will not have permissions to query that database in the the folder. I had to move that file to a different folder that I know I have permissions. When I did that the program worked as expected.

Why you are having so much trouble compiling that simple program is beyond me. Does that project have UNICODE turned on? Check the project settings.

Project --> Properties --> Configuration Properties --> General. Then in the right side of the screen, third item from the botom change Character Set to "Not Set"

On Windows 7 (and probably Windows Vista too) you will not have permissions to query that database in the the folder. I had to move that file to a different folder that I know I have permissions. When I did that the program worked as expected.

Why you are having so much trouble compiling that simple program is beyond me. Does that project have UNICODE turned on? Check the project settings.

Project --> Properties --> Configuration Properties --> General. Then in the right side of the screen, third item from the botom change Character Set to "Not Set"

I am sorry, I could not find the Configuration Properties part and I am wondering why strcpy_s does not works as expected? Does that means this project is not unicode ready.

The attachment provided shows the screenshots I have tried to find the setting while the attachment to both DLL and console applications are as below:
DLL: http://www.4shared.com/file/cu1OR3h1/GetPCD.html
Console: http://www.4shared.com/file/jzq7CECH/Console.html

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.