I am attempting to use IBM's EHLLAPI to interface with their Personal Communicator Terminal Emulator. I have copied their sample code from this page, but it's giving me an error when I try to build it.
1>------ Build started: Project: PCOMAPI, Configuration: Debug Win32 ------
1> Source.cpp
1>Source.obj : error LNK2019: unresolved external symbol _hllapi#16 referenced in function _main
1>C:\Users\[username]\Documents\Visual Studio 2013\Projects\VPARSAPI\Debug\PCOMAPI.exe : fatal error LNK1120: 1 unresolved externals
I'm not entirely certain what this _hllapi#16 is, and I'm not seeing it in the code. It has been a while since I've worked with C++, so it may be something simple I'm missing. The code is as follows:
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include "hapi_c.h"
int main(char **argv, int argc) {
int HFunc, HLen, HRc;
char HBuff[1];
struct HLDConnectPS ConnBuff;
// Send Key string for HOME+string+ENTER:
char SendString[] = "#0Hello World!#E";
HFunc = HA_RESET_SYSTEM;
HLen = 0;
HRc = 0;
hllapi(&HFunc, HBuff, &HLen, &HRc);
if (HRc != HARC_SUCCESS) {
printf("Unable to access EHLLAPI.\n");
return 1;
}
HFunc = HA_CONNECT_PS;
HLen = sizeof(ConnBuff);
HRc = 0;
memset(&ConnBuff, 0x00, sizeof(ConnBuff));
ConnBuff.stps_shortname = 'A';
hllapi(&HFunc, (char *)&ConnBuff, &HLen, &HRc);
switch (HRc) {
case HARC_SUCCESS:
case HARC_BUSY:
case HARC_LOCKED: // All these are OK
break;
case HARC_INVALID_PS:
printf("Host session A does not exist.\n");
return 1;
case HARC_UNAVAILABLE:
printf("Host session A is in use by another EHLLAPI application.\n");
return 1;
case HARC_SYSTEM_ERROR:
printf("System error connecting to session A.\n");
return 1;
default:
printf("Error connecting to session A.\n");
return 1;
}
HFunc = HA_SENDKEY;
HLen = strlen(SendString);
HRc = 0;
hllapi(&HFunc, SendString, &HLen, &HRc);
switch (HRc) {
case HARC_SUCCESS:
break;
case HARC_BUSY:
case HARC_LOCKED:
printf("Send failed, host session locked or busy.\n");
break;
default:
printf("Send failed.\n");
break;
}
HFunc = HA_DISCONNECT_PS;
HLen = 0;
HRc = 0;
hllapi(&HFunc, HBuff, &HLen, &HRc);
printf("EHLLAPI program ended.\n");
return 0;
}
My linker flags are:
/OUT:"C:\Users[username]\Documents\Visual Studio
2013\Projects\VPARSAPI\Debug\PCOMAPI.exe" /MANIFEST /NXCOMPAT
/PDB:"C:\Users[username]\Documents\Visual Studio
2013\Projects\VPARSAPI\Debug\PCOMAPI.pdb" /DYNAMICBASE "kernel32.lib"
"user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib"
"shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib"
"odbccp32.lib" /DEBUG /MACHINE:X86 /INCREMENTAL
/PGD:"C:\Users[username]\Documents\Visual
Studio2013\Projects\VPARSAPI\Debug\PCOMAPI.pgd" /SUBSYSTEM:CONSOLE
/MANIFESTUAC:"level='asInvoker' uiAccess='false'"
/ManifestFile:"Debug\PCOMAPI.exe.intermediate.manifest"
/ERRORREPORT:PROMPT /NOLOGO /TLBID:1
That is a linker error. You need to pass to the linker the .lib file, the import library, for the EHLLAPI library.
In fact, looking at the documentation, there are a host of .lib files with this library. You'll need to study the documentation carefully to work out which ones you need.
As stated under the section Compiling and Linking you have to include pcscal32.lib for static linking, so the symbols in *hapi_c.h* can be resolved.
Related
I am getting the error on compile in VS:
LNK2001 unresolved external symbol _main File: MSVCRT.lib(exe_main.obj)
This error only occurs when compiling in Release x86, and not Debug x86.
#include "includes.h"
BOOL APIENTRY DllMain(
HINSTANCE handle,
DWORD fdwReason,
LPVOID lpReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
AllocConsole();
freopen("CONIN$", "r", stdin);
freopen("CONOUT$", "w", stdout);
_beginthreadex(NULL, 0, directxThread, 0, 0, 0);
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
This is likely a problem with your IDE/compiler command. If possible, you should check the exact command sent to cl.exe (the Microsoft compiler) when release mode is enabled, and ensure that MSVCRT.lib is present in the compiler command. See this link for more information.
If MSVCRT.lib is not in your compile command, you will have to add MSVCRT.lib as an additional input/dependency to your compiler in your project settings, if you're using an IDE like Visual Studio. If you're using the command line, you can simply add the term.
I've created simple test which creates two thread; first one (WorkerThreadFun) executes infinite loop and second one (WorkerGuardThreadFun) terminates it with small timeout.
Thread to be terminated does not seem to do expicit allocation (at least inside WorkerThreadFun) and uses only stack variables of plain C type so I hope the stack will be deallocated by TerminateThread() with CloseHandle().
By some reason this test leaks memory on my Win7.
Where is the unbalanced heap allocation?
#include <windows.h>
#include <synchapi.h>
#include <assert.h>
#include <stdio.h>
#define STK_SIZE 4097
typedef enum
{
GRD_IDLE,
GRD_READY,
GRD_TASKSTARTING,
GRD_TASKWAITING
} GuardThreadState;
typedef struct
{
HANDLE mHworkerThread;
HANDLE mHworkerGroupThread;
volatile int mIsWorkerStarted;
GuardThreadState mGuardThreadState;
CRITICAL_SECTION mLock;
CONDITION_VARIABLE mThreadReadyCond;
CONDITION_VARIABLE mStartTaskCond;
CONDITION_VARIABLE mTaskFinishedCond;
} WorkerThreadHolder;
/*
typedef VOID(WINAPI *PRtlFreeUserThreadStack)(HANDLE hProcess, HANDLE hThread);
static PRtlFreeUserThreadStack RtlFreeUserThreadStack = NULL;
*/
DWORD WINAPI WorkerThreadFun(_In_ LPVOID p);
DWORD WINAPI WorkerGuardThreadFun(_In_ LPVOID p);
void Start(WorkerThreadHolder *workerThreadHolderPtr);
void ExecuteTask(WorkerThreadHolder *workerThreadHolderPtr);
/*----------------------------------------------------------------------------*/
DWORD WINAPI WorkerThreadFun(_In_ LPVOID p)
{
/* use stack variables only in this thread in hope the stack will be deallocated by TerminateThread() */
WorkerThreadHolder *workerThreadHolderPtr = (WorkerThreadHolder *)p;
volatile int i;
workerThreadHolderPtr->mIsWorkerStarted = 1;
/*WakeAllConditionVariable(&workerThreadHolderPtr->mThreadReadyCond);*/
/* do nothing for infinite long time */
for(i = 0;; ++i)
i = i;
/*WakeAllConditionVariable(&workerThreadHolderPtr->mTaskFinishedCond);*/
return 0;
}
DWORD WINAPI WorkerGuardThreadFun(_In_ LPVOID p)
{
const DWORD taskExecutionTimeoutInMillisec = 1;
WorkerThreadHolder *workerThreadHolderPtr = (WorkerThreadHolder *)p;
EnterCriticalSection(&workerThreadHolderPtr->mLock);
workerThreadHolderPtr->mGuardThreadState = GRD_READY;
WakeAllConditionVariable(&workerThreadHolderPtr->mThreadReadyCond);
for (;;)
{
for (;;)
{
SleepConditionVariableCS(
&workerThreadHolderPtr->mStartTaskCond,
&workerThreadHolderPtr->mLock,
INFINITE);
if (workerThreadHolderPtr->mGuardThreadState == GRD_TASKSTARTING)
break;
}
workerThreadHolderPtr->mGuardThreadState = GRD_TASKWAITING;
{
BOOL isTaskFinishedOk = FALSE;
for (;;)
{
isTaskFinishedOk =
SleepConditionVariableCS(
&workerThreadHolderPtr->mTaskFinishedCond,
&workerThreadHolderPtr->mLock,
taskExecutionTimeoutInMillisec);
if (!isTaskFinishedOk)
break;
}
if (isTaskFinishedOk)
{
/* never happens in this test */
}
else
{
BOOL isClosed;
TerminateThread(workerThreadHolderPtr->mHworkerThread, 0);
/*if (RtlFreeUserThreadStack != NULL)
RtlFreeUserThreadStack(GetCurrentProcess(), workerThreadHolderPtr->mHworkerThread);*/
isClosed = CloseHandle(workerThreadHolderPtr->mHworkerThread);
workerThreadHolderPtr->mIsWorkerStarted = 0;
workerThreadHolderPtr->mHworkerThread =
CreateThread(
NULL,
STK_SIZE,
WorkerThreadFun,
(PVOID)workerThreadHolderPtr,
STACK_SIZE_PARAM_IS_A_RESERVATION,
NULL);
}
}
workerThreadHolderPtr->mGuardThreadState = GRD_READY;
WakeAllConditionVariable(&workerThreadHolderPtr->mThreadReadyCond);
}
return 0;
}
void Start(WorkerThreadHolder *workerThreadHolderPtr)
{
workerThreadHolderPtr->mGuardThreadState = GRD_IDLE;
workerThreadHolderPtr->mIsWorkerStarted = 0;
InitializeConditionVariable(&workerThreadHolderPtr->mThreadReadyCond);
InitializeConditionVariable(&workerThreadHolderPtr->mStartTaskCond);
InitializeConditionVariable(&workerThreadHolderPtr->mTaskFinishedCond);
InitializeCriticalSection(&workerThreadHolderPtr->mLock);
workerThreadHolderPtr->mHworkerThread =
CreateThread(
NULL,
STK_SIZE,
WorkerThreadFun,
(LPVOID)workerThreadHolderPtr,
STACK_SIZE_PARAM_IS_A_RESERVATION,
NULL);
workerThreadHolderPtr->mHworkerGroupThread =
CreateThread(
NULL,
0,
WorkerGuardThreadFun,
(LPVOID)workerThreadHolderPtr,
0,
NULL);
}
void ExecuteTask(WorkerThreadHolder *workerThreadHolderPtr)
{
assert(workerThreadHolderPtr->mHworkerThread != NULL);
assert(workerThreadHolderPtr->mHworkerGroupThread != NULL);
EnterCriticalSection(&workerThreadHolderPtr->mLock);
for (;;)
{
if (workerThreadHolderPtr->mGuardThreadState == GRD_READY /* && workerThreadHolderPtr->mIsWorkerStarted != 0 */)
break;
SleepConditionVariableCS(
&workerThreadHolderPtr->mThreadReadyCond,
&workerThreadHolderPtr->mLock,
INFINITE);
}
/* just poll */
for (;;)
{
if (workerThreadHolderPtr->mIsWorkerStarted != 0)
break;
}
workerThreadHolderPtr->mGuardThreadState = GRD_TASKSTARTING;
WakeAllConditionVariable(&workerThreadHolderPtr->mStartTaskCond);
LeaveCriticalSection(&workerThreadHolderPtr->mLock);
}
/*----------------------------------------------------------------------------*/
int main(int argc, char *argv[])
{
int i;
WorkerThreadHolder workerThreadHolder;
/*
HMODULE NTLibrary = GetModuleHandleW(L"ntdll.dll");
RtlFreeUserThreadStack = (PRtlFreeUserThreadStack)GetProcAddress(NTLibrary, "RtlFreeUserThreadStack");
*/
Start(&workerThreadHolder);
for(i = 0;; ++i)
{
ExecuteTask(&workerThreadHolder);
printf("%d Execution started...\n", i);
/*fflush(stdout);*/
}
return 0;
}
Tested with Visual Studio 2015, vc command line:
/GS- /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /Fd"Debug\vc140.pdb" /Zc:inline /fp:precise /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /Gd /Oy /MDd /Fa"Debug\" /nologo /Fo"Debug\" /Fp"Debug\ConsoleApplication1.pch"
linker:
/OUT:"C:\Users\cherney\documents\visual studio 2015\Projects\ConsoleApplication1\Debug\ConsoleApplication1.exe" /MANIFEST /NXCOMPAT /PDB:"C:\Users\cherney\documents\visual studio 2015\Projects\ConsoleApplication1\Debug\ConsoleApplication1.pdb" /DYNAMICBASE "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /DEBUG /MACHINE:X86 /INCREMENTAL /PGD:"C:\Users\cherney\documents\visual studio 2015\Projects\ConsoleApplication1\Debug\ConsoleApplication1.pgd" /SUBSYSTEM:CONSOLE /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /ManifestFile:"Debug\ConsoleApplication1.exe.intermediate.manifest" /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
'TerminateThread' is 'dangerous' and in fact some de-allocations may not occur (see https://learn.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-terminatethread). Best to redesign the code to cleanly exit threads without the use of 'TerminateThread'.
My problem is very simple and the title explains it all. Basically, when I compile my program with Visual Studio 2013, the dll injection works perfectly fine. When I compile the exact same program in Qt Creator, it doesn't.
I seem to have the same problem as this fellow: Why does Qt not work with dll injection?
Here is my code:
Injector.h
#ifndef INJECTOR_H_INCLUDED
#define INJECTOR_H_INCLUDED
#include <Windows.h>
#include <string>
class Injector
{
public:
/**
* Loads a DLL into the remote process
* #Return true on sucess, false on failure
*/
bool InjectDll(DWORD processId, std::string dllPath);
private:
};
#endif // INJECTOR_H_INCLUDED
Injector.cpp
#include "Injector.h"
bool Injector::InjectDll(DWORD processId, std::string dllPath)
{
HANDLE hThread, hProcess;
void* pLibRemote = 0; // the address (in the remote process) where szLibPath will be copied to;
HMODULE hKernel32 = GetModuleHandleA("Kernel32");
char DllFullPathName[_MAX_PATH];
GetFullPathNameA(dllPath.c_str(), _MAX_PATH, DllFullPathName, NULL);
printf("Loading dll: %s\n", DllFullPathName);
// Get process handle
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId);
// copy file path in szLibPath
char szLibPath[_MAX_PATH];
strcpy_s(szLibPath, DllFullPathName);
// 1. Allocate memory in the remote process for szLibPath
pLibRemote = VirtualAllocEx(hProcess, NULL, sizeof(szLibPath), MEM_COMMIT, PAGE_READWRITE);
if (pLibRemote == NULL)
{
printf("Couldn't allocate memory, please restart with administrator privileges\n");
return false;
}
// 2. Write szLibPath to the allocated memory
WriteProcessMemory(hProcess, pLibRemote, (void*)szLibPath, sizeof(szLibPath), NULL);
// 3. Force remote process to load dll
hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)GetProcAddress(hKernel32, "LoadLibraryA"), pLibRemote, 0, NULL);
if (hThread == NULL)
{
printf("Couldn't load DLL");
return false;
}
printf("Dll successfully loaded\n");
return true;
}
main.cpp
#include "injector.h"
int main(int argc, char *argv[])
{
Injector inject;
DWORD processId = 6224;
inject.InjectDll(processId, "MyDLL.dll");
system("pause");
}
And this is the DLL (I use the same DLL in both scenario, I don't recompile it):
#include <Windows.h>
#include <stdio.h>
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
AllocConsole();
freopen("CONOUT$", "w", stdout);
printf("base address: %X\n", (DWORD)GetModuleHandle(NULL));
break;
case DLL_PROCESS_DETACH:
FreeConsole();
}
return TRUE;
}
The program compiled in VS2013 correctly injects the dll, while the program compiled in Qt Creator says the dll injection was successful, yet the dll is never injected.
NOTE: The program I'm trying to inject is the same in both scenario and was NOT made with Qt.
Here are the compilers output:
Visual Studio:
cl /c /Zi /W3 /WX- /sdl /O2 /Oi /Oy- /GL /D _CRT_SECURE_NO_WARNINGS /D
_MBCS /Gm- /EHsc /MD /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /Fo"Release\" /Fd"Release\vc120.pdb" /Gd /TP /analyze-
/errorReport:prompt Injector.cpp main.cpp
Qt:
C:\Qt\Qt5.4.0\Tools\QtCreator\bin\jom.exe -f Makefile.Release cl -c
-nologo -Zm200 -Zc:wchar_t -FS -O2 -MD -Zc:strictStrings -GR -W3 -w34100 -w34189 -EHsc -DUNICODE -DWIN32 -DWIN64 -DQT_NO_DEBUG -DQT_CORE_LIB -DNDEBUG -I"C:\Qt\Qt5.4.0\5.4\msvc2013_64_opengl\include" -I"C:\Qt\Qt5.4.0\5.4\msvc2013_64_opengl\include\QtCore" -I"release" -I"." -I"C:\Qt\Qt5.4.0\5.4\msvc2013_64_opengl\mkspecs\win32-msvc2013" -Forelease\ #C:\Users\JFG\AppData\Local\Temp\injector.obj.7040.0.jom injector.cpp link /NOLOGO /DYNAMICBASE /NXCOMPAT /INCREMENTAL:NO
/SUBSYSTEM:CONSOLE "/MANIFESTDEPENDENCY:type='win32'
name='Microsoft.Windows.Common-Controls' version='6.0.0.0'
publicKeyToken='6595b64144ccf1df' language=''
processorArchitecture=''" /MANIFEST:embed
/OUT:release\test_dll_inection_qt.exe
#C:\Users\JFG\AppData\Local\Temp\test_dll_inection_qt.exe.7040.469.jom
Any help would be appreciated, thank you.
The problem was that Qt compiled my program in 64bit while visual studio compiled it in 32bit.
I'm still not sure why injecting a 32bit dll in a 32bit target fails because of a 64bit injector, but for now I solved my problem...
I am trying to learn SQLite3 API, when I debug fatal errors occur.
Known that i configured the linker to compile it as a console.
Error 1 error LNK2019: unresolved external symbol _CryptUnprotectData#28 referenced in function _main ....\"filename".obj
Error 2 error LNK1120: 1 unresolved externals Debug\"filename".exe
Here is the code :
#include <stdio.h>
#include <conio.h>
#include "sqlite3.h"
#include <stdlib.h>
#include <Windows.h>
int main()
{
sqlite3_initialize();
sqlite3 *sqlHandle;
int call;
char *tail = NULL;
sqlite3_stmt *stmt = NULL;
const FILE *fileHandle = "C:\\Users\\"username"\\Desktop\\Data.sqlite";
call = sqlite3_open_v2(fileHandle, &sqlHandle, SQLITE_OPEN_READONLY,NULL);
if (call != SQLITE_OK)
{
sqlite3_close(sqlHandle);
exit(EXIT_SUCCESS);
}
//preparing statement to be executed
if (sqlite3_prepare_v2(sqlHandle, "SELECT action_url,username_value,password_value FROM logins", sizeof(char)*60, &stmt, &tail) != SQLITE_OK)
{
sqlite3_close(sqlHandle);
printf("Can't retrieve data: %s\n", sqlite3_errmsg(sqlHandle));
}
CRYPT_INTEGER_BLOB *blob;
CRYPT_INTEGER_BLOB *UnprotectedBlob = NULL;
while (sqlite3_step(stmt) == SQLITE_ROW)
{
blob = sqlite3_column_text(stmt, 2);
if (CryptUnprotectData(blob, NULL, NULL, NULL, NULL, 0, UnprotectedBlob))
{
printf("%s | %s | %s \n",
sqlite3_column_text(stmt, 0),
sqlite3_column_text(stmt, 1),
UnprotectedBlob->cbData);
}
}
sqlite3_finalize(stmt);
sqlite3_close(sqlHandle);
sqlite3_shutdown();
_getch();
return 1;
}
You need to link with the CryptoAPI library. You can do that either from the project properties for the linker (Configuration Properties > Linker > Input > Additional dependencies), or from code with a #pragma directive.
#pragma comment(lib, "Crypt32")
I am trying to create a simple C++ app that would search and list all .wav files on my PC. I am trying to figure out the LNK 1120 error but with no luck. Can anyone point me in the right direction with this one and tell me what am I doing wrong here?
#include "stdafx.h"
#include "iostream"
#include "Shlwapi.h"
#include "windows.h"
void FindFilesRecursively(LPCTSTR lpFolder, LPCTSTR lpFilePattern);
int _tmain(int argc, _TCHAR* argv[])
{
LPCTSTR loc = "C://";
LPCTSTR ft = ".wav";
FindFilesRecursively(loc, ft);
return 0;
}
void FindFilesRecursively(LPCTSTR lpFolder, LPCTSTR lpFilePattern)
{
TCHAR szFullPattern[MAX_PATH];
WIN32_FIND_DATA FindFileData;
HANDLE hFindFile;
// first we are going to process any subdirectories
PathCombine(szFullPattern, lpFolder, _T("*"));
hFindFile = FindFirstFile(szFullPattern, &FindFileData);
if(hFindFile != INVALID_HANDLE_VALUE)
{
do
{
if(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
// found a subdirectory; recurse into it
PathCombine(szFullPattern, lpFolder, FindFileData.cFileName);
FindFilesRecursively(szFullPattern, lpFilePattern);
}
} while(FindNextFile(hFindFile, &FindFileData));
FindClose(hFindFile);
}
// now we are going to look for the matching files
PathCombine(szFullPattern, lpFolder, lpFilePattern);
hFindFile = FindFirstFile(szFullPattern, &FindFileData);
if(hFindFile != INVALID_HANDLE_VALUE)
{
do
{
if(!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
// found a file; do something with it
PathCombine(szFullPattern, lpFolder, FindFileData.cFileName);
std::cout << (_T("%s\n"), szFullPattern);
}
} while(FindNextFile(hFindFile, &FindFileData));
FindClose(hFindFile);
}
}
These are the error messages that I receive
1>------ Build started: Project: SearchForFile, Configuration: Debug Win32 ------
1>SearchForFile.cpp
1>SearchForFile.obj : error LNK2019: unresolved external symbol __imp__PathCombineA#12 referenced in function "void __cdecl FindFilesRecursively(char const *,char const *)" (?FindFilesRecursively##YAXPBD0#Z)
1>c:\users\User\documents\visual studio 2010\Projects\SearchForFile\Debug\SearchForFile.exe : fatal error LNK1120: 1 unresolved externals
> ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
The PathCombine function is in the Shlwapi.lib library, you will need to add this library to your projects linker settings.
Open your project settings and navigate to "Configuration Properties->Linker->Input" and go to the option for "Additional Dependencies" and add the library Shlwapi.lib there.