Merge pull request #2148 from awakecoding/master
Virtual Channel System Improvement
This commit is contained in:
commit
4c455b8a40
@ -48,9 +48,17 @@ typedef BOOL (*psPeerLogon)(freerdp_peer* client, SEC_WINNT_AUTH_IDENTITY* ident
|
||||
typedef int (*psPeerSendChannelData)(freerdp_peer* client, UINT16 channelId, BYTE* data, int size);
|
||||
typedef int (*psPeerReceiveChannelData)(freerdp_peer* client, UINT16 channelId, BYTE* data, int size, int flags, int totalSize);
|
||||
|
||||
typedef HANDLE (*psPeerVirtualChannelOpen)(freerdp_peer* client, const char* name, UINT32 flags);
|
||||
typedef BOOL (*psPeerVirtualChannelClose)(freerdp_peer* client, HANDLE hChannel);
|
||||
typedef int (*psPeerVirtualChannelRead)(freerdp_peer* client, HANDLE hChannel, BYTE* buffer, UINT32 length);
|
||||
typedef int (*psPeerVirtualChannelWrite)(freerdp_peer* client, HANDLE hChannel, BYTE* buffer, UINT32 length);
|
||||
typedef void* (*psPeerVirtualChannelGetData)(freerdp_peer* client, HANDLE hChannel);
|
||||
typedef int (*psPeerVirtualChannelSetData)(freerdp_peer* client, HANDLE hChannel, void* data);
|
||||
|
||||
struct rdp_freerdp_peer
|
||||
{
|
||||
rdpContext* context;
|
||||
|
||||
int sockfd;
|
||||
char hostname[50];
|
||||
|
||||
@ -79,6 +87,13 @@ struct rdp_freerdp_peer
|
||||
psPeerSendChannelData SendChannelData;
|
||||
psPeerReceiveChannelData ReceiveChannelData;
|
||||
|
||||
psPeerVirtualChannelOpen VirtualChannelOpen;
|
||||
psPeerVirtualChannelClose VirtualChannelClose;
|
||||
psPeerVirtualChannelRead VirtualChannelRead;
|
||||
psPeerVirtualChannelWrite VirtualChannelWrite;
|
||||
psPeerVirtualChannelGetData VirtualChannelGetData;
|
||||
psPeerVirtualChannelSetData VirtualChannelSetData;
|
||||
|
||||
int pId;
|
||||
UINT32 ack_frame_id;
|
||||
BOOL local;
|
||||
|
@ -2332,15 +2332,15 @@ int freerdp_image24_copy(BYTE* pDstData, DWORD DstFormat, int nDstStep, int nXDs
|
||||
dstFlip = FREERDP_PIXEL_FORMAT_FLIP(DstFormat);
|
||||
dstType = FREERDP_PIXEL_FORMAT_TYPE(DstFormat);
|
||||
|
||||
nSrcPad = (nSrcStep - (nWidth * srcBytesPerPixel));
|
||||
nDstPad = (nDstStep - (nWidth * dstBytesPerPixel));
|
||||
|
||||
if (nSrcStep < 0)
|
||||
nSrcStep = srcBytesPerPixel * nWidth;
|
||||
|
||||
if (nDstStep < 0)
|
||||
nDstStep = dstBytesPerPixel * nWidth;
|
||||
|
||||
nSrcPad = (nSrcStep - (nWidth * srcBytesPerPixel));
|
||||
nDstPad = (nDstStep - (nWidth * dstBytesPerPixel));
|
||||
|
||||
if (srcFlip != dstFlip)
|
||||
vFlip = TRUE;
|
||||
|
||||
@ -2448,7 +2448,83 @@ int freerdp_image24_copy(BYTE* pDstData, DWORD DstFormat, int nDstStep, int nXDs
|
||||
}
|
||||
else if (dstBytesPerPixel == 3)
|
||||
{
|
||||
BYTE* pSrcPixel;
|
||||
BYTE* pDstPixel;
|
||||
|
||||
if (!invert)
|
||||
{
|
||||
if (!vFlip)
|
||||
{
|
||||
pSrcPixel = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 3)];
|
||||
pDstPixel = &pDstData[(nYDst * nDstStep) + (nXDst * 3)];
|
||||
|
||||
for (y = 0; y < nHeight; y++)
|
||||
{
|
||||
CopyMemory(pDstPixel, pSrcPixel, nWidth * 3);
|
||||
pSrcPixel = &pSrcPixel[nSrcStep];
|
||||
pDstPixel = &pDstPixel[nDstStep];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pSrcPixel = &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + (nXSrc * 3)];
|
||||
pDstPixel = &pDstData[(nYDst * nDstStep) + (nXDst * 3)];
|
||||
|
||||
for (y = 0; y < nHeight; y++)
|
||||
{
|
||||
CopyMemory(pDstPixel, pSrcPixel, nWidth * 3);
|
||||
pSrcPixel = &pSrcPixel[-nSrcStep];
|
||||
pDstPixel = &pDstPixel[nDstStep];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!vFlip)
|
||||
{
|
||||
pSrcPixel = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 3)];
|
||||
pDstPixel = &pDstData[(nYDst * nDstStep) + (nXDst * 3)];
|
||||
|
||||
for (y = 0; y < nHeight; y++)
|
||||
{
|
||||
for (x = 0; x < nWidth; x++)
|
||||
{
|
||||
pDstPixel[0] = pSrcPixel[2];
|
||||
pDstPixel[1] = pSrcPixel[1];
|
||||
pDstPixel[2] = pSrcPixel[0];
|
||||
|
||||
pSrcPixel += 3;
|
||||
pDstPixel += 3;
|
||||
}
|
||||
|
||||
pSrcPixel = &pSrcPixel[nSrcPad];
|
||||
pDstPixel = &pDstPixel[nDstPad];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pSrcPixel = &pSrcData[((nYSrc + nHeight - 1) * nSrcStep) + (nXSrc * 3)];
|
||||
pDstPixel = &pDstData[(nYDst * nDstStep) + (nXDst * 3)];
|
||||
|
||||
for (y = 0; y < nHeight; y++)
|
||||
{
|
||||
for (x = 0; x < nWidth; x++)
|
||||
{
|
||||
pDstPixel[0] = pSrcPixel[2];
|
||||
pDstPixel[1] = pSrcPixel[1];
|
||||
pDstPixel[2] = pSrcPixel[0];
|
||||
|
||||
pSrcPixel += 3;
|
||||
pDstPixel += 3;
|
||||
}
|
||||
|
||||
pSrcPixel = &pSrcPixel[-((nSrcStep - nSrcPad) + nSrcStep)];
|
||||
pDstPixel = &pDstPixel[nDstPad];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
else if (dstBytesPerPixel == 2)
|
||||
{
|
||||
|
@ -265,11 +265,13 @@ int interleaved_decompress(BITMAP_INTERLEAVED_CONTEXT* interleaved, BYTE* pSrcDa
|
||||
|
||||
SrcFormat = PIXEL_FORMAT_RGB24_VF;
|
||||
|
||||
#if 0
|
||||
if ((SrcFormat == DstFormat) && !nXDst && !nYDst && (scanline == nDstStep))
|
||||
{
|
||||
RleDecompress24to24(pSrcData, SrcSize, pDstData, scanline, nWidth, nHeight);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (BufferSize > interleaved->TempSize)
|
||||
{
|
||||
@ -292,11 +294,13 @@ int interleaved_decompress(BITMAP_INTERLEAVED_CONTEXT* interleaved, BYTE* pSrcDa
|
||||
|
||||
SrcFormat = (bpp == 16) ? PIXEL_FORMAT_RGB16_VF : PIXEL_FORMAT_RGB15_VF;
|
||||
|
||||
#if 0
|
||||
if ((SrcFormat == DstFormat) && !nXDst && !nYDst && (scanline == nDstStep))
|
||||
{
|
||||
RleDecompress16to16(pSrcData, SrcSize, pDstData, scanline, nWidth, nHeight);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (BufferSize > interleaved->TempSize)
|
||||
{
|
||||
@ -319,11 +323,13 @@ int interleaved_decompress(BITMAP_INTERLEAVED_CONTEXT* interleaved, BYTE* pSrcDa
|
||||
|
||||
SrcFormat = PIXEL_FORMAT_RGB8_VF;
|
||||
|
||||
#if 0
|
||||
if ((SrcFormat == DstFormat) && !nXDst && !nYDst && (scanline == nDstStep))
|
||||
{
|
||||
RleDecompress8to8(pSrcData, SrcSize, pDstData, scanline, nWidth, nHeight);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (BufferSize > interleaved->TempSize)
|
||||
{
|
||||
|
@ -143,8 +143,36 @@ BOOL freerdp_channel_peer_process(freerdp_peer* client, wStream* s, UINT16 chann
|
||||
Stream_Read_UINT32(s, flags);
|
||||
chunkLength = Stream_GetRemainingLength(s);
|
||||
|
||||
IFCALL(client->ReceiveChannelData, client,
|
||||
channelId, Stream_Pointer(s), chunkLength, flags, length);
|
||||
if (client->VirtualChannelRead)
|
||||
{
|
||||
UINT32 index;
|
||||
BOOL found = FALSE;
|
||||
HANDLE hChannel = 0;
|
||||
rdpContext* context = client->context;
|
||||
rdpMcs* mcs = context->rdp->mcs;
|
||||
rdpMcsChannel* mcsChannel = NULL;
|
||||
|
||||
for (index = 0; index < mcs->channelCount; index++)
|
||||
{
|
||||
mcsChannel = &(mcs->channels[index]);
|
||||
|
||||
if (mcsChannel->ChannelId == channelId)
|
||||
{
|
||||
hChannel = (HANDLE) mcsChannel->handle;
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
return FALSE;
|
||||
|
||||
client->VirtualChannelRead(client, hChannel, Stream_Pointer(s), Stream_GetRemainingLength(s));
|
||||
}
|
||||
else if (client->ReceiveChannelData)
|
||||
{
|
||||
client->ReceiveChannelData(client, channelId, Stream_Pointer(s), chunkLength, flags, length);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -1059,7 +1059,8 @@ rdpMcs* mcs_new(rdpTransport* transport)
|
||||
{
|
||||
rdpMcs* mcs;
|
||||
|
||||
mcs = (rdpMcs *)calloc(1, sizeof(rdpMcs));
|
||||
mcs = (rdpMcs*) calloc(1, sizeof(rdpMcs));
|
||||
|
||||
if (!mcs)
|
||||
return NULL;
|
||||
|
||||
@ -1073,7 +1074,11 @@ rdpMcs* mcs_new(rdpTransport* transport)
|
||||
|
||||
mcs->channelCount = 0;
|
||||
mcs->channelMaxCount = CHANNEL_MAX_COUNT;
|
||||
mcs->channels = (rdpMcsChannel *)calloc(mcs->channelMaxCount, sizeof(rdpMcsChannel));
|
||||
|
||||
mcs->baseChannelId = MCS_GLOBAL_CHANNEL_ID + 1;
|
||||
|
||||
mcs->channels = (rdpMcsChannel*) calloc(mcs->channelMaxCount, sizeof(rdpMcsChannel));
|
||||
|
||||
if (!mcs->channels)
|
||||
goto out_free;
|
||||
|
||||
|
@ -139,6 +139,7 @@ struct rdp_mcs
|
||||
rdpSettings* settings;
|
||||
|
||||
UINT16 userId;
|
||||
UINT16 baseChannelId;
|
||||
UINT16 messageChannelId;
|
||||
|
||||
DomainParameters domainParameters;
|
||||
|
@ -37,6 +37,161 @@
|
||||
extern const char* DATA_PDU_TYPE_STRINGS[80];
|
||||
#endif
|
||||
|
||||
static HANDLE freerdp_peer_virtual_channel_open(freerdp_peer* client, const char* name, UINT32 flags)
|
||||
{
|
||||
int length;
|
||||
UINT32 index;
|
||||
BOOL joined = FALSE;
|
||||
rdpMcsChannel* mcsChannel = NULL;
|
||||
rdpPeerChannel* peerChannel = NULL;
|
||||
rdpMcs* mcs = client->context->rdp->mcs;
|
||||
|
||||
if (flags & WTS_CHANNEL_OPTION_DYNAMIC)
|
||||
return NULL; /* not yet supported */
|
||||
|
||||
length = strlen(name);
|
||||
|
||||
if (length > 8)
|
||||
return NULL; /* SVC maximum name length is 8 */
|
||||
|
||||
for (index = 0; index < mcs->channelCount; index++)
|
||||
{
|
||||
mcsChannel = &(mcs->channels[index]);
|
||||
|
||||
if (!mcsChannel->joined)
|
||||
continue;
|
||||
|
||||
if (strncmp(name, mcsChannel->Name, length) == 0)
|
||||
{
|
||||
joined = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!joined)
|
||||
return NULL; /* channel is not joined */
|
||||
|
||||
peerChannel = (rdpPeerChannel*) mcsChannel->handle;
|
||||
|
||||
if (peerChannel)
|
||||
{
|
||||
/* channel is already open */
|
||||
return (HANDLE) peerChannel;
|
||||
}
|
||||
|
||||
peerChannel = (rdpPeerChannel*) calloc(1, sizeof(rdpPeerChannel));
|
||||
|
||||
if (peerChannel)
|
||||
{
|
||||
peerChannel->index = index;
|
||||
peerChannel->client = client;
|
||||
peerChannel->channelFlags = flags;
|
||||
peerChannel->channelId = mcsChannel->ChannelId;
|
||||
peerChannel->mcsChannel = mcsChannel;
|
||||
mcsChannel->handle = (void*) peerChannel;
|
||||
}
|
||||
|
||||
return (HANDLE) peerChannel;
|
||||
}
|
||||
|
||||
static BOOL freerdp_peer_virtual_channel_close(freerdp_peer* client, HANDLE hChannel)
|
||||
{
|
||||
rdpMcsChannel* mcsChannel = NULL;
|
||||
rdpPeerChannel* peerChannel = NULL;
|
||||
|
||||
if (!hChannel)
|
||||
return FALSE;
|
||||
|
||||
peerChannel = (rdpPeerChannel*) hChannel;
|
||||
mcsChannel = peerChannel->mcsChannel;
|
||||
|
||||
mcsChannel->handle = NULL;
|
||||
free(peerChannel);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int freerdp_peer_virtual_channel_read(freerdp_peer* client, HANDLE hChannel, BYTE* buffer, UINT32 length)
|
||||
{
|
||||
return 0; /* this needs to be implemented by the server application */
|
||||
}
|
||||
|
||||
static int freerdp_peer_virtual_channel_write(freerdp_peer* client, HANDLE hChannel, BYTE* buffer, UINT32 length)
|
||||
{
|
||||
wStream* s;
|
||||
UINT32 flags;
|
||||
UINT32 chunkSize;
|
||||
UINT32 maxChunkSize;
|
||||
UINT32 totalLength;
|
||||
rdpRdp* rdp = client->context->rdp;
|
||||
rdpPeerChannel* peerChannel = (rdpPeerChannel*) hChannel;
|
||||
rdpMcsChannel* mcsChannel = peerChannel->mcsChannel;
|
||||
|
||||
if (!hChannel)
|
||||
return -1;
|
||||
|
||||
if (peerChannel->channelFlags & WTS_CHANNEL_OPTION_DYNAMIC)
|
||||
return -1; /* not yet supported */
|
||||
|
||||
maxChunkSize = rdp->settings->VirtualChannelChunkSize;
|
||||
|
||||
totalLength = length;
|
||||
flags = CHANNEL_FLAG_FIRST;
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
s = rdp_send_stream_init(rdp);
|
||||
|
||||
if (length > maxChunkSize)
|
||||
{
|
||||
chunkSize = rdp->settings->VirtualChannelChunkSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
chunkSize = length;
|
||||
flags |= CHANNEL_FLAG_LAST;
|
||||
}
|
||||
|
||||
if (mcsChannel->options & CHANNEL_OPTION_SHOW_PROTOCOL)
|
||||
flags |= CHANNEL_FLAG_SHOW_PROTOCOL;
|
||||
|
||||
Stream_Write_UINT32(s, totalLength);
|
||||
Stream_Write_UINT32(s, flags);
|
||||
Stream_EnsureRemainingCapacity(s, chunkSize);
|
||||
Stream_Write(s, buffer, chunkSize);
|
||||
|
||||
rdp_send(rdp, s, peerChannel->channelId);
|
||||
|
||||
buffer += chunkSize;
|
||||
length -= chunkSize;
|
||||
flags = 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void* freerdp_peer_virtual_channel_get_data(freerdp_peer* client, HANDLE hChannel)
|
||||
{
|
||||
rdpPeerChannel* peerChannel = (rdpPeerChannel*) hChannel;
|
||||
|
||||
if (!hChannel)
|
||||
return NULL;
|
||||
|
||||
return peerChannel->extra;
|
||||
}
|
||||
|
||||
int freerdp_peer_virtual_channel_set_data(freerdp_peer* client, HANDLE hChannel, void* data)
|
||||
{
|
||||
rdpPeerChannel* peerChannel = (rdpPeerChannel*) hChannel;
|
||||
|
||||
if (!hChannel)
|
||||
return -1;
|
||||
|
||||
peerChannel->extra = data;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static BOOL freerdp_peer_initialize(freerdp_peer* client)
|
||||
{
|
||||
rdpRdp* rdp = client->context->rdp;
|
||||
@ -427,8 +582,7 @@ static BOOL freerdp_peer_is_write_blocked(freerdp_peer* peer)
|
||||
|
||||
static int freerdp_peer_drain_output_buffer(freerdp_peer* peer)
|
||||
{
|
||||
|
||||
rdpTransport *transport = peer->context->rdp->transport;
|
||||
rdpTransport* transport = peer->context->rdp->transport;
|
||||
|
||||
return tranport_drain_output_buffer(transport);
|
||||
}
|
||||
@ -500,6 +654,12 @@ freerdp_peer* freerdp_peer_new(int sockfd)
|
||||
client->SendChannelData = freerdp_peer_send_channel_data;
|
||||
client->IsWriteBlocked = freerdp_peer_is_write_blocked;
|
||||
client->DrainOutputBuffer = freerdp_peer_drain_output_buffer;
|
||||
client->VirtualChannelOpen = freerdp_peer_virtual_channel_open;
|
||||
client->VirtualChannelClose = freerdp_peer_virtual_channel_close;
|
||||
client->VirtualChannelWrite = freerdp_peer_virtual_channel_write;
|
||||
client->VirtualChannelRead = NULL; /* must be defined by server application */
|
||||
client->VirtualChannelGetData = freerdp_peer_virtual_channel_get_data;
|
||||
client->VirtualChannelSetData = freerdp_peer_virtual_channel_set_data;
|
||||
}
|
||||
|
||||
return client;
|
||||
|
@ -21,6 +21,9 @@
|
||||
#define __PEER
|
||||
|
||||
#include "rdp.h"
|
||||
#include "mcs.h"
|
||||
#include "server.h"
|
||||
|
||||
#include <freerdp/peer.h>
|
||||
|
||||
#endif /* __PEER */
|
||||
|
@ -296,30 +296,30 @@ static void wts_read_drdynvc_pdu(rdpPeerChannel* channel)
|
||||
}
|
||||
}
|
||||
|
||||
static int wts_write_variable_uint(wStream* stream, UINT32 val)
|
||||
static int wts_write_variable_uint(wStream* s, UINT32 val)
|
||||
{
|
||||
int cb;
|
||||
|
||||
if (val <= 0xFF)
|
||||
{
|
||||
cb = 0;
|
||||
Stream_Write_UINT8(stream, val);
|
||||
Stream_Write_UINT8(s, val);
|
||||
}
|
||||
else if (val <= 0xFFFF)
|
||||
{
|
||||
cb = 1;
|
||||
Stream_Write_UINT16(stream, val);
|
||||
Stream_Write_UINT16(s, val);
|
||||
}
|
||||
else
|
||||
{
|
||||
cb = 2;
|
||||
Stream_Write_UINT32(stream, val);
|
||||
Stream_Write_UINT32(s, val);
|
||||
}
|
||||
|
||||
return cb;
|
||||
}
|
||||
|
||||
static void wts_write_drdynvc_header(wStream *s, BYTE Cmd, UINT32 ChannelId)
|
||||
static void wts_write_drdynvc_header(wStream* s, BYTE Cmd, UINT32 ChannelId)
|
||||
{
|
||||
BYTE* bm;
|
||||
int cbChId;
|
||||
@ -477,9 +477,10 @@ HANDLE WTSVirtualChannelManagerGetEventHandle(HANDLE hServer)
|
||||
return MessageQueue_Event(vcm->queue);
|
||||
}
|
||||
|
||||
static rdpMcsChannel* wts_get_joined_channel_by_name(rdpMcs *mcs, const char *channel_name)
|
||||
static rdpMcsChannel* wts_get_joined_channel_by_name(rdpMcs* mcs, const char* channel_name)
|
||||
{
|
||||
UINT32 index;
|
||||
|
||||
if (!mcs || !channel_name || !strlen(channel_name))
|
||||
return NULL;
|
||||
|
||||
@ -489,14 +490,16 @@ static rdpMcsChannel* wts_get_joined_channel_by_name(rdpMcs *mcs, const char *ch
|
||||
{
|
||||
if (_strnicmp(mcs->channels[index].Name, channel_name, strlen(channel_name)) == 0)
|
||||
return &mcs->channels[index];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static rdpMcsChannel* wts_get_joined_channel_by_id(rdpMcs *mcs, const UINT16 channel_id)
|
||||
static rdpMcsChannel* wts_get_joined_channel_by_id(rdpMcs* mcs, const UINT16 channel_id)
|
||||
{
|
||||
UINT32 index;
|
||||
|
||||
if (!mcs || !channel_id)
|
||||
return NULL;
|
||||
|
||||
@ -506,12 +509,13 @@ static rdpMcsChannel* wts_get_joined_channel_by_id(rdpMcs *mcs, const UINT16 cha
|
||||
{
|
||||
if (mcs->channels[index].ChannelId == channel_id)
|
||||
return &mcs->channels[index];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BOOL WTSIsChannelJoinedByName(freerdp_peer *client, const char *channel_name)
|
||||
BOOL WTSIsChannelJoinedByName(freerdp_peer* client, const char* channel_name)
|
||||
{
|
||||
if (!client || !client->context || !client->context->rdp)
|
||||
return FALSE;
|
||||
@ -519,7 +523,7 @@ BOOL WTSIsChannelJoinedByName(freerdp_peer *client, const char *channel_name)
|
||||
return wts_get_joined_channel_by_name(client->context->rdp->mcs, channel_name) == NULL ? FALSE : TRUE;
|
||||
}
|
||||
|
||||
BOOL WTSIsChannelJoinedById(freerdp_peer *client, const UINT16 channel_id)
|
||||
BOOL WTSIsChannelJoinedById(freerdp_peer* client, const UINT16 channel_id)
|
||||
{
|
||||
if (!client || !client->context || !client->context->rdp)
|
||||
return FALSE;
|
||||
@ -537,27 +541,30 @@ BOOL WTSVirtualChannelManagerIsChannelJoined(HANDLE hServer, const char* name)
|
||||
return wts_get_joined_channel_by_name(vcm->rdp->mcs, name) == NULL ? FALSE : TRUE;
|
||||
}
|
||||
|
||||
UINT16 WTSChannelGetId(freerdp_peer *client, const char *channel_name)
|
||||
UINT16 WTSChannelGetId(freerdp_peer* client, const char* channel_name)
|
||||
{
|
||||
rdpMcsChannel *channel;
|
||||
rdpMcsChannel* channel;
|
||||
|
||||
if (!client || !client->context || !client->context->rdp)
|
||||
return 0;
|
||||
|
||||
channel = wts_get_joined_channel_by_name(client->context->rdp->mcs, channel_name);
|
||||
|
||||
if (!channel)
|
||||
return 0;
|
||||
|
||||
return channel->ChannelId;
|
||||
}
|
||||
|
||||
BOOL WTSChannelSetHandleByName(freerdp_peer *client, const char *channel_name, void *handle)
|
||||
BOOL WTSChannelSetHandleByName(freerdp_peer* client, const char* channel_name, void* handle)
|
||||
{
|
||||
rdpMcsChannel *channel;
|
||||
rdpMcsChannel* channel;
|
||||
|
||||
if (!client || !client->context || !client->context->rdp)
|
||||
return FALSE;
|
||||
|
||||
channel = wts_get_joined_channel_by_name(client->context->rdp->mcs, channel_name);
|
||||
|
||||
if (!channel)
|
||||
return FALSE;
|
||||
|
||||
@ -565,13 +572,15 @@ BOOL WTSChannelSetHandleByName(freerdp_peer *client, const char *channel_name, v
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL WTSChannelSetHandleById(freerdp_peer *client, const UINT16 channel_id, void *handle)
|
||||
BOOL WTSChannelSetHandleById(freerdp_peer* client, const UINT16 channel_id, void* handle)
|
||||
{
|
||||
rdpMcsChannel *channel;
|
||||
rdpMcsChannel* channel;
|
||||
|
||||
if (!client || !client->context || !client->context->rdp)
|
||||
return FALSE;
|
||||
|
||||
channel = wts_get_joined_channel_by_id(client->context->rdp->mcs, channel_id);
|
||||
|
||||
if (!channel)
|
||||
return FALSE;
|
||||
|
||||
@ -579,26 +588,30 @@ BOOL WTSChannelSetHandleById(freerdp_peer *client, const UINT16 channel_id, void
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void *WTSChannelGetHandleByName(freerdp_peer *client, const char *channel_name)
|
||||
void* WTSChannelGetHandleByName(freerdp_peer* client, const char *channel_name)
|
||||
{
|
||||
rdpMcsChannel *channel;
|
||||
rdpMcsChannel* channel;
|
||||
|
||||
if (!client || !client->context || !client->context->rdp)
|
||||
return NULL;
|
||||
|
||||
channel = wts_get_joined_channel_by_name(client->context->rdp->mcs, channel_name);
|
||||
|
||||
if (!channel)
|
||||
return NULL;
|
||||
|
||||
return channel->handle;
|
||||
}
|
||||
|
||||
void *WTSChannelGetHandleById(freerdp_peer *client, const UINT16 channel_id)
|
||||
void* WTSChannelGetHandleById(freerdp_peer* client, const UINT16 channel_id)
|
||||
{
|
||||
rdpMcsChannel *channel;
|
||||
rdpMcsChannel* channel;
|
||||
|
||||
if (!client || !client->context || !client->context->rdp)
|
||||
return NULL;
|
||||
|
||||
channel = wts_get_joined_channel_by_id(client->context->rdp->mcs, channel_id);
|
||||
|
||||
if (!channel)
|
||||
return NULL;
|
||||
|
||||
@ -1054,15 +1067,18 @@ BOOL WINAPI FreeRDP_WTSVirtualChannelRead(HANDLE hChannelHandle, ULONG TimeOut,
|
||||
buffer = (BYTE*) (messageCtx + 1);
|
||||
|
||||
*pBytesRead = messageCtx->length - messageCtx->offset;
|
||||
|
||||
if (Buffer == NULL || BufferSize == 0)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (*pBytesRead > BufferSize)
|
||||
*pBytesRead = BufferSize;
|
||||
|
||||
CopyMemory(Buffer, buffer + messageCtx->offset, *pBytesRead);
|
||||
messageCtx->offset += *pBytesRead;
|
||||
|
||||
if (messageCtx->offset >= messageCtx->length)
|
||||
{
|
||||
MessageQueue_Peek(channel->queue, &message, TRUE);
|
||||
|
@ -28,9 +28,11 @@
|
||||
#include <winpr/stream.h>
|
||||
#include <winpr/collections.h>
|
||||
|
||||
typedef struct rdp_peer_channel rdpPeerChannel;
|
||||
typedef struct WTSVirtualChannelManager WTSVirtualChannelManager;
|
||||
|
||||
#include "rdp.h"
|
||||
#include "mcs.h"
|
||||
|
||||
#define CREATE_REQUEST_PDU 0x01
|
||||
#define DATA_FIRST_PDU 0x02
|
||||
@ -59,22 +61,23 @@ enum
|
||||
DVC_OPEN_STATE_CLOSED = 3
|
||||
};
|
||||
|
||||
typedef struct rdp_peer_channel rdpPeerChannel;
|
||||
|
||||
struct rdp_peer_channel
|
||||
{
|
||||
WTSVirtualChannelManager* vcm;
|
||||
freerdp_peer* client;
|
||||
|
||||
void* extra;
|
||||
UINT16 index;
|
||||
UINT32 channelId;
|
||||
UINT16 channelType;
|
||||
UINT16 index;
|
||||
UINT32 channelFlags;
|
||||
|
||||
wStream* receiveData;
|
||||
wMessageQueue* queue;
|
||||
|
||||
BYTE dvc_open_state;
|
||||
UINT32 dvc_total_length;
|
||||
rdpMcsChannel* mcsChannel;
|
||||
};
|
||||
|
||||
struct WTSVirtualChannelManager
|
||||
|
@ -42,8 +42,8 @@ extern "C" {
|
||||
|
||||
/* Engine */
|
||||
|
||||
rdtkEngine* rdtk_engine_new();
|
||||
void rdtk_engine_free(rdtkEngine* engine);
|
||||
RDTK_EXPORT rdtkEngine* rdtk_engine_new();
|
||||
RDTK_EXPORT void rdtk_engine_free(rdtkEngine* engine);
|
||||
|
||||
/* Surface */
|
||||
|
||||
|
@ -138,6 +138,7 @@ typedef struct _wArrayList wArrayList;
|
||||
|
||||
WINPR_API int ArrayList_Capacity(wArrayList* arrayList);
|
||||
WINPR_API int ArrayList_Count(wArrayList* arrayList);
|
||||
WINPR_API int ArrayList_Items(wArrayList* arrayList, ULONG_PTR** ppItems);
|
||||
WINPR_API BOOL ArrayList_IsFixedSized(wArrayList* arrayList);
|
||||
WINPR_API BOOL ArrayList_IsReadOnly(wArrayList* arrayList);
|
||||
WINPR_API BOOL ArrayList_IsSynchronized(wArrayList* arrayList);
|
||||
@ -326,27 +327,33 @@ WINPR_API void CountdownEvent_Free(wCountdownEvent* countdown);
|
||||
|
||||
/* Hash Table */
|
||||
|
||||
typedef void (*KEY_VALUE_FREE_FN)(void* context, void* key, void* value);
|
||||
typedef UINT32 (*HASH_TABLE_HASH_FN)(void* key);
|
||||
typedef BOOL (*HASH_TABLE_KEY_COMPARE_FN)(void* key1, void* key2);
|
||||
typedef BOOL (*HASH_TABLE_VALUE_COMPARE_FN)(void* value1, void* value2);
|
||||
typedef void* (*HASH_TABLE_KEY_CLONE_FN)(void* key);
|
||||
typedef void* (*HASH_TABLE_VALUE_CLONE_FN)(void* value);
|
||||
typedef void (*HASH_TABLE_KEY_FREE_FN)(void* key);
|
||||
typedef void (*HASH_TABLE_VALUE_FREE_FN)(void* value);
|
||||
|
||||
struct _wHashTable
|
||||
{
|
||||
BOOL synchronized;
|
||||
CRITICAL_SECTION lock;
|
||||
|
||||
long numOfBuckets;
|
||||
long numOfElements;
|
||||
int numOfBuckets;
|
||||
int numOfElements;
|
||||
float idealRatio;
|
||||
float lowerRehashThreshold;
|
||||
float upperRehashThreshold;
|
||||
wKeyValuePair** bucketArray;
|
||||
int (*keycmp)(void* key1, void* key2);
|
||||
int (*valuecmp)(void* value1, void* value2);
|
||||
unsigned long (*hashFunction)(void* key);
|
||||
void (*keyDeallocator)(void* key);
|
||||
void (*valueDeallocator)(void* value);
|
||||
|
||||
void* context;
|
||||
KEY_VALUE_FREE_FN pfnKeyValueFree;
|
||||
HASH_TABLE_HASH_FN hash;
|
||||
HASH_TABLE_KEY_COMPARE_FN keyCompare;
|
||||
HASH_TABLE_VALUE_COMPARE_FN valueCompare;
|
||||
HASH_TABLE_KEY_CLONE_FN keyClone;
|
||||
HASH_TABLE_VALUE_CLONE_FN valueClone;
|
||||
HASH_TABLE_KEY_FREE_FN keyFree;
|
||||
HASH_TABLE_VALUE_FREE_FN valueFree;
|
||||
};
|
||||
typedef struct _wHashTable wHashTable;
|
||||
|
||||
@ -359,9 +366,16 @@ WINPR_API BOOL HashTable_ContainsKey(wHashTable* table, void* key);
|
||||
WINPR_API BOOL HashTable_ContainsValue(wHashTable* table, void* value);
|
||||
WINPR_API void* HashTable_GetItemValue(wHashTable* table, void* key);
|
||||
WINPR_API BOOL HashTable_SetItemValue(wHashTable* table, void* key, void* value);
|
||||
WINPR_API void HashTable_SetFreeFunction(wHashTable* table, void* context, KEY_VALUE_FREE_FN pfnKeyValueFree);
|
||||
WINPR_API int HashTable_GetKeys(wHashTable* table, ULONG_PTR** ppKeys);
|
||||
|
||||
WINPR_API UINT32 HashTable_PointerHash(void* pointer);
|
||||
WINPR_API BOOL HashTable_PointerCompare(void* pointer1, void* pointer2);
|
||||
|
||||
WINPR_API UINT32 HashTable_StringHash(void* key);
|
||||
WINPR_API BOOL HashTable_StringCompare(void* string1, void* string2);
|
||||
WINPR_API void* HashTable_StringClone(void* str);
|
||||
WINPR_API void HashTable_StringFree(void* str);
|
||||
|
||||
WINPR_API wHashTable* HashTable_New(BOOL synchronized);
|
||||
WINPR_API void HashTable_Free(wHashTable* table);
|
||||
|
||||
|
@ -73,16 +73,10 @@ WINPR_API DWORD ExpandEnvironmentStringsW(LPCWSTR lpSrc, LPWSTR lpDst, DWORD nSi
|
||||
WINPR_API BOOL FreeEnvironmentStringsA(LPCH lpszEnvironmentBlock);
|
||||
WINPR_API BOOL FreeEnvironmentStringsW(LPWCH lpszEnvironmentBlock);
|
||||
|
||||
WINPR_API LPCH MergeEnvironmentStrings(PCSTR original, PCSTR merge);
|
||||
|
||||
WINPR_API DWORD GetEnvironmentVariableEBA(LPCSTR envBlock, LPCSTR lpName, LPSTR lpBuffer, DWORD nSize);
|
||||
WINPR_API BOOL SetEnvironmentVariableEBA(LPSTR * envBlock,LPCSTR lpName, LPCSTR lpValue);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef UNICODE
|
||||
#define GetCurrentDirectory GetCurrentDirectoryW
|
||||
#define SetCurrentDirectory SetCurrentDirectoryW
|
||||
@ -111,5 +105,18 @@ WINPR_API BOOL SetEnvironmentVariableEBA(LPSTR * envBlock,LPCSTR lpName, LPCSTR
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
WINPR_API LPCH MergeEnvironmentStrings(PCSTR original, PCSTR merge);
|
||||
|
||||
WINPR_API DWORD GetEnvironmentVariableEBA(LPCSTR envBlock, LPCSTR lpName, LPSTR lpBuffer, DWORD nSize);
|
||||
WINPR_API BOOL SetEnvironmentVariableEBA(LPSTR* envBlock, LPCSTR lpName, LPCSTR lpValue);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* WINPR_ENVIRONMENT_H */
|
||||
|
||||
|
@ -33,6 +33,9 @@ extern "C" {
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#define DUPLICATE_CLOSE_SOURCE 0x00000001
|
||||
#define DUPLICATE_SAME_ACCESS 0x00000002
|
||||
|
||||
#define HANDLE_FLAG_INHERIT 0x00000001
|
||||
#define HANDLE_FLAG_PROTECT_FROM_CLOSE 0x00000002
|
||||
|
||||
|
@ -58,14 +58,20 @@ typedef struct _wIniFile wIniFile;
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
WINPR_API int IniFile_Parse(wIniFile* ini, const char* filename);
|
||||
WINPR_API int IniFile_ParseString(wIniFile* ini, const char* iniString);
|
||||
WINPR_API int IniFile_ReadBuffer(wIniFile* ini, const char* buffer);
|
||||
WINPR_API int IniFile_ReadFile(wIniFile* ini, const char* filename);
|
||||
|
||||
WINPR_API char* IniFile_WriteBuffer(wIniFile* ini);
|
||||
WINPR_API int IniFile_WriteFile(wIniFile* ini, const char* filename);
|
||||
|
||||
WINPR_API char** IniFile_GetSectionNames(wIniFile* ini, int* count);
|
||||
WINPR_API char** IniFile_GetSectionKeyNames(wIniFile* ini, const char* section, int* count);
|
||||
|
||||
WINPR_API char* IniFile_GetKeyValueString(wIniFile* ini, const char* section, const char* key);
|
||||
WINPR_API UINT32 IniFile_GetKeyValueInt(wIniFile* ini, const char* section, const char* key);
|
||||
WINPR_API const char* IniFile_GetKeyValueString(wIniFile* ini, const char* section, const char* key);
|
||||
WINPR_API int IniFile_GetKeyValueInt(wIniFile* ini, const char* section, const char* key);
|
||||
|
||||
WINPR_API int IniFile_SetKeyValueString(wIniFile* ini, const char* section, const char* key, const char* value);
|
||||
WINPR_API int IniFile_SetKeyValueInt(wIniFile* ini, const char* section, const char* key, int value);
|
||||
|
||||
WINPR_API wIniFile* IniFile_New();
|
||||
WINPR_API void IniFile_Free(wIniFile* ini);
|
||||
|
@ -73,24 +73,6 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
#ifdef __GNUC__
|
||||
#define DECLSPEC_EXPORT __attribute__((dllexport))
|
||||
#define DECLSPEC_IMPORT __attribute__((dllimport))
|
||||
#else
|
||||
#define DECLSPEC_EXPORT __declspec(dllexport)
|
||||
#define DECLSPEC_IMPORT __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#if defined(__GNUC__) && __GNUC__ >= 4
|
||||
#define DECLSPEC_EXPORT __attribute__ ((visibility("default")))
|
||||
#define DECLSPEC_IMPORT
|
||||
#else
|
||||
#define DECLSPEC_EXPORT
|
||||
#define DECLSPEC_IMPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef DECLSPEC_NORETURN
|
||||
#if (defined(__GNUC__) || defined(_MSC_VER) || defined(__clang__))
|
||||
#define DECLSPEC_NORETURN __declspec(noreturn)
|
||||
@ -971,5 +953,23 @@ char (*__countof_helper(_CountofType (&_Array)[_SizeOfArray]))[_SizeOfArray];
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
#ifdef __GNUC__
|
||||
#define DECLSPEC_EXPORT __attribute__((dllexport))
|
||||
#define DECLSPEC_IMPORT __attribute__((dllimport))
|
||||
#else
|
||||
#define DECLSPEC_EXPORT __declspec(dllexport)
|
||||
#define DECLSPEC_IMPORT __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#if defined(__GNUC__) && __GNUC__ >= 4
|
||||
#define DECLSPEC_EXPORT __attribute__ ((visibility("default")))
|
||||
#define DECLSPEC_IMPORT
|
||||
#else
|
||||
#define DECLSPEC_EXPORT
|
||||
#define DECLSPEC_IMPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* WINPR_SPEC_H */
|
||||
|
||||
|
@ -71,6 +71,7 @@ PCSTR inet_ntop(INT Family, PVOID pAddr, PSTR pStringBuf, size_t StringBufSize);
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include <winpr/error.h>
|
||||
@ -79,6 +80,10 @@ PCSTR inet_ntop(INT Family, PVOID pAddr, PSTR pStringBuf, size_t StringBufSize);
|
||||
typedef UINT_PTR SOCKET;
|
||||
typedef struct sockaddr_storage SOCKADDR_STORAGE;
|
||||
|
||||
#ifndef INVALID_SOCKET
|
||||
#define INVALID_SOCKET (SOCKET)(~0)
|
||||
#endif
|
||||
|
||||
#define WSADESCRIPTION_LEN 256
|
||||
#define WSASYS_STATUS_LEN 128
|
||||
|
||||
|
@ -410,8 +410,6 @@ typedef struct tagWTSSESSION_NOTIFICATION
|
||||
#define WTS_SESSION_LOCK 0x7
|
||||
#define WTS_SESSION_UNLOCK 0x8
|
||||
#define WTS_SESSION_REMOTE_CONTROL 0x9
|
||||
#define WTS_SESSION_CREATE 0xA
|
||||
#define WTS_SESSION_TERMINATE 0xB
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -453,10 +451,12 @@ WINPR_API HWND WINAPI CreateWindowExW(DWORD dwExStyle, LPCWSTR lpClassName,
|
||||
LPCWSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight,
|
||||
HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam);
|
||||
|
||||
#ifndef WINPR_NO_CREATE_WINDOW
|
||||
#define CreateWindowA(lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam) \
|
||||
CreateWindowExA(0L, lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam)
|
||||
#define CreateWindowW(lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam) \
|
||||
CreateWindowExW(0L, lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam)
|
||||
#endif
|
||||
|
||||
WINPR_API HWND WINAPI FindWindowA(LPCSTR lpClassName, LPCSTR lpWindowName);
|
||||
WINPR_API HWND WINAPI FindWindowW(LPCWSTR lpClassName, LPCWSTR lpWindowName);
|
||||
@ -519,7 +519,9 @@ WINPR_API LRESULT WINAPI DefWindowProcW(HWND hWnd, UINT Msg, WPARAM wParam, LPAR
|
||||
#define RegisterClass RegisterClassW
|
||||
#define RegisterClassEx RegisterClassExW
|
||||
#define UnregisterClass UnregisterClassW
|
||||
#ifndef WINPR_NO_CREATE_WINDOW
|
||||
#define CreateWindow CreateWindowW
|
||||
#endif
|
||||
#define CreateWindowEx CreateWindowExW
|
||||
#define FindWindow FindWindowW
|
||||
#define FindWindowEx FindWindowExW
|
||||
@ -540,7 +542,9 @@ WINPR_API LRESULT WINAPI DefWindowProcW(HWND hWnd, UINT Msg, WPARAM wParam, LPAR
|
||||
#define RegisterClass RegisterClassA
|
||||
#define RegisterClassEx RegisterClassExA
|
||||
#define UnregisterClass UnregisterClassA
|
||||
#ifndef WINPR_NO_CREATE_WINDOW
|
||||
#define CreateWindow CreateWindowA
|
||||
#endif
|
||||
#define CreateWindowEx CreateWindowExA
|
||||
#define FindWindow FindWindowA
|
||||
#define FindWindowEx FindWindowExA
|
||||
@ -561,5 +565,13 @@ WINPR_API LRESULT WINAPI DefWindowProcW(HWND hWnd, UINT Msg, WPARAM wParam, LPAR
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef WTS_SESSION_CREATE
|
||||
#define WTS_SESSION_CREATE 0xA
|
||||
#endif
|
||||
|
||||
#ifndef WTS_SESSION_TERMINATE
|
||||
#define WTS_SESSION_TERMINATE 0xB
|
||||
#endif
|
||||
|
||||
#endif /* WINPR_WND_H */
|
||||
|
||||
|
@ -167,63 +167,6 @@ DWORD GetEnvironmentVariableA(LPCSTR lpName, LPSTR lpBuffer, DWORD nSize)
|
||||
return length;
|
||||
}
|
||||
|
||||
DWORD GetEnvironmentVariableEBA(LPCSTR envBlock, LPCSTR lpName, LPSTR lpBuffer, DWORD nSize)
|
||||
{
|
||||
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))
|
||||
{
|
||||
fLength = strlen(penvb);
|
||||
foundEquals = strstr(penvb,"=");
|
||||
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,nLength) == 0)
|
||||
#else
|
||||
if (strncmp(penvb,lpName,nLength) == 0)
|
||||
#endif
|
||||
{
|
||||
env = foundEquals + 1;
|
||||
break;
|
||||
}
|
||||
penvb += (fLength +1);
|
||||
}
|
||||
|
||||
if (!env)
|
||||
return 0;
|
||||
|
||||
vLength = strlen(env);
|
||||
|
||||
if ((vLength + 1 > nSize) || (!lpBuffer))
|
||||
return vLength + 1;
|
||||
|
||||
CopyMemory(lpBuffer, env, vLength + 1);
|
||||
|
||||
return vLength;
|
||||
}
|
||||
|
||||
|
||||
|
||||
DWORD GetEnvironmentVariableW(LPCWSTR lpName, LPWSTR lpBuffer, DWORD nSize)
|
||||
{
|
||||
return 0;
|
||||
@ -248,38 +191,6 @@ BOOL SetEnvironmentVariableA(LPCSTR lpName, LPCSTR lpValue)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL SetEnvironmentVariableEBA(LPSTR * envBlock,LPCSTR lpName, LPCSTR lpValue)
|
||||
{
|
||||
int length;
|
||||
char* envstr;
|
||||
char* newEB;
|
||||
|
||||
|
||||
if (!lpName)
|
||||
return FALSE;
|
||||
|
||||
if (lpValue)
|
||||
{
|
||||
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) + 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;
|
||||
}
|
||||
|
||||
|
||||
BOOL SetEnvironmentVariableW(LPCWSTR lpName, LPCWSTR lpValue)
|
||||
{
|
||||
return TRUE;
|
||||
@ -342,137 +253,6 @@ LPCH GetEnvironmentStrings(VOID)
|
||||
return lpszEnvironmentBlock;
|
||||
}
|
||||
|
||||
LPCH MergeEnvironmentStrings(PCSTR original, PCSTR merge)
|
||||
{
|
||||
|
||||
const char * cp;
|
||||
char* p;
|
||||
int offset;
|
||||
int length;
|
||||
const char* envp;
|
||||
DWORD cchEnvironmentBlock;
|
||||
LPCH lpszEnvironmentBlock;
|
||||
const char **mergeStrings;
|
||||
int mergeStringLenth;
|
||||
int mergeArraySize = 128;
|
||||
int run;
|
||||
int mergeLength;
|
||||
int foundMerge;
|
||||
char * foundEquals;
|
||||
// first build an char ** of the merge env strings
|
||||
|
||||
mergeStrings = (LPCSTR*) malloc(mergeArraySize * sizeof(char *));
|
||||
ZeroMemory(mergeStrings,mergeArraySize * sizeof(char *));
|
||||
mergeStringLenth = 0;
|
||||
|
||||
cp = merge;
|
||||
while( *cp && *(cp+1)) {
|
||||
length = strlen(cp);
|
||||
if (mergeStringLenth == mergeArraySize ) {
|
||||
mergeArraySize += 128;
|
||||
mergeStrings = (LPCSTR*) realloc(mergeStrings, mergeArraySize * sizeof(char *));
|
||||
|
||||
}
|
||||
mergeStrings[mergeStringLenth] = cp;
|
||||
cp += length + 1;
|
||||
mergeStringLenth++;
|
||||
}
|
||||
|
||||
offset = 0;
|
||||
|
||||
cchEnvironmentBlock = 128;
|
||||
lpszEnvironmentBlock = (LPCH) malloc(cchEnvironmentBlock * sizeof(CHAR));
|
||||
|
||||
envp = original;
|
||||
|
||||
while ((original != NULL) && (*envp && *(envp+1)))
|
||||
{
|
||||
length = strlen(envp);
|
||||
|
||||
while ((offset + length + 8) > cchEnvironmentBlock)
|
||||
{
|
||||
cchEnvironmentBlock *= 2;
|
||||
lpszEnvironmentBlock = (LPCH) realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR));
|
||||
}
|
||||
|
||||
p = &(lpszEnvironmentBlock[offset]);
|
||||
|
||||
// check if this value is in the mergeStrings
|
||||
foundMerge = 0;
|
||||
for (run = 0; run < mergeStringLenth; run ++) {
|
||||
if (mergeStrings[run] == NULL) {
|
||||
continue;
|
||||
}
|
||||
mergeLength =strlen(mergeStrings[run]);
|
||||
foundEquals = strstr(mergeStrings[run],"=");
|
||||
if (foundEquals == NULL) {
|
||||
continue;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
if (strnicmp(envp,mergeStrings[run],foundEquals - mergeStrings[run] + 1) == 0) {
|
||||
#else
|
||||
if (strncmp(envp,mergeStrings[run],foundEquals - mergeStrings[run] + 1) == 0) {
|
||||
#endif
|
||||
// found variable in merge list ... use this ....
|
||||
if (*(foundEquals + 1) == '\0') {
|
||||
// check if the argument is set ... if not remove variable ...
|
||||
foundMerge = 1;
|
||||
} else {
|
||||
|
||||
while ((offset + mergeLength + 8) > cchEnvironmentBlock)
|
||||
{
|
||||
cchEnvironmentBlock *= 2;
|
||||
lpszEnvironmentBlock = (LPCH) realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR));
|
||||
}
|
||||
foundMerge = 1;
|
||||
CopyMemory(p, mergeStrings[run], mergeLength);
|
||||
mergeStrings[run] = NULL;
|
||||
p[mergeLength] = '\0';
|
||||
offset += (mergeLength + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (foundMerge == 0) {
|
||||
CopyMemory(p, envp, length * sizeof(CHAR));
|
||||
p[length] = '\0';
|
||||
offset += (length + 1);
|
||||
}
|
||||
envp += (length +1);
|
||||
}
|
||||
|
||||
// now merge the not already merged env
|
||||
for (run = 0; run < mergeStringLenth; run ++) {
|
||||
if (mergeStrings[run] == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
mergeLength =strlen(mergeStrings[run]);
|
||||
|
||||
while ((offset + mergeLength + 8) > cchEnvironmentBlock)
|
||||
{
|
||||
cchEnvironmentBlock *= 2;
|
||||
lpszEnvironmentBlock = (LPCH) realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR));
|
||||
}
|
||||
|
||||
p = &(lpszEnvironmentBlock[offset]);
|
||||
|
||||
CopyMemory(p, mergeStrings[run], mergeLength);
|
||||
mergeStrings[run] = NULL;
|
||||
p[mergeLength] = '\0';
|
||||
offset += (mergeLength + 1);
|
||||
}
|
||||
|
||||
|
||||
lpszEnvironmentBlock[offset] = '\0';
|
||||
|
||||
free(mergeStrings);
|
||||
|
||||
return lpszEnvironmentBlock;
|
||||
}
|
||||
|
||||
|
||||
LPWCH GetEnvironmentStringsW(VOID)
|
||||
{
|
||||
return NULL;
|
||||
@ -513,3 +293,256 @@ BOOL FreeEnvironmentStringsW(LPWCH lpszEnvironmentBlock)
|
||||
|
||||
#endif
|
||||
|
||||
LPCH MergeEnvironmentStrings(PCSTR original, PCSTR merge)
|
||||
{
|
||||
const char* cp;
|
||||
char* p;
|
||||
int offset;
|
||||
int length;
|
||||
const char* envp;
|
||||
DWORD cchEnvironmentBlock;
|
||||
LPCH lpszEnvironmentBlock;
|
||||
const char** mergeStrings;
|
||||
int mergeStringLength;
|
||||
int mergeArraySize = 128;
|
||||
int run;
|
||||
int mergeLength;
|
||||
int foundMerge;
|
||||
char* foundEquals;
|
||||
|
||||
mergeStrings = (LPCSTR*) calloc(mergeArraySize, sizeof(char*));
|
||||
|
||||
if (!mergeStrings)
|
||||
return NULL;
|
||||
|
||||
mergeStringLength = 0;
|
||||
|
||||
cp = merge;
|
||||
|
||||
while (*cp && *(cp + 1))
|
||||
{
|
||||
length = strlen(cp);
|
||||
|
||||
if (mergeStringLength == mergeArraySize)
|
||||
{
|
||||
mergeArraySize += 128;
|
||||
mergeStrings = (LPCSTR*) realloc(mergeStrings, mergeArraySize * sizeof(char*));
|
||||
|
||||
if (!mergeStrings)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mergeStrings[mergeStringLength] = cp;
|
||||
cp += length + 1;
|
||||
mergeStringLength++;
|
||||
}
|
||||
|
||||
offset = 0;
|
||||
|
||||
cchEnvironmentBlock = 128;
|
||||
lpszEnvironmentBlock = (LPCH) malloc(cchEnvironmentBlock * sizeof(CHAR));
|
||||
|
||||
if (!lpszEnvironmentBlock)
|
||||
return NULL;
|
||||
|
||||
envp = original;
|
||||
|
||||
while ((original != NULL) && (*envp && *(envp+1)))
|
||||
{
|
||||
length = strlen(envp);
|
||||
|
||||
while ((offset + length + 8) > cchEnvironmentBlock)
|
||||
{
|
||||
cchEnvironmentBlock *= 2;
|
||||
lpszEnvironmentBlock = (LPCH) realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR));
|
||||
|
||||
if (!lpszEnvironmentBlock)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = &(lpszEnvironmentBlock[offset]);
|
||||
|
||||
// check if this value is in the mergeStrings
|
||||
foundMerge = 0;
|
||||
|
||||
for (run = 0; run < mergeStringLength; run ++)
|
||||
{
|
||||
if (!mergeStrings[run])
|
||||
continue;
|
||||
|
||||
mergeLength = strlen(mergeStrings[run]);
|
||||
foundEquals = strstr(mergeStrings[run], "=");
|
||||
|
||||
if (!foundEquals)
|
||||
continue;
|
||||
|
||||
if (strncmp(envp, mergeStrings[run], foundEquals - mergeStrings[run] + 1) == 0)
|
||||
{
|
||||
// found variable in merge list ... use this ....
|
||||
if (*(foundEquals + 1) == '\0')
|
||||
{
|
||||
// check if the argument is set ... if not remove variable ...
|
||||
foundMerge = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
while ((offset + mergeLength + 8) > cchEnvironmentBlock)
|
||||
{
|
||||
cchEnvironmentBlock *= 2;
|
||||
lpszEnvironmentBlock = (LPCH) realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR));
|
||||
|
||||
if (!lpszEnvironmentBlock)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
foundMerge = 1;
|
||||
CopyMemory(p, mergeStrings[run], mergeLength);
|
||||
mergeStrings[run] = NULL;
|
||||
p[mergeLength] = '\0';
|
||||
offset += (mergeLength + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (foundMerge == 0)
|
||||
{
|
||||
CopyMemory(p, envp, length * sizeof(CHAR));
|
||||
p[length] = '\0';
|
||||
offset += (length + 1);
|
||||
}
|
||||
|
||||
envp += (length +1);
|
||||
}
|
||||
|
||||
// now merge the not already merged env
|
||||
for (run = 0; run < mergeStringLength; run ++)
|
||||
{
|
||||
if (!mergeStrings[run])
|
||||
continue;
|
||||
|
||||
mergeLength = strlen(mergeStrings[run]);
|
||||
|
||||
while ((offset + mergeLength + 8) > cchEnvironmentBlock)
|
||||
{
|
||||
cchEnvironmentBlock *= 2;
|
||||
lpszEnvironmentBlock = (LPCH) realloc(lpszEnvironmentBlock, cchEnvironmentBlock * sizeof(CHAR));
|
||||
|
||||
if (!lpszEnvironmentBlock)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = &(lpszEnvironmentBlock[offset]);
|
||||
|
||||
CopyMemory(p, mergeStrings[run], mergeLength);
|
||||
mergeStrings[run] = NULL;
|
||||
p[mergeLength] = '\0';
|
||||
offset += (mergeLength + 1);
|
||||
}
|
||||
|
||||
lpszEnvironmentBlock[offset] = '\0';
|
||||
|
||||
free(mergeStrings);
|
||||
|
||||
return lpszEnvironmentBlock;
|
||||
}
|
||||
|
||||
DWORD GetEnvironmentVariableEBA(LPCSTR envBlock, LPCSTR lpName, LPSTR lpBuffer, DWORD nSize)
|
||||
{
|
||||
int vLength = 0;
|
||||
char* env = NULL;
|
||||
char* foundEquals;
|
||||
const char* penvb = envBlock;
|
||||
int nLength, fLength, lpNameLength;
|
||||
|
||||
if (!lpName || NULL == envBlock)
|
||||
return 0;
|
||||
|
||||
lpNameLength = strlen(lpName);
|
||||
|
||||
if (lpNameLength < 1)
|
||||
return 0;
|
||||
|
||||
while (*penvb && *(penvb + 1))
|
||||
{
|
||||
fLength = strlen(penvb);
|
||||
foundEquals = strstr(penvb,"=");
|
||||
|
||||
if (!foundEquals)
|
||||
{
|
||||
/* if no = sign is found the envBlock is broken */
|
||||
return 0;
|
||||
}
|
||||
|
||||
nLength = foundEquals - penvb;
|
||||
|
||||
if (nLength != lpNameLength)
|
||||
{
|
||||
penvb += (fLength +1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(penvb, lpName, nLength) == 0)
|
||||
{
|
||||
env = foundEquals + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
penvb += (fLength +1);
|
||||
}
|
||||
|
||||
if (!env)
|
||||
return 0;
|
||||
|
||||
vLength = strlen(env);
|
||||
|
||||
if ((vLength + 1 > nSize) || (!lpBuffer))
|
||||
return vLength + 1;
|
||||
|
||||
CopyMemory(lpBuffer, env, vLength + 1);
|
||||
|
||||
return vLength;
|
||||
}
|
||||
|
||||
BOOL SetEnvironmentVariableEBA(LPSTR* envBlock, LPCSTR lpName, LPCSTR lpValue)
|
||||
{
|
||||
int length;
|
||||
char* envstr;
|
||||
char* newEB;
|
||||
|
||||
if (!lpName)
|
||||
return FALSE;
|
||||
|
||||
if (lpValue)
|
||||
{
|
||||
length = strlen(lpName) + strlen(lpValue) + 2; /* +2 because of = and \0 */
|
||||
envstr = (char*) malloc(length + 1); /* +1 because of closing \0 */
|
||||
|
||||
if (!envstr)
|
||||
return FALSE;
|
||||
|
||||
sprintf_s(envstr, length, "%s=%s", lpName, lpValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
length = strlen(lpName) + 2; /* +2 because of = and \0 */
|
||||
envstr = (char*) malloc(length + 1); /* +1 because of closing \0 */
|
||||
|
||||
if (!envstr)
|
||||
return FALSE;
|
||||
|
||||
sprintf_s(envstr, length, "%s=", lpName);
|
||||
}
|
||||
|
||||
envstr[length] = '\0';
|
||||
|
||||
newEB = MergeEnvironmentStrings((LPCSTR) *envBlock, envstr);
|
||||
|
||||
free(envstr);
|
||||
|
||||
if (*envBlock)
|
||||
free(*envBlock);
|
||||
|
||||
*envBlock = newEB;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -276,8 +276,9 @@ BOOL CloseHandle(HANDLE hObject)
|
||||
}
|
||||
|
||||
BOOL DuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle,
|
||||
LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions)
|
||||
LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions)
|
||||
{
|
||||
*((ULONG_PTR*) lpTargetHandle) = hSourceHandle;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -366,6 +366,8 @@ typedef NTSTATUS (WINAPI * NT_DEVICE_IO_CONTROL_FILE_FN)(HANDLE FileHandle, HAND
|
||||
|
||||
typedef NTSTATUS (WINAPI * NT_CLOSE_FN)(HANDLE Handle);
|
||||
|
||||
typedef NTSTATUS (WINAPI * NT_WAIT_FOR_SINGLE_OBJECT_FN)(HANDLE Handle, BOOLEAN Alertable, PLARGE_INTEGER Timeout);
|
||||
|
||||
static RTL_INIT_ANSI_STRING_FN pRtlInitAnsiString = NULL;
|
||||
static RTL_INIT_UNICODE_STRING_FN pRtlInitUnicodeString = NULL;
|
||||
static RTL_ANSI_STRING_TO_UNICODE_STRING_FN pRtlAnsiStringToUnicodeString = NULL;
|
||||
@ -377,6 +379,7 @@ static NT_READ_FILE_FN pNtReadFile = NULL;
|
||||
static NT_WRITE_FILE_FN pNtWriteFile = NULL;
|
||||
static NT_DEVICE_IO_CONTROL_FILE_FN pNtDeviceIoControlFile = NULL;
|
||||
static NT_CLOSE_FN pNtClose = NULL;
|
||||
static NT_WAIT_FOR_SINGLE_OBJECT_FN pNtWaitForSingleObject = NULL;
|
||||
|
||||
static void NtdllModuleInit()
|
||||
{
|
||||
@ -402,6 +405,7 @@ static void NtdllModuleInit()
|
||||
pNtWriteFile = (NT_WRITE_FILE_FN) GetProcAddress(NtdllModule, "NtWriteFile");
|
||||
pNtDeviceIoControlFile = (NT_DEVICE_IO_CONTROL_FILE_FN) GetProcAddress(NtdllModule, "NtDeviceIoControlFile");
|
||||
pNtClose = (NT_CLOSE_FN) GetProcAddress(NtdllModule, "NtClose");
|
||||
pNtWaitForSingleObject = (NT_WAIT_FOR_SINGLE_OBJECT_FN) GetProcAddress(NtdllModule, "NtWaitForSingleObject");
|
||||
}
|
||||
|
||||
VOID _RtlInitAnsiString(PANSI_STRING DestinationString, PCSZ SourceString)
|
||||
@ -533,5 +537,15 @@ NTSTATUS _NtClose(HANDLE Handle)
|
||||
return pNtClose(Handle);
|
||||
}
|
||||
|
||||
NTSTATUS _NtWaitForSingleObject(HANDLE Handle, BOOLEAN Alertable, PLARGE_INTEGER Timeout)
|
||||
{
|
||||
NtdllModuleInit();
|
||||
|
||||
if (!pNtWaitForSingleObject)
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
|
||||
return pNtWaitForSingleObject(Handle, Alertable, Timeout);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -147,15 +147,17 @@ RPC_STATUS RpcStringBindingParseW(RPC_WSTR StringBinding, RPC_WSTR* ObjUuid, RPC
|
||||
|
||||
RPC_STATUS RpcStringFreeA(RPC_CSTR* String)
|
||||
{
|
||||
WLog_ERR(TAG, "Not implemented");
|
||||
free(String);
|
||||
if (String)
|
||||
free(*String);
|
||||
|
||||
return RPC_S_OK;
|
||||
}
|
||||
|
||||
RPC_STATUS RpcStringFreeW(RPC_WSTR* String)
|
||||
{
|
||||
WLog_ERR(TAG, "Not implemented");
|
||||
free(String);
|
||||
if (String)
|
||||
free(*String);
|
||||
|
||||
return RPC_S_OK;
|
||||
}
|
||||
|
||||
|
@ -52,6 +52,16 @@ int ArrayList_Count(wArrayList *arrayList)
|
||||
return arrayList->size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the internal list of items contained in the ArrayList.
|
||||
*/
|
||||
|
||||
int ArrayList_Items(wArrayList* arrayList, ULONG_PTR** ppItems)
|
||||
{
|
||||
*ppItems = (ULONG_PTR*) arrayList->array;
|
||||
return arrayList->size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether the ArrayList has a fixed size.
|
||||
*/
|
||||
|
@ -33,9 +33,50 @@
|
||||
* http://www.pomakis.com/hashtable/hashtable.h
|
||||
*/
|
||||
|
||||
static int isProbablePrime(long oddNumber)
|
||||
BOOL HashTable_PointerCompare(void* pointer1, void* pointer2)
|
||||
{
|
||||
long i;
|
||||
return (pointer1 == pointer2);
|
||||
}
|
||||
|
||||
UINT32 HashTable_PointerHash(void* pointer)
|
||||
{
|
||||
return ((UINT32) (UINT_PTR) pointer) >> 4;
|
||||
}
|
||||
|
||||
BOOL HashTable_StringCompare(void* string1, void* string2)
|
||||
{
|
||||
if (!string1 || !string2)
|
||||
return (string1 == string2);
|
||||
|
||||
return (strcmp((char*) string1, (char*) string2) == 0);
|
||||
}
|
||||
|
||||
UINT32 HashTable_StringHash(void* key)
|
||||
{
|
||||
UINT32 c;
|
||||
UINT32 hash = 5381;
|
||||
BYTE* str = (BYTE*) key;
|
||||
|
||||
/* djb2 algorithm */
|
||||
while ((c = *str++) != '\0')
|
||||
hash = (hash * 33) + c;
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
void* HashTable_StringClone(void* str)
|
||||
{
|
||||
return _strdup((char*) str);
|
||||
}
|
||||
|
||||
void HashTable_StringFree(void* str)
|
||||
{
|
||||
free(str);
|
||||
}
|
||||
|
||||
static int HashTable_IsProbablePrime(int oddNumber)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 3; i < 51; i += 2)
|
||||
{
|
||||
@ -48,55 +89,54 @@ static int isProbablePrime(long oddNumber)
|
||||
return 1; /* maybe */
|
||||
}
|
||||
|
||||
static long calculateIdealNumOfBuckets(wHashTable* table)
|
||||
static long HashTable_CalculateIdealNumOfBuckets(wHashTable* table)
|
||||
{
|
||||
long idealNumOfBuckets = table->numOfElements / ((long) table->idealRatio);
|
||||
int idealNumOfBuckets = table->numOfElements / ((int) table->idealRatio);
|
||||
|
||||
if (idealNumOfBuckets < 5)
|
||||
idealNumOfBuckets = 5;
|
||||
else
|
||||
idealNumOfBuckets |= 0x01;
|
||||
|
||||
while (!isProbablePrime(idealNumOfBuckets))
|
||||
while (!HashTable_IsProbablePrime(idealNumOfBuckets))
|
||||
idealNumOfBuckets += 2;
|
||||
|
||||
return idealNumOfBuckets;
|
||||
}
|
||||
|
||||
void HashTable_Rehash(wHashTable* table, long numOfBuckets)
|
||||
void HashTable_Rehash(wHashTable* table, int numOfBuckets)
|
||||
{
|
||||
int index;
|
||||
long hashValue;
|
||||
UINT32 hashValue;
|
||||
wKeyValuePair* pair;
|
||||
wKeyValuePair* nextPair;
|
||||
wKeyValuePair** newBucketArray;
|
||||
|
||||
if (numOfBuckets == 0)
|
||||
numOfBuckets = calculateIdealNumOfBuckets(table);
|
||||
numOfBuckets = HashTable_CalculateIdealNumOfBuckets(table);
|
||||
|
||||
if (numOfBuckets == table->numOfBuckets)
|
||||
return; /* already the right size! */
|
||||
|
||||
newBucketArray = (wKeyValuePair**) malloc(numOfBuckets * sizeof(wKeyValuePair*));
|
||||
newBucketArray = (wKeyValuePair**) calloc(numOfBuckets, sizeof(wKeyValuePair*));
|
||||
|
||||
if (newBucketArray == NULL)
|
||||
if (!newBucketArray)
|
||||
{
|
||||
/* Couldn't allocate memory for the new array. This isn't a fatal
|
||||
* error; we just can't perform the rehash. */
|
||||
/*
|
||||
* Couldn't allocate memory for the new array.
|
||||
* This isn't a fatal error; we just can't perform the rehash.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
for (index = 0; index < numOfBuckets; index++)
|
||||
newBucketArray[index] = NULL;
|
||||
|
||||
for (index = 0; index < table->numOfBuckets; index++)
|
||||
{
|
||||
pair = table->bucketArray[index];
|
||||
|
||||
while (pair != NULL)
|
||||
while (pair)
|
||||
{
|
||||
nextPair = pair->next;
|
||||
hashValue = table->hashFunction(pair->key) % numOfBuckets;
|
||||
hashValue = table->hash(pair->key) % numOfBuckets;
|
||||
pair->next = newBucketArray[hashValue];
|
||||
newBucketArray[hashValue] = pair;
|
||||
pair = nextPair;
|
||||
@ -116,40 +156,21 @@ void HashTable_SetIdealRatio(wHashTable* table, float idealRatio,
|
||||
table->upperRehashThreshold = upperRehashThreshold;
|
||||
}
|
||||
|
||||
unsigned long HashTable_StringHashFunction(void* key)
|
||||
{
|
||||
int c;
|
||||
unsigned long hash = 5381;
|
||||
unsigned char* str = (unsigned char*) key;
|
||||
|
||||
/* djb2 algorithm */
|
||||
while ((c = *str++) != '\0')
|
||||
hash = (hash * 33) + c;
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
wKeyValuePair* HashTable_Get(wHashTable* table, void* key)
|
||||
{
|
||||
long hashValue = table->hashFunction(key) % table->numOfBuckets;
|
||||
wKeyValuePair* pair = table->bucketArray[hashValue];
|
||||
UINT32 hashValue;
|
||||
wKeyValuePair* pair;
|
||||
|
||||
while (pair != NULL && table->keycmp(key, pair->key) != 0)
|
||||
hashValue = table->hash(key) % table->numOfBuckets;
|
||||
|
||||
pair = table->bucketArray[hashValue];
|
||||
|
||||
while (pair && !table->keyCompare(key, pair->key))
|
||||
pair = pair->next;
|
||||
|
||||
return pair;
|
||||
}
|
||||
|
||||
static int pointercmp(void* pointer1, void* pointer2)
|
||||
{
|
||||
return (pointer1 != pointer2);
|
||||
}
|
||||
|
||||
static unsigned long pointerHashFunction(void* pointer)
|
||||
{
|
||||
return ((unsigned long) pointer) >> 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* C equivalent of the C# Hashtable Class:
|
||||
* http://msdn.microsoft.com/en-us/library/system.collections.hashtable.aspx
|
||||
@ -179,35 +200,51 @@ int HashTable_Count(wHashTable* table)
|
||||
int HashTable_Add(wHashTable* table, void* key, void* value)
|
||||
{
|
||||
int status = 0;
|
||||
long hashValue;
|
||||
UINT32 hashValue;
|
||||
wKeyValuePair* pair;
|
||||
wKeyValuePair* newPair;
|
||||
|
||||
if (!key || !value)
|
||||
return -1;
|
||||
|
||||
if (table->keyClone)
|
||||
{
|
||||
key = table->keyClone(key);
|
||||
|
||||
if (!key)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (table->valueClone)
|
||||
{
|
||||
value = table->valueClone(value);
|
||||
|
||||
if (!value)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (table->synchronized)
|
||||
EnterCriticalSection(&table->lock);
|
||||
|
||||
hashValue = table->hashFunction(key) % table->numOfBuckets;
|
||||
hashValue = table->hash(key) % table->numOfBuckets;
|
||||
pair = table->bucketArray[hashValue];
|
||||
|
||||
while (pair != NULL && table->keycmp(key, pair->key) != 0)
|
||||
while (pair && !table->keyCompare(key, pair->key))
|
||||
pair = pair->next;
|
||||
|
||||
if (pair)
|
||||
{
|
||||
if (pair->key != key)
|
||||
{
|
||||
if (table->keyDeallocator)
|
||||
table->keyDeallocator((void*) pair->key);
|
||||
if (table->keyFree)
|
||||
table->keyFree(pair->key);
|
||||
pair->key = key;
|
||||
}
|
||||
|
||||
if (pair->value != value)
|
||||
{
|
||||
if (table->valueDeallocator)
|
||||
table->valueDeallocator(pair->value);
|
||||
if (table->valueFree)
|
||||
table->valueFree(pair->value);
|
||||
pair->value = value;
|
||||
}
|
||||
}
|
||||
@ -249,15 +286,19 @@ int HashTable_Add(wHashTable* table, void* key, void* value)
|
||||
|
||||
BOOL HashTable_Remove(wHashTable* table, void* key)
|
||||
{
|
||||
UINT32 hashValue;
|
||||
BOOL status = TRUE;
|
||||
long hashValue = table->hashFunction(key) % table->numOfBuckets;
|
||||
wKeyValuePair* pair = table->bucketArray[hashValue];
|
||||
wKeyValuePair* pair = NULL;
|
||||
wKeyValuePair* previousPair = NULL;
|
||||
|
||||
if (table->synchronized)
|
||||
EnterCriticalSection(&table->lock);
|
||||
|
||||
while (pair && table->keycmp(key, pair->key) != 0)
|
||||
hashValue = table->hash(key) % table->numOfBuckets;
|
||||
|
||||
pair = table->bucketArray[hashValue];
|
||||
|
||||
while (pair && !table->keyCompare(key, pair->key))
|
||||
{
|
||||
previousPair = pair;
|
||||
pair = pair->next;
|
||||
@ -269,11 +310,11 @@ BOOL HashTable_Remove(wHashTable* table, void* key)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (table->keyDeallocator)
|
||||
table->keyDeallocator((void*) pair->key);
|
||||
if (table->keyFree)
|
||||
table->keyFree(pair->key);
|
||||
|
||||
if (table->valueDeallocator)
|
||||
table->valueDeallocator(pair->value);
|
||||
if (table->valueFree)
|
||||
table->valueFree(pair->value);
|
||||
|
||||
if (previousPair)
|
||||
previousPair->next = pair->next;
|
||||
@ -331,6 +372,14 @@ BOOL HashTable_SetItemValue(wHashTable* table, void* key, void* value)
|
||||
BOOL status = TRUE;
|
||||
wKeyValuePair* pair;
|
||||
|
||||
if (table->valueClone && value)
|
||||
{
|
||||
value = table->valueClone(value);
|
||||
|
||||
if (!value)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (table->synchronized)
|
||||
EnterCriticalSection(&table->lock);
|
||||
|
||||
@ -368,14 +417,11 @@ void HashTable_Clear(wHashTable* table)
|
||||
{
|
||||
nextPair = pair->next;
|
||||
|
||||
if (table->pfnKeyValueFree)
|
||||
table->pfnKeyValueFree(table->context, pair->key, pair->value);
|
||||
if (table->keyFree)
|
||||
table->keyFree(pair->key);
|
||||
|
||||
if (table->keyDeallocator)
|
||||
table->keyDeallocator((void*) pair->key);
|
||||
|
||||
if (table->valueDeallocator)
|
||||
table->valueDeallocator(pair->value);
|
||||
if (table->valueFree)
|
||||
table->valueFree(pair->value);
|
||||
|
||||
free(pair);
|
||||
|
||||
@ -410,8 +456,17 @@ int HashTable_GetKeys(wHashTable* table, ULONG_PTR** ppKeys)
|
||||
|
||||
iKey = 0;
|
||||
count = table->numOfElements;
|
||||
|
||||
pKeys = (ULONG_PTR*) calloc(count, sizeof(ULONG_PTR));
|
||||
|
||||
if (!pKeys)
|
||||
{
|
||||
if (table->synchronized)
|
||||
LeaveCriticalSection(&table->lock);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (index = 0; index < table->numOfBuckets; index++)
|
||||
{
|
||||
pair = table->bucketArray[index];
|
||||
@ -491,7 +546,7 @@ BOOL HashTable_ContainsValue(wHashTable* table, void* value)
|
||||
|
||||
while (pair)
|
||||
{
|
||||
if (table->valuecmp(value, pair->value) == 0)
|
||||
if (table->valueCompare(value, pair->value))
|
||||
{
|
||||
status = TRUE;
|
||||
break;
|
||||
@ -510,19 +565,12 @@ BOOL HashTable_ContainsValue(wHashTable* table, void* value)
|
||||
return status;
|
||||
}
|
||||
|
||||
void HashTable_SetFreeFunction(wHashTable* table, void* context, KEY_VALUE_FREE_FN pfnKeyValueFree)
|
||||
{
|
||||
table->context = context;
|
||||
table->pfnKeyValueFree = pfnKeyValueFree;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construction, Destruction
|
||||
*/
|
||||
|
||||
wHashTable* HashTable_New(BOOL synchronized)
|
||||
{
|
||||
int index;
|
||||
wHashTable* table;
|
||||
|
||||
table = (wHashTable*) calloc(1, sizeof(wHashTable));
|
||||
@ -530,12 +578,13 @@ wHashTable* HashTable_New(BOOL synchronized)
|
||||
if (table)
|
||||
{
|
||||
table->synchronized = synchronized;
|
||||
|
||||
InitializeCriticalSectionAndSpinCount(&(table->lock), 4000);
|
||||
|
||||
table->numOfBuckets = 64;
|
||||
table->numOfElements = 0;
|
||||
|
||||
table->bucketArray = (wKeyValuePair**) malloc(table->numOfBuckets * sizeof(wKeyValuePair*));
|
||||
table->bucketArray = (wKeyValuePair**) calloc(table->numOfBuckets, sizeof(wKeyValuePair*));
|
||||
|
||||
if (!table->bucketArray)
|
||||
{
|
||||
@ -543,18 +592,17 @@ wHashTable* HashTable_New(BOOL synchronized)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (index = 0; index < table->numOfBuckets; index++)
|
||||
table->bucketArray[index] = NULL;
|
||||
|
||||
table->idealRatio = 3.0;
|
||||
table->lowerRehashThreshold = 0.0;
|
||||
table->upperRehashThreshold = 15.0;
|
||||
|
||||
table->keycmp = pointercmp;
|
||||
table->valuecmp = pointercmp;
|
||||
table->hashFunction = pointerHashFunction;
|
||||
table->keyDeallocator = NULL;
|
||||
table->valueDeallocator = NULL;
|
||||
table->hash = HashTable_PointerHash;
|
||||
table->keyCompare = HashTable_PointerCompare;
|
||||
table->valueCompare = HashTable_PointerCompare;
|
||||
table->keyClone = NULL;
|
||||
table->valueClone = NULL;
|
||||
table->keyFree = NULL;
|
||||
table->valueFree = NULL;
|
||||
}
|
||||
|
||||
return table;
|
||||
@ -576,11 +624,11 @@ void HashTable_Free(wHashTable* table)
|
||||
{
|
||||
nextPair = pair->next;
|
||||
|
||||
if (table->keyDeallocator)
|
||||
table->keyDeallocator((void*) pair->key);
|
||||
if (table->keyFree)
|
||||
table->keyFree(pair->key);
|
||||
|
||||
if (table->valueDeallocator)
|
||||
table->valueDeallocator(pair->value);
|
||||
if (table->valueFree)
|
||||
table->valueFree(pair->value);
|
||||
|
||||
free(pair);
|
||||
|
||||
|
@ -43,6 +43,10 @@ int IniFile_Load_String(wIniFile* ini, const char* iniString)
|
||||
return -1;
|
||||
|
||||
ini->buffer = (char*) malloc(fileSize + 2);
|
||||
|
||||
if (!ini->buffer)
|
||||
return -1;
|
||||
|
||||
CopyMemory(ini->buffer, iniString, fileSize);
|
||||
|
||||
ini->buffer[fileSize] = '\n';
|
||||
@ -53,25 +57,26 @@ int IniFile_Load_String(wIniFile* ini, const char* iniString)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int IniFile_Load_File(wIniFile* ini, const char* filename)
|
||||
int IniFile_Open_File(wIniFile* ini, const char* filename)
|
||||
{
|
||||
long int fileSize;
|
||||
|
||||
if (ini->readOnly)
|
||||
{
|
||||
ini->fp = fopen(filename, "r");
|
||||
}
|
||||
else
|
||||
{
|
||||
ini->fp = fopen(filename, "r+");
|
||||
|
||||
if (!ini->fp)
|
||||
ini->fp = fopen(filename, "w+");
|
||||
}
|
||||
ini->fp = fopen(filename, "w+");
|
||||
|
||||
if (!ini->fp)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int IniFile_Load_File(wIniFile* ini, const char* filename)
|
||||
{
|
||||
int fileSize;
|
||||
|
||||
if (IniFile_Open_File(ini, filename) < 0)
|
||||
return -1;
|
||||
|
||||
fseek(ini->fp, 0, SEEK_END);
|
||||
fileSize = ftell(ini->fp);
|
||||
fseek(ini->fp, 0, SEEK_SET);
|
||||
@ -85,6 +90,9 @@ int IniFile_Load_File(wIniFile* ini, const char* filename)
|
||||
|
||||
ini->buffer = (char*) malloc(fileSize + 2);
|
||||
|
||||
if (!ini->buffer)
|
||||
return -1;
|
||||
|
||||
if (fread(ini->buffer, fileSize, 1, ini->fp) != 1)
|
||||
{
|
||||
free(ini->buffer);
|
||||
@ -92,6 +100,9 @@ int IniFile_Load_File(wIniFile* ini, const char* filename)
|
||||
return -1;
|
||||
}
|
||||
|
||||
fclose(ini->fp);
|
||||
ini->fp = NULL;
|
||||
|
||||
ini->buffer[fileSize] = '\n';
|
||||
ini->buffer[fileSize + 1] = '\0';
|
||||
|
||||
@ -147,11 +158,12 @@ wIniFileKey* IniFile_Key_New(const char* name, const char* value)
|
||||
|
||||
void IniFile_Key_Free(wIniFileKey* key)
|
||||
{
|
||||
if (key)
|
||||
{
|
||||
free(key->name);
|
||||
free(key->value);
|
||||
}
|
||||
if (!key)
|
||||
return;
|
||||
|
||||
free(key->name);
|
||||
free(key->value);
|
||||
free(key);
|
||||
}
|
||||
|
||||
wIniFileSection* IniFile_Section_New(const char* name)
|
||||
@ -169,41 +181,109 @@ wIniFileSection* IniFile_Section_New(const char* name)
|
||||
|
||||
void IniFile_Section_Free(wIniFileSection* section)
|
||||
{
|
||||
if (section)
|
||||
{
|
||||
free(section);
|
||||
}
|
||||
}
|
||||
int index;
|
||||
|
||||
int IniFile_AddSection(wIniFile* ini, const char* name)
|
||||
{
|
||||
if ((ini->nSections + 1) >= (ini->cSections))
|
||||
{
|
||||
ini->cSections *= 2;
|
||||
ini->sections = (wIniFileSection**) realloc(ini->sections, sizeof(wIniFileSection*) * ini->cSections);
|
||||
}
|
||||
|
||||
ini->sections[ini->nSections] = IniFile_Section_New(name);
|
||||
ini->nSections++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int IniFile_AddKey(wIniFile* ini, wIniFileSection* section, const char* name, const char* value)
|
||||
{
|
||||
if (!section)
|
||||
return -1;
|
||||
|
||||
if ((section->nKeys + 1) >= (section->cKeys))
|
||||
return;
|
||||
|
||||
for (index = 0; index < section->nKeys; index++)
|
||||
{
|
||||
section->cKeys *= 2;
|
||||
section->keys = (wIniFileKey**) realloc(section->keys, sizeof(wIniFileKey*) * section->cKeys);
|
||||
IniFile_Key_Free(section->keys[index]);
|
||||
}
|
||||
|
||||
section->keys[section->nKeys] = IniFile_Key_New(name, value);
|
||||
section->nKeys++;
|
||||
free(section);
|
||||
}
|
||||
|
||||
return 1;
|
||||
wIniFileSection* IniFile_GetSection(wIniFile* ini, const char* name)
|
||||
{
|
||||
int index;
|
||||
wIniFileSection* section = NULL;
|
||||
|
||||
for (index = 0; index < ini->nSections; index++)
|
||||
{
|
||||
if (_stricmp(name, ini->sections[index]->name) == 0)
|
||||
{
|
||||
section = ini->sections[index];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return section;
|
||||
}
|
||||
|
||||
wIniFileSection* IniFile_AddSection(wIniFile* ini, const char* name)
|
||||
{
|
||||
wIniFileSection* section;
|
||||
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
section = IniFile_GetSection(ini, name);
|
||||
|
||||
if (!section)
|
||||
{
|
||||
if ((ini->nSections + 1) >= (ini->cSections))
|
||||
{
|
||||
ini->cSections *= 2;
|
||||
ini->sections = (wIniFileSection**) realloc(ini->sections, sizeof(wIniFileSection*) * ini->cSections);
|
||||
}
|
||||
|
||||
section = IniFile_Section_New(name);
|
||||
ini->sections[ini->nSections] = section;
|
||||
ini->nSections++;
|
||||
}
|
||||
|
||||
return section;
|
||||
}
|
||||
|
||||
wIniFileKey* IniFile_GetKey(wIniFile* ini, wIniFileSection* section, const char* name)
|
||||
{
|
||||
int index;
|
||||
wIniFileKey* key = NULL;
|
||||
|
||||
for (index = 0; index < section->nKeys; index++)
|
||||
{
|
||||
if (_stricmp(name, section->keys[index]->name) == 0)
|
||||
{
|
||||
key = section->keys[index];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
wIniFileKey* IniFile_AddKey(wIniFile* ini, wIniFileSection* section, const char* name, const char* value)
|
||||
{
|
||||
wIniFileKey* key;
|
||||
|
||||
if (!section)
|
||||
return NULL;
|
||||
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
key = IniFile_GetKey(ini, section, name);
|
||||
|
||||
if (!key)
|
||||
{
|
||||
if ((section->nKeys + 1) >= (section->cKeys))
|
||||
{
|
||||
section->cKeys *= 2;
|
||||
section->keys = (wIniFileKey**) realloc(section->keys, sizeof(wIniFileKey*) * section->cKeys);
|
||||
}
|
||||
|
||||
key = IniFile_Key_New(name, value);
|
||||
section->keys[section->nKeys] = key;
|
||||
section->nKeys++;
|
||||
}
|
||||
else
|
||||
{
|
||||
free(key->value);
|
||||
key->value = _strdup(value);
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
int IniFile_Load(wIniFile* ini)
|
||||
@ -277,14 +357,14 @@ int IniFile_Load(wIniFile* ini)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int IniFile_ParseString(wIniFile* ini, const char* iniString)
|
||||
int IniFile_ReadBuffer(wIniFile* ini, const char* buffer)
|
||||
{
|
||||
int status;
|
||||
|
||||
ini->readOnly = TRUE;
|
||||
ini->filename = NULL;
|
||||
|
||||
status = IniFile_Load_String(ini, iniString);
|
||||
status = IniFile_Load_String(ini, buffer);
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
@ -294,14 +374,16 @@ int IniFile_ParseString(wIniFile* ini, const char* iniString)
|
||||
return status;
|
||||
}
|
||||
|
||||
int IniFile_Parse(wIniFile* ini, const char* filename)
|
||||
int IniFile_ReadFile(wIniFile* ini, const char* filename)
|
||||
{
|
||||
int status;
|
||||
|
||||
ini->readOnly = TRUE;
|
||||
|
||||
free(ini->filename);
|
||||
ini->filename = _strdup(filename);
|
||||
|
||||
status = IniFile_Load_File(ini, ini->filename);
|
||||
status = IniFile_Load_File(ini, filename);
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
@ -311,40 +393,6 @@ int IniFile_Parse(wIniFile* ini, const char* filename)
|
||||
return status;
|
||||
}
|
||||
|
||||
wIniFileSection* IniFile_GetSection(wIniFile* ini, const char* name)
|
||||
{
|
||||
int index;
|
||||
wIniFileSection* section = NULL;
|
||||
|
||||
for (index = 0; index < ini->nSections; index++)
|
||||
{
|
||||
if (_stricmp(name, ini->sections[index]->name) == 0)
|
||||
{
|
||||
section = ini->sections[index];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return section;
|
||||
}
|
||||
|
||||
wIniFileKey* IniFile_GetKey(wIniFile* ini, wIniFileSection* section, const char* name)
|
||||
{
|
||||
int index;
|
||||
wIniFileKey* key = NULL;
|
||||
|
||||
for (index = 0; index < section->nKeys; index++)
|
||||
{
|
||||
if (_stricmp(name, section->keys[index]->name) == 0)
|
||||
{
|
||||
key = section->keys[index];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
char** IniFile_GetSectionNames(wIniFile* ini, int* count)
|
||||
{
|
||||
char* p;
|
||||
@ -425,12 +473,12 @@ char** IniFile_GetSectionKeyNames(wIniFile* ini, const char* section, int* count
|
||||
return keyNames;
|
||||
}
|
||||
|
||||
char* IniFile_GetKeyValueString(wIniFile* ini, const char* section, const char* key)
|
||||
const char* IniFile_GetKeyValueString(wIniFile* ini, const char* section, const char* key)
|
||||
{
|
||||
char* value = NULL;
|
||||
const char* value = NULL;
|
||||
wIniFileKey* pKey = NULL;
|
||||
wIniFileSection* pSection = NULL;
|
||||
|
||||
|
||||
pSection = IniFile_GetSection(ini, section);
|
||||
|
||||
if (!pSection)
|
||||
@ -441,14 +489,14 @@ char* IniFile_GetKeyValueString(wIniFile* ini, const char* section, const char*
|
||||
if (!pKey)
|
||||
return NULL;
|
||||
|
||||
value = pKey->value;
|
||||
value = (const char*) pKey->value;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
UINT32 IniFile_GetKeyValueInt(wIniFile* ini, const char* section, const char* key)
|
||||
int IniFile_GetKeyValueInt(wIniFile* ini, const char* section, const char* key)
|
||||
{
|
||||
UINT32 value = 0;
|
||||
int value = 0;
|
||||
wIniFileKey* pKey = NULL;
|
||||
wIniFileSection* pSection = NULL;
|
||||
|
||||
@ -467,6 +515,137 @@ UINT32 IniFile_GetKeyValueInt(wIniFile* ini, const char* section, const char* ke
|
||||
return value;
|
||||
}
|
||||
|
||||
int IniFile_SetKeyValueString(wIniFile* ini, const char* section, const char* key, const char* value)
|
||||
{
|
||||
wIniFileKey* pKey = NULL;
|
||||
wIniFileSection* pSection = NULL;
|
||||
|
||||
pSection = IniFile_GetSection(ini, section);
|
||||
|
||||
if (!pSection)
|
||||
pSection = IniFile_AddSection(ini, section);
|
||||
|
||||
if (!pSection)
|
||||
return -1;
|
||||
|
||||
pKey = IniFile_AddKey(ini, pSection, key, value);
|
||||
|
||||
if (!pKey)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int IniFile_SetKeyValueInt(wIniFile* ini, const char* section, const char* key, int value)
|
||||
{
|
||||
char strVal[128];
|
||||
wIniFileKey* pKey = NULL;
|
||||
wIniFileSection* pSection = NULL;
|
||||
|
||||
sprintf_s(strVal, sizeof(strVal), "%d", value);
|
||||
|
||||
pSection = IniFile_GetSection(ini, section);
|
||||
|
||||
if (!pSection)
|
||||
pSection = IniFile_AddSection(ini, section);
|
||||
|
||||
if (!pSection)
|
||||
return -1;
|
||||
|
||||
pKey = IniFile_AddKey(ini, pSection, key, strVal);
|
||||
|
||||
if (!pKey)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
char* IniFile_WriteBuffer(wIniFile* ini)
|
||||
{
|
||||
int i, j;
|
||||
int offset;
|
||||
int size;
|
||||
char* buffer;
|
||||
wIniFileKey* key;
|
||||
wIniFileSection* section;
|
||||
|
||||
size = 0;
|
||||
|
||||
for (i = 0; i < ini->nSections; i++)
|
||||
{
|
||||
section = ini->sections[i];
|
||||
size += strlen(section->name) + 3;
|
||||
|
||||
for (j = 0; j < section->nKeys; j++)
|
||||
{
|
||||
key = section->keys[j];
|
||||
size += strlen(key->name) + strlen(key->value) + 2;
|
||||
}
|
||||
|
||||
size += 1;
|
||||
}
|
||||
|
||||
size += 1;
|
||||
|
||||
buffer = malloc(size + 1);
|
||||
|
||||
if (!buffer)
|
||||
return NULL;
|
||||
|
||||
offset = 0;
|
||||
|
||||
for (i = 0; i < ini->nSections; i++)
|
||||
{
|
||||
section = ini->sections[i];
|
||||
sprintf_s(&buffer[offset], size - offset, "[%s]\n", section->name);
|
||||
offset += strlen(section->name) + 3;
|
||||
|
||||
for (j = 0; j < section->nKeys; j++)
|
||||
{
|
||||
key = section->keys[j];
|
||||
sprintf_s(&buffer[offset], size - offset, "%s=%s\n", key->name, key->value);
|
||||
offset += strlen(key->name) + strlen(key->value) + 2;
|
||||
}
|
||||
|
||||
sprintf_s(&buffer[offset], size - offset, "\n");
|
||||
offset += 1;
|
||||
}
|
||||
|
||||
buffer[offset] = '\0';
|
||||
size += 1;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
int IniFile_WriteFile(wIniFile* ini, const char* filename)
|
||||
{
|
||||
int length;
|
||||
char* buffer;
|
||||
|
||||
buffer = IniFile_WriteBuffer(ini);
|
||||
|
||||
if (!buffer)
|
||||
return -1;
|
||||
|
||||
length = strlen(buffer);
|
||||
|
||||
ini->readOnly = FALSE;
|
||||
|
||||
if (!filename)
|
||||
filename = ini->filename;
|
||||
|
||||
if (IniFile_Open_File(ini, filename) < 0)
|
||||
return -1;
|
||||
|
||||
fwrite((void*) buffer, length, 1, ini->fp);
|
||||
|
||||
fclose(ini->fp);
|
||||
|
||||
free(buffer);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
wIniFile* IniFile_New()
|
||||
{
|
||||
wIniFile* ini = (wIniFile*) calloc(1, sizeof(wIniFile));
|
||||
@ -483,10 +662,19 @@ wIniFile* IniFile_New()
|
||||
|
||||
void IniFile_Free(wIniFile* ini)
|
||||
{
|
||||
if (ini)
|
||||
{
|
||||
free(ini->filename);
|
||||
int index;
|
||||
|
||||
free(ini);
|
||||
if (!ini)
|
||||
return;
|
||||
|
||||
free(ini->filename);
|
||||
|
||||
for (index = 0; index < ini->nSections; index++)
|
||||
{
|
||||
IniFile_Section_Free(ini->sections[index]);
|
||||
}
|
||||
|
||||
free(ini->sections);
|
||||
|
||||
free(ini);
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ static char* val1 = "val1";
|
||||
static char* val2 = "val2";
|
||||
static char* val3 = "val3";
|
||||
|
||||
int TestHashTable(int argc, char* argv[])
|
||||
int test_hash_table_pointer()
|
||||
{
|
||||
int count;
|
||||
char* value;
|
||||
@ -137,5 +137,153 @@ int TestHashTable(int argc, char* argv[])
|
||||
|
||||
HashTable_Free(table);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int test_hash_table_string()
|
||||
{
|
||||
int count;
|
||||
char* value;
|
||||
wHashTable* table;
|
||||
|
||||
table = HashTable_New(TRUE);
|
||||
|
||||
table->hash = HashTable_StringHash;
|
||||
table->keyCompare = HashTable_StringCompare;
|
||||
table->valueCompare = HashTable_StringCompare;
|
||||
table->keyClone = HashTable_StringClone;
|
||||
table->valueClone = HashTable_StringClone;
|
||||
table->keyFree = HashTable_StringFree;
|
||||
table->valueFree = HashTable_StringFree;
|
||||
|
||||
HashTable_Add(table, key1, val1);
|
||||
HashTable_Add(table, key2, val2);
|
||||
HashTable_Add(table, key3, val3);
|
||||
|
||||
count = HashTable_Count(table);
|
||||
|
||||
if (count != 3)
|
||||
{
|
||||
printf("HashTable_Count: Expected : %d, Actual: %d\n", 3, count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
HashTable_Remove(table, key2);
|
||||
|
||||
count = HashTable_Count(table);
|
||||
|
||||
if (count != 2)
|
||||
{
|
||||
printf("HashTable_Count: Expected : %d, Actual: %d\n", 2, count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
HashTable_Remove(table, key3);
|
||||
|
||||
count = HashTable_Count(table);
|
||||
|
||||
if (count != 1)
|
||||
{
|
||||
printf("HashTable_Count: Expected : %d, Actual: %d\n", 1, count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
HashTable_Remove(table, key1);
|
||||
|
||||
count = HashTable_Count(table);
|
||||
|
||||
if (count != 0)
|
||||
{
|
||||
printf("HashTable_Count: Expected : %d, Actual: %d\n", 0, count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
HashTable_Add(table, key1, val1);
|
||||
HashTable_Add(table, key2, val2);
|
||||
HashTable_Add(table, key3, val3);
|
||||
|
||||
count = HashTable_Count(table);
|
||||
|
||||
if (count != 3)
|
||||
{
|
||||
printf("HashTable_Count: Expected : %d, Actual: %d\n", 3, count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
value = (char*) HashTable_GetItemValue(table, key1);
|
||||
|
||||
if (strcmp(value, val1) != 0)
|
||||
{
|
||||
printf("HashTable_GetItemValue: Expected : %s, Actual: %s\n", val1, value);
|
||||
return -1;
|
||||
}
|
||||
|
||||
value = (char*) HashTable_GetItemValue(table, key2);
|
||||
|
||||
if (strcmp(value, val2) != 0)
|
||||
{
|
||||
printf("HashTable_GetItemValue: Expected : %s, Actual: %s\n", val2, value);
|
||||
return -1;
|
||||
}
|
||||
|
||||
value = (char*) HashTable_GetItemValue(table, key3);
|
||||
|
||||
if (strcmp(value, val3) != 0)
|
||||
{
|
||||
printf("HashTable_GetItemValue: Expected : %s, Actual: %s\n", val3, value);
|
||||
return -1;
|
||||
}
|
||||
|
||||
HashTable_SetItemValue(table, key2, "apple");
|
||||
|
||||
value = (char*) HashTable_GetItemValue(table, key2);
|
||||
|
||||
if (strcmp(value, "apple") != 0)
|
||||
{
|
||||
printf("HashTable_GetItemValue: Expected : %s, Actual: %s\n", "apple", value);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!HashTable_Contains(table, key2))
|
||||
{
|
||||
printf("HashTable_Contains: Expected : %d, Actual: %d\n", TRUE, FALSE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!HashTable_Remove(table, key2))
|
||||
{
|
||||
printf("HashTable_Remove: Expected : %d, Actual: %d\n", TRUE, FALSE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (HashTable_Remove(table, key2))
|
||||
{
|
||||
printf("HashTable_Remove: Expected : %d, Actual: %d\n", FALSE, TRUE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
HashTable_Clear(table);
|
||||
|
||||
count = HashTable_Count(table);
|
||||
|
||||
if (count != 0)
|
||||
{
|
||||
printf("HashTable_Count: Expected : %d, Actual: %d\n", 0, count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
HashTable_Free(table);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int TestHashTable(int argc, char* argv[])
|
||||
{
|
||||
if (test_hash_table_pointer() < 0)
|
||||
return 1;
|
||||
|
||||
if (test_hash_table_string() < 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -32,9 +32,9 @@ int TestIni(int argc, char* argv[])
|
||||
int i, j;
|
||||
int nKeys;
|
||||
int nSections;
|
||||
char* sValue;
|
||||
UINT32 iValue;
|
||||
wIniFile* ini;
|
||||
const char* sValue;
|
||||
char** keyNames;
|
||||
char** sectionNames;
|
||||
|
||||
@ -42,7 +42,7 @@ int TestIni(int argc, char* argv[])
|
||||
|
||||
ini = IniFile_New();
|
||||
|
||||
IniFile_ParseString(ini, TEST_INI_01);
|
||||
IniFile_ReadBuffer(ini, TEST_INI_01);
|
||||
|
||||
sectionNames = IniFile_GetSectionNames(ini, &nSections);
|
||||
|
||||
@ -109,7 +109,7 @@ int TestIni(int argc, char* argv[])
|
||||
|
||||
ini = IniFile_New();
|
||||
|
||||
IniFile_ParseString(ini, TEST_INI_02);
|
||||
IniFile_ReadBuffer(ini, TEST_INI_02);
|
||||
|
||||
sectionNames = IniFile_GetSectionNames(ini, &nSections);
|
||||
|
||||
|
@ -482,6 +482,9 @@ int _bind(SOCKET s, const struct sockaddr* addr, int namelen)
|
||||
|
||||
status = bind(fd, addr, (socklen_t) namelen);
|
||||
|
||||
if (status < 0)
|
||||
return SOCKET_ERROR;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -502,6 +505,9 @@ int _connect(SOCKET s, const struct sockaddr* name, int namelen)
|
||||
|
||||
status = connect(fd, name, (socklen_t) namelen);
|
||||
|
||||
if (status < 0)
|
||||
return SOCKET_ERROR;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -684,9 +690,15 @@ int _shutdown(SOCKET s, int how)
|
||||
|
||||
SOCKET _socket(int af, int type, int protocol)
|
||||
{
|
||||
int fd;
|
||||
SOCKET s;
|
||||
|
||||
s = (SOCKET) socket(af, type, protocol);
|
||||
fd = socket(af, type, protocol);
|
||||
|
||||
if (fd < 1)
|
||||
return INVALID_SOCKET;
|
||||
|
||||
s = (SOCKET) fd;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
@ -18,6 +18,10 @@
|
||||
winpr_module_add(wtsapi.c
|
||||
wtsapi.h)
|
||||
|
||||
if(WIN32)
|
||||
winpr_module_add(wtsapi_win32.c wtsapi_win32.h)
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
@ -32,6 +32,10 @@
|
||||
|
||||
#include "wtsapi.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "wtsapi_win32.h"
|
||||
#endif
|
||||
|
||||
#include "../log.h"
|
||||
#define TAG WINPR_TAG("wtsapi")
|
||||
|
||||
@ -193,8 +197,10 @@ int WtsApi32_InitializeWtsApi(void)
|
||||
WTSAPI32_LOAD_PROC(IsChildSessionsEnabled, WTS_IS_CHILD_SESSIONS_ENABLED_FN);
|
||||
WTSAPI32_LOAD_PROC(GetChildSessionId, WTS_GET_CHILD_SESSION_ID_FN);
|
||||
WTSAPI32_LOAD_PROC(GetActiveConsoleSessionId, WTS_GET_ACTIVE_CONSOLE_SESSION_ID_FN);
|
||||
#endif
|
||||
g_WtsApi = &WtsApi32_WtsApiFunctionTable;
|
||||
Win32_InitializeWinSta(g_WtsApi);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -599,16 +605,16 @@ void InitializeWtsApiStubs_Env()
|
||||
|
||||
void InitializeWtsApiStubs_FreeRDS()
|
||||
{
|
||||
char* prefix;
|
||||
char* libdir;
|
||||
wIniFile* ini;
|
||||
const char* prefix;
|
||||
const char* libdir;
|
||||
|
||||
if (g_WtsApi)
|
||||
return;
|
||||
|
||||
ini = IniFile_New();
|
||||
|
||||
if (IniFile_Parse(ini, "/var/run/freerds.instance") < 0)
|
||||
if (IniFile_ReadFile(ini, "/var/run/freerds.instance") < 0)
|
||||
{
|
||||
IniFile_Free(ini);
|
||||
WLog_ERR(TAG, "failed to parse freerds.instance");
|
||||
@ -646,6 +652,7 @@ void InitializeWtsApiStubs(void)
|
||||
|
||||
g_Initialized = TRUE;
|
||||
InitializeWtsApiStubs_Env();
|
||||
|
||||
#ifdef _WIN32
|
||||
WtsApi32_InitializeWtsApi();
|
||||
#endif
|
||||
|
731
winpr/libwinpr/wtsapi/wtsapi_win32.c
Normal file
731
winpr/libwinpr/wtsapi/wtsapi_win32.c
Normal file
@ -0,0 +1,731 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Windows Terminal Services API
|
||||
*
|
||||
* Copyright 2013-2014 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/io.h>
|
||||
#include <winpr/nt.h>
|
||||
#include <winpr/library.h>
|
||||
|
||||
#include <winpr/wtsapi.h>
|
||||
|
||||
#include "wtsapi_win32.h"
|
||||
|
||||
#include "wtsapi.h"
|
||||
|
||||
#define WTSAPI_CHANNEL_MAGIC 0x44484356
|
||||
|
||||
struct _WTSAPI_CHANNEL
|
||||
{
|
||||
UINT32 magic;
|
||||
HANDLE hServer;
|
||||
DWORD SessionId;
|
||||
HANDLE hFile;
|
||||
HANDLE hEvent;
|
||||
char* VirtualName;
|
||||
|
||||
DWORD flags;
|
||||
BYTE* chunk;
|
||||
BOOL dynamic;
|
||||
BOOL readSync;
|
||||
BOOL readAsync;
|
||||
BOOL readDone;
|
||||
UINT32 readSize;
|
||||
UINT32 readOffset;
|
||||
BYTE* readBuffer;
|
||||
BOOL showProtocol;
|
||||
BOOL waitObjectMode;
|
||||
OVERLAPPED overlapped;
|
||||
CHANNEL_PDU_HEADER* header;
|
||||
};
|
||||
typedef struct _WTSAPI_CHANNEL WTSAPI_CHANNEL;
|
||||
|
||||
static BOOL g_Initialized = FALSE;
|
||||
static HMODULE g_WinStaModule = NULL;
|
||||
|
||||
typedef HANDLE (WINAPI * fnWinStationVirtualOpen)(HANDLE hServer, DWORD SessionId, LPSTR pVirtualName);
|
||||
typedef HANDLE (WINAPI * fnWinStationVirtualOpenEx)(HANDLE hServer, DWORD SessionId, LPSTR pVirtualName, DWORD flags);
|
||||
|
||||
static fnWinStationVirtualOpen pfnWinStationVirtualOpen = NULL;
|
||||
static fnWinStationVirtualOpenEx pfnWinStationVirtualOpenEx = NULL;
|
||||
|
||||
BOOL WINAPI Win32_WTSVirtualChannelClose(HANDLE hChannel);
|
||||
|
||||
BOOL Win32_WTSVirtualChannelReadAsync(WTSAPI_CHANNEL* pChannel)
|
||||
{
|
||||
BOOL status = TRUE;
|
||||
DWORD numBytes = 0;
|
||||
|
||||
if (pChannel->readAsync)
|
||||
return TRUE;
|
||||
|
||||
ZeroMemory(&(pChannel->overlapped), sizeof(OVERLAPPED));
|
||||
pChannel->overlapped.hEvent = pChannel->hEvent;
|
||||
ResetEvent(pChannel->hEvent);
|
||||
|
||||
if (pChannel->showProtocol)
|
||||
{
|
||||
ZeroMemory(pChannel->header, sizeof(CHANNEL_PDU_HEADER));
|
||||
|
||||
status = ReadFile(pChannel->hFile, pChannel->header,
|
||||
sizeof(CHANNEL_PDU_HEADER), &numBytes, &(pChannel->overlapped));
|
||||
}
|
||||
else
|
||||
{
|
||||
status = ReadFile(pChannel->hFile, pChannel->chunk,
|
||||
CHANNEL_CHUNK_LENGTH, &numBytes, &(pChannel->overlapped));
|
||||
|
||||
if (status)
|
||||
{
|
||||
pChannel->readOffset = 0;
|
||||
pChannel->header->length = numBytes;
|
||||
|
||||
pChannel->readDone = TRUE;
|
||||
SetEvent(pChannel->hEvent);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (status)
|
||||
{
|
||||
fprintf(stderr, "Unexpected ReadFile status: %d numBytes: %d\n", status, numBytes);
|
||||
return FALSE; /* ReadFile should return FALSE and set ERROR_IO_PENDING */
|
||||
}
|
||||
|
||||
if (GetLastError() != ERROR_IO_PENDING)
|
||||
{
|
||||
fprintf(stderr, "ReadFile: GetLastError() = %d\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pChannel->readAsync = TRUE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
HANDLE WINAPI Win32_WTSVirtualChannelOpen_Internal(HANDLE hServer, DWORD SessionId, LPSTR pVirtualName, DWORD flags)
|
||||
{
|
||||
HANDLE hFile;
|
||||
HANDLE hChannel;
|
||||
WTSAPI_CHANNEL* pChannel;
|
||||
|
||||
if (!pVirtualName)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hFile = pfnWinStationVirtualOpenEx(hServer, SessionId, pVirtualName, flags);
|
||||
|
||||
if (!hFile)
|
||||
return NULL;
|
||||
|
||||
pChannel = (WTSAPI_CHANNEL*) calloc(1, sizeof(WTSAPI_CHANNEL));
|
||||
|
||||
if (!pChannel)
|
||||
{
|
||||
CloseHandle(hFile);
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hChannel = (HANDLE) pChannel;
|
||||
pChannel->magic = WTSAPI_CHANNEL_MAGIC;
|
||||
pChannel->hServer = hServer;
|
||||
pChannel->SessionId = SessionId;
|
||||
pChannel->hFile = hFile;
|
||||
pChannel->VirtualName = _strdup(pVirtualName);
|
||||
|
||||
pChannel->flags = flags;
|
||||
pChannel->dynamic = (flags & WTS_CHANNEL_OPTION_DYNAMIC) ? TRUE : FALSE;
|
||||
|
||||
pChannel->showProtocol = pChannel->dynamic;
|
||||
|
||||
pChannel->readSize = CHANNEL_PDU_LENGTH;
|
||||
pChannel->readBuffer = (BYTE*) malloc(pChannel->readSize);
|
||||
|
||||
pChannel->header = (CHANNEL_PDU_HEADER*) pChannel->readBuffer;
|
||||
pChannel->chunk = &(pChannel->readBuffer[sizeof(CHANNEL_PDU_HEADER)]);
|
||||
|
||||
pChannel->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
pChannel->overlapped.hEvent = pChannel->hEvent;
|
||||
|
||||
if (!pChannel->hEvent || !pChannel->VirtualName || !pChannel->readBuffer)
|
||||
{
|
||||
Win32_WTSVirtualChannelClose(hChannel);
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return hChannel;
|
||||
}
|
||||
|
||||
HANDLE WINAPI Win32_WTSVirtualChannelOpen(HANDLE hServer, DWORD SessionId, LPSTR pVirtualName)
|
||||
{
|
||||
return Win32_WTSVirtualChannelOpen_Internal(hServer, SessionId, pVirtualName, 0);
|
||||
}
|
||||
|
||||
HANDLE WINAPI Win32_WTSVirtualChannelOpenEx(DWORD SessionId, LPSTR pVirtualName, DWORD flags)
|
||||
{
|
||||
return Win32_WTSVirtualChannelOpen_Internal(0, SessionId, pVirtualName, flags);
|
||||
}
|
||||
|
||||
BOOL WINAPI Win32_WTSVirtualChannelClose(HANDLE hChannel)
|
||||
{
|
||||
BOOL status = TRUE;
|
||||
WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*) hChannel;
|
||||
|
||||
if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (pChannel->hFile)
|
||||
{
|
||||
if (pChannel->readAsync)
|
||||
{
|
||||
CancelIo(pChannel->hFile);
|
||||
pChannel->readAsync = FALSE;
|
||||
}
|
||||
|
||||
status = CloseHandle(pChannel->hFile);
|
||||
pChannel->hFile = NULL;
|
||||
}
|
||||
|
||||
if (pChannel->hEvent)
|
||||
{
|
||||
CloseHandle(pChannel->hEvent);
|
||||
pChannel->hEvent = NULL;
|
||||
}
|
||||
|
||||
if (pChannel->VirtualName)
|
||||
{
|
||||
free(pChannel->VirtualName);
|
||||
pChannel->VirtualName = NULL;
|
||||
}
|
||||
|
||||
if (pChannel->readBuffer)
|
||||
{
|
||||
free(pChannel->readBuffer);
|
||||
pChannel->readBuffer = NULL;
|
||||
}
|
||||
|
||||
pChannel->magic = 0;
|
||||
free(pChannel);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
BOOL WINAPI Win32_WTSVirtualChannelRead_Static(WTSAPI_CHANNEL* pChannel, DWORD dwMilliseconds, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesTransferred)
|
||||
{
|
||||
if (pChannel->readDone)
|
||||
{
|
||||
DWORD numBytesRead = 0;
|
||||
DWORD numBytesToRead = 0;
|
||||
|
||||
*lpNumberOfBytesTransferred = 0;
|
||||
|
||||
numBytesToRead = nNumberOfBytesToRead;
|
||||
|
||||
if (numBytesToRead > (pChannel->header->length - pChannel->readOffset))
|
||||
numBytesToRead = (pChannel->header->length - pChannel->readOffset);
|
||||
|
||||
CopyMemory(lpBuffer, &(pChannel->chunk[pChannel->readOffset]), numBytesToRead);
|
||||
*lpNumberOfBytesTransferred += numBytesToRead;
|
||||
pChannel->readOffset += numBytesToRead;
|
||||
|
||||
if (pChannel->readOffset != pChannel->header->length)
|
||||
{
|
||||
SetLastError(ERROR_MORE_DATA);
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
pChannel->readDone = FALSE;
|
||||
Win32_WTSVirtualChannelReadAsync(pChannel);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else if (pChannel->readSync)
|
||||
{
|
||||
BOOL bSuccess;
|
||||
OVERLAPPED overlapped;
|
||||
DWORD numBytesRead = 0;
|
||||
DWORD numBytesToRead = 0;
|
||||
|
||||
*lpNumberOfBytesTransferred = 0;
|
||||
|
||||
ZeroMemory(&overlapped, sizeof(OVERLAPPED));
|
||||
|
||||
numBytesToRead = nNumberOfBytesToRead;
|
||||
|
||||
if (numBytesToRead > (pChannel->header->length - pChannel->readOffset))
|
||||
numBytesToRead = (pChannel->header->length - pChannel->readOffset);
|
||||
|
||||
if (ReadFile(pChannel->hFile, lpBuffer, numBytesToRead, &numBytesRead, &overlapped))
|
||||
{
|
||||
*lpNumberOfBytesTransferred += numBytesRead;
|
||||
pChannel->readOffset += numBytesRead;
|
||||
|
||||
if (pChannel->readOffset != pChannel->header->length)
|
||||
{
|
||||
SetLastError(ERROR_MORE_DATA);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pChannel->readSync = FALSE;
|
||||
Win32_WTSVirtualChannelReadAsync(pChannel);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (GetLastError() != ERROR_IO_PENDING)
|
||||
return FALSE;
|
||||
|
||||
bSuccess = GetOverlappedResult(pChannel->hFile, &overlapped, &numBytesRead, TRUE);
|
||||
|
||||
if (!bSuccess)
|
||||
return FALSE;
|
||||
|
||||
*lpNumberOfBytesTransferred += numBytesRead;
|
||||
pChannel->readOffset += numBytesRead;
|
||||
|
||||
if (pChannel->readOffset != pChannel->header->length)
|
||||
{
|
||||
SetLastError(ERROR_MORE_DATA);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pChannel->readSync = FALSE;
|
||||
Win32_WTSVirtualChannelReadAsync(pChannel);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else if (pChannel->readAsync)
|
||||
{
|
||||
BOOL bSuccess;
|
||||
DWORD numBytesRead = 0;
|
||||
DWORD numBytesToRead = 0;
|
||||
|
||||
*lpNumberOfBytesTransferred = 0;
|
||||
|
||||
if (WaitForSingleObject(pChannel->hEvent, dwMilliseconds) != WAIT_TIMEOUT)
|
||||
{
|
||||
bSuccess = GetOverlappedResult(pChannel->hFile,
|
||||
&(pChannel->overlapped), &numBytesRead, TRUE);
|
||||
|
||||
pChannel->readOffset = 0;
|
||||
pChannel->header->length = numBytesRead;
|
||||
|
||||
if (!bSuccess && (GetLastError() != ERROR_MORE_DATA))
|
||||
return FALSE;
|
||||
|
||||
numBytesToRead = nNumberOfBytesToRead;
|
||||
|
||||
if (numBytesRead < numBytesToRead)
|
||||
{
|
||||
numBytesToRead = numBytesRead;
|
||||
nNumberOfBytesToRead = numBytesRead;
|
||||
}
|
||||
|
||||
CopyMemory(lpBuffer, pChannel->chunk, numBytesToRead);
|
||||
*lpNumberOfBytesTransferred += numBytesToRead;
|
||||
((BYTE*) lpBuffer) += numBytesToRead;
|
||||
nNumberOfBytesToRead -= numBytesToRead;
|
||||
pChannel->readOffset += numBytesToRead;
|
||||
|
||||
pChannel->readAsync = FALSE;
|
||||
|
||||
if (!nNumberOfBytesToRead)
|
||||
{
|
||||
Win32_WTSVirtualChannelReadAsync(pChannel);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
pChannel->readSync = TRUE;
|
||||
|
||||
numBytesRead = 0;
|
||||
|
||||
bSuccess = Win32_WTSVirtualChannelRead_Static(pChannel, dwMilliseconds,
|
||||
lpBuffer, nNumberOfBytesToRead, &numBytesRead);
|
||||
|
||||
*lpNumberOfBytesTransferred += numBytesRead;
|
||||
return bSuccess;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetLastError(ERROR_IO_INCOMPLETE);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINAPI Win32_WTSVirtualChannelRead_Dynamic(WTSAPI_CHANNEL* pChannel, DWORD dwMilliseconds, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesTransferred)
|
||||
{
|
||||
if (pChannel->readSync)
|
||||
{
|
||||
BOOL bSuccess;
|
||||
OVERLAPPED overlapped;
|
||||
DWORD numBytesRead = 0;
|
||||
DWORD numBytesToRead = 0;
|
||||
|
||||
*lpNumberOfBytesTransferred = 0;
|
||||
|
||||
ZeroMemory(&overlapped, sizeof(OVERLAPPED));
|
||||
|
||||
numBytesToRead = nNumberOfBytesToRead;
|
||||
|
||||
if (numBytesToRead > (pChannel->header->length - pChannel->readOffset))
|
||||
numBytesToRead = (pChannel->header->length - pChannel->readOffset);
|
||||
|
||||
if (ReadFile(pChannel->hFile, lpBuffer, numBytesToRead, &numBytesRead, &overlapped))
|
||||
{
|
||||
*lpNumberOfBytesTransferred += numBytesRead;
|
||||
pChannel->readOffset += numBytesRead;
|
||||
|
||||
if (pChannel->readOffset != pChannel->header->length)
|
||||
{
|
||||
SetLastError(ERROR_MORE_DATA);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pChannel->readSync = FALSE;
|
||||
Win32_WTSVirtualChannelReadAsync(pChannel);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (GetLastError() != ERROR_IO_PENDING)
|
||||
return FALSE;
|
||||
|
||||
bSuccess = GetOverlappedResult(pChannel->hFile, &overlapped, &numBytesRead, TRUE);
|
||||
|
||||
if (!bSuccess)
|
||||
return FALSE;
|
||||
|
||||
*lpNumberOfBytesTransferred += numBytesRead;
|
||||
pChannel->readOffset += numBytesRead;
|
||||
|
||||
if (pChannel->readOffset != pChannel->header->length)
|
||||
{
|
||||
SetLastError(ERROR_MORE_DATA);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pChannel->readSync = FALSE;
|
||||
Win32_WTSVirtualChannelReadAsync(pChannel);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else if (pChannel->readAsync)
|
||||
{
|
||||
BOOL bSuccess;
|
||||
DWORD numBytesRead = 0;
|
||||
|
||||
*lpNumberOfBytesTransferred = 0;
|
||||
|
||||
if (WaitForSingleObject(pChannel->hEvent, dwMilliseconds) != WAIT_TIMEOUT)
|
||||
{
|
||||
bSuccess = GetOverlappedResult(pChannel->hFile,
|
||||
&(pChannel->overlapped), &numBytesRead, TRUE);
|
||||
|
||||
if (pChannel->showProtocol)
|
||||
{
|
||||
if (numBytesRead != sizeof(CHANNEL_PDU_HEADER))
|
||||
return FALSE;
|
||||
|
||||
if (!bSuccess && (GetLastError() != ERROR_MORE_DATA))
|
||||
return FALSE;
|
||||
|
||||
CopyMemory(lpBuffer, pChannel->header, numBytesRead);
|
||||
*lpNumberOfBytesTransferred += numBytesRead;
|
||||
((BYTE*) lpBuffer) += numBytesRead;
|
||||
nNumberOfBytesToRead -= numBytesRead;
|
||||
}
|
||||
|
||||
pChannel->readAsync = FALSE;
|
||||
|
||||
if (!pChannel->header->length)
|
||||
{
|
||||
Win32_WTSVirtualChannelReadAsync(pChannel);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
pChannel->readSync = TRUE;
|
||||
pChannel->readOffset = 0;
|
||||
|
||||
if (!nNumberOfBytesToRead)
|
||||
{
|
||||
SetLastError(ERROR_MORE_DATA);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
numBytesRead = 0;
|
||||
|
||||
bSuccess = Win32_WTSVirtualChannelRead_Dynamic(pChannel, dwMilliseconds,
|
||||
lpBuffer, nNumberOfBytesToRead, &numBytesRead);
|
||||
|
||||
*lpNumberOfBytesTransferred += numBytesRead;
|
||||
return bSuccess;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetLastError(ERROR_IO_INCOMPLETE);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINAPI Win32_WTSVirtualChannelRead(HANDLE hChannel, DWORD dwMilliseconds, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesTransferred)
|
||||
{
|
||||
WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*) hChannel;
|
||||
|
||||
if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!pChannel->waitObjectMode)
|
||||
{
|
||||
OVERLAPPED overlapped;
|
||||
|
||||
ZeroMemory(&overlapped, sizeof(OVERLAPPED));
|
||||
|
||||
if (ReadFile(pChannel->hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesTransferred, &overlapped))
|
||||
return TRUE;
|
||||
|
||||
if (GetLastError() != ERROR_IO_PENDING)
|
||||
return FALSE;
|
||||
|
||||
if (!dwMilliseconds)
|
||||
{
|
||||
CancelIo(pChannel->hFile);
|
||||
*lpNumberOfBytesTransferred = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (WaitForSingleObject(pChannel->hFile, dwMilliseconds) != WAIT_TIMEOUT)
|
||||
return GetOverlappedResult(pChannel->hFile, &overlapped, lpNumberOfBytesTransferred, FALSE);
|
||||
|
||||
CancelIo(pChannel->hFile);
|
||||
SetLastError(ERROR_IO_INCOMPLETE);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pChannel->dynamic)
|
||||
{
|
||||
return Win32_WTSVirtualChannelRead_Dynamic(pChannel, dwMilliseconds,
|
||||
lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesTransferred);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Win32_WTSVirtualChannelRead_Static(pChannel, dwMilliseconds,
|
||||
lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesTransferred);
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINAPI Win32_WTSVirtualChannelWrite(HANDLE hChannel, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesTransferred)
|
||||
{
|
||||
OVERLAPPED overlapped;
|
||||
WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*) hChannel;
|
||||
|
||||
if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ZeroMemory(&overlapped, sizeof(OVERLAPPED));
|
||||
|
||||
if (WriteFile(pChannel->hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesTransferred, &overlapped))
|
||||
return TRUE;
|
||||
|
||||
if (GetLastError() == ERROR_IO_PENDING)
|
||||
return GetOverlappedResult(pChannel->hFile, &overlapped, lpNumberOfBytesTransferred, TRUE);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#ifndef FILE_DEVICE_TERMSRV
|
||||
#define FILE_DEVICE_TERMSRV 0x00000038
|
||||
#endif
|
||||
|
||||
BOOL Win32_WTSVirtualChannelPurge_Internal(HANDLE hChannelHandle, ULONG IoControlCode)
|
||||
{
|
||||
DWORD error;
|
||||
NTSTATUS ntstatus;
|
||||
IO_STATUS_BLOCK ioStatusBlock;
|
||||
WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*) hChannelHandle;
|
||||
|
||||
if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ntstatus = _NtDeviceIoControlFile(pChannel->hFile, 0, 0, 0, &ioStatusBlock, IoControlCode, 0, 0, 0, 0);
|
||||
|
||||
if (ntstatus == STATUS_PENDING)
|
||||
{
|
||||
ntstatus = _NtWaitForSingleObject(pChannel->hFile, 0, 0);
|
||||
|
||||
if (ntstatus >= 0)
|
||||
ntstatus = ioStatusBlock.Status;
|
||||
}
|
||||
|
||||
if (ntstatus == STATUS_BUFFER_OVERFLOW)
|
||||
{
|
||||
ntstatus = STATUS_BUFFER_TOO_SMALL;
|
||||
error = _RtlNtStatusToDosError(ntstatus);
|
||||
SetLastError(error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (ntstatus < 0)
|
||||
{
|
||||
error = _RtlNtStatusToDosError(ntstatus);
|
||||
SetLastError(error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL WINAPI Win32_WTSVirtualChannelPurgeInput(HANDLE hChannelHandle)
|
||||
{
|
||||
return Win32_WTSVirtualChannelPurge_Internal(hChannelHandle, (FILE_DEVICE_TERMSRV << 16) | 0x0107);
|
||||
}
|
||||
|
||||
BOOL WINAPI Win32_WTSVirtualChannelPurgeOutput(HANDLE hChannelHandle)
|
||||
{
|
||||
return Win32_WTSVirtualChannelPurge_Internal(hChannelHandle, (FILE_DEVICE_TERMSRV << 16) | 0x010B);
|
||||
}
|
||||
|
||||
BOOL WINAPI Win32_WTSVirtualChannelQuery(HANDLE hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass, PVOID* ppBuffer, DWORD* pBytesReturned)
|
||||
{
|
||||
WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*) hChannelHandle;
|
||||
|
||||
if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (WtsVirtualClass == WTSVirtualClientData)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
else if (WtsVirtualClass == WTSVirtualFileHandle)
|
||||
{
|
||||
*pBytesReturned = sizeof(HANDLE);
|
||||
*ppBuffer = LocalAlloc(LMEM_ZEROINIT, *pBytesReturned);
|
||||
|
||||
if (*ppBuffer == NULL)
|
||||
{
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CopyMemory(*ppBuffer, &(pChannel->hFile), *pBytesReturned);
|
||||
}
|
||||
else if (WtsVirtualClass == WTSVirtualEventHandle)
|
||||
{
|
||||
*pBytesReturned = sizeof(HANDLE);
|
||||
*ppBuffer = LocalAlloc(LMEM_ZEROINIT, *pBytesReturned);
|
||||
|
||||
if (*ppBuffer == NULL)
|
||||
{
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CopyMemory(*ppBuffer, &(pChannel->hEvent), *pBytesReturned);
|
||||
|
||||
Win32_WTSVirtualChannelReadAsync(pChannel);
|
||||
pChannel->waitObjectMode = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID WINAPI Win32_WTSFreeMemory(PVOID pMemory)
|
||||
{
|
||||
LocalFree(pMemory);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL WINAPI Win32_WTSFreeMemoryExW(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory, ULONG NumberOfEntries)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL WINAPI Win32_WTSFreeMemoryExA(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory, ULONG NumberOfEntries)
|
||||
{
|
||||
return WTSFreeMemoryExW(WTSTypeClass, pMemory, NumberOfEntries);
|
||||
}
|
||||
|
||||
int Win32_InitializeWinSta(PWtsApiFunctionTable pWtsApi)
|
||||
{
|
||||
g_WinStaModule = LoadLibraryA("winsta.dll");
|
||||
|
||||
if (!g_WinStaModule)
|
||||
return -1;
|
||||
|
||||
pfnWinStationVirtualOpen = (fnWinStationVirtualOpen) GetProcAddress(g_WinStaModule, "WinStationVirtualOpen");
|
||||
pfnWinStationVirtualOpenEx = (fnWinStationVirtualOpenEx) GetProcAddress(g_WinStaModule, "WinStationVirtualOpenEx");
|
||||
|
||||
if (!pfnWinStationVirtualOpenEx)
|
||||
return -1;
|
||||
|
||||
pWtsApi->pVirtualChannelOpen = Win32_WTSVirtualChannelOpen;
|
||||
pWtsApi->pVirtualChannelOpenEx = Win32_WTSVirtualChannelOpenEx;
|
||||
pWtsApi->pVirtualChannelClose = Win32_WTSVirtualChannelClose;
|
||||
pWtsApi->pVirtualChannelRead = Win32_WTSVirtualChannelRead;
|
||||
pWtsApi->pVirtualChannelWrite = Win32_WTSVirtualChannelWrite;
|
||||
pWtsApi->pVirtualChannelPurgeInput = Win32_WTSVirtualChannelPurgeInput;
|
||||
pWtsApi->pVirtualChannelPurgeOutput = Win32_WTSVirtualChannelPurgeOutput;
|
||||
pWtsApi->pVirtualChannelQuery = Win32_WTSVirtualChannelQuery;
|
||||
pWtsApi->pFreeMemory = Win32_WTSFreeMemory;
|
||||
//pWtsApi->pFreeMemoryExW = Win32_WTSFreeMemoryExW;
|
||||
//pWtsApi->pFreeMemoryExA = Win32_WTSFreeMemoryExA;
|
||||
|
||||
return 1;
|
||||
}
|
27
winpr/libwinpr/wtsapi/wtsapi_win32.h
Normal file
27
winpr/libwinpr/wtsapi/wtsapi_win32.h
Normal file
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Windows Terminal Services API
|
||||
*
|
||||
* Copyright 2013-2014 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.
|
||||
*/
|
||||
|
||||
#ifndef WINPR_WTSAPI_WIN32_PRIVATE_H
|
||||
#define WINPR_WTSAPI_WIN32_PRIVATE_H
|
||||
|
||||
#include <winpr/wtsapi.h>
|
||||
|
||||
int Win32_InitializeWinSta(PWtsApiFunctionTable pWtsApi);
|
||||
|
||||
#endif /* WINPR_WTSAPI_WIN32_PRIVATE_H */
|
Loading…
Reference in New Issue
Block a user