Merge branch 'master' of github.com:FreeRDP/FreeRDP
@ -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()
|
||||
|
@ -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.");
|
||||
|
41
channels/audin/client/winmm/CMakeLists.txt
Normal file
@ -0,0 +1,41 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP cmake build script
|
||||
#
|
||||
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
#
|
||||
# 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")
|
309
channels/audin/client/winmm/audin_winmm.c
Normal file
@ -0,0 +1,309 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Audio Input Redirection Virtual Channel - WinMM implementation
|
||||
*
|
||||
* Copyright 2013 Zhang Zhaolong <zhangzl2013@126.com>
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <Windows.h>
|
||||
#include <MMSystem.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/cmdline.h>
|
||||
#include <freerdp/addin.h>
|
||||
|
||||
#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, "<device>", 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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -33,6 +33,15 @@
|
||||
#include <freerdp/constants.h>
|
||||
#include <freerdp/channels/rdpdr.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <dbt.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
BIN
client/Windows/resource/bg.bmp
Normal file
After Width: | Height: | Size: 49 KiB |
BIN
client/Windows/resource/close.bmp
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
client/Windows/resource/close_active.bmp
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
client/Windows/resource/lock.bmp
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
client/Windows/resource/lock_active.bmp
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
client/Windows/resource/minimize.bmp
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
client/Windows/resource/minimize_active.bmp
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
client/Windows/resource/restore.bmp
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
client/Windows/resource/restore_active.bmp
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
client/Windows/resource/unlock.bmp
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
client/Windows/resource/unlock_active.bmp
Normal file
After Width: | Height: | Size: 1.7 KiB |
466
client/Windows/wf_floatbar.c
Normal file
@ -0,0 +1,466 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Windows Float Bar
|
||||
*
|
||||
* Copyright 2013 Zhang Zhaolong <zhangzl2013@126.com>
|
||||
*
|
||||
* 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 <Windows.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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);
|
||||
}
|
30
client/Windows/wf_floatbar.h
Normal file
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Windows Float Bar
|
||||
*
|
||||
* Copyright 2013 Zhang Zhaolong <zhangzl2013@126.com>
|
||||
*
|
||||
* 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
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include <freerdp/codec/nsc.h>
|
||||
#include <freerdp/client/file.h>
|
||||
|
||||
#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;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|