code_device/twain/sane_helper.cpp

175 lines
4.3 KiB
C++

#include "sane_helper.h"
#include "huagao/brand.h"
#include "utils.h"
#include <string.h>
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// win util
#if OS_WIN
#define LoadLibraryExA win_util::load_dll
namespace win_util
{
std::string get_registry_string(HKEY root, const char* path, const char* name)
{
HKEY key = NULL;
RegOpenKeyA(root, path, &key);
if (!key)
return "";
char* buf = NULL;
DWORD len = 0;
DWORD type = REG_SZ;
std::string ret("");
RegQueryValueExA(key, name, NULL, &type, (LPBYTE)buf, &len);
if (len)
{
buf = new char[len + 4];
memset(buf, 0, (len + 4) * sizeof(*buf));
RegQueryValueExA(key, name, NULL, &type, (LPBYTE)buf, &len);
ret = buf;
delete[] buf;
}
RegCloseKey(key);
return ret;
}
HMODULE load_dll(const char* path_dll, int flag, int* err)
{
HMODULE h = LoadLibraryA(path_dll);
int ret = GetLastError();
utils::to_log(1, "[TWAIN]Load: LoadLibraryA(%s) = %d\r\n", path_dll, ret);
if (!h && (ret == ERROR_MOD_NOT_FOUND || ret == ERROR_BAD_EXE_FORMAT))
{
std::string dir(path_dll);
size_t pos = dir.rfind('\\');
char path[MAX_PATH] = { 0 };
GetDllDirectoryA(_countof(path) - 1, path);
if (pos != std::wstring::npos)
dir.erase(pos);
utils::to_log(LOG_LEVEL_FATAL, "[TWAIN]Load: change directory to '%s' and retry LoadLibraryA(%s) ...\r\n", dir.c_str(), path_dll);
SetDllDirectoryA(dir.c_str());
h = LoadLibraryA(path_dll);
// h = LoadLibraryExW(path_dll, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
ret = GetLastError();
utils::to_log(1, "[TWAIN]Load: trying LoadLibraryA(%s) = %d, restore directory to '%s'\r\n", path_dll, ret, path);
SetDllDirectoryA(path);
}
if (err)
*err = ret;
return h;
}
};
#else
#include <dlfcn.h>
#endif
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// sane_helper
sane_helper::sane_helper()
{
// find sane root directory ...
#if OS_WIN
std::string path(win_util::get_registry_string(HKEY_LOCAL_MACHINE, (std::string("Software\\") + PRODUCT_VENDOR + "Scan").c_str(), sizeof(void*) == 4 ? "DriverPath" : "DriverPath64"));
dll_root_ = path + PATH_SEPARATOR;
#else
std::string path(utils::get_module_full_path("libc"));
size_t pos = path.rfind(PATH_SEPARATOR[0]);
if(pos++ != std::string::npos)
{
path.erase(pos);
dll_root_ = std::move(path);
dll_root_ += "sane/";
}
#endif
utils::to_log(1, "sane path is: %s\n", dll_root_.c_str());
}
sane_helper::~sane_helper()
{
clear();
}
void sane_helper::clear(void)
{
invoke_sane_init = nullptr;
invoke_sane_exit = nullptr;
invoke_sane_get_devices = nullptr;
invoke_sane_open = nullptr;
invoke_sane_close = nullptr;
invoke_sane_get_option_descriptor = nullptr;
invoke_sane_control_option = nullptr;
invoke_sane_get_parameters = nullptr;
invoke_sane_start = nullptr;
invoke_sane_read = nullptr;
invoke_sane_cancel = nullptr;
invoke_sane_set_io_mode = nullptr;
invoke_sane_get_select_fd = nullptr;
invoke_sane_strstatus = nullptr;
if(dll_handle_)
{
FreeLibrary(dll_handle_);
dll_handle_ = nullptr;
}
}
bool sane_helper::load_sane(const char* vendor) // libsane_hgsane.so.1, and vendor is 'hgsane'
{
#if OS_WIN
std::string file(dll_root_ + "sane.dll"), func("sane_");
#else
std::string file(dll_root_ + "libsane-" + vendor + ".so.1"), func("sane_");
#endif
bool ok = true;
clear();
dll_handle_ = LoadLibraryExA(file.c_str(), 0, RTLD_NOW);
if(!dll_handle_)
{
utils::to_log(7, "load sane library(%s) = %s\n", file.c_str(), strerror(errno));
return false;
}
func += vendor;
func += "_";
#define GET_PROC_ADDR(api) \
*(void**)&invoke_sane_##api = GetProcAddress(dll_handle_, (func + #api).c_str()); \
ok &= invoke_sane_##api != nullptr;
GET_PROC_ADDR(init);
GET_PROC_ADDR(init_ex);
GET_PROC_ADDR(exit);
GET_PROC_ADDR(get_devices);
GET_PROC_ADDR(open);
GET_PROC_ADDR(close);
GET_PROC_ADDR(get_option_descriptor);
GET_PROC_ADDR(control_option);
GET_PROC_ADDR(get_parameters);
GET_PROC_ADDR(start);
GET_PROC_ADDR(read);
GET_PROC_ADDR(cancel);
GET_PROC_ADDR(set_io_mode);
GET_PROC_ADDR(get_select_fd);
GET_PROC_ADDR(strstatus);
if(!ok)
clear();
return ok;
}