20#include <freerdp/config.h>
27#include <winpr/path.h>
28#include <winpr/string.h>
29#include <winpr/library.h>
31#include <freerdp/addin.h>
32#include <freerdp/build-config.h>
34#include <freerdp/log.h>
35#define TAG FREERDP_TAG("addin")
37static inline BOOL is_path_required(LPCSTR path,
size_t len)
39 if (!path || (len <= 1))
42 if (strcmp(path,
".") == 0)
48LPSTR freerdp_get_library_install_path(
void)
50 LPCSTR pszLibraryPath = FREERDP_LIBRARY_PATH;
51 LPCSTR pszInstallPrefix = FREERDP_INSTALL_PREFIX;
52 const size_t cchLibraryPath = strlen(pszLibraryPath) + 1;
53 const size_t cchInstallPrefix = strlen(pszInstallPrefix) + 1;
54 const size_t cchPath = cchInstallPrefix + cchLibraryPath;
55 const BOOL needInstallPath = is_path_required(pszInstallPrefix, cchInstallPrefix);
56 const BOOL needLibPath = is_path_required(pszLibraryPath, cchLibraryPath);
58 if (!needInstallPath && !needLibPath)
61 char* pszPath = (LPSTR)calloc(cchPath + 1,
sizeof(
char));
67 CopyMemory(pszPath, pszInstallPrefix, cchInstallPrefix);
71 char* result = GetCombinedPath(pszPath, pszLibraryPath);
79LPSTR freerdp_get_dynamic_addin_install_path(
void)
81#if defined(WITH_ADD_PLUGIN_TO_RPATH)
84 LPCSTR pszAddinPath = FREERDP_ADDIN_PATH;
85 LPCSTR pszInstallPrefix = FREERDP_INSTALL_PREFIX;
86 const size_t cchAddinPath = strlen(pszAddinPath) + 1;
87 const size_t cchInstallPrefix = strlen(pszInstallPrefix) + 1;
88 const size_t cchPath = cchInstallPrefix + cchAddinPath;
89 const BOOL needInstallPath = is_path_required(pszInstallPrefix, cchInstallPrefix);
90 const BOOL needLibPath = is_path_required(pszAddinPath, cchAddinPath);
93 "freerdp_get_dynamic_addin_install_path <- pszInstallPrefix: %s, pszAddinPath: %s",
94 pszInstallPrefix, pszAddinPath);
96 if (!needInstallPath && !needLibPath)
99 char* pszPath = calloc(cchPath + 1,
sizeof(CHAR));
105 CopyMemory(pszPath, pszInstallPrefix, cchInstallPrefix);
109 char* result = GetCombinedPath(pszPath, pszAddinPath);
116 WLog_DBG(TAG,
"freerdp_get_dynamic_addin_install_path -> pszPath: %s", pszPath);
122PVIRTUALCHANNELENTRY freerdp_load_dynamic_addin(LPCSTR pszFileName, LPCSTR pszPath,
125 LPSTR pszAddinInstallPath = freerdp_get_dynamic_addin_install_path();
126 PVIRTUALCHANNELENTRY entry =
nullptr;
128 PCSTR pszExt =
nullptr;
130 HINSTANCE library =
nullptr;
131 size_t cchFileName = 0;
132 size_t cchFilePath = 0;
133 LPSTR pszAddinFile =
nullptr;
134 LPSTR pszFilePath =
nullptr;
135 LPSTR pszRelativeFilePath =
nullptr;
136 size_t cchAddinFile = 0;
137 size_t cchAddinInstallPath = 0;
139 if (!pszFileName || !pszEntryName)
142 WLog_DBG(TAG,
"freerdp_load_dynamic_addin <- pszFileName: %s, pszPath: %s, pszEntryName: %s",
143 pszFileName, pszPath, pszEntryName);
145 cchFileName = strlen(pszFileName);
148 pszExt = strrchr(pszFileName,
'.');
151 pszExt = PathGetSharedLibraryExtensionA(PATH_SHARED_LIB_EXT_WITH_DOT);
152 cchExt = strlen(pszExt);
158 pszAddinFile = _strdup(pszFileName);
165 cchAddinFile = cchFileName + cchExt + 2 +
sizeof(FREERDP_SHARED_LIBRARY_PREFIX);
166 pszAddinFile = (LPSTR)malloc(cchAddinFile + 1);
171 (void)sprintf_s(pszAddinFile, cchAddinFile, FREERDP_SHARED_LIBRARY_PREFIX
"%s%s",
172 pszFileName, pszExt);
175 cchAddinFile = strlen(pszAddinFile);
180 size_t relPathLen = strlen(pszPath) + cchAddinFile + 1;
181 pszRelativeFilePath = calloc(relPathLen,
sizeof(CHAR));
183 if (!pszRelativeFilePath)
186 (void)sprintf_s(pszRelativeFilePath, relPathLen,
"%s", pszPath);
187 char* result = GetCombinedPath(pszRelativeFilePath, pszAddinFile);
188 free(pszRelativeFilePath);
189 pszRelativeFilePath = result;
190 if (!pszRelativeFilePath)
194 pszRelativeFilePath = _strdup(pszAddinFile);
196 if (!pszRelativeFilePath)
200 if (pszAddinInstallPath)
202 cchAddinInstallPath = strlen(pszAddinInstallPath);
203 cchFilePath = cchAddinInstallPath + cchFileName + 32;
204 pszFilePath = (LPSTR)malloc(cchFilePath + 1);
209 CopyMemory(pszFilePath, pszAddinInstallPath, cchAddinInstallPath);
210 pszFilePath[cchAddinInstallPath] =
'\0';
212 char* result = GetCombinedPath(pszFilePath, pszRelativeFilePath);
214 pszFilePath = result;
219 pszFilePath = _strdup(pszRelativeFilePath);
221 library = LoadLibraryX(pszFilePath);
226 entry = GetProcAddressAs(library, pszEntryName, PVIRTUALCHANNELENTRY);
228 free(pszRelativeFilePath);
231 free(pszAddinInstallPath);
233 if (!entry && library)
234 FreeLibrary(library);
239PVIRTUALCHANNELENTRY freerdp_load_dynamic_channel_addin_entry(LPCSTR pszName, LPCSTR pszSubsystem,
240 LPCSTR pszType, DWORD dwFlags)
242 PVIRTUALCHANNELENTRY entry =
nullptr;
243 LPSTR pszFileName =
nullptr;
244 const size_t cchBaseFileName =
sizeof(FREERDP_SHARED_LIBRARY_PREFIX) + 32;
246 size_t subsystemLen = 0;
248 size_t cchFileName = 0;
251 nameLen = strnlen(pszName, MAX_PATH);
253 subsystemLen = strnlen(pszSubsystem, MAX_PATH);
255 typeLen = strnlen(pszType, MAX_PATH);
257 if (pszName && pszSubsystem && pszType)
259 cchFileName = cchBaseFileName + nameLen + subsystemLen + typeLen;
260 pszFileName = (LPSTR)malloc(cchFileName);
265 (void)sprintf_s(pszFileName, cchFileName,
"%s-client-%s-%s", pszName, pszSubsystem,
268 else if (pszName && pszSubsystem)
270 cchFileName = cchBaseFileName + nameLen + subsystemLen;
271 pszFileName = (LPSTR)malloc(cchFileName);
276 (void)sprintf_s(pszFileName, cchFileName,
"%s-client-%s", pszName, pszSubsystem);
280 cchFileName = cchBaseFileName + nameLen;
281 pszFileName = (LPSTR)malloc(cchFileName);
286 (void)sprintf_s(pszFileName, cchFileName,
"%s-client", pszName);
294 LPCSTR pszExtension = PathGetSharedLibraryExtensionA(0);
295 const char pszPrefix[] = FREERDP_SHARED_LIBRARY_PREFIX;
298 cchFileName += strnlen(pszPrefix, ARRAYSIZE(pszPrefix));
300 cchFileName += strnlen(pszExtension, MAX_PATH) + 1;
301 LPSTR tmp = calloc(cchFileName,
sizeof(CHAR));
303 rc = sprintf_s(tmp, cchFileName,
"%s%s.%s", pszPrefix, pszFileName, pszExtension);
307 if (!pszFileName || (rc < 0))
316 LPSTR pszEntryName =
nullptr;
317 size_t cchEntryName = 0;
319 cchEntryName = 64 + nameLen;
320 pszEntryName = (LPSTR)malloc(cchEntryName + 1);
328 (void)sprintf_s(pszEntryName, cchEntryName + 1,
"freerdp_%s_client_subsystem_entry",
330 entry = freerdp_load_dynamic_addin(pszFileName,
nullptr, pszEntryName);
338 if (dwFlags & FREERDP_ADDIN_CHANNEL_STATIC)
340 if (dwFlags & FREERDP_ADDIN_CHANNEL_ENTRYEX)
341 entry = freerdp_load_dynamic_addin(pszFileName,
nullptr,
"VirtualChannelEntryEx");
343 entry = freerdp_load_dynamic_addin(pszFileName,
nullptr,
"VirtualChannelEntry");
345 else if (dwFlags & FREERDP_ADDIN_CHANNEL_DYNAMIC)
346 entry = freerdp_load_dynamic_addin(pszFileName,
nullptr,
"DVCPluginEntry");
347 else if (dwFlags & FREERDP_ADDIN_CHANNEL_DEVICE)
348 entry = freerdp_load_dynamic_addin(pszFileName,
nullptr,
"DeviceServiceEntry");
350 entry = freerdp_load_dynamic_addin(pszFileName,
nullptr, pszType);
356static FREERDP_LOAD_CHANNEL_ADDIN_ENTRY_FN freerdp_load_static_channel_addin_entry =
nullptr;
358int freerdp_register_addin_provider(FREERDP_LOAD_CHANNEL_ADDIN_ENTRY_FN provider,
359 WINPR_ATTR_UNUSED DWORD dwFlags)
361 freerdp_load_static_channel_addin_entry = provider;
365FREERDP_LOAD_CHANNEL_ADDIN_ENTRY_FN freerdp_get_current_addin_provider(
void)
367 return freerdp_load_static_channel_addin_entry;
370PVIRTUALCHANNELENTRY freerdp_load_channel_addin_entry(LPCSTR pszName, LPCSTR pszSubsystem,
371 LPCSTR pszType, DWORD dwFlags)
373 PVIRTUALCHANNELENTRY entry =
nullptr;
375 if (freerdp_load_static_channel_addin_entry)
376 entry = freerdp_load_static_channel_addin_entry(pszName, pszSubsystem, pszType, dwFlags);
379 entry = freerdp_load_dynamic_channel_addin_entry(pszName, pszSubsystem, pszType, dwFlags);
382 WLog_WARN(TAG,
"Failed to load channel %s [%s]", pszName, pszSubsystem);