diff --git a/CMakeLists.txt b/CMakeLists.txt
index 80531b497..22c361b1a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -111,6 +111,10 @@ if(MSVC)
message(STATUS "Random freeing errors are a common sign of runtime issues")
endif()
configure_msvc_runtime()
+
+ if(NOT DEFINED CMAKE_SUPPRESS_REGENERATION)
+ set(CMAKE_SUPPRESS_REGENERATION ON)
+ endif()
endif()
# Compiler-specific flags
diff --git a/client/Android/FreeRDPCore/res/values-es/strings.xml b/client/Android/FreeRDPCore/res/values-es/strings.xml
new file mode 100644
index 000000000..2f9d36d8e
--- /dev/null
+++ b/client/Android/FreeRDPCore/res/values-es/strings.xml
@@ -0,0 +1,175 @@
+
+
+
+ Si
+ No
+ Cancelar
+ Continuar
+ Ingresar
+ Salir
+
+ Salida
+ Sobre
+ Ayuda
+ Nueva conexión
+ Configuracion
+
+ Conexión
+ Conectar
+ Editar
+ Borrar
+
+ Teclado
+ Funcion teclado
+ Puntero Tactil
+ Inicio
+ desconectart
+
+ Conexión Manual
+ Sesiones Activas
+
+ Connectarse a iWinCloud
+
+ Login
+ No hay escritorios virtuales
+ Conectando ...
+ Desconectando ...
+ Conexión perdida
+ Contraseña equivocada
+ Usuario Invalido
+ Agregar escritorio virtual de iWinCloud
+
+ Host
+ Su nombre
+ IP
+ Puerto
+ Credenciales de iWinCloud
+ Credenciales
+ Usuario
+ Contraseña
+ Dominio
+ Configuracion
+ Pantalla
+ Configuracion Pantalla
+ Colores
+
+ - Calidad Normal (16 Bit)
+ - Calidad Optima (24 Bit)
+ - Calidad maxima (32 Bit)
+
+
+ - 16
+ - 24
+ - 32
+
+ Resolucion
+ Automatico
+ Manual
+
+ - Automatico
+ - Manual
+ - 640x480
+ - 720x480
+ - 800x600
+ - 1024x768
+ - 1280x1024
+ - 1440x900
+ - 1920x1080
+ - 1920x1200
+
+
+ - automatico
+ - manual
+ - 640x480
+ - 720x480
+ - 800x600
+ - 1024x768
+ - 1280x1024
+ - 1440x900
+ - 1920x1080
+ - 1920x1200
+
+ Ancho
+ Altura
+ Rendimiento
+ Configuracion Rendimiento
+ RemoteFX
+ Fondo escritorio
+ Fuente suave
+ Composicion escritorio
+ Contenidos de la ventana mientras se arrastra
+ Animacion del menu
+ Estilo visual
+ Avanzado
+ Configuracion Avanzada
+ Configuracion 3G
+ Pantalla 3G
+ Rendimiento 3G
+ Seguridad
+
+ - Automatico
+ - RDP
+ - TLS
+ - NLA
+
+
+ - 0
+ - 1
+ - 2
+ - 3
+
+ Programa Remoto
+ Directorio de trabajo
+ Modo Consola
+
+ *******
+ no configurado
+ Interfaze Usuario
+ Ocultar barra de estado
+ Ocultar controles de zoom
+ Intercambiar botones del mouse
+ invertir desplazamiento
+ Puntero táctil de desplazamiento automático
+ Mostrar cuadro de diálogo en la salida
+ Ahorro de energía
+ Cerrar las conexiones inactivas
+ Seguridad
+ Aceptar todos los certificados
+ Borrar el Cache de los certificados
+ Despues %1$d Minutos
+ Desabilitado
+
+ Configuración de la conexión
+ Configuración
+ iWinCloud - iWinCloud para Android
+ Conexiones RDP
+ Ayuda
+ Sobre
+
+ Cancelar sin guardar?
+ Pulse el botón "Cancelar" para abortar! \ NPulse "Continuar" para especificar los campos obligatorios!
+ No se pudo establecer una conexión con iWinCloud!
+
+ Los ajustes de pantalla se han cambiado porque el escritorio virtual no es compatible con la configuración especificada!
+ Eliminado el cache del certificado!
+ No se pudo borrar el caché del certificado!
+
+ verificar el certificado
+ La identidad de su escritorio de iWinCloud debe ser verificada. ¿Desea conectarse de todos modos?
+ Por favor, introduzca sus credenciales
+ Crear acceso directo
+ Nombre corto:
+ Conectando ...
+ Ingresando a ...
+ Sobre iWinCloud
+ Version: %1$s\n\u00A9 2012 iWinCloud LLc
+ Guardar configuración de conexión?
+ La configuración de conexión no se han guardado! ¿Quieres guardarlos?
+ Guardar Conexión
+ ¿Desea guardar los cambios realizados en la configuración de conexión?
+ No volver a preguntar
+ Salir del programa?
+ Esta seguro que desea salir del programa?
+ Borrar Certificados?
+ Esta seguro que desea borrar todos los certificados?
+
diff --git a/client/Android/FreeRDPCore/res/values-fr/strings.xml b/client/Android/FreeRDPCore/res/values-fr/strings.xml
new file mode 100644
index 000000000..95f3d6490
--- /dev/null
+++ b/client/Android/FreeRDPCore/res/values-fr/strings.xml
@@ -0,0 +1,174 @@
+
+
+ "Oui"
+ "Non"
+ "Annuler"
+ "Continuer"
+ "Se connecter"
+ "Déconnexion"
+
+ "Quitter"
+ "À propos"
+ "Aide"
+ "Nouvelle connexion"
+ "Paramètres"
+
+ "Connexion"
+ "Connexion"
+ "Éditer"
+ "Supprimer"
+
+ "Clavier"
+ "Touches de fonction"
+ "Pointeur tactile"
+ "Accueil"
+ "Se déconnecter"
+
+ "Connexions manuelles"
+ "Sessions actives"
+
+ "Connexion à l'ordinateur"
+
+ "Se connecter"
+ "Pas de connexion"
+ "Connexion..."
+ "Déconnexion…"
+ "Perte de la connexion"
+ "Mot de passe incorrect"
+ "Nom d'utilisateur invalide"
+ "Ajouter une connexion"
+
+ "Hôte"
+ "Étiquette"
+ "Hôte"
+ "Port"
+ "Authentifiant"
+ "Authentifiant"
+ "Nom d'utilisateur"
+ "Mot de passe"
+ "Nom de domaine"
+ "Paramètres"
+ "Écran"
+ "Paramètres d'écran"
+ "Couleurs"
+
+ - "Hautes couleurs (16 bits)"
+ - "Couleurs vraies (24 bits)"
+ - "Haute qualité (32 bits)"
+
+
+ - "16"
+ - "24"
+ - "32"
+
+ "Résolution"
+ "Automatique"
+ "Personalisé"
+
+ - "Automatique"
+ - "Personalisé"
+ - "640x480"
+ - "720x480"
+ - "800x600"
+ - "1024x768"
+ - "1280x1024"
+ - "1440x900"
+ - "1920x1080"
+ - "1920x1200"
+
+
+ - "Automatique"
+ - "Personalisé"
+ - "640x480"
+ - "720x480"
+ - "800x600"
+ - "1024x768"
+ - "1280x1024"
+ - "1440x900"
+ - "1920x1080"
+ - "1920x1200"
+
+ "Largeur"
+ "Hauteur"
+ "Performance"
+ "Paramètres de performance"
+ "RemoteFX"
+ "Fond d'écran"
+ "Lissage des polices"
+ "Effets visuels Aero"
+ "Afficher le contenu des fenêtres en mouvement"
+ "Animations de menu"
+ "Styles visuels"
+ "Avancé"
+ "Paramètres avancés"
+ "Paramètres 3G"
+ "Écran 3G"
+ "Performance 3G"
+ "Securité"
+
+ - "Automatique"
+ - "RDP"
+ - "TLS"
+ - "NLA"
+
+
+ - "0"
+ - "1"
+ - "2"
+ - "3"
+
+ "Lancement de programme"
+ "Répertoire de travail"
+ "Mode console"
+
+ "*******"
+ "Valeur non définie"
+ "Interface utilisateur"
+ "Masquer la barre d'état"
+ "Masquer les contrôles zoom"
+ "Inverser les boutons de la souris"
+ "Inverser le défilement de la souris"
+ "Défilement automatique du pointeur tactile"
+ "Confirmer au moment de quitter"
+ "Economie d'énergie"
+ "Fermer les connexions inactives"
+ "Securité"
+ "Accepter tous les certificats"
+ "Vider la cache de certificats"
+ "Après %1$d minutes"
+ "Désactivé"
+
+ "Paramètres de connexion"
+ "Paramètres"
+ "aFreeRDP - FreeRDP pour Android"
+ "Connexions RDP"
+ "Aide"
+ "À propos"
+
+ "Annuler sans enregistrer?"
+ "Appuyez sur \"Annuler\" pour annuler, ou cliquez sur «Continuer» pour spécifier les champs obligatoires."
+ "Impossible d'établir une connexion au serveur!"
+
+ "Les paramètres de l'écran ont changé parce que le serveur ne prend pas en charge les paramètres que vous avez spécifiés!"
+ "La cache de certificats a été supprimée!"
+ "Impossible de supprimer la cache de certificat!"
+
+ "Validation de certificat"
+ "L'identité de l'ordinateur distant ne peut pas être vérifiée. Voulez-vous poursuivre la connexion?"
+ "Veuillez entrer votre nom d'usager et mot de passe"
+ "Créer un raccourci"
+ "Nom du raccourci:"
+ "Connexion..."
+ "Connexion..."
+ "À propos de aFreeRDP"
+ "Version: %1$s \ n \ u00A9 2012 Technologies GmbH Thinstuff"
+ "Enregistrer les paramètres de connexion?"
+ "Vos paramètres de connexion n'ont pas été sauvegardés! Voulez-vous les enregistrer?"
+ "Enregistrer la connexion?"
+ "Voulez-vous enregistrer les modifications que vous avez apportées aux paramètres de connexion?"
+ "Ne plus demander"
+ "Quittez l'application?"
+ "Êtes-vous sûr de vouloir quitter l'application?"
+ "Êtes-vous sûrs de vouloir supprimer les certificats?"
+ "Êtes-vous sûr de vouloir supprimer tous les certificats mis en cache?"
+
diff --git a/client/Android/FreeRDPCore/res/xml/application_settings.xml b/client/Android/FreeRDPCore/res/xml/application_settings.xml
index 9d7cc0a67..0df4ea126 100644
--- a/client/Android/FreeRDPCore/res/xml/application_settings.xml
+++ b/client/Android/FreeRDPCore/res/xml/application_settings.xml
@@ -29,5 +29,4 @@
-
diff --git a/client/Android/FreeRDPCore/res/xml/bookmark_settings.xml b/client/Android/FreeRDPCore/res/xml/bookmark_settings.xml
index c49d4272a..0564537d7 100644
--- a/client/Android/FreeRDPCore/res/xml/bookmark_settings.xml
+++ b/client/Android/FreeRDPCore/res/xml/bookmark_settings.xml
@@ -12,7 +12,7 @@
-
+
diff --git a/client/Android/FreeRDPCore/res/xml/credentials_settings.xml b/client/Android/FreeRDPCore/res/xml/credentials_settings.xml
index 0247b66cd..a27be58c1 100644
--- a/client/Android/FreeRDPCore/res/xml/credentials_settings.xml
+++ b/client/Android/FreeRDPCore/res/xml/credentials_settings.xml
@@ -11,8 +11,8 @@
-->
-
-
-
+
+
+
diff --git a/client/Mac/CMakeLists.txt b/client/Mac/CMakeLists.txt
index 2183eb9d2..80b03ca62 100644
--- a/client/Mac/CMakeLists.txt
+++ b/client/Mac/CMakeLists.txt
@@ -6,12 +6,10 @@ set(MODULE_PREFIX "FREERDP_CLIENT_MAC")
set(FRAMEWORK_HEADERS_PATH /System/Library/Frameworks/Cocoa.framework/Versions/A/Headers/)
include_directories(${FRAMEWORK_HEADERS_PATH} /System/Library/Frameworks)
-
-# set(CMAKE_OSX_SYSROOT MacOSX10.7.sdk)
+
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -mmacosx-version-min=10.4")
set(GUI_TYPE MACOSX_BUNDLE)
-# Import libraries
find_library(FOUNDATION_LIBRARY Foundation)
find_library(COCOA_LIBRARY Cocoa)
find_library(APPKIT_LIBRARY AppKit)
@@ -33,16 +31,32 @@ mark_as_advanced(COCOA_LIBRARY FOUNDATION_LIBRARY APPKIT_LIBRARY)
set(EXTRA_LIBS ${COCOA_LIBRARY} ${FOUNDATION_LIBRARY} ${APPKIT_LIBRARY})
set(APP_TYPE MACOSX_BUNDLE)
-# OS X Interface Builder files
-file(GLOB ${MODULE_NAME}_XIBS *.xib)
+set(${MODULE_NAME}_XIBS
+ MainMenu.xib
+ PasswordDialog.xib)
-set(${MODULE_NAME}_RESOURCES ${${MODULE_NAME}_XIBS} ${MACOSX_BUNDLE_ICON_FILE})
+set(${MODULE_NAME}_RESOURCES
+ ${${MODULE_NAME}_XIBS}
+ ${MACOSX_BUNDLE_ICON_FILE})
-# Headers
-file(GLOB ${MODULE_NAME}_HEADERS *.h)
+set(${MODULE_NAME}_HEADERS
+ AppDelegate.h
+ MRDPCursor.h
+ MRDPRailView.h
+ MRDPRailWindow.h
+ MRDPView.h
+ MRDPWindow.h
+ PasswordDialog.h)
-# Source
-file(GLOB ${MODULE_NAME}_SOURCES *.m)
+set(${MODULE_NAME}_SOURCES
+ main.m
+ AppDelegate.m
+ MRDPCursor.m
+ MRDPRailView.m
+ MRDPRailWindow.m
+ MRDPView.m
+ MRDPWindow.m
+ PasswordDialog.m)
add_executable(${MODULE_NAME}
${APP_TYPE}
@@ -63,13 +77,6 @@ set_target_properties(${MODULE_NAME} PROPERTIES RESOURCE "${${MODULE_NAME}_RESOU
# Support for automatic reference counting requires non-fragile abi.
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fobjc-nonfragile-abi")
-# XCode project architecture to native architecture of build machine
-# -----------------------------------------------------------------------------------------------------
-# Issue: Had some issues with FreeRDP project building only 64 bit and
-# MacFreeRDP attempting to link to both 32 and 64 for dual target.
-# In the future the FreeRDP Xcode project should be pulled in for a couple of reasons:
-# 1) better step-into debugging 2) automatic dependency compilation and multi-arch compilation + linkage
-# If you know the solutions for 1 and 2, please add below.
set_target_properties(${MODULE_NAME} PROPERTIES XCODE_ATTRIBUTE_ARCHS "$(NATIVE_ARCH_ACTUAL)")
# Set the info plist to the custom instance
diff --git a/client/Windows/CMakeLists.txt b/client/Windows/CMakeLists.txt
index 678a9b5a1..0f2b26d65 100644
--- a/client/Windows/CMakeLists.txt
+++ b/client/Windows/CMakeLists.txt
@@ -37,7 +37,11 @@ set(${MODULE_PREFIX}_SRCS
resource.h)
if(WITH_CLIENT_INTERFACE)
- add_library(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
+ if(CLIENT_INTERFACE_SHARED)
+ add_library(${MODULE_NAME} SHARED ${${MODULE_PREFIX}_SRCS})
+ else()
+ add_library(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
+ endif()
set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION} PREFIX "lib")
else()
set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} cli/wfreerdp.c cli/wfreerdp.h)
diff --git a/client/Windows/wf_event.c b/client/Windows/wf_event.c
index a81c9f1ae..c96897fb5 100644
--- a/client/Windows/wf_event.c
+++ b/client/Windows/wf_event.c
@@ -37,6 +37,9 @@ static HWND g_focus_hWnd;
#define X_POS(lParam) (lParam & 0xFFFF)
#define Y_POS(lParam) ((lParam >> 16) & 0xFFFF)
+BOOL wf_scale_blt(wfInfo* wfi, HDC hdc, int x, int y, int w, int h, HDC hdcSrc, int x1, int y1, DWORD rop);
+void wf_scale_mouse_event(wfInfo* wfi, rdpInput* input, UINT16 flags, UINT16 x, UINT16 y);
+
LRESULT CALLBACK wf_ll_kbd_proc(int nCode, WPARAM wParam, LPARAM lParam)
{
wfInfo* wfi;
@@ -167,6 +170,10 @@ LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam
switch (Msg)
{
+ case WM_ERASEBKGND:
+ /* Say we handled it - prevents flickering */
+ return (LRESULT) 1;
+
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
@@ -175,31 +182,29 @@ LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam
w = ps.rcPaint.right - ps.rcPaint.left + 1;
h = ps.rcPaint.bottom - ps.rcPaint.top + 1;
- //fprintf(stderr, "WM_PAINT: x:%d y:%d w:%d h:%d\n", x, y, w, h);
-
- BitBlt(hdc, x, y, w, h, wfi->primary->hdc, x - wfi->offset_x, y - wfi->offset_y, SRCCOPY);
+ wf_scale_blt(wfi, hdc, x, y, w, h, wfi->primary->hdc, x - wfi->offset_x, y - wfi->offset_y, SRCCOPY);
EndPaint(hWnd, &ps);
break;
case WM_LBUTTONDOWN:
- input->MouseEvent(input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON1, X_POS(lParam) - wfi->offset_x, Y_POS(lParam) - wfi->offset_y);
+ wf_scale_mouse_event(wfi, input,PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON1, X_POS(lParam) - wfi->offset_x, Y_POS(lParam) - wfi->offset_y);
break;
case WM_LBUTTONUP:
- input->MouseEvent(input, PTR_FLAGS_BUTTON1, X_POS(lParam) - wfi->offset_x, Y_POS(lParam) - wfi->offset_y);
+ wf_scale_mouse_event(wfi, input, PTR_FLAGS_BUTTON1, X_POS(lParam) - wfi->offset_x, Y_POS(lParam) - wfi->offset_y);
break;
case WM_RBUTTONDOWN:
- input->MouseEvent(input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON2, X_POS(lParam) - wfi->offset_x, Y_POS(lParam) - wfi->offset_y);
+ wf_scale_mouse_event(wfi, input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON2, X_POS(lParam) - wfi->offset_x, Y_POS(lParam) - wfi->offset_y);
break;
case WM_RBUTTONUP:
- input->MouseEvent(input, PTR_FLAGS_BUTTON2, X_POS(lParam) - wfi->offset_x, Y_POS(lParam) - wfi->offset_y);
+ wf_scale_mouse_event(wfi, input, PTR_FLAGS_BUTTON2, X_POS(lParam) - wfi->offset_x, Y_POS(lParam) - wfi->offset_y);
break;
case WM_MOUSEMOVE:
- input->MouseEvent(input, PTR_FLAGS_MOVE, X_POS(lParam) - wfi->offset_x, Y_POS(lParam) - wfi->offset_y);
+ wf_scale_mouse_event(wfi, input, PTR_FLAGS_MOVE, X_POS(lParam) - wfi->offset_x, Y_POS(lParam) - wfi->offset_y);
break;
case WM_MOUSEWHEEL:
@@ -257,3 +262,60 @@ LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam
return 0;
}
+
+BOOL wf_scale_blt(wfInfo* wfi, HDC hdc, int x, int y, int w, int h, HDC hdcSrc, int x1, int y1, DWORD rop)
+{
+ int ww, wh, dw, dh;
+
+ if (!wfi->client_width)
+ wfi->client_width = wfi->width;
+
+ if (!wfi->client_height)
+ wfi->client_height = wfi->height;
+
+ ww = wfi->client_width;
+ wh = wfi->client_height;
+ dw = wfi->instance->settings->DesktopWidth;
+ dh = wfi->instance->settings->DesktopHeight;
+
+ if (!ww)
+ ww = dw;
+
+ if (!wh)
+ wh = dh;
+
+ if (!wfi->instance->settings->SmartSizing || (ww == dw && wh == dh))
+ {
+ return BitBlt(hdc, x, y, w, h, wfi->primary->hdc, x1, y1, SRCCOPY);
+ }
+ else
+ {
+ SetStretchBltMode(hdc, HALFTONE);
+ SetBrushOrgEx(hdc, 0, 0, NULL);
+
+ return StretchBlt(hdc, x * ww / dw, y * wh / dh, ww, wh, wfi->primary->hdc, x1, y1, dw, dh, SRCCOPY);
+ }
+
+ return TRUE;
+}
+
+void wf_scale_mouse_event(wfInfo* wfi, rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
+{
+ int ww, wh, dw, dh;
+
+ if (!wfi->client_width)
+ wfi->client_width = wfi->width;
+
+ if (!wfi->client_height)
+ wfi->client_height = wfi->height;
+
+ ww = wfi->client_width;
+ wh = wfi->client_height;
+ dw = wfi->instance->settings->DesktopWidth;
+ dh = wfi->instance->settings->DesktopHeight;
+
+ if ((ww == dw) && (wh == dh))
+ input->MouseEvent(input, flags, x, y);
+ else
+ input->MouseEvent(input, flags, x * dw / ww, y * dh / wh);
+}
diff --git a/client/Windows/wf_gdi.c b/client/Windows/wf_gdi.c
index 39c590f1c..3a15fe26a 100644
--- a/client/Windows/wf_gdi.c
+++ b/client/Windows/wf_gdi.c
@@ -166,14 +166,54 @@ HBRUSH wf_create_brush(wfInfo * wfi, rdpBrush* brush, UINT32 color, int bpp)
return br;
}
+void wf_scale_rect(wfInfo* wfi, RECT* source)
+{
+ int ww, wh, dw, dh;
+
+ if (!wfi->client_width)
+ wfi->client_width = wfi->width;
+
+ if (!wfi->client_height)
+ wfi->client_height = wfi->height;
+
+ ww = wfi->client_width;
+ wh = wfi->client_height;
+ dw = wfi->instance->settings->DesktopWidth;
+ dh = wfi->instance->settings->DesktopHeight;
+
+ if (!ww)
+ ww = dw;
+
+ if (!wh)
+ wh = dh;
+
+ if (wfi->instance->settings->SmartSizing && (ww != dw || wh != dh))
+ {
+ source->bottom = MIN(dh, MAX(0, source->bottom * wh / dh + 2));
+ source->top = MIN(dh, MAX(0, source->top * wh / dh - 2));
+ source->left = MIN(dw, MAX(0, source->left * ww / dw - 2));
+ source->right = MIN(dw, MAX(0, source->right * ww / dw + 2));
+ }
+}
+
void wf_invalidate_region(wfInfo* wfi, int x, int y, int width, int height)
{
+ RECT rect;
+
wfi->update_rect.left = x + wfi->offset_x;
wfi->update_rect.top = y + wfi->offset_y;
wfi->update_rect.right = wfi->update_rect.left + width;
wfi->update_rect.bottom = wfi->update_rect.top + height;
+
+ wf_scale_rect(wfi, &(wfi->update_rect));
InvalidateRect(wfi->hwnd, &(wfi->update_rect), FALSE);
- gdi_InvalidateRegion(wfi->hdc, x, y, width, height);
+
+ rect.left = x;
+ rect.right = width;
+ rect.top = y;
+ rect.bottom = height;
+ wf_scale_rect(wfi, &rect);
+ gdi_InvalidateRegion(wfi->hdc, rect.left, rect.top, rect.right, rect.bottom);
}
void wf_update_offset(wfInfo* wfi)
diff --git a/client/Windows/wf_interface.c b/client/Windows/wf_interface.c
index 055f93591..09c465e88 100644
--- a/client/Windows/wf_interface.c
+++ b/client/Windows/wf_interface.c
@@ -534,6 +534,8 @@ DWORD WINAPI wf_thread(LPVOID lpParam)
int index;
int rcount;
int wcount;
+ int width;
+ int height;
BOOL msg_ret;
int quit_msg;
void* rfds[32];
@@ -626,7 +628,30 @@ DWORD WINAPI wf_thread(LPVOID lpParam)
{
msg_ret = GetMessage(&msg, NULL, 0, 0);
- if (msg_ret == 0 || msg_ret == -1)
+ if (instance->settings->EmbeddedWindow)
+ {
+ if ((msg.message == WM_SETFOCUS) && (msg.lParam == 1))
+ {
+ PostMessage(((wfContext*) instance->context)->wfi->hwnd, WM_SETFOCUS, 0, 0);
+ }
+ else if ((msg.message == WM_KILLFOCUS) && (msg.lParam == 1))
+ {
+ PostMessage(((wfContext*) instance->context)->wfi->hwnd, WM_KILLFOCUS, 0, 0);
+ }
+ }
+
+ if (msg.message == WM_SIZE)
+ {
+ width = LOWORD(msg.lParam);
+ height = HIWORD(msg.lParam);
+
+ ((wfContext*) instance->context)->wfi->client_width = width;
+ ((wfContext*) instance->context)->wfi->client_height = height;
+
+ SetWindowPos(((wfContext*) instance->context)->wfi->hwnd, HWND_TOP, 0, 0, width, height, SWP_FRAMECHANGED);
+ }
+
+ if ((msg_ret == 0) || (msg_ret == -1))
{
quit_msg = TRUE;
break;
@@ -721,11 +746,9 @@ int freerdp_client_global_uninit()
wfInfo* freerdp_client_new(int argc, char** argv)
{
int index;
+ int status;
wfInfo* wfi;
freerdp* instance;
- HINSTANCE hInstance;
-
- hInstance = GetModuleHandle(NULL);
instance = freerdp_new();
instance->PreConnect = wf_pre_connect;
@@ -745,16 +768,27 @@ wfInfo* freerdp_client_new(int argc, char** argv)
wfi->client = instance->context->client;
instance->context->argc = argc;
- instance->context->argv = argv;
-
instance->context->argv = (char**) malloc(sizeof(char*) * argc);
for (index = 0; index < argc; index++)
- {
instance->context->argv[index] = _strdup(argv[index]);
- }
- wfi->hWndParent = NULL;
+ status = freerdp_client_parse_command_line_arguments(instance->context->argc, instance->context->argv, instance->settings);
+
+ return wfi;
+}
+
+int freerdp_client_start(wfInfo* wfi)
+{
+ HWND hWndParent;
+ HINSTANCE hInstance;
+ freerdp* instance = wfi->instance;
+
+ hInstance = GetModuleHandle(NULL);
+ hWndParent = (HWND) instance->settings->ParentWindowId;
+ instance->settings->EmbeddedWindow = (hWndParent) ? TRUE : FALSE;
+
+ wfi->hWndParent = hWndParent;
wfi->hInstance = hInstance;
wfi->cursor = LoadCursor(NULL, IDC_ARROW);
wfi->icon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON1));
@@ -774,24 +808,14 @@ wfInfo* freerdp_client_new(int argc, char** argv)
wfi->wndClass.hIconSm = wfi->icon;
RegisterClassEx(&(wfi->wndClass));
- return wfi;
-}
-
-int freerdp_client_start(wfInfo* wfi)
-{
- int status;
- freerdp* instance = wfi->instance;
-
wfi->keyboardThread = CreateThread(NULL, 0, wf_keyboard_thread, (void*) wfi, 0, NULL);
if (!wfi->keyboardThread)
return -1;
- status = freerdp_client_parse_command_line_arguments(instance->context->argc, instance->context->argv, instance->settings);
-
freerdp_client_load_addins(instance->context->channels, instance->settings);
- wfi->thread = CreateThread(NULL, 0, wf_thread, (void*) instance, 0, NULL);
+ wfi->thread = CreateThread(NULL, 0, wf_thread, (void*) instance, 0, &wfi->mainThreadId);
if (!wfi->thread)
return -1;
@@ -801,6 +825,29 @@ int freerdp_client_start(wfInfo* wfi)
int freerdp_client_stop(wfInfo* wfi)
{
+ PostThreadMessage(wfi->mainThreadId, WM_QUIT, 0, 0);
+ return 0;
+}
+
+int freerdp_client_focus_in(wfInfo* wfi)
+{
+ PostThreadMessage(wfi->mainThreadId, WM_SETFOCUS, 0, 1);
+ return 0;
+}
+
+int freerdp_client_focus_out(wfInfo* wfi)
+{
+ PostThreadMessage(wfi->mainThreadId, WM_KILLFOCUS, 0, 1);
+ return 0;
+}
+
+int wf_set_window_size(wfInfo* wfi, int width, int height)
+{
+ if ((width != wfi->client_width) || (height != wfi->client_height))
+ {
+ PostThreadMessage(wfi->mainThreadId, WM_SIZE, SIZE_RESTORED, ((UINT) height << 16) | (UINT) width);
+ }
+
return 0;
}
diff --git a/client/Windows/wf_interface.h b/client/Windows/wf_interface.h
index c9f8a3ef3..16891db82 100644
--- a/client/Windows/wf_interface.h
+++ b/client/Windows/wf_interface.h
@@ -81,6 +81,8 @@ struct wf_info
int fullscreen;
int percentscreen;
char window_title[64];
+ int client_width;
+ int client_height;
HANDLE thread;
HANDLE keyboardThread;
@@ -105,8 +107,10 @@ struct wf_info
HBRUSH brush;
HBRUSH org_brush;
RECT update_rect;
+ RECT scale_update_rect;
wfBitmap* tile;
+ DWORD mainThreadId;
RFX_CONTEXT* rfx_context;
NSC_CONTEXT* nsc_context;
@@ -125,6 +129,11 @@ FREERDP_API int freerdp_client_global_uninit();
FREERDP_API int freerdp_client_start(wfInfo* cfi);
FREERDP_API int freerdp_client_stop(wfInfo* cfi);
+FREERDP_API int freerdp_client_focus_in(wfInfo* cfi);
+FREERDP_API int freerdp_client_focus_out(wfInfo* cfi);
+
+FREERDP_API int freerdp_client_set_window_size(wfInfo* cfi, int width, int height);
+
FREERDP_API cfInfo* freerdp_client_new(int argc, char** argv);
FREERDP_API int freerdp_client_free(wfInfo* cfi);
diff --git a/client/X11/CMakeLists.txt b/client/X11/CMakeLists.txt
index 0461a3550..7d08ea670 100644
--- a/client/X11/CMakeLists.txt
+++ b/client/X11/CMakeLists.txt
@@ -44,7 +44,11 @@ set(${MODULE_PREFIX}_SRCS
xf_interface.h)
if(WITH_CLIENT_INTERFACE)
- add_library(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
+ if(CLIENT_INTERFACE_SHARED)
+ add_library(${MODULE_NAME} SHARED ${${MODULE_PREFIX}_SRCS})
+ else()
+ add_library(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
+ endif()
set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION} PREFIX "lib")
else()
set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} cli/xfreerdp.c cli/xfreerdp.h)
diff --git a/client/X11/cli/xfreerdp.c b/client/X11/cli/xfreerdp.c
index b242c11ee..a2911207e 100644
--- a/client/X11/cli/xfreerdp.c
+++ b/client/X11/cli/xfreerdp.c
@@ -49,8 +49,7 @@ int main(int argc, char* argv[])
GetExitCodeThread(xfi->thread, &dwExitCode);
- freerdp_context_free(instance);
- freerdp_free(instance);
+ freerdp_client_free(xfi);
freerdp_client_global_uninit();
diff --git a/client/X11/xf_interface.c b/client/X11/xf_interface.c
index c2d6d0a60..3d27a5b49 100644
--- a/client/X11/xf_interface.c
+++ b/client/X11/xf_interface.c
@@ -1382,9 +1382,6 @@ void* xf_thread(void* param)
freerdp_channels_free(channels);
freerdp_disconnect(instance);
gdi_free(instance);
- freerdp_client_free(xfi);
-
- exit_code = 123;
ExitThread(exit_code);
}
@@ -1475,8 +1472,6 @@ xfInfo* freerdp_client_new(int argc, char** argv)
freerdp_context_new(instance);
instance->context->argc = argc;
- instance->context->argv = argv;
-
instance->context->argv = (char**) malloc(sizeof(char*) * argc);
for (index = 0; index < argc; index++)
@@ -1544,12 +1539,25 @@ void freerdp_client_free(xfInfo* xfi)
{
if (xfi)
{
+ int index;
+ rdpContext* context;
+
xf_window_free(xfi);
free(xfi->bmp_codec_none);
XCloseDisplay(xfi->display);
+ context = (rdpContext*) xfi->context;
+
+ for (index = 0; index < context->argc; index++)
+ free(context->argv[index]);
+
+ free(context->argv);
+
+ freerdp_context_free(xfi->instance);
+ freerdp_free(xfi->instance);
+
free(xfi);
}
}
diff --git a/client/common/cmdline.c b/client/common/cmdline.c
index e2927eb2a..dc5e6a681 100644
--- a/client/common/cmdline.c
+++ b/client/common/cmdline.c
@@ -52,6 +52,7 @@ COMMAND_LINE_ARGUMENT_A args[] =
{ "workarea", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Work area" },
{ "t", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, "title", "Window title" },
{ "decorations", COMMAND_LINE_VALUE_BOOL, NULL, NULL, BoolValueTrue, -1, NULL, "Window decorations" },
+ { "smart-sizing", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Scale remote desktop to window size" },
{ "a", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, "addin", "Addin" },
{ "vc", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "Static virtual channel" },
{ "dvc", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "Dynamic virtual channel" },
@@ -62,6 +63,7 @@ COMMAND_LINE_ARGUMENT_A args[] =
{ "gu", COMMAND_LINE_VALUE_REQUIRED, "[\\] or [@]", NULL, NULL, -1, NULL, "Gateway username" },
{ "gp", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Gateway password" },
{ "gd", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Gateway domain" },
+ { "load-balance-info", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Load balance info" },
{ "app", COMMAND_LINE_VALUE_REQUIRED, "|| or ", NULL, NULL, -1, NULL, "Remote application program" },
{ "app-name", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Remote application name for user interface" },
{ "app-icon", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Remote application icon for user interface" },
@@ -1090,6 +1092,10 @@ int freerdp_client_parse_command_line_arguments(int argc, char** argv, rdpSettin
{
settings->Decorations = arg->Value ? TRUE : FALSE;
}
+ CommandLineSwitchCase(arg, "smart-sizing")
+ {
+ settings->SmartSizing = arg->Value ? TRUE : FALSE;
+ }
CommandLineSwitchCase(arg, "bpp")
{
settings->ColorDepth = atoi(arg->Value);
@@ -1209,6 +1215,11 @@ int freerdp_client_parse_command_line_arguments(int argc, char** argv, rdpSettin
settings->DisableWallpaper = TRUE;
settings->DisableFullWindowDrag = TRUE;
}
+ CommandLineSwitchCase(arg, "load-balance-info")
+ {
+ settings->LoadBalanceInfo = (BYTE*) _strdup(arg->Value);
+ settings->LoadBalanceInfoLength = strlen((char*) settings->LoadBalanceInfo);
+ }
CommandLineSwitchCase(arg, "app-name")
{
settings->RemoteApplicationName = _strdup(arg->Value);
diff --git a/client/common/file.c b/client/common/file.c
index 755aa9391..a13ca239b 100644
--- a/client/common/file.c
+++ b/client/common/file.c
@@ -308,7 +308,7 @@ BOOL freerdp_client_parse_rdp_file_buffer_ascii(rdpFile* file, BYTE* buffer, siz
line = strtok_s((char*) buffer, "\r\n", &context);
- while (line != NULL)
+ while (line)
{
length = strlen(line);
@@ -458,8 +458,7 @@ BOOL freerdp_client_parse_rdp_file(rdpFile* file, char* name)
if (file_size < 1)
return FALSE;
- buffer = (BYTE*) malloc(file_size);
-
+ buffer = (BYTE*) malloc(file_size + 2);
read_size = fread(buffer, file_size, 1, fp);
if (!read_size)
@@ -475,6 +474,9 @@ BOOL freerdp_client_parse_rdp_file(rdpFile* file, char* name)
return FALSE;
}
+ buffer[file_size] = '\0';
+ buffer[file_size + 1] = '\0';
+
return freerdp_client_parse_rdp_file_buffer(file, buffer, file_size);
}
@@ -497,7 +499,7 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings*
if (~file->ServerPort)
settings->ServerPort = file->ServerPort;
if (~((size_t) file->FullAddress))
- settings->ServerHostname = file->FullAddress;
+ settings->ServerHostname = _strdup(file->FullAddress);
if (~file->DesktopWidth)
settings->DesktopWidth = file->DesktopWidth;
if (~file->DesktopHeight)
@@ -513,10 +515,16 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings*
if (~file->EnableCredSSPSupport)
settings->NlaSecurity = file->EnableCredSSPSupport;
if (~((size_t) file->AlternateShell))
- settings->AlternateShell = file->AlternateShell;
+ settings->AlternateShell = _strdup(file->AlternateShell);
if (~((size_t) file->ShellWorkingDirectory))
- settings->ShellWorkingDirectory = file->ShellWorkingDirectory;
+ settings->ShellWorkingDirectory = _strdup(file->ShellWorkingDirectory);
+ if (~((size_t) file->LoadBalanceInfo))
+ {
+ settings->LoadBalanceInfo = (BYTE*) _strdup(file->LoadBalanceInfo);
+ settings->LoadBalanceInfoLength = strlen((char*) settings->LoadBalanceInfo);
+ }
+
if (~file->ConnectionType)
{
freerdp_set_connection_type(settings, file->ConnectionType);
@@ -540,7 +548,7 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings*
}
if (~((size_t) file->GatewayHostname))
- settings->GatewayHostname = file->GatewayHostname;
+ settings->GatewayHostname = _strdup(file->GatewayHostname);
if (~file->GatewayUsageMethod)
settings->GatewayUsageMethod = TRUE;
if (~file->PromptCredentialOnce)
@@ -549,17 +557,17 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings*
if (~file->RemoteApplicationMode)
settings->RemoteApplicationMode = file->RemoteApplicationMode;
if (~((size_t) file->RemoteApplicationProgram))
- settings->RemoteApplicationProgram = file->RemoteApplicationProgram;
+ settings->RemoteApplicationProgram = _strdup(file->RemoteApplicationProgram);
if (~((size_t) file->RemoteApplicationName))
- settings->RemoteApplicationName = file->RemoteApplicationName;
+ settings->RemoteApplicationName = _strdup(file->RemoteApplicationName);
if (~((size_t) file->RemoteApplicationIcon))
- settings->RemoteApplicationIcon = file->RemoteApplicationIcon;
+ settings->RemoteApplicationIcon = _strdup(file->RemoteApplicationIcon);
if (~((size_t) file->RemoteApplicationFile))
- settings->RemoteApplicationFile = file->RemoteApplicationFile;
+ settings->RemoteApplicationFile = _strdup(file->RemoteApplicationFile);
if (~((size_t) file->RemoteApplicationGuid))
- settings->RemoteApplicationGuid = file->RemoteApplicationGuid;
+ settings->RemoteApplicationGuid = _strdup(file->RemoteApplicationGuid);
if (~((size_t) file->RemoteApplicationCmdLine))
- settings->RemoteApplicationCmdLine = file->RemoteApplicationCmdLine;
+ settings->RemoteApplicationCmdLine = _strdup(file->RemoteApplicationCmdLine);
if (~file->SpanMonitors)
settings->SpanMonitors = file->SpanMonitors;
diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h
index 9a3375c47..0a078c280 100644
--- a/include/freerdp/settings.h
+++ b/include/freerdp/settings.h
@@ -602,7 +602,11 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL;
#define FreeRDP_AsyncInput 1544
#define FreeRDP_AsyncUpdate 1545
#define FreeRDP_AsyncChannels 1546
-#define FreeRDP_ToggleFullscreen 1547
+#define FreeRDP_AsyncTransport 1547
+#define FreeRDP_ToggleFullscreen 1548
+#define FreeRDP_WmClass 1549
+#define FreeRDP_EmbeddedWindow 1550
+#define FreeRDP_SmartSizing 1551
#define FreeRDP_SoftwareGdi 1601
#define FreeRDP_LocalConnection 1602
#define FreeRDP_AuthenticationOnly 1603
@@ -961,7 +965,9 @@ struct rdp_settings
ALIGN64 BOOL AsyncTransport; /* 1547 */
ALIGN64 BOOL ToggleFullscreen; /* 1548 */
ALIGN64 char* WmClass; /* 1549 */
- UINT64 padding1600[1600 - 1550]; /* 1550 */
+ ALIGN64 BOOL EmbeddedWindow; /* 1550 */
+ ALIGN64 BOOL SmartSizing; /* 1551 */
+ UINT64 padding1600[1600 - 1552]; /* 1552 */
/* Miscellaneous */
ALIGN64 BOOL SoftwareGdi; /* 1601 */
diff --git a/libfreerdp/codec/rfx_decode.c b/libfreerdp/codec/rfx_decode.c
index 15aa4cf00..1acffda27 100644
--- a/libfreerdp/codec/rfx_decode.c
+++ b/libfreerdp/codec/rfx_decode.c
@@ -202,11 +202,12 @@ BOOL rfx_decode_rgb(RFX_CONTEXT* context, wStream* data_in,
else
#endif
{
- if (stream_get_left(data_in) < y_size+cb_size+cr_size)
+ if (stream_get_left(data_in) < y_size + cb_size + cr_size)
{
DEBUG_WARN("rfx_decode_rgb: packet too small for y_size+cb_size+cr_size");
return FALSE;
}
+
rfx_decode_component(context, y_quants, stream_get_tail(data_in), y_size, pSrcDst[0]); /* YData */
stream_seek(data_in, y_size);
@@ -230,5 +231,6 @@ BOOL rfx_decode_rgb(RFX_CONTEXT* context, wStream* data_in,
BufferPool_Return(context->priv->BufferPool, (BYTE*)pSrcDst[0] - 16);
BufferPool_Return(context->priv->BufferPool, (BYTE*)pSrcDst[1] - 16);
BufferPool_Return(context->priv->BufferPool, (BYTE*)pSrcDst[2] - 16);
+
return TRUE;
}
diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c
index dabba597f..4b60d868b 100644
--- a/libfreerdp/core/connection.c
+++ b/libfreerdp/core/connection.c
@@ -135,6 +135,9 @@ BOOL rdp_client_connect(rdpRdp* rdp)
nego_set_cookie_max_length(rdp->nego, settings->CookieMaxLength);
+ if (settings->LoadBalanceInfo)
+ nego_set_routing_token(rdp->nego, settings->LoadBalanceInfo, settings->LoadBalanceInfoLength);
+
if (!nego_connect(rdp->nego))
{
fprintf(stderr, "Error: protocol security negotiation or connection failure\n");
diff --git a/libfreerdp/core/fastpath.c b/libfreerdp/core/fastpath.c
index 56d06a983..8a680d7e7 100644
--- a/libfreerdp/core/fastpath.c
+++ b/libfreerdp/core/fastpath.c
@@ -169,20 +169,21 @@ static BOOL fastpath_recv_update_common(rdpFastPath* fastpath, wStream* s)
rdpUpdate* update = fastpath->rdp->update;
rdpContext* context = update->context;
- if(stream_get_left(s) < 2)
+ if (stream_get_left(s) < 2)
return FALSE;
+
stream_read_UINT16(s, updateType); /* updateType (2 bytes) */
switch (updateType)
{
case UPDATE_TYPE_BITMAP:
- if(!update_read_bitmap(update, s, &update->bitmap_update))
+ if (!update_read_bitmap(update, s, &update->bitmap_update))
return FALSE;
IFCALL(update->BitmapUpdate, context, &update->bitmap_update);
break;
case UPDATE_TYPE_PALETTE:
- if(!update_read_palette(update, s, &update->palette_update))
+ if (!update_read_palette(update, s, &update->palette_update))
return FALSE;
IFCALL(update->Palette, context, &update->palette_update);
break;
@@ -328,6 +329,7 @@ static int fastpath_recv_update_data(rdpFastPath* fastpath, wStream* s)
}
update_stream = NULL;
+
if (fragmentation == FASTPATH_FRAGMENT_SINGLE)
{
totalSize = size;
@@ -340,6 +342,7 @@ static int fastpath_recv_update_data(rdpFastPath* fastpath, wStream* s)
stream_check_size(fastpath->updateData, size);
stream_copy(fastpath->updateData, comp_stream, size);
+
if (stream_get_length(fastpath->updateData) > rdp->settings->MultifragMaxRequestSize)
{
fprintf(stderr, "fastpath PDU is bigger than MultifragMaxRequestSize\n");
diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c
index b1d05fb82..6770a1ab3 100644
--- a/libfreerdp/core/freerdp.c
+++ b/libfreerdp/core/freerdp.c
@@ -340,7 +340,7 @@ void freerdp_context_new(freerdp* instance)
*/
void freerdp_context_free(freerdp* instance)
{
- if (instance->context == NULL)
+ if (!instance->context)
return;
IFCALL(instance->ContextFree, instance, instance->context);
@@ -348,6 +348,8 @@ void freerdp_context_free(freerdp* instance)
rdp_free(instance->context->rdp);
graphics_free(instance->context->graphics);
+ free(instance->context->client);
+
free(instance->context);
instance->context = NULL;
}
diff --git a/libfreerdp/core/message.c b/libfreerdp/core/message.c
index 3e2900b03..3ccea28d3 100644
--- a/libfreerdp/core/message.c
+++ b/libfreerdp/core/message.c
@@ -21,11 +21,18 @@
#include "config.h"
#endif
+#include "rdp.h"
#include "message.h"
+#include "transport.h"
+
+#include
#include
+#include
#include
+//#define WITH_STREAM_POOL 1
+
/* Update */
static void update_message_BeginPaint(rdpContext* context)
@@ -79,13 +86,15 @@ static void update_message_BitmapUpdate(rdpContext* context, BITMAP_UPDATE* bitm
wParam->rectangles = (BITMAP_DATA*) malloc(sizeof(BITMAP_DATA) * wParam->number);
CopyMemory(wParam->rectangles, bitmap->rectangles, sizeof(BITMAP_DATA) * wParam->number);
- /* TODO: increment reference count to original stream instead of copying */
-
for (index = 0; index < wParam->number; index++)
{
+#ifdef WITH_STREAM_POOL
+ StreamPool_AddRef(context->rdp->transport->ReceivePool, bitmap->rectangles[index].bitmapDataStream);
+#else
wParam->rectangles[index].bitmapDataStream = (BYTE*) malloc(wParam->rectangles[index].bitmapLength);
CopyMemory(wParam->rectangles[index].bitmapDataStream, bitmap->rectangles[index].bitmapDataStream,
wParam->rectangles[index].bitmapLength);
+#endif
}
MessageQueue_Post(context->update->queue, (void*) context,
@@ -160,8 +169,12 @@ static void update_message_SurfaceBits(rdpContext* context, SURFACE_BITS_COMMAND
wParam = (SURFACE_BITS_COMMAND*) malloc(sizeof(SURFACE_BITS_COMMAND));
CopyMemory(wParam, surfaceBitsCommand, sizeof(SURFACE_BITS_COMMAND));
+#ifdef WITH_STREAM_POOL
+ StreamPool_AddRef(context->rdp->transport->ReceivePool, surfaceBitsCommand->bitmapData);
+#else
wParam->bitmapData = (BYTE*) malloc(wParam->bitmapDataLength);
CopyMemory(wParam->bitmapData, surfaceBitsCommand->bitmapData, wParam->bitmapDataLength);
+#endif
MessageQueue_Post(context->update->queue, (void*) context,
MakeMessageId(Update, SurfaceBits), (void*) wParam, NULL);
@@ -952,7 +965,14 @@ int update_message_process_update_class(rdpUpdateProxy* proxy, wMessage* msg, in
BITMAP_UPDATE* wParam = (BITMAP_UPDATE*) msg->wParam;
for (index = 0; index < wParam->number; index++)
+ {
+#ifdef WITH_STREAM_POOL
+ rdpContext* context = (rdpContext*) msg->context;
+ StreamPool_Release(context->rdp->transport->ReceivePool, wParam->rectangles[index].bitmapDataStream);
+#else
free(wParam->rectangles[index].bitmapDataStream);
+#endif
+ }
free(wParam);
}
@@ -993,9 +1013,15 @@ int update_message_process_update_class(rdpUpdateProxy* proxy, wMessage* msg, in
case Update_SurfaceBits:
IFCALL(proxy->SurfaceBits, msg->context, (SURFACE_BITS_COMMAND*) msg->wParam);
{
+#ifdef WITH_STREAM_POOL
+ rdpContext* context = (rdpContext*) msg->context;
+ SURFACE_BITS_COMMAND* wParam = (SURFACE_BITS_COMMAND*) msg->wParam;
+ StreamPool_Release(context->rdp->transport->ReceivePool, wParam->bitmapData);
+#else
SURFACE_BITS_COMMAND* wParam = (SURFACE_BITS_COMMAND*) msg->wParam;
free(wParam->bitmapData);
free(wParam);
+#endif
}
break;
diff --git a/libfreerdp/core/nego.c b/libfreerdp/core/nego.c
index 6ee58d9b7..0227620ae 100644
--- a/libfreerdp/core/nego.c
+++ b/libfreerdp/core/nego.c
@@ -490,7 +490,7 @@ int nego_recv(rdpTransport* transport, wStream* s, void* extra)
if (length == 0)
return -1;
- if(!tpdu_read_connection_confirm(s, &li))
+ if (!tpdu_read_connection_confirm(s, &li))
return -1;
if (li > 6)
@@ -563,7 +563,8 @@ BOOL nego_read_request(rdpNego* nego, wStream* s)
BYTE type;
tpkt_read_header(s);
- if(!tpdu_read_connection_request(s, &li))
+
+ if (!tpdu_read_connection_request(s, &li))
return FALSE;
if (li != stream_get_left(s) + 6)
@@ -648,12 +649,14 @@ BOOL nego_send_negotiation_request(rdpNego* nego)
stream_get_mark(s, bm);
stream_seek(s, length);
- if (nego->RoutingToken != NULL)
+ if (nego->RoutingToken)
{
stream_write(s, nego->RoutingToken, nego->RoutingTokenLength);
- length += nego->RoutingTokenLength;
+ stream_write_BYTE(s, 0x0D); /* CR */
+ stream_write_BYTE(s, 0x0A); /* LF */
+ length += nego->RoutingTokenLength + 2;
}
- else if (nego->cookie != NULL)
+ else if (nego->cookie)
{
cookie_length = strlen(nego->cookie);
@@ -669,7 +672,7 @@ BOOL nego_send_negotiation_request(rdpNego* nego)
DEBUG_NEGO("requested_protocols: %d", nego->requested_protocols);
- if (nego->requested_protocols > PROTOCOL_RDP)
+ if ((nego->requested_protocols > PROTOCOL_RDP) || (nego->sendNegoData))
{
/* RDP_NEG_DATA must be present for TLS and NLA */
stream_write_BYTE(s, TYPE_RDP_NEG_REQ);
@@ -762,18 +765,24 @@ void nego_process_negotiation_failure(rdpNego* nego, wStream* s)
case SSL_REQUIRED_BY_SERVER:
DEBUG_NEGO("Error: SSL_REQUIRED_BY_SERVER");
break;
+
case SSL_NOT_ALLOWED_BY_SERVER:
DEBUG_NEGO("Error: SSL_NOT_ALLOWED_BY_SERVER");
break;
+
case SSL_CERT_NOT_ON_SERVER:
DEBUG_NEGO("Error: SSL_CERT_NOT_ON_SERVER");
+ nego->sendNegoData = TRUE;
break;
+
case INCONSISTENT_FLAGS:
DEBUG_NEGO("Error: INCONSISTENT_FLAGS");
break;
+
case HYBRID_REQUIRED_BY_SERVER:
DEBUG_NEGO("Error: HYBRID_REQUIRED_BY_SERVER");
break;
+
default:
DEBUG_NEGO("Error: Unknown protocol security error %d", failureCode);
break;
diff --git a/libfreerdp/core/nego.h b/libfreerdp/core/nego.h
index 48e3d0410..e8f429fb8 100644
--- a/libfreerdp/core/nego.h
+++ b/libfreerdp/core/nego.h
@@ -100,6 +100,7 @@ struct rdp_nego
BOOL security_connected;
UINT32 cookie_max_length;
+ BOOL sendNegoData;
UINT32 selected_protocol;
UINT32 requested_protocols;
BOOL NegotiateSecurityLayer;
diff --git a/libfreerdp/core/settings.c b/libfreerdp/core/settings.c
index c44ae9667..8411b4b88 100644
--- a/libfreerdp/core/settings.c
+++ b/libfreerdp/core/settings.c
@@ -454,6 +454,7 @@ void freerdp_settings_free(rdpSettings* settings)
free(settings->ConfigPath);
free(settings->CurrentPath);
free(settings->HomePath);
+ free(settings->LoadBalanceInfo);
freerdp_device_collection_free(settings);
freerdp_static_channel_collection_free(settings);
freerdp_dynamic_channel_collection_free(settings);
diff --git a/libfreerdp/core/surface.c b/libfreerdp/core/surface.c
index 1c961f5d9..42d39f1ab 100644
--- a/libfreerdp/core/surface.c
+++ b/libfreerdp/core/surface.c
@@ -25,7 +25,7 @@
#include "surface.h"
-static int update_recv_surfcmd_surface_bits(rdpUpdate* update, wStream* s, UINT32 *length)
+static int update_recv_surfcmd_surface_bits(rdpUpdate* update, wStream* s, UINT32* length)
{
int pos;
SURFACE_BITS_COMMAND* cmd = &update->surface_bits_command;
@@ -50,11 +50,11 @@ static int update_recv_surfcmd_surface_bits(rdpUpdate* update, wStream* s, UINT3
pos = stream_get_pos(s) + cmd->bitmapDataLength;
cmd->bitmapData = stream_get_tail(s);
- IFCALL(update->SurfaceBits, update->context, cmd);
-
stream_set_pos(s, pos);
*length = 20 + cmd->bitmapDataLength;
+ IFCALL(update->SurfaceBits, update->context, cmd);
+
return 0;
}
diff --git a/libfreerdp/core/transport.c b/libfreerdp/core/transport.c
index 29f8e6297..c1033e225 100644
--- a/libfreerdp/core/transport.c
+++ b/libfreerdp/core/transport.c
@@ -703,8 +703,7 @@ int transport_check_fds(rdpTransport** ptransport)
}
received = transport->ReceiveBuffer;
- transport->ReceiveBuffer = ObjectPool_Take(transport->ReceivePool);
- transport->ReceiveBuffer->pointer = transport->ReceiveBuffer->buffer;
+ transport->ReceiveBuffer = StreamPool_Take(transport->ReceivePool, 0);
stream_set_pos(received, length);
stream_seal(received);
@@ -720,7 +719,7 @@ int transport_check_fds(rdpTransport** ptransport)
recv_status = transport->ReceiveCallback(transport, received, transport->ReceiveExtra);
- ObjectPool_Return(transport->ReceivePool, received);
+ Stream_Release(received);
if (recv_status < 0)
status = -1;
@@ -799,16 +798,6 @@ static void* transport_client_thread(void* arg)
return NULL;
}
-wStream* transport_receive_buffer_pool_new()
-{
- wStream* pdu = NULL;
-
- pdu = stream_new(BUFFER_SIZE);
- pdu->pointer = pdu->buffer;
-
- return pdu;
-}
-
rdpTransport* transport_new(rdpSettings* settings)
{
rdpTransport* transport;
@@ -826,16 +815,14 @@ rdpTransport* transport_new(rdpSettings* settings)
/* a small 0.1ms delay when transport is blocking. */
transport->SleepInterval = 100;
- transport->ReceivePool = ObjectPool_New(TRUE);
- ObjectPool_Object(transport->ReceivePool)->fnObjectFree = (OBJECT_FREE_FN) stream_free;
- ObjectPool_Object(transport->ReceivePool)->fnObjectNew = (OBJECT_NEW_FN) transport_receive_buffer_pool_new;
+ transport->ReceivePool = StreamPool_New(TRUE, BUFFER_SIZE);
/* receive buffer for non-blocking read. */
- transport->ReceiveBuffer = ObjectPool_Take(transport->ReceivePool);
+ transport->ReceiveBuffer = StreamPool_Take(transport->ReceivePool, 0);
transport->ReceiveEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
/* buffers for blocking read/write */
- transport->ReceiveStream = stream_new(BUFFER_SIZE);
+ transport->ReceiveStream = StreamPool_Take(transport->ReceivePool, 0);
transport->SendStream = stream_new(BUFFER_SIZE);
transport->blocking = TRUE;
@@ -851,11 +838,13 @@ void transport_free(rdpTransport* transport)
if (transport != NULL)
{
if (transport->ReceiveBuffer)
- ObjectPool_Return(transport->ReceivePool, transport->ReceiveBuffer);
+ Stream_Release(transport->ReceiveBuffer);
- ObjectPool_Free(transport->ReceivePool);
+ if (transport->ReceiveStream)
+ Stream_Release(transport->ReceiveStream);
+
+ StreamPool_Free(transport->ReceivePool);
- stream_free(transport->ReceiveStream);
stream_free(transport->SendStream);
CloseHandle(transport->ReceiveEvent);
diff --git a/libfreerdp/core/transport.h b/libfreerdp/core/transport.h
index 0dc04122a..67a2e2783 100644
--- a/libfreerdp/core/transport.h
+++ b/libfreerdp/core/transport.h
@@ -69,7 +69,7 @@ struct rdp_transport
HANDLE GatewayEvent;
BOOL blocking;
BOOL SplitInputOutput;
- wObjectPool* ReceivePool;
+ wStreamPool* ReceivePool;
HANDLE stopEvent;
HANDLE thread;
BOOL async;
diff --git a/winpr/include/winpr/collections.h b/winpr/include/winpr/collections.h
index 32b412529..521e8578e 100644
--- a/winpr/include/winpr/collections.h
+++ b/winpr/include/winpr/collections.h
@@ -28,6 +28,7 @@
#include
#include
+#include
typedef void* (*OBJECT_NEW_FN)(void);
typedef void (*OBJECT_FREE_FN)(void* obj);
diff --git a/winpr/include/winpr/stream.h b/winpr/include/winpr/stream.h
index 3c0924eb0..6910734a0 100644
--- a/winpr/include/winpr/stream.h
+++ b/winpr/include/winpr/stream.h
@@ -28,12 +28,17 @@
extern "C" {
#endif
+typedef struct _wStreamPool wStreamPool;
+
struct _wStream
{
BYTE* buffer;
BYTE* pointer;
size_t length;
size_t capacity;
+
+ DWORD count;
+ wStreamPool* pool;
};
typedef struct _wStream wStream;
@@ -337,6 +342,38 @@ static INLINE BOOL stream_skip(wStream* s, int sz) {
return TRUE;
}
+/* StreamPool */
+
+struct _wStreamPool
+{
+ int aSize;
+ int aCapacity;
+ wStream** aArray;
+
+ int uSize;
+ int uCapacity;
+ wStream** uArray;
+
+ HANDLE mutex;
+ BOOL synchronized;
+ size_t defaultSize;
+};
+
+WINPR_API wStream* StreamPool_Take(wStreamPool* pool, size_t size);
+WINPR_API void StreamPool_Return(wStreamPool* pool, wStream* s);
+
+WINPR_API void Stream_AddRef(wStream* s);
+WINPR_API void Stream_Release(wStream* s);
+
+WINPR_API wStream* StreamPool_Find(wStreamPool* pool, BYTE* ptr);
+WINPR_API void StreamPool_AddRef(wStreamPool* pool, BYTE* ptr);
+WINPR_API void StreamPool_Release(wStreamPool* pool, BYTE* ptr);
+
+WINPR_API void StreamPool_Clear(wStreamPool* pool);
+
+WINPR_API wStreamPool* StreamPool_New(BOOL synchronized, size_t defaultSize);
+WINPR_API void StreamPool_Free(wStreamPool* pool);
+
#ifdef __cplusplus
}
#endif
diff --git a/winpr/include/winpr/string.h b/winpr/include/winpr/string.h
index 6bcae3eee..8cb2466f0 100644
--- a/winpr/include/winpr/string.h
+++ b/winpr/include/winpr/string.h
@@ -25,6 +25,10 @@
#include
#include
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#ifndef _WIN32
#define CSTR_LESS_THAN 1
@@ -174,4 +178,8 @@ WINPR_API int ConvertToUnicode(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteS
WINPR_API int ConvertFromUnicode(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
LPSTR* lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* WINPR_CRT_STRING_H */
diff --git a/winpr/libwinpr/interlocked/interlocked.c b/winpr/libwinpr/interlocked/interlocked.c
index 9065376d3..044c36684 100644
--- a/winpr/libwinpr/interlocked/interlocked.c
+++ b/winpr/libwinpr/interlocked/interlocked.c
@@ -236,7 +236,11 @@ LONG InterlockedCompareExchange(LONG volatile *Destination, LONG Exchange, LONG
#endif /* _WIN32 */
-#if (_WIN32 && (_WIN32_WINNT < 0x0502))
+#if defined(_WIN64)
+
+/* InterlockedCompareExchange64 already defined */
+
+#elif (_WIN32 && (_WIN32_WINNT < 0x0502))
static volatile HANDLE mutex = NULL;
diff --git a/winpr/libwinpr/utils/CMakeLists.txt b/winpr/libwinpr/utils/CMakeLists.txt
index d3f210838..50c6eaad7 100644
--- a/winpr/libwinpr/utils/CMakeLists.txt
+++ b/winpr/libwinpr/utils/CMakeLists.txt
@@ -29,6 +29,7 @@ set(${MODULE_PREFIX}_COLLECTIONS_SRCS
collections/CountdownEvent.c
collections/BufferPool.c
collections/ObjectPool.c
+ collections/StreamPool.c
collections/MessageQueue.c
collections/MessagePipe.c)
diff --git a/winpr/libwinpr/utils/collections/StreamPool.c b/winpr/libwinpr/utils/collections/StreamPool.c
new file mode 100644
index 000000000..96a491acf
--- /dev/null
+++ b/winpr/libwinpr/utils/collections/StreamPool.c
@@ -0,0 +1,323 @@
+/**
+ * WinPR: Windows Portable Runtime
+ * Object Pool
+ *
+ * Copyright 2012 Marc-Andre Moreau
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include
+
+#include
+
+/**
+ * Methods
+ */
+
+void StreamPool_ShiftUsed(wStreamPool* pool, int index, int count)
+{
+ if (count > 0)
+ {
+ if (pool->uSize + count > pool->uCapacity)
+ {
+ pool->uCapacity *= 2;
+ pool->uArray = (wStream**) realloc(pool->uArray, sizeof(wStream*) * pool->uCapacity);
+ }
+
+ MoveMemory(&pool->uArray[index + count], &pool->uArray[index], (pool->uSize - index) * sizeof(wStream*));
+ pool->uSize += count;
+ }
+ else if (count < 0)
+ {
+ MoveMemory(&pool->uArray[index], &pool->uArray[index - count], (pool->uSize + count) * sizeof(wStream*));
+ pool->uSize += count;
+ }
+}
+
+/**
+ * Adds a used stream to the pool.
+ */
+
+void StreamPool_AddUsed(wStreamPool* pool, wStream* s)
+{
+ int index;
+
+ if ((pool->uSize + 1) >= pool->uCapacity)
+ {
+ pool->uCapacity *= 2;
+ pool->uArray = (wStream**) realloc(pool->uArray, sizeof(wStream*) * pool->uCapacity);
+ }
+
+ pool->uArray[(pool->uSize)++] = s;
+}
+
+/**
+ * Removes a used stream from the pool.
+ */
+
+void StreamPool_RemoveUsed(wStreamPool* pool, wStream* s)
+{
+ int index;
+ BOOL found = FALSE;
+
+ for (index = 0; index < pool->uSize; index++)
+ {
+ if (pool->uArray[index] == s)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (found)
+ StreamPool_ShiftUsed(pool, index, -1);
+}
+
+/**
+ * Gets a stream from the pool.
+ */
+
+wStream* StreamPool_Take(wStreamPool* pool, size_t size)
+{
+ wStream* s = NULL;
+
+ if (pool->synchronized)
+ WaitForSingleObject(pool->mutex, INFINITE);
+
+ if (pool->aSize > 0)
+ s = pool->aArray[--(pool->aSize)];
+
+ if (size == 0)
+ size = pool->defaultSize;
+
+ if (!s)
+ {
+ s = Stream_New(NULL, size);
+ }
+ else
+ {
+ Stream_EnsureCapacity(s, size);
+ Stream_Pointer(s) = Stream_Buffer(s);
+ }
+
+ s->pool = pool;
+ s->count = 1;
+
+ StreamPool_AddUsed(pool, s);
+
+ if (pool->synchronized)
+ ReleaseMutex(pool->mutex);
+
+ return s;
+}
+
+/**
+ * Returns an object to the pool.
+ */
+
+void StreamPool_Return(wStreamPool* pool, wStream* s)
+{
+ if (pool->synchronized)
+ WaitForSingleObject(pool->mutex, INFINITE);
+
+ if ((pool->aSize + 1) >= pool->aCapacity)
+ {
+ pool->aCapacity *= 2;
+ pool->aArray = (wStream**) realloc(pool->aArray, sizeof(wStream*) * pool->aCapacity);
+ }
+
+ pool->aArray[(pool->aSize)++] = s;
+ StreamPool_RemoveUsed(pool, s);
+
+ if (pool->synchronized)
+ ReleaseMutex(pool->mutex);
+}
+
+/**
+ * Lock the stream pool
+ */
+
+void StreamPool_Lock(wStreamPool* pool)
+{
+ WaitForSingleObject(pool->mutex, INFINITE);
+}
+
+/**
+ * Unlock the stream pool
+ */
+
+void StreamPool_Unlock(wStreamPool* pool)
+{
+ ReleaseMutex(pool->mutex);
+}
+
+/**
+ * Increment stream reference count
+ */
+
+void Stream_AddRef(wStream* s)
+{
+ if (s->pool)
+ {
+ StreamPool_Lock(s->pool);
+ s->count++;
+ StreamPool_Unlock(s->pool);
+ }
+}
+
+/**
+ * Decrement stream reference count
+ */
+
+void Stream_Release(wStream* s)
+{
+ DWORD count;
+
+ if (s->pool)
+ {
+ StreamPool_Lock(s->pool);
+ count = --(s->count);
+ StreamPool_Unlock(s->pool);
+
+ if (count == 0)
+ StreamPool_Return(s->pool, s);
+ }
+}
+
+/**
+ * Find stream in pool using pointer inside buffer
+ */
+
+wStream* StreamPool_Find(wStreamPool* pool, BYTE* ptr)
+{
+ int index;
+ wStream* s = NULL;
+ BOOL found = FALSE;
+
+ WaitForSingleObject(pool->mutex, INFINITE);
+
+ for (index = 0; index < pool->uSize; index++)
+ {
+ s = pool->uArray[index];
+
+ if ((ptr >= s->buffer) && (ptr < (s->buffer + s->capacity)))
+ {
+ found = TRUE;
+ break;
+ }
+ }
+
+ ReleaseMutex(pool->mutex);
+
+ return (found) ? s : NULL;
+}
+
+/**
+ * Find stream in pool and increment reference count
+ */
+
+void StreamPool_AddRef(wStreamPool* pool, BYTE* ptr)
+{
+ wStream* s;
+
+ s = StreamPool_Find(pool, ptr);
+
+ if (s)
+ Stream_AddRef(s);
+}
+
+/**
+ * Find stream in pool and decrement reference count
+ */
+
+void StreamPool_Release(wStreamPool* pool, BYTE* ptr)
+{
+ wStream* s;
+
+ s = StreamPool_Find(pool, ptr);
+
+ if (s)
+ Stream_Release(s);
+}
+
+/**
+ * Releases the streams currently cached in the pool.
+ */
+
+void StreamPool_Clear(wStreamPool* pool)
+{
+ if (pool->synchronized)
+ WaitForSingleObject(pool->mutex, INFINITE);
+
+ while (pool->aSize > 0)
+ {
+ (pool->aSize)--;
+ Stream_Free(pool->aArray[pool->aSize], TRUE);
+ }
+
+ if (pool->synchronized)
+ ReleaseMutex(pool->mutex);
+}
+
+/**
+ * Construction, Destruction
+ */
+
+wStreamPool* StreamPool_New(BOOL synchronized, size_t defaultSize)
+{
+ wStreamPool* pool = NULL;
+
+ pool = (wStreamPool*) malloc(sizeof(wStreamPool));
+
+ if (pool)
+ {
+ ZeroMemory(pool, sizeof(wStreamPool));
+
+ pool->synchronized = synchronized;
+ pool->defaultSize = defaultSize;
+
+ if (pool->synchronized)
+ pool->mutex = CreateMutex(NULL, FALSE, NULL);
+
+ pool->aSize = 0;
+ pool->aCapacity = 32;
+ pool->aArray = (wStream**) malloc(sizeof(wStream*) * pool->aCapacity);
+
+ pool->uSize = 0;
+ pool->uCapacity = 32;
+ pool->uArray = (wStream**) malloc(sizeof(wStream*) * pool->uCapacity);
+ }
+
+ return pool;
+}
+
+void StreamPool_Free(wStreamPool* pool)
+{
+ if (pool)
+ {
+ StreamPool_Clear(pool);
+
+ if (pool->synchronized)
+ CloseHandle(pool->mutex);
+
+ free(pool->aArray);
+ free(pool->uArray);
+
+ free(pool);
+ }
+}
diff --git a/winpr/libwinpr/utils/test/CMakeLists.txt b/winpr/libwinpr/utils/test/CMakeLists.txt
index cf967be4b..307aae204 100644
--- a/winpr/libwinpr/utils/test/CMakeLists.txt
+++ b/winpr/libwinpr/utils/test/CMakeLists.txt
@@ -9,6 +9,7 @@ set(${MODULE_PREFIX}_TESTS
TestPrint.c
TestArrayList.c
TestCmdLine.c
+ TestStreamPool.c
TestMessageQueue.c
TestMessagePipe.c)
diff --git a/winpr/libwinpr/utils/test/TestStreamPool.c b/winpr/libwinpr/utils/test/TestStreamPool.c
new file mode 100644
index 000000000..ab8a371e4
--- /dev/null
+++ b/winpr/libwinpr/utils/test/TestStreamPool.c
@@ -0,0 +1,101 @@
+
+#include
+#include
+#include
+
+#define BUFFER_SIZE 16384
+
+int TestStreamPool(int argc, char* argv[])
+{
+ wStream* s[5];
+ wStreamPool* pool;
+
+ pool = StreamPool_New(TRUE, BUFFER_SIZE);
+
+ s[0] = StreamPool_Take(pool, 0);
+ s[1] = StreamPool_Take(pool, 0);
+ s[2] = StreamPool_Take(pool, 0);
+
+ printf("StreamPool: aSize: %d uSize: %d\n", pool->aSize, pool->uSize);
+
+ Stream_Release(s[0]);
+ Stream_Release(s[1]);
+ Stream_Release(s[2]);
+
+ printf("StreamPool: aSize: %d uSize: %d\n", pool->aSize, pool->uSize);
+
+ s[3] = StreamPool_Take(pool, 0);
+ s[4] = StreamPool_Take(pool, 0);
+
+ printf("StreamPool: aSize: %d uSize: %d\n", pool->aSize, pool->uSize);
+
+ Stream_Release(s[3]);
+ Stream_Release(s[4]);
+
+ printf("StreamPool: aSize: %d uSize: %d\n", pool->aSize, pool->uSize);
+
+ s[2] = StreamPool_Take(pool, 0);
+ s[3] = StreamPool_Take(pool, 0);
+ s[4] = StreamPool_Take(pool, 0);
+
+ printf("StreamPool: aSize: %d uSize: %d\n", pool->aSize, pool->uSize);
+
+ Stream_AddRef(s[2]);
+
+ Stream_AddRef(s[3]);
+ Stream_AddRef(s[3]);
+
+ Stream_AddRef(s[4]);
+ Stream_AddRef(s[4]);
+ Stream_AddRef(s[4]);
+
+ Stream_Release(s[2]);
+ Stream_Release(s[2]);
+
+ Stream_Release(s[3]);
+ Stream_Release(s[3]);
+ Stream_Release(s[3]);
+
+ Stream_Release(s[4]);
+ Stream_Release(s[4]);
+ Stream_Release(s[4]);
+ Stream_Release(s[4]);
+
+ printf("StreamPool: aSize: %d uSize: %d\n", pool->aSize, pool->uSize);
+
+ s[2] = StreamPool_Take(pool, 0);
+ s[3] = StreamPool_Take(pool, 0);
+ s[4] = StreamPool_Take(pool, 0);
+
+ printf("StreamPool: aSize: %d uSize: %d\n", pool->aSize, pool->uSize);
+
+ StreamPool_AddRef(pool, s[2]->buffer + 1024);
+
+ StreamPool_AddRef(pool, s[3]->buffer + 1024);
+ StreamPool_AddRef(pool, s[3]->buffer + 1024 * 2);
+
+ StreamPool_AddRef(pool, s[4]->buffer + 1024);
+ StreamPool_AddRef(pool, s[4]->buffer + 1024 * 2);
+ StreamPool_AddRef(pool, s[4]->buffer + 1024 * 3);
+
+ printf("StreamPool: aSize: %d uSize: %d\n", pool->aSize, pool->uSize);
+
+ StreamPool_Release(pool, s[2]->buffer + 2048);
+ StreamPool_Release(pool, s[2]->buffer + 2048 * 2);
+
+ StreamPool_Release(pool, s[3]->buffer + 2048);
+ StreamPool_Release(pool, s[3]->buffer + 2048 * 2);
+ StreamPool_Release(pool, s[3]->buffer + 2048 * 3);
+
+ StreamPool_Release(pool, s[4]->buffer + 2048);
+ StreamPool_Release(pool, s[4]->buffer + 2048 * 2);
+ StreamPool_Release(pool, s[4]->buffer + 2048 * 3);
+ StreamPool_Release(pool, s[4]->buffer + 2048 * 4);
+
+ printf("StreamPool: aSize: %d uSize: %d\n", pool->aSize, pool->uSize);
+
+ StreamPool_Free(pool);
+
+ return 0;
+}
+