From 16a0f764450c2a92b5ca62f38b7d0190dffba5a1 Mon Sep 17 00:00:00 2001 From: Perry Werneck Date: Fri, 20 Sep 2019 15:26:17 -0300 Subject: [PATCH] Reimplementing delayed loading on windows. --- client/ipcclient.cbp | 2 ++ client/src/core/windows/tools.cc | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ client/src/include/ipc-client-internals.h | 9 +++++++++ client/src/include/lib3270/ipc.h | 15 +++++++++++++++ client/src/session/local/init.cc | 190 ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 5 files changed, 222 insertions(+), 188 deletions(-) create mode 100644 client/src/core/windows/tools.cc diff --git a/client/ipcclient.cbp b/client/ipcclient.cbp index caf6bac..cdad57c 100644 --- a/client/ipcclient.cbp +++ b/client/ipcclient.cbp @@ -48,11 +48,13 @@ + + diff --git a/client/src/core/windows/tools.cc b/client/src/core/windows/tools.cc new file mode 100644 index 0000000..783c5a4 --- /dev/null +++ b/client/src/core/windows/tools.cc @@ -0,0 +1,194 @@ +/* + * "Software pw3270, desenvolvido com base nos códigos fontes do WC3270 e X3270 + * (Paul Mattes Paul.Mattes@usa.net), de emulação de terminal 3270 para acesso a + * aplicativos mainframe. Registro no INPI sob o nome G3270. + * + * Copyright (C) <2008> + * + * Este programa é software livre. Você pode redistribuí-lo e/ou modificá-lo sob + * os termos da GPL v.2 - Licença Pública Geral GNU, conforme publicado pela + * Free Software Foundation. + * + * Este programa é distribuído na expectativa de ser útil, mas SEM QUALQUER + * GARANTIA; sem mesmo a garantia implícita de COMERCIALIZAÇÃO ou de ADEQUAÇÃO + * A QUALQUER PROPÓSITO EM PARTICULAR. Consulte a Licença Pública Geral GNU para + * obter mais detalhes. + * + * Você deve ter recebido uma cópia da Licença Pública Geral GNU junto com este + * programa; se não, escreva para a Free Software Foundation, Inc., 51 Franklin + * St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Este programa está nomeado como - e possui - linhas de código. + * + * Contatos: + * + * perry.werneck@gmail.com (Alexandre Perry de Souza Werneck) + * erico.mendonca@gmail.com (Erico Mascarenhas Mendonça) + * + */ + +/** + * @file + * + * @brief Win32 convenience methods. + * + * @author perry.werneck@gmail.com + * + */ + + #include + #include + #include + #include + + using std::string; + +/*---[ Implement ]----------------------------------------------------------------------------------*/ + + // https://docs.microsoft.com/en-us/cpp/build/reference/loading-all-imports-for-a-delay-loaded-dll?view=vs-2019 + + PfnDliHook __pfnDliNotifyHook2 = IPC3270_DelayLoadHook; + PfnDliHook __pfnDliFailureHook2 = IPC3270_DelayLoadHook; + + FARPROC WINAPI IPC3270_DelayLoadHook(unsigned reason, DelayLoadInfo * info) { + + // https://docs.microsoft.com/en-us/cpp/build/reference/structure-and-constant-definitions?view=vs-2019 + + debug(__FUNCTION__," ",(const char *) info->szDll); + + switch (reason) { + case dliNoteStartProcessing: + debug(__FUNCTION__,"::dliNoteStartProcessing") + /* + { + string installLocation = TN3270::getInstallLocation(); + if(!installLocation.empty()) { + SetCurrentDirectory(installLocation.c_str()); + } + } + */ + break; + + case dliNoteEndProcessing: + debug(__FUNCTION__,"::dliNoteEndProcessing") + break; + + case dliNotePreLoadLibrary: + debug(__FUNCTION__,"::dliNotePreLoadLibrary"); + + /* + { + // http://otb.manusoft.com/2013/01/using-delayload-to-specify-dependent-dll-path.htm + + string myPath = TN3270::getInstallLocation(); + + myPath += "\\"; + myPath += (const char *) info->szDll; + + debug("Checking ",myPath,"=",access(myPath.c_str(), R_OK)); + + if(access(myPath.c_str(), R_OK) == 0) { + return (FARPROC) LoadLibrary(myPath.c_str()); + } + + } + */ + break; + + case dliNotePreGetProcAddress: + debug(__FUNCTION__,"::dliNotePreGetProcAddress") + break; + + case dliFailLoadLib: + debug(__FUNCTION__,"::dliFailLoadLib") + break; + + case dliFailGetProc: + debug(__FUNCTION__,"::dliFailGetProc") + break; + + default: + debug(__FUNCTION__,"::default") + + } + + // Returning NULL causes the delay load machinery to perform default + // processing for this notification. + return NULL; + + } + + namespace TN3270 { + + std::string getUserName() { + + char username[UNLEN + 1]; + DWORD szName = sizeof(username); + + memset(username,0,UNLEN + 1); + + if(!GetUserName(username, &szName)) { + return ""; + } + + return std::string(username); + + } + + std::string getInstallLocation() { + + LSTATUS rc; + HKEY hKey = 0; + + static const char * keys[] = { + + "Software\\" LIB3270_STRINGIZE_VALUE_OF(PRODUCT_NAME), + "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" LIB3270_STRINGIZE_VALUE_OF(PRODUCT_NAME), + +#ifdef LIB3270_NAME + "Software\\" LIB3270_STRINGIZE_VALUE_OF(LIB3270_NAME), + "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" LIB3270_STRINGIZE_VALUE_OF(LIB3270_NAME), +#endif + + "Software\\pw3270", + "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\pw3270" + }; + + size_t ix; + + string installLocation; + + for(ix = 0; installLocation.empty() && ix < (sizeof(keys)/sizeof(keys[0])); ix++) { + + debug(ix,"=",keys[ix]); + + rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,keys[ix],0,KEY_QUERY_VALUE,&hKey); + if(rc == ERROR_SUCCESS) { + + unsigned long datatype; // #defined in winnt.h (predefined types 0-11) + char datadir[4096]; + unsigned long datalen = sizeof(datadir); + + memset(datadir,0,datalen); + + rc = RegQueryValueExA(hKey,"InstallLocation",NULL,&datatype,(LPBYTE) datadir,&datalen); + if(rc == ERROR_SUCCESS) { + + debug("Found: ",datadir); + + installLocation.assign(datadir); + + } + + RegCloseKey(hKey); + + } + + } + + return installLocation; + } + + } + + diff --git a/client/src/include/ipc-client-internals.h b/client/src/include/ipc-client-internals.h index 12c3c66..182dba4 100644 --- a/client/src/include/ipc-client-internals.h +++ b/client/src/include/ipc-client-internals.h @@ -57,6 +57,7 @@ #include #include #include + #include #ifdef HAVE_LIBINTL #include @@ -101,6 +102,14 @@ /// @brief Check lib3270 return codes, launch exception when failed. TN3270_PRIVATE void chkResponse(int rc); +#ifdef _WIN32 + + /// @brief Get protocol library install location. + TN3270_PRIVATE std::string getInstallLocation(); + TN3270_PRIVATE std::string getUserName(); + +#endif // _WIN32 + namespace Abstract { class TN3270_PRIVATE Session : public TN3270::Session { diff --git a/client/src/include/lib3270/ipc.h b/client/src/include/lib3270/ipc.h index a800796..1ea31ca 100644 --- a/client/src/include/lib3270/ipc.h +++ b/client/src/include/lib3270/ipc.h @@ -40,6 +40,8 @@ #if defined(_WIN32) + #include + #define TN3270_PUBLIC __declspec (dllexport) #define TN3270_PRIVATE @@ -63,6 +65,19 @@ #include +#ifdef _WIN32 + + extern "C" { + + extern __declspec (dllexport) PfnDliHook __pfnDliNotifyHook2; + extern __declspec (dllexport) PfnDliHook __pfnDliFailureHook2; + + FARPROC WINAPI IPC3270_DelayLoadHook(unsigned reason, DelayLoadInfo * info); + + } + +#endif // _WIN32 + namespace TN3270 { class Host; diff --git a/client/src/session/local/init.cc b/client/src/session/local/init.cc index 549a2d7..3338238 100644 --- a/client/src/session/local/init.cc +++ b/client/src/session/local/init.cc @@ -55,198 +55,10 @@ return new Local::Session(); } - #ifdef _WIN32 - - string getUserName() { - - char username[UNLEN + 1]; - DWORD szName = sizeof(username); - - memset(username,0,UNLEN + 1); - - if(!GetUserName(username, &szName)) { - return "?"; - } - - return string(username); - - } - - static void writeLog(HANDLE hEventLog, const char *msg, int rc = (int) GetLastError()) { - - - debug(msg," rc=",rc); - - if(hEventLog) { - - string username = getUserName(); - char lasterror[1024]; - snprintf(lasterror,sizeof(lasterror),"The error code was %d",rc); - - const char *outMsg[] = { - username.c_str(), - msg, - lasterror - }; - - ReportEvent( - hEventLog, - EVENTLOG_ERROR_TYPE, - 1, - 0, - NULL, - (sizeof(outMsg) / sizeof(outMsg[0])), - 0, - outMsg, - NULL - ); - - } - - } - - static string getInstallLocation(HANDLE hEventLog) { - - LSTATUS rc; - HKEY hKey = 0; - - static const char * keys[] = { - - "Software\\" LIB3270_STRINGIZE_VALUE_OF(PRODUCT_NAME), - "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" LIB3270_STRINGIZE_VALUE_OF(PRODUCT_NAME), - -#ifdef LIB3270_NAME - "Software\\" LIB3270_STRINGIZE_VALUE_OF(LIB3270_NAME), - "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" LIB3270_STRINGIZE_VALUE_OF(LIB3270_NAME), -#endif - - "Software\\pw3270", - "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\pw3270" - }; - - size_t ix; - - string installLocation; - - for(ix = 0; installLocation.empty() && ix < (sizeof(keys)/sizeof(keys[0])); ix++) { - - debug(ix,"=",keys[ix]); - - rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,keys[ix],0,KEY_QUERY_VALUE,&hKey); - if(rc == ERROR_SUCCESS) { - - unsigned long datatype; // #defined in winnt.h (predefined types 0-11) - char datadir[4096]; - unsigned long datalen = sizeof(datadir); - - memset(datadir,0,datalen); - - rc = RegQueryValueExA(hKey,"InstallLocation",NULL,&datatype,(LPBYTE) datadir,&datalen); - if(rc == ERROR_SUCCESS) { - - debug("Found: ",datadir); - - installLocation.assign(datadir); - string username = getUserName(); - - const char *outMsg[] = { - username.c_str(), - "Found LIB3270 installation", - keys[ix], - installLocation.c_str() - }; - - ReportEvent( - hEventLog, - EVENTLOG_INFORMATION_TYPE, - 1, - 0, - NULL, - (sizeof(outMsg) / sizeof(outMsg[0])), - 0, - outMsg, - NULL - ); - - } - - RegCloseKey(hKey); - - } - - } - - return installLocation; - } - - #endif // _WIN32 - Local::Session::Session() : Abstract::Session() { std::lock_guard lock(sync); -#ifdef _WIN32 - { - static bool initialized = false; - - if(!initialized) { - -#ifdef LIB3270_NAME - HANDLE hEventLog = RegisterEventSource(NULL, LIB3270_STRINGIZE_VALUE_OF(LIB3270_NAME)); -#else - HANDLE hEventLog = RegisterEventSource(NULL, PACKAGE_NAME); -#endif // LIB3270_NAME - - string installLocation = getInstallLocation(hEventLog); - - if(installLocation.empty()) { - - writeLog(hEventLog, "Can't identify lib3270 installation path"); - - } else { - - // TODO: Understand why SetDefaultDllDirectories & AddDllDirectory causes failure in DNS resolution. - - - SetCurrentDirectory(installLocation.c_str()); - -/* - wchar_t *path = (wchar_t *) malloc(sizeof(datadir)*sizeof(wchar_t)); - mbstowcs(path, datadir, 4095); - - if(!SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_USER_DIRS)) { - writeLog(hEventLog,"SetDefaultDllDirectories has failed"); - } -#ifdef DEBUG - else { - debug("SetDefaultDllDirectories has suceeded"); - } -#endif - - if(!AddDllDirectory(path)) { - string msg = "Can't add "; - msg += datadir; - msg += " to directory path"; - writeLog(hEventLog,msg.c_str()); - } -#ifdef DEBUG - else { - debug("AddDllDirectory has suceeded"); - } -#endif - free(path); - -*/ - } - - initialized = true; - DeregisterEventSource(hEventLog); - - } - - } -#endif // _WIN32 - this->hSession = lib3270_session_new(""); lib3270_set_user_data(this->hSession,(void *) this); @@ -263,6 +75,8 @@ cbk->update_connect = connectHandler; + throw std::runtime_error("Testando pre-load"); + } Local::Session::~Session() { -- libgit2 0.21.2