diff --git a/channels/audin/client/CMakeLists.txt b/channels/audin/client/CMakeLists.txt index 2a370743c..e126eab0d 100644 --- a/channels/audin/client/CMakeLists.txt +++ b/channels/audin/client/CMakeLists.txt @@ -49,3 +49,7 @@ endif() if(WITH_OPENSLES) add_channel_client_subsystem(${MODULE_PREFIX} ${CHANNEL_NAME} "opensles" "") endif() + +if(WITH_WINMM) + add_channel_client_subsystem(${MODULE_PREFIX} ${CHANNEL_NAME} "winmm" "") +endif() diff --git a/channels/audin/client/audin_main.c b/channels/audin/client/audin_main.c index b1b75048e..18632b759 100644 --- a/channels/audin/client/audin_main.c +++ b/channels/audin/client/audin_main.c @@ -607,6 +607,15 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) } #endif +#if defined(WITH_WINMM) + if (!audin->device) + { + audin_set_subsystem(audin, "winmm"); + audin_set_device_name(audin, "default"); + audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args); + } +#endif + if (audin->device == NULL) { DEBUG_WARN("no sound device."); diff --git a/channels/audin/client/winmm/CMakeLists.txt b/channels/audin/client/winmm/CMakeLists.txt new file mode 100644 index 000000000..10db102ad --- /dev/null +++ b/channels/audin/client/winmm/CMakeLists.txt @@ -0,0 +1,41 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# 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. + +define_channel_client_subsystem("audin" "winmm" "") + +set(${MODULE_PREFIX}_SRCS + audin_winmm.c) + +include_directories(..) + +add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "") + +set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") + +set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS + MONOLITHIC ${MONOLITHIC_BUILD} + MODULE freerdp + MODULES freerdp-utils) + +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winmm.lib) + +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) + + +install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client/winmm") diff --git a/channels/audin/client/winmm/audin_winmm.c b/channels/audin/client/winmm/audin_winmm.c new file mode 100644 index 000000000..8881c04b0 --- /dev/null +++ b/channels/audin/client/winmm/audin_winmm.c @@ -0,0 +1,309 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Audio Input Redirection Virtual Channel - WinMM implementation + * + * Copyright 2013 Zhang Zhaolong + * + * 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 +#include + +#include +#include + +#include +#include +#include + +#include "audin_main.h" + +typedef struct _AudinWinmmDevice +{ + IAudinDevice iface; + + char* device_name; + AudinReceive receive; + void* user_data; + HANDLE thread; + HANDLE stopEvent; + HWAVEIN hWaveIn; + PWAVEFORMATEX *ppwfx; + PWAVEFORMATEX pwfx_cur; + UINT32 ppwfx_size; + UINT32 cFormats; + UINT32 frames_per_packet; +} AudinWinmmDevice; + +static void CALLBACK waveInProc(HWAVEIN hWaveIn, UINT uMsg, DWORD_PTR dwInstance, + DWORD_PTR dwParam1, DWORD_PTR dwParam2) +{ + AudinWinmmDevice* winmm = (AudinWinmmDevice*) dwInstance; + PWAVEHDR pWaveHdr; + + switch(uMsg) + { + case WIM_CLOSE: + break; + + case WIM_DATA: + pWaveHdr = (WAVEHDR *)dwParam1; + if (WHDR_DONE == (WHDR_DONE & pWaveHdr->dwFlags)) + { + if (pWaveHdr->dwBytesRecorded + && !(WaitForSingleObject(winmm->stopEvent, 0) == WAIT_OBJECT_0)) + { + winmm->receive(pWaveHdr->lpData, pWaveHdr->dwBytesRecorded, winmm->user_data); + waveInAddBuffer(hWaveIn, pWaveHdr, sizeof(WAVEHDR)); + } + } + break; + + case WIM_OPEN: + break; + + default: + break; + } +} + +static DWORD audin_winmm_thread_func(void* arg) +{ + AudinWinmmDevice* winmm = (AudinWinmmDevice*) arg; + char *buffer; + int size, i; + WAVEHDR waveHdr[4]; + + if (!winmm->hWaveIn) + { + if (MMSYSERR_NOERROR != waveInOpen(&winmm->hWaveIn, WAVE_MAPPER, winmm->pwfx_cur, + (DWORD_PTR)waveInProc, (DWORD_PTR)winmm, CALLBACK_FUNCTION)) + { + return 0; + } + } + + size = (winmm->pwfx_cur->wBitsPerSample * winmm->pwfx_cur->nChannels * winmm->frames_per_packet + 7) / 8; + for (i = 0; i < 4; i++) + { + buffer = (char *) malloc(size); + waveHdr[i].dwBufferLength = size; + waveHdr[i].dwFlags = 0; + waveHdr[i].lpData = buffer; + if (MMSYSERR_NOERROR != waveInPrepareHeader(winmm->hWaveIn, &waveHdr[i], sizeof(waveHdr[i]))) + { + DEBUG_DVC("waveInPrepareHeader failed."); + } + if (MMSYSERR_NOERROR != waveInAddBuffer(winmm->hWaveIn, &waveHdr[i], sizeof(waveHdr[i]))) + { + DEBUG_DVC("waveInAddBuffer failed."); + } + } + waveInStart(winmm->hWaveIn); + + WaitForSingleObject(winmm->stopEvent, INFINITE); + + waveInStop(winmm->hWaveIn); + + for (i = 0; i < 4; i++) + { + if (MMSYSERR_NOERROR != waveInUnprepareHeader(winmm->hWaveIn, &waveHdr[i], sizeof(waveHdr[i]))) + { + DEBUG_DVC("waveInUnprepareHeader failed."); + } + free(waveHdr[i].lpData); + } + + waveInClose(winmm->hWaveIn); + winmm->hWaveIn = NULL; + + return 0; +} + +static void audin_winmm_free(IAudinDevice* device) +{ + AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; + int i; + + for (i = 0; i < winmm->cFormats; i++) + { + free(winmm->ppwfx[i]); + } + + free(winmm->ppwfx); + free(winmm->device_name); + free(winmm); +} + +static void audin_winmm_close(IAudinDevice* device) +{ + AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; + + DEBUG_DVC(""); + + SetEvent(winmm->stopEvent); + + WaitForSingleObject(winmm->thread, INFINITE); + + CloseHandle(winmm->thread); + CloseHandle(winmm->stopEvent); + + winmm->thread = NULL; + winmm->stopEvent = NULL; + winmm->receive = NULL; + winmm->user_data = NULL; +} + +static void audin_winmm_set_format(IAudinDevice* device, audinFormat* format, UINT32 FramesPerPacket) +{ + AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; + int i; + + winmm->frames_per_packet = FramesPerPacket; + + for (i = 0; i < winmm->cFormats; i++) + { + if (winmm->ppwfx[i]->wFormatTag == format->wFormatTag + && winmm->ppwfx[i]->nChannels == format->nChannels + && winmm->ppwfx[i]->wBitsPerSample == format->wBitsPerSample) + { + winmm->pwfx_cur = winmm->ppwfx[i]; + break; + } + } +} + +static BOOL audin_winmm_format_supported(IAudinDevice* device, audinFormat* format) +{ + AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; + PWAVEFORMATEX pwfx; + BYTE *data; + + pwfx = (PWAVEFORMATEX)malloc(sizeof(WAVEFORMATEX) + format->cbSize); + pwfx->cbSize = format->cbSize; + pwfx->wFormatTag = format->wFormatTag; + pwfx->nChannels = format->nChannels; + pwfx->nSamplesPerSec = format->nSamplesPerSec; + pwfx->nBlockAlign = format->nBlockAlign; + pwfx->wBitsPerSample = format->wBitsPerSample; + data = (BYTE *)pwfx + sizeof(WAVEFORMATEX); + + memcpy(data, format->data, format->cbSize); + + if (pwfx->wFormatTag == WAVE_FORMAT_PCM) + { + pwfx->nAvgBytesPerSec = pwfx->nSamplesPerSec * pwfx->nBlockAlign; + if (MMSYSERR_NOERROR == waveInOpen(NULL, WAVE_MAPPER, pwfx, 0, 0, WAVE_FORMAT_QUERY)) + { + if (winmm->cFormats >= winmm->ppwfx_size) + { + winmm->ppwfx_size *= 2; + winmm->ppwfx = realloc(winmm->ppwfx, sizeof(PWAVEFORMATEX) * winmm->ppwfx_size); + } + winmm->ppwfx[winmm->cFormats++] = pwfx; + + return 1; + } + } + + free(pwfx); + return 0; +} + +static void audin_winmm_open(IAudinDevice* device, AudinReceive receive, void* user_data) +{ + AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; + + DEBUG_DVC(""); + + winmm->receive = receive; + winmm->user_data = user_data; + + winmm->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + winmm->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) audin_winmm_thread_func, winmm, 0, NULL); +} + +static COMMAND_LINE_ARGUMENT_A audin_winmm_args[] = +{ + { "audio-dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "audio device name" }, + { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } +}; + +static void audin_winmm_parse_addin_args(AudinWinmmDevice* device, ADDIN_ARGV* args) +{ + int status; + DWORD flags; + COMMAND_LINE_ARGUMENT_A* arg; + AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; + + flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON; + + status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv, audin_winmm_args, flags, winmm, NULL, NULL); + + arg = audin_winmm_args; + + do + { + if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) + continue; + + CommandLineSwitchStart(arg) + + CommandLineSwitchCase(arg, "audio-dev") + { + winmm->device_name = _strdup(arg->Value); + } + + CommandLineSwitchEnd(arg) + } + while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); +} + +#ifdef STATIC_CHANNELS +#define freerdp_audin_client_subsystem_entry winmm_freerdp_audin_client_subsystem_entry +#endif + +int freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints) +{ + ADDIN_ARGV* args; + AudinWinmmDevice* winmm; + + winmm = (AudinWinmmDevice*) malloc(sizeof(AudinWinmmDevice)); + ZeroMemory(winmm, sizeof(AudinWinmmDevice)); + + winmm->iface.Open = audin_winmm_open; + winmm->iface.FormatSupported = audin_winmm_format_supported; + winmm->iface.SetFormat = audin_winmm_set_format; + winmm->iface.Close = audin_winmm_close; + winmm->iface.Free = audin_winmm_free; + + args = pEntryPoints->args; + + audin_winmm_parse_addin_args(winmm, args); + + if (!winmm->device_name) + winmm->device_name = _strdup("default"); + + winmm->ppwfx_size = 10; + winmm->ppwfx = malloc(sizeof(PWAVEFORMATEX) * winmm->ppwfx_size); + + pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) winmm); + + return 0; +} diff --git a/channels/drdynvc/client/dvcman.c b/channels/drdynvc/client/dvcman.c index fae74d81b..71222d13e 100644 --- a/channels/drdynvc/client/dvcman.c +++ b/channels/drdynvc/client/dvcman.c @@ -413,13 +413,13 @@ int dvcman_close_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelI IFCALL(context->OnChannelDisconnected, context, channel->channel_name, channel->pInterface); + free(channel->channel_name); + DEBUG_DVC("dvcman_close_channel: channel %d closed", ChannelId); ichannel = (IWTSVirtualChannel*) channel; ichannel->Close(ichannel); } - free(channel->channel_name); - return 0; } diff --git a/channels/drive/client/drive_file.c b/channels/drive/client/drive_file.c index a9fdec1d7..eb430fec6 100644 --- a/channels/drive/client/drive_file.c +++ b/channels/drive/client/drive_file.c @@ -177,9 +177,9 @@ static BOOL drive_file_init(DRIVE_FILE* file, UINT32 DesiredAccess, UINT32 Creat struct STAT st; BOOL exists; #ifdef WIN32 - const static int mode = _S_IREAD | _S_IWRITE ; + const static int mode = _S_IREAD | _S_IWRITE ; #else - const static int mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH; + const static int mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH; BOOL largeFile = FALSE; #endif int oflag = 0; @@ -265,8 +265,10 @@ static BOOL drive_file_init(DRIVE_FILE* file, UINT32 DesiredAccess, UINT32 Creat #ifndef WIN32 if (largeFile) { - oflag |= O_LARGEFILE; + oflag |= O_LARGEFILE; } +#else + oflag |= O_BINARY; #endif file->fd = OPEN(file->fullpath, oflag, mode); @@ -426,7 +428,7 @@ BOOL drive_file_query_information(DRIVE_FILE* file, UINT32 FsInformationClass, w BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length, wStream* input) { char* s = NULL; - mode_t m; + mode_t m; UINT64 size; int status; char* fullpath; @@ -456,7 +458,7 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN tv[1].tv_sec = (LastWriteTime > 0 ? FILE_TIME_RDP_TO_SYSTEM(LastWriteTime) : st.st_mtime); tv[1].tv_usec = 0; #ifndef WIN32 -/* TODO on win32 */ + /* TODO on win32 */ #ifdef ANDROID utimes(file->fullpath, tv); #else @@ -474,15 +476,17 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN fchmod(file->fd, st.st_mode); } #endif - break; + break; case FileEndOfFileInformation: /* http://msdn.microsoft.com/en-us/library/cc232067.aspx */ case FileAllocationInformation: /* http://msdn.microsoft.com/en-us/library/cc232076.aspx */ +#ifndef _WIN32 Stream_Read_UINT64(input, size); if (ftruncate(file->fd, size) != 0) return FALSE; +#endif break; case FileDispositionInformation: @@ -509,10 +513,16 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN fullpath = drive_file_combine_fullpath(file->basepath, s); free(s); - /* TODO rename does not work on win32 */ - if (rename(file->fullpath, fullpath) == 0) +#ifdef _WIN32 + if (file->fd) + close(file->fd); +#endif + if (rename(file->fullpath, fullpath) == 0) { drive_file_set_fullpath(file, fullpath); +#ifdef _WIN32 + file->fd = OPEN(fullpath, O_RDWR | O_BINARY); +#endif } else { diff --git a/channels/drive/client/drive_file.h b/channels/drive/client/drive_file.h index 769a18def..28ac5780a 100644 --- a/channels/drive/client/drive_file.h +++ b/channels/drive/client/drive_file.h @@ -40,13 +40,13 @@ #endif #ifdef _WIN32 -#define STAT stat +#define STAT __stat64 #define OPEN _open #define close _close #define read _read #define write _write -#define LSEEK _lseek -#define FSTAT fstat +#define LSEEK _lseeki64 +#define FSTAT _fstat64 #define STATVFS statvfs #define mkdir(a,b) _mkdir(a) #define rmdir _rmdir diff --git a/channels/drive/client/drive_main.c b/channels/drive/client/drive_main.c index db85303be..1ad78fbb3 100644 --- a/channels/drive/client/drive_main.c +++ b/channels/drive/client/drive_main.c @@ -576,29 +576,29 @@ static void drive_process_irp(DRIVE_DEVICE* drive, IRP* irp) static void* drive_thread_func(void* arg) { - IRP* irp; - wMessage message; - DRIVE_DEVICE* drive = (DRIVE_DEVICE*) arg; + IRP* irp; + wMessage message; + DRIVE_DEVICE* drive = (DRIVE_DEVICE*) arg; - while (1) - { - if (!MessageQueue_Wait(drive->IrpQueue)) - break; + while (1) + { + if (!MessageQueue_Wait(drive->IrpQueue)) + break; - if (!MessageQueue_Peek(drive->IrpQueue, &message, TRUE)) - break; + if (!MessageQueue_Peek(drive->IrpQueue, &message, TRUE)) + break; - if (message.id == WMQ_QUIT) - break; + if (message.id == WMQ_QUIT) + break; - irp = (IRP*) message.wParam; + irp = (IRP*) message.wParam; - if (irp) - drive_process_irp(drive, irp); - } + if (irp) + drive_process_irp(drive, irp); + } - ExitThread(0); - return NULL; + ExitThread(0); + return NULL; } static void drive_irp_request(DEVICE* device, IRP* irp) @@ -712,13 +712,13 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) drive->Path = _strdup("/"); } - drive_register_drive_path(pEntryPoints, drive->Name, drive->Path); + drive_register_drive_path(pEntryPoints, drive->Name, drive->Path); #else sys_code_page = GetACP(); - /* Special case: path[0] == '*' -> export all drives */ + /* Special case: path[0] == '*' -> export all drives */ /* Special case: path[0] == '%' -> user home dir */ - if (strcmp(drive->Path, "%") == 0) + if (strcmp(drive->Path, "%") == 0) { _snprintf(buf, sizeof(buf), "%s\\", getenv("USERPROFILE")); drive_register_drive_path(pEntryPoints, drive->Name, _strdup(buf)); @@ -733,7 +733,7 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) for (dev = devlist, i = 0; *dev; dev += 4, i++) { if (*dev > 'B') - { + { /* Suppress disk drives A and B to avoid pesty messages */ len = _snprintf(buf, sizeof(buf) - 4, "%s", drive->Name); buf[len] = '_'; @@ -744,11 +744,11 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) } } } - else - { + else + { drive_register_drive_path(pEntryPoints, drive->Name, drive->Path); } #endif - - return 0; - } + + return 0; +} diff --git a/channels/rdpdr/client/devman.c b/channels/rdpdr/client/devman.c index 7ff21273f..8ecaf4dd1 100644 --- a/channels/rdpdr/client/devman.c +++ b/channels/rdpdr/client/devman.c @@ -67,6 +67,15 @@ void devman_free(DEVMAN* devman) free(devman); } +void devman_unregister_device(DEVMAN* devman, void* key) +{ + DEVICE* device; + + device = (DEVICE *)ListDictionary_Remove(devman->devices, key); + if (device) + devman_device_free(device); +} + static void devman_register_device(DEVMAN* devman, DEVICE* device) { void* key = NULL; diff --git a/channels/rdpdr/client/devman.h b/channels/rdpdr/client/devman.h index dd2126d91..9164052cd 100644 --- a/channels/rdpdr/client/devman.h +++ b/channels/rdpdr/client/devman.h @@ -23,6 +23,7 @@ #include "rdpdr_main.h" +void devman_unregister_device(DEVMAN* devman, void* key); BOOL devman_load_device_service(DEVMAN* devman, RDPDR_DEVICE* device); DEVICE* devman_get_device_by_id(DEVMAN* devman, UINT32 id); diff --git a/channels/rdpdr/client/rdpdr_main.c b/channels/rdpdr/client/rdpdr_main.c index 309228688..2627e08c0 100644 --- a/channels/rdpdr/client/rdpdr_main.c +++ b/channels/rdpdr/client/rdpdr_main.c @@ -33,6 +33,15 @@ #include #include +#ifdef _WIN32 +#include +#include +#else +#include +#include +#include +#endif + #ifdef HAVE_UNISTD_H #include #endif @@ -44,6 +53,432 @@ #include "rdpdr_main.h" +typedef struct _DEVICE_DRIVE_EXT DEVICE_DRIVE_EXT; + +struct _DEVICE_DRIVE_EXT +{ + DEVICE device; + char* path; +}; + +static void rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, BOOL userLoggedOn); + +static void rdpdr_send_device_list_remove_request(rdpdrPlugin* rdpdr, UINT32 count, UINT32 ids[]) +{ + wStream* s; + int i; + + s = Stream_New(NULL, 256); + + Stream_Write_UINT16(s, RDPDR_CTYP_CORE); + Stream_Write_UINT16(s, PAKID_CORE_DEVICELIST_REMOVE); + Stream_Write_UINT32(s, count); + + for (i = 0; i < count; i++) + Stream_Write_UINT32(s, ids[i]); + + Stream_SealLength(s); + + rdpdr_send(rdpdr, s); +} + +#ifdef _WIN32 + +LRESULT CALLBACK hotplug_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + rdpdrPlugin *rdpdr; + PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam; + + rdpdr = (rdpdrPlugin *)GetWindowLongPtr(hWnd, GWLP_USERDATA); + + switch(Msg) + { + case WM_DEVICECHANGE: + switch (wParam) + { + case DBT_DEVICEARRIVAL: + if (lpdb -> dbch_devicetype == DBT_DEVTYP_VOLUME) + { + PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb; + DWORD unitmask = lpdbv->dbcv_unitmask; + int i; + char drive_path[4] = { 'c', ':', '/', '\0'}; + + for (i = 0; i < 26; i++) + { + if (unitmask & 0x01) + { + RDPDR_DRIVE* drive; + + drive_path[0] = 'A' + i; + + drive = (RDPDR_DRIVE*) malloc(sizeof(RDPDR_DRIVE)); + ZeroMemory(drive, sizeof(RDPDR_DRIVE)); + + drive->Type = RDPDR_DTYP_FILESYSTEM; + + drive->Path = _strdup(drive_path); + drive_path[1] = '\0'; + drive->Name = _strdup(drive_path); + devman_load_device_service(rdpdr->devman, (RDPDR_DEVICE *)drive); + rdpdr_send_device_list_announce_request(rdpdr, TRUE); + } + unitmask = unitmask >> 1; + } + } + break; + + case DBT_DEVICEREMOVECOMPLETE: + if (lpdb -> dbch_devicetype == DBT_DEVTYP_VOLUME) + { + PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb; + DWORD unitmask = lpdbv->dbcv_unitmask; + int i, j, count; + char drive_name_upper, drive_name_lower; + + ULONG_PTR *keys; + DEVICE_DRIVE_EXT *device_ext; + UINT32 ids[1]; + + for (i = 0; i < 26; i++) + { + if (unitmask & 0x01) + { + drive_name_upper = 'A' + i; + drive_name_lower = 'a' + i; + + count = ListDictionary_GetKeys(rdpdr->devman->devices, &keys); + + for (j = 0; j < count; j++) + { + device_ext = (DEVICE_DRIVE_EXT *)ListDictionary_GetItemValue(rdpdr->devman->devices, (void *)keys[j]); + if (device_ext->path[0] == drive_name_upper || device_ext->path[0] == drive_name_lower) + { + devman_unregister_device(rdpdr->devman, (void *)keys[j]); + ids[0] = keys[j]; + rdpdr_send_device_list_remove_request(rdpdr, 1, ids); + break; + } + } + } + unitmask = unitmask >> 1; + } + } + break; + + default: + break; + } + break; + + default: + return DefWindowProc(hWnd, Msg, wParam, lParam); + } + return DefWindowProc(hWnd, Msg, wParam, lParam); +} + +static void* drive_hotplug_thread_func(void* arg) +{ + rdpdrPlugin *rdpdr; + WNDCLASSEX wnd_cls; + HWND hwnd; + MSG msg; + BOOL bRet; + DEV_BROADCAST_HANDLE NotificationFilter; + HDEVNOTIFY hDevNotify; + + rdpdr = (rdpdrPlugin *)arg; + + /* init windows class */ + wnd_cls.cbSize = sizeof(WNDCLASSEX); + wnd_cls.style = CS_HREDRAW | CS_VREDRAW; + wnd_cls.lpfnWndProc = hotplug_proc; + wnd_cls.cbClsExtra = 0; + wnd_cls.cbWndExtra = 0; + wnd_cls.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wnd_cls.hCursor = NULL; + wnd_cls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); + wnd_cls.lpszMenuName = NULL; + wnd_cls.lpszClassName = L"DRIVE_HOTPLUG"; + wnd_cls.hInstance = NULL; + wnd_cls.hIconSm = LoadIcon(NULL, IDI_APPLICATION); + RegisterClassEx(&wnd_cls); + + /* create window */ + hwnd = CreateWindowEx(0, L"DRIVE_HOTPLUG", NULL, + 0, 0, 0, 0, 0, + NULL, NULL, NULL, NULL); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)rdpdr); + + rdpdr->hotplug_wnd = hwnd; + /* register device interface to hwnd */ + NotificationFilter.dbch_size = sizeof(DEV_BROADCAST_HANDLE); + NotificationFilter.dbch_devicetype = DBT_DEVTYP_HANDLE; + hDevNotify = RegisterDeviceNotification(hwnd, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE); + + /* message loop */ + while ((bRet = GetMessage(&msg, 0, 0, 0)) != 0) + { + if (bRet == -1) + { + break; + } + else + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + UnregisterDeviceNotification(hDevNotify); + + return NULL; +} + +static void drive_hotplug_thread_terminate(rdpdrPlugin* rdpdr) +{ + if (rdpdr->hotplug_wnd) + PostMessage(rdpdr->hotplug_wnd, WM_QUIT, 0, 0); +} + +#else + +#define MAX_USB_DEVICES 100 + +typedef struct _hotplug_dev { + char* path; + BOOL to_add; +} hotplug_dev; + +static char* next_line(FILE* fd, size_t* len) +{ + size_t newsiz; + int c; + char* newbuf; + char* lrbuf; + int lrsiz; + + *len = 0; + lrsiz = 0; + lrbuf = NULL; + newbuf = NULL; + + for (;;) + { + c = fgetc(fd); + if (ferror(fd)) + return NULL; + + if (c == EOF) + { + if (*len == 0) + return NULL; + else + { + lrbuf[(*len)] = '\0'; + return lrbuf; + } + } + else + { + if (*len == lrsiz) + { + newsiz = lrsiz + 4096; + newbuf = realloc(lrbuf, newsiz); + if (newbuf == NULL) + return NULL; + lrbuf = newbuf; + lrsiz = newsiz; + } + lrbuf[(*len)] = c; + + if (c == '\n') + { + lrbuf[(*len)] = '\0'; + return lrbuf; + } + + (*len)++; + } + } +} + +static char* get_word(char* str, unsigned int* offset) +{ + char* p; + char* tmp; + int wlen; + + if (*offset >= strlen(str)) + return NULL; + + p = str + *offset; + tmp = p; + + while (*tmp != ' ' && *tmp != '\0') + tmp++; + + wlen = tmp - p; + *offset += wlen; + + /* in case there are more than one space between words */ + while (*(str + *offset) == ' ') + (*offset)++; + + return strndup(p, wlen); +} + +static void handle_hotplug(rdpdrPlugin* rdpdr) +{ + FILE *f; + size_t len; + char *line; + char *word; + unsigned int wlen; + + hotplug_dev dev_array[MAX_USB_DEVICES]; + int i, j; + int size = 0; + + int count; + DEVICE_DRIVE_EXT *device_ext; + ULONG_PTR *keys; + UINT32 ids[1]; + + f = fopen("/proc/mounts", "r"); + if (f == NULL) + { + return; + } + + while ((line = next_line(f, &len))) + { + wlen = 0; + while ((word = get_word(line, &wlen))) + { + /* copy hotpluged device mount point to the dev_array */ + if (strstr(word, "/mnt/") != NULL || strstr(word, "/media/") != NULL) + { + dev_array[size].path = strdup(word); + dev_array[size++].to_add = TRUE; + } + free(word); + } + free(line); + } + + fclose(f); + + /* delete removed devices */ + count = ListDictionary_GetKeys(rdpdr->devman->devices, &keys); + + for (j = 0; j < count; j++) + { + BOOL dev_found = FALSE; + + device_ext = (DEVICE_DRIVE_EXT *)ListDictionary_GetItemValue(rdpdr->devman->devices, (void *)keys[j]); + + /* not plugable device */ + if (strstr(device_ext->path, "/mnt/") == NULL && strstr(device_ext->path, "/media/") == NULL) + continue; + + for (i = 0; i < size; i++) + { + if (strstr(device_ext->path, dev_array[i].path) != NULL) + { + dev_found = TRUE; + dev_array[i].to_add = FALSE; + break; + } + } + + if (!dev_found) + { + devman_unregister_device(rdpdr->devman, (void *)keys[j]); + ids[0] = keys[j]; + rdpdr_send_device_list_remove_request(rdpdr, 1, ids); + } + } + + /* add new devices */ + for (i = 0; i < size; i++) + { + RDPDR_DRIVE* drive; + + if (dev_array[i].to_add) + { + char* name; + + drive = (RDPDR_DRIVE*) malloc(sizeof(RDPDR_DRIVE)); + ZeroMemory(drive, sizeof(RDPDR_DRIVE)); + + drive->Type = RDPDR_DTYP_FILESYSTEM; + + drive->Path = _strdup(dev_array[i].path); + name = strrchr(drive->Path, '/') + 1; + drive->Name = _strdup(name); + devman_load_device_service(rdpdr->devman, (RDPDR_DEVICE *)drive); + } + + free(dev_array[i].path); + dev_array[i].path = NULL; + } + rdpdr_send_device_list_announce_request(rdpdr, TRUE); +} + +static void* drive_hotplug_thread_func(void* arg) +{ + rdpdrPlugin* rdpdr; + int mfd; + fd_set rfds; + struct timeval tv; + int rv; + + rdpdr = (rdpdrPlugin *)arg; + + rdpdr->stop_event = CreateEvent(NULL, TRUE, FALSE, NULL); + + mfd = open("/proc/mounts", O_RDONLY, 0); + if (mfd < 0) + { + fprintf(stderr, "ERROR: Unable to open /proc/mounts."); + return NULL; + } + + FD_ZERO(&rfds); + FD_SET(mfd, &rfds); + tv.tv_sec = 1; + tv.tv_usec = 0; + + while ((rv = select(mfd+1, NULL, NULL, &rfds, &tv)) >= 0) + { + if (WaitForSingleObject(rdpdr->stop_event, 0) == WAIT_OBJECT_0) + break; + + if (FD_ISSET(mfd, &rfds)) + { + /* file /proc/mounts changed, handle this */ + handle_hotplug(rdpdr); + } + + FD_ZERO(&rfds); + FD_SET(mfd, &rfds); + tv.tv_sec = 1; + tv.tv_usec = 0; + } + + return NULL; +} + +static void drive_hotplug_thread_terminate(rdpdrPlugin* rdpdr) +{ + if (rdpdr->stop_event) + SetEvent(rdpdr->stop_event); +} + +#endif + + static void rdpdr_process_connect(rdpdrPlugin* rdpdr) { UINT32 index; @@ -58,6 +493,11 @@ static void rdpdr_process_connect(rdpdrPlugin* rdpdr) for (index = 0; index < settings->DeviceCount; index++) { device = settings->DeviceArray[index]; + if (strcmp(device->Name, "*") == 0) + { + rdpdr->hotplug_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)drive_hotplug_thread_func, rdpdr, 0, NULL); + continue; + } devman_load_device_service(rdpdr->devman, device); } } @@ -497,6 +937,10 @@ static void rdpdr_virtual_channel_event_terminated(rdpdrPlugin* rdpdr) MessagePipe_Free(rdpdr->MsgPipe); CloseHandle(rdpdr->thread); + drive_hotplug_thread_terminate(rdpdr); + + WaitForSingleObject(rdpdr->hotplug_thread, INFINITE); + rdpdr->channelEntryPoints.pVirtualChannelClose(rdpdr->OpenHandle); if (rdpdr->data_in) diff --git a/channels/rdpdr/client/rdpdr_main.h b/channels/rdpdr/client/rdpdr_main.h index f0699fce9..e3a56c1d7 100644 --- a/channels/rdpdr/client/rdpdr_main.h +++ b/channels/rdpdr/client/rdpdr_main.h @@ -52,6 +52,14 @@ struct rdpdr_plugin UINT16 versionMinor; UINT16 clientID; char computerName[256]; + + /* hotplug support */ + HANDLE hotplug_thread; +#ifdef _WIN32 + HWND hotplug_wnd; +#else + HANDLE stop_event; +#endif }; int rdpdr_send(rdpdrPlugin* rdpdr, wStream* s); diff --git a/channels/rdpsnd/server/rdpsnd_main.c b/channels/rdpsnd/server/rdpsnd_main.c index 4bc7107d5..f56d407e4 100644 --- a/channels/rdpsnd/server/rdpsnd_main.c +++ b/channels/rdpsnd/server/rdpsnd_main.c @@ -201,12 +201,7 @@ static void* rdpsnd_server_thread(void* arg) Stream_SetPosition(s, 0); if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0, - (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned)) - { - if (BytesReturned) - Stream_Seek(s, BytesReturned); - } - else + (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned) == FALSE) { if (!BytesReturned) break; diff --git a/client/Windows/CMakeLists.txt b/client/Windows/CMakeLists.txt index d01b6b07f..1e5cab1d8 100644 --- a/client/Windows/CMakeLists.txt +++ b/client/Windows/CMakeLists.txt @@ -33,6 +33,8 @@ set(${MODULE_PREFIX}_SRCS wf_rail.h wf_interface.c wf_interface.h + wf_floatbar.c + wf_floatbar.h wfreerdp.rc resource.h) diff --git a/client/Windows/resource.h b/client/Windows/resource.h index 5ee440fa5..89c1e79ba 100644 --- a/client/Windows/resource.h +++ b/client/Windows/resource.h @@ -1,2 +1,13 @@ -#define IDI_ICON1 101 +#define IDI_ICON1 101 +#define IDB_BACKGROUND 102 +#define IDB_MINIMIZE 103 +#define IDB_MINIMIZE_ACT 104 +#define IDB_LOCK 105 +#define IDB_LOCK_ACT 106 +#define IDB_UNLOCK 107 +#define IDB_UNLOCK_ACT 108 +#define IDB_CLOSE 109 +#define IDB_CLOSE_ACT 100 +#define IDB_RESTORE 111 +#define IDB_RESTORE_ACT 112 diff --git a/client/Windows/resource/bg.bmp b/client/Windows/resource/bg.bmp new file mode 100644 index 000000000..c97ef5d99 Binary files /dev/null and b/client/Windows/resource/bg.bmp differ diff --git a/client/Windows/resource/close.bmp b/client/Windows/resource/close.bmp new file mode 100644 index 000000000..8fce91657 Binary files /dev/null and b/client/Windows/resource/close.bmp differ diff --git a/client/Windows/resource/close_active.bmp b/client/Windows/resource/close_active.bmp new file mode 100644 index 000000000..2c58a3de6 Binary files /dev/null and b/client/Windows/resource/close_active.bmp differ diff --git a/client/Windows/resource/lock.bmp b/client/Windows/resource/lock.bmp new file mode 100644 index 000000000..91d7384d9 Binary files /dev/null and b/client/Windows/resource/lock.bmp differ diff --git a/client/Windows/resource/lock_active.bmp b/client/Windows/resource/lock_active.bmp new file mode 100644 index 000000000..78e2ed45e Binary files /dev/null and b/client/Windows/resource/lock_active.bmp differ diff --git a/client/Windows/resource/minimize.bmp b/client/Windows/resource/minimize.bmp new file mode 100644 index 000000000..f4c5f6c7a Binary files /dev/null and b/client/Windows/resource/minimize.bmp differ diff --git a/client/Windows/resource/minimize_active.bmp b/client/Windows/resource/minimize_active.bmp new file mode 100644 index 000000000..152fad298 Binary files /dev/null and b/client/Windows/resource/minimize_active.bmp differ diff --git a/client/Windows/resource/restore.bmp b/client/Windows/resource/restore.bmp new file mode 100644 index 000000000..d74eddf23 Binary files /dev/null and b/client/Windows/resource/restore.bmp differ diff --git a/client/Windows/resource/restore_active.bmp b/client/Windows/resource/restore_active.bmp new file mode 100644 index 000000000..f88bc4d9a Binary files /dev/null and b/client/Windows/resource/restore_active.bmp differ diff --git a/client/Windows/resource/unlock.bmp b/client/Windows/resource/unlock.bmp new file mode 100644 index 000000000..8359ae7cc Binary files /dev/null and b/client/Windows/resource/unlock.bmp differ diff --git a/client/Windows/resource/unlock_active.bmp b/client/Windows/resource/unlock_active.bmp new file mode 100644 index 000000000..59d730d6e Binary files /dev/null and b/client/Windows/resource/unlock_active.bmp differ diff --git a/client/Windows/wf_floatbar.c b/client/Windows/wf_floatbar.c new file mode 100644 index 000000000..b331dc5c0 --- /dev/null +++ b/client/Windows/wf_floatbar.c @@ -0,0 +1,466 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Windows Float Bar + * + * Copyright 2013 Zhang Zhaolong + * + * 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. + */ + +#include +#include + +#include "wf_interface.h" +#include "wf_floatbar.h" +#include "wf_window.h" +#include "wf_gdi.h" +#include "resource.h" + +typedef struct _Button Button; + +/* TIMERs */ +#define TIMER_HIDE 1 +#define TIMER_ANIMAT_SHOW 2 +#define TIMER_ANIMAT_HIDE 3 + +/* Button Type */ +#define BUTTON_LOCKPIN 0 +#define BUTTON_MINIMIZE 1 +#define BUTTON_RESTORE 2 +#define BUTTON_CLOSE 3 +#define BTN_MAX 4 + +/* bmp size */ +#define BACKGROUND_W 581 +#define BACKGROUND_H 29 +#define LOCK_X 13 +#define MINIMIZE_X (BACKGROUND_W - 91) +#define CLOSE_X (BACKGROUND_W - 37) +#define RESTORE_X (BACKGROUND_W - 64) + +#define BUTTON_Y 2 +#define BUTTON_WIDTH 24 +#define BUTTON_HEIGHT 24 + +struct _Button { + FloatBar* floatbar; + int type; + int x, y, h, w; + int active; + HBITMAP bmp; + HBITMAP bmp_act; + + /* Lock Specified */ + HBITMAP locked_bmp; + HBITMAP locked_bmp_act; + HBITMAP unlocked_bmp; + HBITMAP unlocked_bmp_act; +}; + +struct _FloatBar { + HWND parent; + HWND hwnd; + RECT rect; + LONG width; + LONG height; + wfContext* wfc; + Button* buttons[BTN_MAX]; + BOOL shown; + BOOL locked; + HDC hdcmem; + HBITMAP background; +}; + +static int button_hit(Button* button) +{ + FloatBar* floatbar = button->floatbar; + + switch (button->type) + { + case BUTTON_LOCKPIN: + if (!floatbar->locked) + { + button->bmp = button->locked_bmp; + button->bmp_act = button->locked_bmp_act; + } + else + { + button->bmp = button->unlocked_bmp; + button->bmp_act = button->unlocked_bmp_act; + } + + floatbar->locked = ~floatbar->locked; + InvalidateRect(button->floatbar->hwnd, NULL, FALSE); + UpdateWindow(button->floatbar->hwnd); + break; + + case BUTTON_MINIMIZE: + ShowWindow(floatbar->parent, SW_MINIMIZE); + break; + + case BUTTON_RESTORE: + wf_toggle_fullscreen(floatbar->wfc); + break; + + case BUTTON_CLOSE: + SendMessage(floatbar->parent, WM_DESTROY, 0 , 0); + break; + + default: + return 0; + } + + return 0; +} + +static int button_paint(Button* button, HDC hdc) +{ + FloatBar* floatbar = button->floatbar; + + SelectObject(floatbar->hdcmem, button->active ? button->bmp_act : button->bmp); + StretchBlt(hdc, button->x, button->y, button->w, button->h, floatbar->hdcmem, 0, 0, button->w, button->h, SRCCOPY); + + return 0; +} + +static Button* floatbar_create_button(FloatBar* floatbar, int type, int resid, int resid_act, int x, int y, int h, int w) +{ + Button *button; + HDC hDC; + HDC hMemDC; + HBITMAP hBitmap; + HBITMAP hOldBitmap; + BITMAP bm; + + button = (Button *)malloc(sizeof(Button)); + + if (!button) + return NULL; + + button->floatbar = floatbar; + button->type = type; + button->x = x; + button->y = y; + button->w = w; + button->h = h; + button->active = FALSE; + + button->bmp = (HBITMAP)LoadImage(floatbar->wfc->hInstance, MAKEINTRESOURCE(resid), IMAGE_BITMAP, w, h, LR_DEFAULTCOLOR); + button->bmp_act = (HBITMAP)LoadImage(floatbar->wfc->hInstance, MAKEINTRESOURCE(resid_act), IMAGE_BITMAP, w, h, LR_DEFAULTCOLOR); + + return button; +} + +static Button* floatbar_create_lock_button(FloatBar* floatbar, + int unlock_resid, int unlock_resid_act, + int lock_resid, int lock_resid_act, + int x, int y, int h, int w) +{ + Button* button; + + button = floatbar_create_button(floatbar, BUTTON_LOCKPIN, unlock_resid, unlock_resid_act, x, y, h, w); + + if (!button) + return NULL; + + button->unlocked_bmp = button->bmp; + button->unlocked_bmp_act = button->bmp_act; + button->locked_bmp = (HBITMAP)LoadImage(floatbar->wfc->hInstance, MAKEINTRESOURCE(lock_resid), IMAGE_BITMAP, w, h, LR_DEFAULTCOLOR); + button->locked_bmp_act = (HBITMAP)LoadImage(floatbar->wfc->hInstance, MAKEINTRESOURCE(lock_resid_act), IMAGE_BITMAP, w, h, LR_DEFAULTCOLOR); + + return button; +} + +static Button* floatbar_get_button(FloatBar* floatbar, int x, int y) +{ + int i; + + if (y > BUTTON_Y && y < BUTTON_Y + BUTTON_HEIGHT) + for (i = 0; i < BTN_MAX; i++) + if (x > floatbar->buttons[i]->x && x < floatbar->buttons[i]->x + floatbar->buttons[i]->w) + return floatbar->buttons[i]; + + return NULL; +} + +static int floatbar_paint(FloatBar* floatbar, HDC hdc) +{ + int i; + + if (!floatbar->wfc->fullscreen) + return -1; + + /* paint background */ + SelectObject(floatbar->hdcmem, floatbar->background); + StretchBlt(hdc, 0, 0, BACKGROUND_W, BACKGROUND_H, floatbar->hdcmem, 0, 0, BACKGROUND_W, BACKGROUND_H, SRCCOPY); + + /* paint buttons */ + for (i = 0; i < BTN_MAX; i++) + button_paint(floatbar->buttons[i], hdc); + + return 0; +} + +static int floatbar_animation(FloatBar* floatbar, BOOL show) +{ + SetTimer(floatbar->hwnd, show ? TIMER_ANIMAT_SHOW : TIMER_ANIMAT_HIDE, 10, NULL); + floatbar->shown = show; + return 0; +} + +LRESULT CALLBACK floatbar_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + static int dragging = FALSE; + static int lbtn_dwn = FALSE; + static int btn_dwn_x = 0; + static FloatBar* floatbar; + static TRACKMOUSEEVENT tme; + + PAINTSTRUCT ps; + Button* button; + HDC hdc; + int pos_x; + int pos_y; + + int xScreen = GetSystemMetrics(SM_CXSCREEN); + + switch(Msg) + { + case WM_CREATE: + floatbar = (FloatBar *)((CREATESTRUCT *)lParam)->lpCreateParams; + floatbar->hwnd = hWnd; + floatbar->parent = GetParent(hWnd); + + GetWindowRect(floatbar->hwnd, &floatbar->rect); + floatbar->width = floatbar->rect.right - floatbar->rect.left; + floatbar->height = floatbar->rect.bottom - floatbar->rect.top; + + hdc = GetDC(hWnd); + floatbar->hdcmem = CreateCompatibleDC(hdc); + ReleaseDC(hWnd, hdc); + + tme.cbSize = sizeof(TRACKMOUSEEVENT); + tme.dwFlags = TME_LEAVE; + tme.hwndTrack = hWnd; + tme.dwHoverTime = HOVER_DEFAULT; + + SetTimer(hWnd, TIMER_HIDE, 3000, NULL); + break; + + case WM_PAINT: + hdc = BeginPaint(hWnd, &ps); + floatbar_paint(floatbar, hdc); + EndPaint(hWnd, &ps); + break; + + case WM_LBUTTONDOWN: + pos_x = lParam & 0xffff; + pos_y = (lParam >> 16) & 0xffff; + + button = floatbar_get_button(floatbar, pos_x, pos_y); + if (!button) + { + SetCapture(hWnd); + dragging = TRUE; + btn_dwn_x = lParam & 0xffff; + } + else + lbtn_dwn = TRUE; + + break; + + case WM_LBUTTONUP: + pos_x = lParam & 0xffff; + pos_y = (lParam >> 16) & 0xffff; + + ReleaseCapture(); + dragging = FALSE; + + if (lbtn_dwn) + { + button = floatbar_get_button(floatbar, pos_x, pos_y); + if (button) + button_hit(button); + lbtn_dwn = FALSE; + } + break; + + case WM_MOUSEMOVE: + KillTimer(hWnd, TIMER_HIDE); + pos_x = lParam & 0xffff; + pos_y = (lParam >> 16) & 0xffff; + + if (!floatbar->shown) + floatbar_animation(floatbar, TRUE); + + if (dragging) + { + floatbar->rect.left = floatbar->rect.left + (lParam & 0xffff) - btn_dwn_x; + + if (floatbar->rect.left < 0) + floatbar->rect.left = 0; + else if (floatbar->rect.left > xScreen - floatbar->width) + floatbar->rect.left = xScreen - floatbar->width; + + MoveWindow(hWnd, floatbar->rect.left, floatbar->rect.top, floatbar->width, floatbar->height, TRUE); + } + else + { + int i; + + for (i = 0; i < BTN_MAX; i++) + floatbar->buttons[i]->active = FALSE; + + button = floatbar_get_button(floatbar, pos_x, pos_y); + if (button) + button->active = TRUE; + + InvalidateRect(hWnd, NULL, FALSE); + UpdateWindow(hWnd); + } + + TrackMouseEvent(&tme); + break; + + case WM_CAPTURECHANGED: + dragging = FALSE; + break; + + case WM_MOUSELEAVE: + { + int i; + + for (i = 0; i < BTN_MAX; i++) + floatbar->buttons[i]->active = FALSE; + + InvalidateRect(hWnd, NULL, FALSE); + UpdateWindow(hWnd); + + SetTimer(hWnd, TIMER_HIDE, 3000, NULL); + break; + } + case WM_TIMER: + switch (wParam) + { + case TIMER_HIDE: + { + KillTimer(hWnd, TIMER_HIDE); + if (!floatbar->locked) + floatbar_animation(floatbar, FALSE); + break; + } + case TIMER_ANIMAT_SHOW: + { + static int y = 0; + + MoveWindow(floatbar->hwnd, floatbar->rect.left, (y++ - floatbar->height), floatbar->width, floatbar->height, TRUE); + if (y == floatbar->height) + { + y = 0; + KillTimer(hWnd, wParam); + } + break; + } + case TIMER_ANIMAT_HIDE: + { + static int y = 0; + + MoveWindow(floatbar->hwnd, floatbar->rect.left, -y++, floatbar->width, floatbar->height, TRUE); + if (y == floatbar->height) + { + y = 0; + KillTimer(hWnd, wParam); + } + break; + } + default: + break; + } + break; + + case WM_DESTROY: + DeleteDC(floatbar->hdcmem); + PostQuitMessage(0); + break; + + default: + return DefWindowProc(hWnd, Msg, wParam, lParam); + } + return 0; +} + +static FloatBar* floatbar_create(wfContext* wfc) +{ + FloatBar* floatbar; + + floatbar = (FloatBar *)malloc(sizeof(FloatBar)); + + if (!floatbar) + return NULL; + + floatbar->locked = FALSE; + floatbar->shown = TRUE; + floatbar->hwnd = NULL; + floatbar->parent = wfc->hwnd; + floatbar->wfc = wfc; + floatbar->hdcmem = NULL; + + floatbar->background = (HBITMAP)LoadImage(wfc->hInstance, MAKEINTRESOURCE(IDB_BACKGROUND), IMAGE_BITMAP, BACKGROUND_W, BACKGROUND_H, LR_DEFAULTCOLOR); + floatbar->buttons[0] = floatbar_create_button(floatbar, BUTTON_MINIMIZE, IDB_MINIMIZE, IDB_MINIMIZE_ACT, MINIMIZE_X, BUTTON_Y, BUTTON_HEIGHT, BUTTON_WIDTH); + floatbar->buttons[1] = floatbar_create_button(floatbar, BUTTON_RESTORE, IDB_RESTORE, IDB_RESTORE_ACT, RESTORE_X, BUTTON_Y, BUTTON_HEIGHT, BUTTON_WIDTH); + floatbar->buttons[2] = floatbar_create_button(floatbar, BUTTON_CLOSE, IDB_CLOSE, IDB_CLOSE_ACT, CLOSE_X, BUTTON_Y, BUTTON_HEIGHT, BUTTON_WIDTH); + floatbar->buttons[3] = floatbar_create_lock_button(floatbar, IDB_UNLOCK, IDB_UNLOCK_ACT, IDB_LOCK, IDB_LOCK_ACT, LOCK_X, BUTTON_Y, BUTTON_HEIGHT, BUTTON_WIDTH); + + return floatbar; +} + +int floatbar_hide(FloatBar* floatbar) +{ + MoveWindow(floatbar->hwnd, floatbar->rect.left, -floatbar->height, floatbar->width, floatbar->height, TRUE); + return 0; +} + +int floatbar_show(FloatBar* floatbar) +{ + MoveWindow(floatbar->hwnd, floatbar->rect.left, floatbar->rect.top, floatbar->width, floatbar->height, TRUE); + return 0; +} + +void floatbar_window_create(wfContext *wfc) +{ + WNDCLASSEX wnd_cls; + HWND barWnd; + int x = (GetSystemMetrics(SM_CXSCREEN) - BACKGROUND_W) / 2; + + wnd_cls.cbSize = sizeof(WNDCLASSEX); + wnd_cls.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; + wnd_cls.lpfnWndProc = floatbar_proc; + wnd_cls.cbClsExtra = 0; + wnd_cls.cbWndExtra = 0; + wnd_cls.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wnd_cls.hCursor = LoadCursor(wfc->hInstance, IDC_ARROW); + wnd_cls.hbrBackground = NULL; + wnd_cls.lpszMenuName = NULL; + wnd_cls.lpszClassName = L"floatbar"; + wnd_cls.hInstance = wfc->hInstance; + wnd_cls.hIconSm = LoadIcon(NULL, IDI_APPLICATION); + + RegisterClassEx(&wnd_cls); + + wfc->floatbar = floatbar_create(wfc); + + barWnd = CreateWindowEx(WS_EX_TOPMOST, L"floatbar", L"floatbar", WS_CHILD, x, 0, BACKGROUND_W, BACKGROUND_H, wfc->hwnd, NULL, wfc->hInstance, wfc->floatbar); + if (barWnd == NULL) + return; + ShowWindow(barWnd, SW_SHOWNORMAL); +} diff --git a/client/Windows/wf_floatbar.h b/client/Windows/wf_floatbar.h new file mode 100644 index 000000000..7b6f67dd0 --- /dev/null +++ b/client/Windows/wf_floatbar.h @@ -0,0 +1,30 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Windows Float Bar + * + * Copyright 2013 Zhang Zhaolong + * + * 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. + */ + +#ifndef __WF_FLOATBAR_H__ +#define __WF_FLOATBAR_H__ + +typedef struct _FloatBar FloatBar; +typedef struct wf_context wfContext; + +void floatbar_window_create(wfContext* wfc); +int floatbar_show(FloatBar* floatbar); +int floatbar_hide(FloatBar* floatbar); + +#endif diff --git a/client/Windows/wf_gdi.c b/client/Windows/wf_gdi.c index 2b6b7ade6..2a7daedc0 100644 --- a/client/Windows/wf_gdi.c +++ b/client/Windows/wf_gdi.c @@ -322,6 +322,11 @@ void wf_toggle_fullscreen(wfContext* wfc) wfc->disablewindowtracking = TRUE; } + if (wfc->fullscreen) + floatbar_show(wfc->floatbar); + else + floatbar_hide(wfc->floatbar); + SetParent(wfc->hwnd, wfc->fullscreen ? NULL : wfc->hWndParent); wf_resize_window(wfc); ShowWindow(wfc->hwnd, SW_SHOW); @@ -515,12 +520,18 @@ void wf_gdi_polyline(wfContext* wfc, POLYLINE_ORDER* polyline) if (polyline->numPoints > 0) { + POINT temp; + + temp.x = polyline->xStart; + temp.y = polyline->yStart; pts = (POINT*) malloc(sizeof(POINT) * polyline->numPoints); for (i = 0; i < (int) polyline->numPoints; i++) { - pts[i].x = polyline->points[i].x; - pts[i].y = polyline->points[i].y; + temp.x += polyline->points[i].x; + temp.y += polyline->points[i].y; + pts[i].x = temp.x; + pts[i].y = temp.y; if (wfc->drawing == wfc->primary) wf_invalidate_region(wfc, pts[i].x, pts[i].y, pts[i].x + 1, pts[i].y + 1); diff --git a/client/Windows/wf_interface.c b/client/Windows/wf_interface.c index 7a0cb6d03..6eca6cab9 100644 --- a/client/Windows/wf_interface.c +++ b/client/Windows/wf_interface.c @@ -263,18 +263,16 @@ BOOL wf_pre_connect(freerdp* instance) { if (settings->UseMultimon) { - settings->DesktopWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN); - settings->DesktopHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN); + desktopWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN); + desktopHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN); } else { - settings->DesktopWidth = GetSystemMetrics(SM_CXSCREEN); - settings->DesktopHeight = GetSystemMetrics(SM_CYSCREEN); + desktopWidth = GetSystemMetrics(SM_CXSCREEN); + desktopHeight = GetSystemMetrics(SM_CYSCREEN); } } - desktopWidth = (desktopWidth + 3) & (~3); - if (desktopWidth != settings->DesktopWidth) { freerdp_set_param_uint32(settings, FreeRDP_DesktopWidth, desktopWidth); @@ -446,6 +444,7 @@ BOOL wf_post_connect(freerdp* instance) freerdp_channels_post_connect(instance->context->channels, instance); wf_cliprdr_init(wfc, instance->context->channels); + floatbar_window_create(wfc); return TRUE; } diff --git a/client/Windows/wf_interface.h b/client/Windows/wf_interface.h index 38d1261c8..b9aa4056c 100644 --- a/client/Windows/wf_interface.h +++ b/client/Windows/wf_interface.h @@ -37,6 +37,7 @@ #include #include +#include "wf_floatbar.h" #include "wf_event.h" #ifdef __cplusplus @@ -132,6 +133,7 @@ struct wf_context int yCurrentScroll; // current vertical scroll value int yMaxScroll; // maximum vertical scroll value cliprdrContext *cliprdr_context; + FloatBar* floatbar; }; typedef struct wf_context wfContext; diff --git a/client/Windows/wfreerdp.rc b/client/Windows/wfreerdp.rc index ef912b2d7..135f64104 100644 Binary files a/client/Windows/wfreerdp.rc and b/client/Windows/wfreerdp.rc differ diff --git a/client/X11/xf_window.c b/client/X11/xf_window.c index b428048a5..5b7c96b17 100644 --- a/client/X11/xf_window.c +++ b/client/X11/xf_window.c @@ -539,8 +539,7 @@ xfWindow* xf_CreateWindow(xfContext* xfc, rdpWindow* wnd, int x, int y, int widt window->handle = XCreateWindow(xfc->display, RootWindowOfScreen(xfc->screen), x, y, window->width, window->height, 0, xfc->depth, InputOutput, xfc->visual, - CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap | - CWBorderPixel | CWWinGravity | CWBitGravity, &xfc->attribs); + 0, &xfc->attribs); DEBUG_X11_LMS("Create window=0x%X rc={l=%d t=%d r=%d b=%d} w=%d h=%d rdp=0x%X", (UINT32) window->handle, window->left, window->top, window->right, window->bottom, diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index e72022eb3..d2168b39e 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -866,8 +866,7 @@ void tls_print_certificate_name_mismatch_error(char* hostname, char* common_name int index; assert(NULL != hostname); - assert(NULL != common_name); - + fprintf(stderr, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); fprintf(stderr, "@ WARNING: CERTIFICATE NAME MISMATCH! @\n"); fprintf(stderr, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); @@ -875,17 +874,14 @@ void tls_print_certificate_name_mismatch_error(char* hostname, char* common_name fprintf(stderr, "does not match %s given in the certificate:\n", alt_names_count < 1 ? "the name" : "any of the names"); fprintf(stderr, "Common Name (CN):\n"); fprintf(stderr, "\t%s\n", common_name ? common_name : "no CN found in certificate"); - if (alt_names_count > 1) + if (alt_names_count > 0) { assert(NULL != alt_names); fprintf(stderr, "Alternative names:\n"); - if (alt_names_count > 1) + for (index = 0; index < alt_names_count; index++) { - for (index = 0; index < alt_names_count; index++) - { - assert(alt_names[index]); - fprintf(stderr, "\t %s\n", alt_names[index]); - } + assert(alt_names[index]); + fprintf(stderr, "\t %s\n", alt_names[index]); } } fprintf(stderr, "A valid certificate for the wrong name should NOT be trusted!\n"); diff --git a/winpr/libwinpr/environment/environment.c b/winpr/libwinpr/environment/environment.c index 7e998e998..e56c0b1e2 100644 --- a/winpr/libwinpr/environment/environment.c +++ b/winpr/libwinpr/environment/environment.c @@ -165,48 +165,57 @@ DWORD GetEnvironmentVariableA(LPCSTR lpName, LPSTR lpBuffer, DWORD nSize) DWORD GetEnvironmentVariableEBA(LPCSTR envBlock, LPCSTR lpName, LPSTR lpBuffer, DWORD nSize) { - int length; + int vLength = 0; char* env = NULL; const char * penvb = envBlock; char *foundEquals; + int nLength, fLength, lpNameLength; + + if (!lpName || NULL == envBlock) + return 0; + + lpNameLength = strlen(lpName); + if (0 == lpNameLength) + return 0; while (*penvb && *(penvb+1)) { - length = strlen(penvb); + fLength = strlen(penvb); foundEquals = strstr(penvb,"="); - if (foundEquals == NULL) { + if (foundEquals == NULL) + { + /* if no = sign is found the envBlock is broken */ + return 0; + } + nLength = foundEquals - penvb; + if (nLength != lpNameLength) + { + penvb += (fLength +1); continue; } #ifdef _WIN32 - if (strnicmp(penvb,lpName,foundEquals - penvb) == 0) { + if (strnicmp(penvb,lpName,nLength) == 0) #else - if (strncmp(penvb,lpName,foundEquals - penvb) == 0) { + if (strncmp(penvb,lpName,nLength) == 0) #endif - if (*(penvb + (foundEquals - penvb)) == '=') { - // found variable ... - if (foundEquals == NULL) { - return 0; - } else { - env = foundEquals + 1; - break; - } - } + { + env = foundEquals + 1; + break; } - penvb += (length +1); + penvb += (fLength +1); } - if (!env) return 0; - length = strlen(env); + vLength = strlen(env); - if ((length + 1 > nSize) || (!lpBuffer)) - return length + 1; + if ((vLength + 1 > nSize) || (!lpBuffer)) + return vLength + 1; - CopyMemory(lpBuffer, env, length + 1); + CopyMemory(lpBuffer, env, vLength + 1); - return length; + return vLength; } @@ -252,33 +261,23 @@ BOOL SetEnvironmentVariableEBA(LPSTR * envBlock,LPCSTR lpName, LPCSTR lpValue) if (lpValue) { - - length = strlen(lpName) + strlen(lpValue) + 1; - envstr = (char*) malloc(length + 1); - sprintf_s(envstr, length + 1, "%s=%s", lpName, lpValue); - envstr[length] = '\0'; - - newEB = MergeEnvironmentStrings((LPCSTR)*envBlock,envstr); - free(envstr); - if (*envBlock != NULL) - free(*envBlock); - *envBlock = newEB; - return TRUE; + length = strlen(lpName) + strlen(lpValue) + 2; /* +2 because of = and \0 */ + envstr = (char*) malloc(length + 1); /* +1 because of closing \0 */ + sprintf_s(envstr, length, "%s=%s", lpName, lpValue); } else { - length = strlen(lpName) + 1; - envstr = (char*) malloc(length + 1); - sprintf_s(envstr, length + 1, "%s=", lpName); - envstr[length] = '\0'; - - newEB = MergeEnvironmentStrings((LPCSTR)*envBlock,envstr); - free(envstr); - if (*envBlock != NULL) - free(*envBlock); - *envBlock = newEB; - return TRUE; + length = strlen(lpName) + 2; /* +2 because of = and \0 */ + envstr = (char*) malloc(length + 1); /* +1 because of closing \0 */ + sprintf_s(envstr, length, "%s=", lpName); } + envstr[length] = '\0'; + newEB = MergeEnvironmentStrings((LPCSTR)*envBlock,envstr); + free(envstr); + if (*envBlock != NULL) + free(*envBlock); + *envBlock = newEB; + return TRUE; } @@ -364,6 +363,7 @@ LPCH MergeEnvironmentStrings(PCSTR original, PCSTR merge) // first build an char ** of the merge env strings mergeStrings = (LPCSTR*) malloc(mergeArraySize * sizeof(char *)); + ZeroMemory(mergeStrings,mergeArraySize * sizeof(char *)); mergeStringLenth = 0; cp = merge; diff --git a/winpr/libwinpr/environment/test/TestEnvironmentGetSetEB.c b/winpr/libwinpr/environment/test/TestEnvironmentGetSetEB.c index dbf248a6a..4e27f8e41 100644 --- a/winpr/libwinpr/environment/test/TestEnvironmentGetSetEB.c +++ b/winpr/libwinpr/environment/test/TestEnvironmentGetSetEB.c @@ -13,8 +13,12 @@ int TestEnvironmentGetSetEB(int argc, char* argv[]) LPTCH lpszEnvironmentBlock = "SHELL=123\0test=1\0test1=2\0DISPLAY=WINPR_TEST_VALUE\0\0"; LPTCH lpszEnvironmentBlockNew = NULL; + /* Get length of an variable */ length = GetEnvironmentVariableEBA(lpszEnvironmentBlock,"DISPLAY", NULL, 0); + if (0 == length) + return -1; + /* Get the variable itself */ p = (LPSTR) malloc(length); length = GetEnvironmentVariableEBA(lpszEnvironmentBlock,"DISPLAY", p, length); @@ -22,14 +26,47 @@ int TestEnvironmentGetSetEB(int argc, char* argv[]) if (strcmp(p, "WINPR_TEST_VALUE") != 0) { + free(p); return -1; } free(p); - lpszEnvironmentBlockNew = (LPTCH) malloc(1024); - memcpy(lpszEnvironmentBlockNew,lpszEnvironmentBlock,56); + /* Get length of an non-existing variable */ + length = GetEnvironmentVariableEBA(lpszEnvironmentBlock,"BLA", NULL, 0); + if (0 != length) + { + printf("Unset variable returned\n"); + return -1; + } + /* Get length of an similar called variables */ + length = GetEnvironmentVariableEBA(lpszEnvironmentBlock,"XDISPLAY", NULL, 0); + if (0 != length) + { + printf("Similar named variable returned (XDISPLAY, length %d)\n", length); + return -1; + } + length = GetEnvironmentVariableEBA(lpszEnvironmentBlock,"DISPLAYX", NULL, 0); + if (0 != length) + { + printf("Similar named variable returned (DISPLAYX, length %d)\n", length); + return -1; + } + length = GetEnvironmentVariableEBA(lpszEnvironmentBlock,"DISPLA", NULL, 0); + if (0 != length) + { + printf("Similar named variable returned (DISPLA, length %d)\n", length); + return -1; + } + length = GetEnvironmentVariableEBA(lpszEnvironmentBlock,"ISPLAY", NULL, 0); + if (0 != length) + { + printf("Similar named variable returned (ISPLAY, length %d)\n", length); + return -1; + } + + /* Set variable in empty environment block */ if (SetEnvironmentVariableEBA(&lpszEnvironmentBlockNew, "test", "5")) { if (GetEnvironmentVariableEBA(lpszEnvironmentBlockNew,"test", test, 1023)) @@ -44,13 +81,12 @@ int TestEnvironmentGetSetEB(int argc, char* argv[]) return -1; } } - - //free(lpszEnvironmentBlockNew); - + /* Clear variable */ if (SetEnvironmentVariableEBA(&lpszEnvironmentBlockNew, "test", NULL)) { if (GetEnvironmentVariableEBA(lpszEnvironmentBlockNew,"test", test, 1023)) { + free(lpszEnvironmentBlockNew); return -1; } else @@ -58,6 +94,34 @@ int TestEnvironmentGetSetEB(int argc, char* argv[]) // not found .. this is expected } } + free(lpszEnvironmentBlockNew); + + lpszEnvironmentBlockNew = (LPTCH) malloc(1024); + memcpy(lpszEnvironmentBlockNew,lpszEnvironmentBlock,56); + + /* Set variable in empty environment block */ + if (SetEnvironmentVariableEBA(&lpszEnvironmentBlockNew, "test", "5")) + { + if (0 != GetEnvironmentVariableEBA(lpszEnvironmentBlockNew,"testr", test, 1023)) + { + printf("GetEnvironmentVariableEBA returned unset variable\n"); + free(lpszEnvironmentBlockNew); + return -1; + } + if (GetEnvironmentVariableEBA(lpszEnvironmentBlockNew,"test", test, 1023)) + { + if (strcmp(test,"5") != 0) + { + free(lpszEnvironmentBlockNew); + return -1; + } + } + else + { + free(lpszEnvironmentBlockNew); + return -1; + } + } free(lpszEnvironmentBlockNew); #endif diff --git a/winpr/libwinpr/thread/process.c b/winpr/libwinpr/thread/process.c index d3945f28e..f6cdb24f6 100644 --- a/winpr/libwinpr/thread/process.c +++ b/winpr/libwinpr/thread/process.c @@ -251,6 +251,10 @@ BOOL _CreateProcessExA(HANDLE hToken, DWORD dwLogonFlags, if (token->UserId) setuid((uid_t) token->UserId); + + /* TODO: add better cwd handling and error checking */ + if (lpCurrentDirectory && strlen(lpCurrentDirectory) > 0) + chdir(lpCurrentDirectory); } if (execve(filename, pArgs, envp) < 0)