I am using Leadtools 17.5. If I statically link the Leadtools Dlls into my 64 bit C++ Application and then call L_SetLicenseBuffer everything works fine and the return value is zero. But for security reasons, the final product is not allowed to add those DLLs into the System32 folder and is also not allowed to change the system path, and since multiple applications are using the tools I want to install them in a common folder (C:\Program Files\Common Files\LeadTools\17.5 for example) and use AddDllDirectory to add the path to the DLL search path. So I decided to load the DLLs dynamically at the run-time. So I created a definition for the function like this:
typedef L_INT (EXT_FUNCTION* TL_SetLicenseBuffer)(L_UCHAR* pLicenseBuffer, L_SSIZE_T nSize, L_TCHAR* pszDeveloperKey);
typedef L_BOOL (EXT_FUNCTION* TL_IsSupportLocked)(L_UINT uType);
then created a function pointer like this:
TL_SetLicenseBuffer pfSetLicenseBuffer = NULL;
TL_IsSupportLocked pfIsSupportLocked = NULL;
then add the paths to where the DLLs are to the DLL search path:
AddDllDirectory(LEAD_DLL_PATH);
AddDllDirectory(LEAD_FILTER_PATH);
and set the default directory search path for DLLs to be the user defined:
SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_USER_DIRS);
then load the DLL and get the address of the functions I need:
HINSTANCE hKrn = LoadLibrary(L"ltkrnx.dll");
pfSetLicenseBuffer = (TL_SetLicenseBuffer)GetProcAddress(hKrn, "L_SetLicenseBuffer");
pfIsSupportLocked = (TL_IsSupportLocked)GetProcAddress(hKrn, "L_IsSupportLocked");
now if I use the function pointer with the same parameters as before, the function fails and returns -13 and any subsequent call to for example to pfIsSupportLocked shows the nag dialog:
retCode = pfSetLicenseBuffer(pLicenseData, LicSize, pKeyStr); // retCode is -13
pfIsSupportLocked(L_SUPPORT_DOCUMENT); // Shows nag dialog
Does anyone know how I can fix this?
Thank you
Sam
The first thing you need to do is check the debugger output and make sure that the DLL you are expecting to get loaded is the one getting loaded by verifying the path. It is possible that you have multiple versions of LTKRNX.DLL in your search path. I have tested your code here and it returned SUCCESS:
typedef L_INT (EXT_FUNCTION* TL_SetLicenseBuffer)(L_UCHAR* pLicenseBuffer, L_SSIZE_T nSize, L_TCHAR* pszDeveloperKey);
typedef L_BOOL (EXT_FUNCTION* TL_IsSupportLocked)(L_UINT uType);
HINSTANCE hKrn = LoadLibrary(L"ltkrnx.dll");
TL_SetLicenseBuffer pfSetLicenseBuffer = NULL;
TL_IsSupportLocked pfIsSupportLocked = NULL;
pfSetLicenseBuffer = (TL_SetLicenseBuffer)GetProcAddress(hKrn, "L_SetLicenseBuffer");
pfIsSupportLocked = (TL_IsSupportLocked)GetProcAddress(hKrn, "L_IsSupportLocked");
L_INT retCode = pfSetLicenseBuffer(szLICAnsi, _countof(szLICAnsi), pKeyStr);
if(retCode == SUCCESS)
bRet = pfIsSupportLocked(L_SUPPORT_DOCUMENT);
else
printf("Problem!");
Also what PaulMcKenzie suggested is another way to verify that your calls to LoadLibrary are working correctly. If you still cannot figure it out, you can contact our Technical Support to assist you with this issue at support#leadtools.com
I was not able to make the dynamic loading to work at all, but I was able to use Delay loading to work.What I had to do was to go back to linking the extracted .Lib files to my application and then tell compiler to load the associated DLLs with delay, which gave me a chance to create Notification Hooks to __pfnDliNotifyHook2 and __pfnDliFailureHook2 and that way I could use LoadLibrary to load the delayed loaded Dlls from correct location.But that only fixed half the problem because some of these Dlls are dependent on other DLLs and when I used the full path to load the DLL that I wanted, it could not find the secondary DLLs (which were located in the same directory as the one I was loading) and that would cause LoadLibrary to fail. The solution was to keep track of those dependencies and pre-load them. I am including some of the code to fix the issue for anyone whom might run into similar situation later on.P. S. I am using Embarcadero's C++ Builder, so Some of the objects like the Strings, TStringList and Exception may not be exactly what everyone is familiar with, but the concept should work in VC++ as well.
#include <map>
struct TDllDependency
{
TStringList* Dependency;
HMODULE hDll;
__fastcall TDllDependency(void)
{
hDll = NULL;
Dependency = new TStringList();
}
virtual __fastcall ~TDllDependency(void)
{
delete Dependency;
}
};
class TDllModList : public std::map<System::String, TDllDependency>
{
public:
void __fastcall CheckDependency(const System::String& aName);
};
//---------------------------------------------------------------------------
System::String __fastcall GetLtDllPath(void)
{
wchar_t* pfPath = NULL;
System::String dllPath;
SHGetKnownFolderPath(FOLDERID_ProgramFilesCommon, KF_FLAG_DEFAULT, NULL, &pfPath);
if (NULL != pfPath)
{
dllPath = IncludeTrailingBackslash(pfPath) + L"LeadTools\\17.5\\";
::CoTaskMemFree(pfPath);
}
return dllPath;
}
System::String mDllPath(GetLtDllPath());
TDllModList DllModList;
void __fastcall InitDllDepends()
{
DllModList.clear();
#if defined(_WIN64)
DllModList[L"ltimgefxx.dll"].Dependency->CommaText = L"ltdisx.dll,ltimgutlx.dll";
DllModList[L"ltefxx.dll"].Dependency->CommaText = L"ltdisx.dll,ltimgutlx.dll";
DllModList[L"ltimgcorx.dll"].Dependency->CommaText = L"ltdisx.dll,ltimgutlx.dll";
DllModList[L"ltdlgimgefxx.dll"].Dependency->CommaText = L"ltdisx.dll,ltdlgkrnx.dll,ltdlgcomx.dll,ltdlgctrlx.dll,ltdlgutlx.dll,ltimgefxx.dll,ltimgsfxx.dll,ltimgcorx.dll,ltimgclrx.dll";
DllModList[L"ltdlgutlx.dll"].Dependency->CommaText = L"ltdisx.dll,ltfilx.dll,ltdlgkrnx.dll,ltimgclrx.dll,ltimgcorx.dll,ltimgefxx.dll,ltimgsfxx.dll";
DllModList[L"ltdlgctrlx.dll"].Dependency->CommaText = L"ltdlgutlx.dll,ltdlgkrnx.dll,ltdisx.dll,ltfilx.dll,ltimgefxx.dll";
DllModList[L"ltdlgcomx.dll"].Dependency->CommaText = L"ltdlgkrnx.dll,ltdlgctrlx.dll,ltdlgutlx.dll";
#elif defined(__WIN32__)
DllModList[L"ltimgefxu.dll"].Dependency->CommaText = L"ltdisu.dll,ltimgutlu.dll";
DllModList[L"ltefxu.dll"].Dependency->CommaText = L"ltdisu.dll,ltimgutlu.dll";
DllModList[L"ltimgcoru.dll"].Dependency->CommaText = L"ltdisu.dll,ltimgutlu.dll";
DllModList[L"ltdlgimgefxu.dll"].Dependency->CommaText = L"ltdisu.dll,ltdlgkrnu.dll,ltdlgcomu.dll,ltdlgctrlu.dll,ltdlgutlu.dll,ltimgefxu.dll,ltimgsfxu.dll,ltimgcoru.dll,ltimgclru.dll";
DllModList[L"ltdlgutlu.dll"].Dependency->CommaText = L"ltdisu.dll,ltfilu.dll,ltdlgkrnu.dll,ltimgclru.dll,ltimgcoru.dll,ltimgefxu.dll,ltimgsfxu.dll";
DllModList[L"ltdlgctrlu.dll"].Dependency->CommaText = L"ltdlgutlu.dll,ltdlgkrnu.dll,ltdisu.dll,ltfilu.dll,ltimgefxu.dll";
DllModList[L"ltdlgcomu.dll"].Dependency->CommaText = L"ltdlgkrnu.dll,ltdlgctrlu.dll,ltdlgutlu.dll";
#endif
};
HMODULE SafeLoadLeadDll(const System::String tName)
{
System::String tPath;
HMODULE retVal = NULL;
DllModList.CheckDependency(tName);
tPath = mDllPath + tName;
if(FileExists(tPath))
retVal = ::LoadLibrary(tPath.c_str());
return retVal;
}
FARPROC WINAPI MyDliNotifyHook(unsigned dliNotify, PDelayLoadInfo pdli)
{
FARPROC retVal = NULL;
System::String tStr(pdli->szDll);
tStr = tStr.LowerCase();
if(dliNotePreLoadLibrary == dliNotify)
{
TDllModList::iterator i = DllModList.find(tStr);
if(DllModList.end() == i)
{
retVal = (FARPROC)SafeLoadLeadDll(tStr);
DllModList[tStr].hDll = (HMODULE)retVal;
}
else if(NULL == i->second.hDll)
{
i->second.hDll = SafeLoadLeadDll(tStr);
retVal = (FARPROC)i->second.hDll;
}
else
retVal = (FARPROC)i->second.hDll;
}
else if(dliFailLoadLib == dliNotify)
{
tStr = L"Compleatly falied to load " + tStr;
::OutputDebugString(tStr.c_str());
}
return retVal;
}
FARPROC WINAPI MyDliFailureHook(unsigned dliNotify, PDelayLoadInfo pdli)
{
FARPROC retVal = NULL;
if(dliNotePreLoadLibrary == dliNotify)
{
System::String tMsg = pdli->szDll;
tMsg = L"Failed to load \"" + tMsg + L"\".\n" + SysErrorMessage(::GetLastError());
throw Exception(tMsg);
}
return retVal;
}
extern "C" PfnDliHook __pfnDliNotifyHook2 = MyDliNotifyHook;
extern "C" PfnDliHook __pfnDliFailureHook2 = MyDliFailureHook;
void __fastcall TDllModList::CheckDependency(const System::String& aName)
{
TDllModList::iterator i = find(aName);
if(end() != i)
{
int len = i->second.Dependency->Count;
int j;
System::String tPath;
for(j = 0; j < len; j++)
{
if(end() == find(i->second.Dependency->Strings[j]))
{
CheckDependency(i->second.Dependency->Strings[j]);
tPath = mDllPath + i->second.Dependency->Strings[j];
(*this)[i->second.Dependency->Strings[j]].hDll = ::LoadLibrary(tPath.c_str());
}
}
}
}
//---------------------------------------------------------------------------
And of course InitDllDepends(); should be called at the beginning of WinMain to set things up correctly.
This is some old code not written by me. It compiles with GCC 3.4.6, but now we are checking the build with GCC 4.4.7 and the build fails.
I hope this code is enough to go on:
list<Chapter*> * tocP; //Chapter is a class
tocP = NULL;
if (_searchChapter)
{
_chapter = _manager->GetCurrentChapter(); // _chapter is a Chapter*
}
else
{
tocP = _manager->GetTableOfContents();
if (tocP != NULL && tocP->size() > 0)
_chapter = tocP->front();
}
...
list<Chapter*>::iterator chp;
if (tocP != NULL && tocP->size() > 0)
for (chp=find(tocP->begin(),tocP->end(),_chapter); chp != tocP->end(); ++chp) // this code fails
{
//code to process chapter
}
error message is:
../src/HelpSearchC.C: In member function 'int HelpSearchC_i::DoSearch()':
../src/HelpSearchC.C:685: error: no matching function for call to 'find(std::_List_iterator<Chapter*>,
std::_List_iterator<Chapter*>, Chapter*&)'
You have to add #include <algorithm> on top of the file. The function find is defined within this header.
I am trying to modify the proxy settings in C++ without using visual C++. I found this:
const wchar_t* proxyName = pnt.wc_str(); // pnt is a wxString declared earlier in the code.
INTERNET_PER_CONN_OPTION_LIST OptionList;
INTERNET_PER_CONN_OPTION Option[3];
unsigned long listSize = sizeof(INTERNET_PER_CONN_OPTION_LIST);
Option[0].dwOption = INTERNET_PER_CONN_PROXY_SERVER;
Option[1].dwOption = INTERNET_PER_CONN_FLAGS;
Option[2].dwOption = INTERNET_PER_CONN_PROXY_BYPASS;
OptionList.dwSize = sizeof(INTERNET_PER_CONN_OPTION_LIST);
OptionList.pszConnection = NULL;
OptionList.dwOptionCount = 3;
OptionList.dwOptionError = 0;
DWORD proxyType = PROXY_TYPE_DIRECT;
if (proxyName)
{
if (proxyName[0])
{
proxyType = PROXY_TYPE_PROXY;
}
}
Option[0].Value.pszValue = (LPWSTR)proxyName;
Option[1].Value.dwValue = proxyType;
if (on)
{
Option[2].Value.pszValue = (LPWSTR)L"";
}
else
{
Option[2].Value.pszValue = (LPWSTR)L"";
}
OptionList.pOptions = Option;
if (!InternetSetOption(0, INTERNET_OPTION_PER_CONNECTION_OPTION, &OptionList, listSize))
{
// handle error
}
InternetSetOption(0, INTERNET_OPTION_PROXY_SETTINGS_CHANGED, NULL, NULL);
However because I have to use MinGW and MinGW's wininet.h is very different, I get "'INTERNET_PER_CONN_OPTION_LIST' was not declared in this scope" among other "not declared" messages. In all my searching I have not found anything on it, thanks to visual c++ being so prominent. I found this but it has almost no views, doesn't have any answers, and has not been touched almost a month and it's not even quite what I am looking for. I can't seem to find any documentation either. Any ideas? Thanks in advanced!
I am trying to mix two wav files using LibSoX on Windows. I can do this by using sox from the command line using the following command:
sox -m f1.wav f2.wav out.wav
However I want to do this programmatically using a C/C++ function and linking with LibSoX. I have built LibSoX successfully and have tried out the sample programs which do not cover a "mix" of two audio files.
Has someone done this earlier? It would be great if you can give a code snippet or at least some pointers to do this using LibSoX calls
Want to share the solution (workaround) which I made for the above issue. Basically, mixing is not exposed as an exported function call. Mixing can be done via the command line of course, so there could be two solutions: 1) spawning a process (sox.exe) via the program and 2) via libsox. I needed a libsox based solution as the function which was going to call the mixing function, could not spawn a process (constraint). So I moved the main function functionality from sox to a new method in libsox which I exported :) . So now I can pass the same command line switches to my function, and get the job done using libsox! This would be a "workaround" ideally, till Chris Bagwell exposes the mixing (and other missing) functionality from libsox.
Though this is an old question, I came across this same problem recently. In order to use the sox.c main method from your code, you'll need to reset all the globals after a call is made. sox.c was intended to run once then exit. To do that you can add a function like below. Then you can rename main, sox_main_private and things will basically work to use the command line calls directly building your argv array manually by calling sox_main()
// reset the globals so that multiple calls can be made to sox_main
static void cleanup_globals(void)
{
file_count = 0;
input_count = 0;
output_count = 0;
current_input = 0;
input_wide_samples = 0;
read_wide_samples = 0;
output_samples = 0;
input_eof = sox_false;
output_eof = sox_false;
user_abort = sox_false;
user_skip = sox_false;
user_restart_eff = sox_false;
success = 0;
files = NULL;
user_efftab = NULL;
user_efftab_size = 0;
effects_chain = NULL;
save_output_eff = NULL;
user_effargs_size = NULL; /* array: size of user_effargs for each chain */
nuser_effects = NULL; /* array: number of effects in each chain */
current_eff_chain = 0;
eff_chain_count = 0;
very_first_effchain = sox_true;
effects_filename = NULL;
play_rate_arg = NULL;
norm_level = NULL;
}
int sox_main(int argc, char *argv[])
{
#if DEBUG
printf("sox_main:\n");
int i = 0;
while (i < argc) {
printf("%s ", argv[i]);
i++;
}
printf("\n");
#endif
sox_main_private(argc, argv);
cleanup_globals();
return 0;
}
I'm trying to have FFI support for my new programming language, which is written in C++ with QT Creator using the MinGW toolchain.
To do this I used a custom-built version of libffi found here: http://ftp.gnome.org/pub/GNOME/binaries/win32/dependencies/libffi-dev_3.0.6-1_win32.zip
I also tried it with another build: http://pkgs.org/fedora-14/fedora-updates-i386/mingw32-libffi-3.0.9-1.fc14.noarch.rpm.html by downloading the SRPM file on Linux, extracting it, and copying the needed files to a Windows partition.
Anyway, I included the required header file, added the import library to the project and put the .dll beside the application's .exe, it compiles and runs, calling MessageBeep() successfully. I tried it next with MessageBoxA(), but it keeps crashing. The debugger doesn't seem to provide much useful information (edit: beside the fact that a call to MessageBoxA did happen) so I keep fiddling with stuff and re-running to no avail.
To isolate the problem from the details of my language, I tried to manually call MessageBoxA by filling myself all the parameters, resulting in the code below, still crashing.
So my question distills to: How can I get the code snippet below to run under QT Creator/MinGW and actually show a message box?
#include "libffi/include/ffi.h"
#include <QLibrary>
void testMessageBox()
{
int n = 4;
ffi_cif cif;
ffi_type **ffi_argTypes = new ffi_type*[n];
void **values = new void*[n];
values[0] = new ulong(0);
values[1] = (void *) "hello";
values[2] = (void *) "mommy";
values[3] = new int32_t(0);
ffi_argTypes[0] = &ffi_type_ulong;
ffi_argTypes[1] = &ffi_type_pointer;
ffi_argTypes[2] = &ffi_type_pointer;
ffi_argTypes[3] = &ffi_type_uint32;
ffi_type *c_retType = &ffi_type_sint32;
int32_t rc; // return value
if (ffi_prep_cif(&cif, FFI_STDCALL, n, c_retType, ffi_argTypes) == FFI_OK)
{
QLibrary lib("user32.dll");
lib.load();
void *msgbox = lib.resolve("MessageBoxA");
ffi_call(&cif, (void (*)()) msgbox, &rc, values);
}
}
you should pass the address to the values array instead of the values. the working code under mingw64 is
#include <stdio.h>
#include <ffi.h>
#include <Windows.h>
int main()
{
ffi_cif cif;
HINSTANCE dllHandle = LoadLibrary("user32.dll");
int n = 4;
ffi_type *ffi_argTypes[4];
void *values[4];
UINT64 a=0;
UINT32 b=0;
TCHAR* s1= "hello";
TCHAR* s2= "hello2";
values[0] = &a;
values[1] = &s1;
values[2] = &s2;
values[3] = &b;
ffi_argTypes[0] = &ffi_type_uint64;
ffi_argTypes[1] = &ffi_type_pointer;
ffi_argTypes[2] = &ffi_type_pointer;
ffi_argTypes[3] = &ffi_type_uint;
ffi_type *c_retType = &ffi_type_sint;
ffi_type rc; // return value
if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, &ffi_type_sint, ffi_argTypes) == FFI_OK) {
ffi_call(&cif, FFI_FN(GetProcAddress(dllHandle,"MessageBoxA")), &rc, values);
}
return 0;
}