typedef struct rdp_shadow_capture rdpShadowCapture;
typedef struct rdp_shadow_subsystem rdpShadowSubsystem;
-typedef rdpShadowSubsystem* (*pfnShadowCreateSubsystem)(rdpShadowServer* server);
+typedef struct _RDP_SHADOW_ENTRY_POINTS RDP_SHADOW_ENTRY_POINTS;
+typedef int (*pfnShadowSubsystemEntry)(RDP_SHADOW_ENTRY_POINTS* pEntryPoints);
+
+typedef rdpShadowSubsystem* (*pfnShadowSubsystemNew)();
+typedef void (*pfnShadowSubsystemFree)(rdpShadowSubsystem* subsystem);
typedef int (*pfnShadowSubsystemInit)(rdpShadowSubsystem* subsystem);
typedef int (*pfnShadowSubsystemUninit)(rdpShadowSubsystem* subsystem);
+
typedef int (*pfnShadowSubsystemStart)(rdpShadowSubsystem* subsystem);
typedef int (*pfnShadowSubsystemStop)(rdpShadowSubsystem* subsystem);
-typedef void (*pfnShadowSubsystemFree)(rdpShadowSubsystem* subsystem);
-typedef int (*pfnShadowEnumMonitors)(rdpShadowSubsystem* subsystem, MONITOR_DEF* monitors, int maxMonitors);
+typedef int (*pfnShadowEnumMonitors)(MONITOR_DEF* monitors, int maxMonitors);
typedef int (*pfnShadowSurfaceCopy)(rdpShadowSubsystem* subsystem);
typedef int (*pfnShadowSurfaceUpdate)(rdpShadowSubsystem* subsystem, REGION16* subRect);
freerdp_listener* listener;
};
+struct _RDP_SHADOW_ENTRY_POINTS
+{
+ pfnShadowSubsystemNew New;
+ pfnShadowSubsystemFree Free;
+
+ pfnShadowSubsystemInit Init;
+ pfnShadowSubsystemUninit Uninit;
+
+ pfnShadowSubsystemStart Start;
+ pfnShadowSubsystemStop Stop;
+
+ pfnShadowEnumMonitors EnumMonitors;
+};
+
#define RDP_SHADOW_SUBSYSTEM_COMMON() \
+ RDP_SHADOW_ENTRY_POINTS ep; \
HANDLE event; \
int numMonitors; \
int selectedMonitor; \
wMessagePipe* MsgPipe; \
SYNCHRONIZATION_BARRIER barrier; \
\
- pfnShadowSubsystemInit Init; \
- pfnShadowSubsystemUninit Uninit; \
- pfnShadowSubsystemStart Start; \
- pfnShadowSubsystemStop Stop; \
- pfnShadowSubsystemFree Free; \
- \
- pfnShadowEnumMonitors EnumMonitors; \
- pfnShadowSurfaceCopy SurfaceCopy; \
- pfnShadowSurfaceUpdate SurfaceUpdate; \
- \
pfnShadowSynchronizeEvent SynchronizeEvent; \
pfnShadowKeyboardEvent KeyboardEvent; \
pfnShadowUnicodeKeyboardEvent UnicodeKeyboardEvent; \
FREERDP_API int shadow_server_init(rdpShadowServer* server);
FREERDP_API int shadow_server_uninit(rdpShadowServer* server);
-FREERDP_API int shadow_enum_monitors(MONITOR_DEF* monitors, int maxMonitors, UINT32 flags);
+FREERDP_API int shadow_enum_monitors(MONITOR_DEF* monitors, int maxMonitors, const char* name);
FREERDP_API rdpShadowServer* shadow_server_new();
FREERDP_API void shadow_server_free(rdpShadowServer* server);
return NULL;
}
-int mac_shadow_enum_monitors(macShadowSubsystem* subsystem, MONITOR_DEF* monitors, int maxMonitors)
+int mac_shadow_enum_monitors(MONITOR_DEF* monitors, int maxMonitors)
{
int index;
size_t wide, high;
free(subsystem);
}
-macShadowSubsystem* mac_shadow_subsystem_new(rdpShadowServer* server)
+macShadowSubsystem* mac_shadow_subsystem_new()
{
macShadowSubsystem* subsystem;
if (!subsystem)
return NULL;
- subsystem->Init = (pfnShadowSubsystemInit) mac_shadow_subsystem_init;
- subsystem->Uninit = (pfnShadowSubsystemInit) mac_shadow_subsystem_uninit;
- subsystem->Start = (pfnShadowSubsystemStart) mac_shadow_subsystem_start;
- subsystem->Stop = (pfnShadowSubsystemStop) mac_shadow_subsystem_stop;
- subsystem->Free = (pfnShadowSubsystemFree) mac_shadow_subsystem_free;
-
- subsystem->EnumMonitors = (pfnShadowEnumMonitors) mac_shadow_enum_monitors;
-
subsystem->SynchronizeEvent = (pfnShadowSynchronizeEvent) mac_shadow_input_synchronize_event;
subsystem->KeyboardEvent = (pfnShadowKeyboardEvent) mac_shadow_input_keyboard_event;
subsystem->UnicodeKeyboardEvent = (pfnShadowUnicodeKeyboardEvent) mac_shadow_input_unicode_keyboard_event;
return subsystem;
}
-rdpShadowSubsystem* Mac_ShadowCreateSubsystem(rdpShadowServer* server)
+int Mac_ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints)
{
- return (rdpShadowSubsystem*) mac_shadow_subsystem_new(server);
+ pEntryPoints->New = (pfnShadowSubsystemNew) mac_shadow_subsystem_new;
+ pEntryPoints->Free = (pfnShadowSubsystemFree) mac_shadow_subsystem_free;
+
+ pEntryPoints->Init = (pfnShadowSubsystemInit) mac_shadow_subsystem_init;
+ pEntryPoints->Uninit = (pfnShadowSubsystemInit) mac_shadow_subsystem_uninit;
+
+ pEntryPoints->Start = (pfnShadowSubsystemStart) mac_shadow_subsystem_start;
+ pEntryPoints->Stop = (pfnShadowSubsystemStop) mac_shadow_subsystem_stop;
+
+ pEntryPoints->EnumMonitors = (pfnShadowEnumMonitors) mac_shadow_enum_monitors;
+
+ return 1;
}
#endif
-int win_shadow_enum_monitors(winShadowSubsystem* subsystem, MONITOR_DEF* monitors, int maxMonitors)
+int win_shadow_enum_monitors(MONITOR_DEF* monitors, int maxMonitors)
{
HDC hdc;
int index;
int win_shadow_subsystem_init(winShadowSubsystem* subsystem)
{
- HDC hdc;
int status;
- DWORD iDevNum = 0;
MONITOR_DEF* virtualScreen;
- DISPLAY_DEVICE DisplayDevice;
-
- ZeroMemory(&DisplayDevice, sizeof(DISPLAY_DEVICE));
- DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
-
- if (!EnumDisplayDevices(NULL, iDevNum, &DisplayDevice, 0))
- return -1;
- hdc = CreateDC(DisplayDevice.DeviceName, NULL, NULL, NULL);
-
- subsystem->width = GetDeviceCaps(hdc, HORZRES);
- subsystem->height = GetDeviceCaps(hdc, VERTRES);
- subsystem->bpp = GetDeviceCaps(hdc, BITSPIXEL);
-
- DeleteDC(hdc);
+ subsystem->numMonitors = win_shadow_enum_monitors(subsystem->monitors, 16);
#if defined(WITH_WDS_API)
status = win_shadow_wds_init(subsystem);
virtualScreen->bottom = subsystem->height;
virtualScreen->flags = 1;
- if (subsystem->numMonitors < 1)
- {
- subsystem->numMonitors = 1;
- subsystem->monitors[0].left = virtualScreen->left;
- subsystem->monitors[0].top = virtualScreen->top;
- subsystem->monitors[0].right = virtualScreen->right;
- subsystem->monitors[0].bottom = virtualScreen->bottom;
- subsystem->monitors[0].flags = 1;
- }
-
WLog_INFO(TAG, "width: %d height: %d", subsystem->width, subsystem->height);
return 1;
free(subsystem);
}
-winShadowSubsystem* win_shadow_subsystem_new(rdpShadowServer* server)
+winShadowSubsystem* win_shadow_subsystem_new()
{
winShadowSubsystem* subsystem;
if (!subsystem)
return NULL;
- subsystem->Init = (pfnShadowSubsystemInit) win_shadow_subsystem_init;
- subsystem->Uninit = (pfnShadowSubsystemInit) win_shadow_subsystem_uninit;
- subsystem->Start = (pfnShadowSubsystemStart) win_shadow_subsystem_start;
- subsystem->Stop = (pfnShadowSubsystemStop) win_shadow_subsystem_stop;
- subsystem->Free = (pfnShadowSubsystemFree) win_shadow_subsystem_free;
-
- subsystem->EnumMonitors = (pfnShadowEnumMonitors) win_shadow_enum_monitors;
-
subsystem->SynchronizeEvent = (pfnShadowSynchronizeEvent) win_shadow_input_synchronize_event;
subsystem->KeyboardEvent = (pfnShadowKeyboardEvent) win_shadow_input_keyboard_event;
subsystem->UnicodeKeyboardEvent = (pfnShadowUnicodeKeyboardEvent) win_shadow_input_unicode_keyboard_event;
return subsystem;
}
-rdpShadowSubsystem* Win_ShadowCreateSubsystem(rdpShadowServer* server)
+int Win_ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints)
{
- return (rdpShadowSubsystem*) win_shadow_subsystem_new(server);
+ pEntryPoints->New = (pfnShadowSubsystemNew) win_shadow_subsystem_new;
+ pEntryPoints->Free = (pfnShadowSubsystemFree) win_shadow_subsystem_free;
+
+ pEntryPoints->Init = (pfnShadowSubsystemInit) win_shadow_subsystem_init;
+ pEntryPoints->Uninit = (pfnShadowSubsystemInit) win_shadow_subsystem_uninit;
+
+ pEntryPoints->Start = (pfnShadowSubsystemStart) win_shadow_subsystem_start;
+ pEntryPoints->Stop = (pfnShadowSubsystemStop) win_shadow_subsystem_stop;
+
+ pEntryPoints->EnumMonitors = (pfnShadowEnumMonitors) win_shadow_enum_monitors;
+
+ return 1;
}
return 1;
}
-int x11_shadow_enum_monitors(x11ShadowSubsystem* subsystem, MONITOR_DEF* monitors, int maxMonitors)
+int x11_shadow_enum_monitors(MONITOR_DEF* monitors, int maxMonitors)
{
int index;
+ Display* display;
+ int displayWidth;
+ int displayHeight;
int numMonitors = 0;
MONITOR_DEF* monitor;
+ if (!getenv("DISPLAY"))
+ setenv("DISPLAY", ":0", 1);
+
+ display = XOpenDisplay(NULL);
+
+ if (!display)
+ {
+ WLog_ERR(TAG, "failed to open display: %s", XDisplayName(NULL));
+ return -1;
+ }
+
+ displayWidth = WidthOfScreen(DefaultScreenOfDisplay(display));
+ displayHeight = HeightOfScreen(DefaultScreenOfDisplay(display));
+
#ifdef WITH_XINERAMA
- if (x11_shadow_xinerama_init(subsystem) > 0)
{
+ int major, minor;
+ int xinerama_event;
+ int xinerama_error;
XineramaScreenInfo* screen;
XineramaScreenInfo* screens;
- screens = XineramaQueryScreens(subsystem->display, &numMonitors);
+ if (XineramaQueryExtension(display, &xinerama_event, &xinerama_error) &&
+ XDamageQueryVersion(display, &major, &minor) && XineramaIsActive(display))
+ {
+ screens = XineramaQueryScreens(display, &numMonitors);
- if (numMonitors > maxMonitors)
- numMonitors = maxMonitors;
+ if (numMonitors > maxMonitors)
+ numMonitors = maxMonitors;
- if (screens && (numMonitors > 0))
- {
- for (index = 0; index < numMonitors; index++)
+ if (screens && (numMonitors > 0))
{
- screen = &screens[index];
- monitor = &monitors[index];
-
- monitor->left = screen->x_org;
- monitor->top = screen->y_org;
- monitor->right = monitor->left + screen->width;
- monitor->bottom = monitor->top + screen->height;
- monitor->flags = (index == 0) ? 1 : 0;
+ for (index = 0; index < numMonitors; index++)
+ {
+ screen = &screens[index];
+ monitor = &monitors[index];
+
+ monitor->left = screen->x_org;
+ monitor->top = screen->y_org;
+ monitor->right = monitor->left + screen->width;
+ monitor->bottom = monitor->top + screen->height;
+ monitor->flags = (index == 0) ? 1 : 0;
+ }
}
- }
- XFree(screens);
+ XFree(screens);
+ }
}
#endif
index = 0;
numMonitors = 1;
- x11_shadow_subsystem_base_init(subsystem);
-
monitor = &monitors[index];
monitor->left = 0;
monitor->top = 0;
- monitor->right = subsystem->width;
- monitor->bottom = subsystem->height;
+ monitor->right = displayWidth;
+ monitor->bottom = displayHeight;
monitor->flags = 1;
}
XPixmapFormatValues* pfs;
MONITOR_DEF* virtualScreen;
- x11_shadow_subsystem_base_init(subsystem);
+ subsystem->numMonitors = x11_shadow_enum_monitors(subsystem->monitors, 16);
- subsystem->numMonitors = x11_shadow_enum_monitors(subsystem, subsystem->monitors, 16);
+ x11_shadow_subsystem_base_init(subsystem);
extensions = XListExtensions(subsystem->display, &nextensions);
virtualScreen->bottom = subsystem->height;
virtualScreen->flags = 1;
- if (subsystem->numMonitors < 1)
- {
- subsystem->numMonitors = 1;
- subsystem->monitors[0].left = virtualScreen->left;
- subsystem->monitors[0].top = virtualScreen->top;
- subsystem->monitors[0].right = virtualScreen->right;
- subsystem->monitors[0].bottom = virtualScreen->bottom;
- subsystem->monitors[0].flags = 1;
- }
-
WLog_INFO(TAG, "X11 Extensions: XFixes: %d Xinerama: %d XDamage: %d XShm: %d",
subsystem->use_xfixes, subsystem->use_xinerama, subsystem->use_xdamage, subsystem->use_xshm);
free(subsystem);
}
-x11ShadowSubsystem* x11_shadow_subsystem_new(rdpShadowServer* server)
+x11ShadowSubsystem* x11_shadow_subsystem_new()
{
x11ShadowSubsystem* subsystem;
if (!subsystem)
return NULL;
- subsystem->Init = (pfnShadowSubsystemInit) x11_shadow_subsystem_init;
- subsystem->Uninit = (pfnShadowSubsystemInit) x11_shadow_subsystem_uninit;
- subsystem->Start = (pfnShadowSubsystemStart) x11_shadow_subsystem_start;
- subsystem->Stop = (pfnShadowSubsystemStop) x11_shadow_subsystem_stop;
- subsystem->Free = (pfnShadowSubsystemFree) x11_shadow_subsystem_free;
-
- subsystem->EnumMonitors = (pfnShadowEnumMonitors) x11_shadow_enum_monitors;
-
subsystem->SynchronizeEvent = (pfnShadowSynchronizeEvent) x11_shadow_input_synchronize_event;
subsystem->KeyboardEvent = (pfnShadowKeyboardEvent) x11_shadow_input_keyboard_event;
subsystem->UnicodeKeyboardEvent = (pfnShadowUnicodeKeyboardEvent) x11_shadow_input_unicode_keyboard_event;
return subsystem;
}
-rdpShadowSubsystem* X11_ShadowCreateSubsystem(rdpShadowServer* server)
+int X11_ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints)
{
- return (rdpShadowSubsystem*) x11_shadow_subsystem_new(server);
+ pEntryPoints->New = (pfnShadowSubsystemNew) x11_shadow_subsystem_new;
+ pEntryPoints->Free = (pfnShadowSubsystemFree) x11_shadow_subsystem_free;
+
+ pEntryPoints->Init = (pfnShadowSubsystemInit) x11_shadow_subsystem_init;
+ pEntryPoints->Uninit = (pfnShadowSubsystemInit) x11_shadow_subsystem_uninit;
+
+ pEntryPoints->Start = (pfnShadowSubsystemStart) x11_shadow_subsystem_start;
+ pEntryPoints->Stop = (pfnShadowSubsystemStop) x11_shadow_subsystem_stop;
+
+ pEntryPoints->EnumMonitors = (pfnShadowEnumMonitors) x11_shadow_enum_monitors;
+
+ return 1;
}
StopEvent = server->StopEvent;
subsystem = server->subsystem;
- if (subsystem->Start)
- {
- subsystem->Start(subsystem);
- }
+ shadow_subsystem_start(server->subsystem);
while (1)
{
listener->Close(listener);
- if (subsystem->Stop)
- {
- subsystem->Stop(subsystem);
- }
+ shadow_subsystem_stop(server->subsystem);
ExitThread(0);
server->listener->info = (void*) server;
server->listener->PeerAccepted = shadow_client_accepted;
- server->subsystem = shadow_subsystem_new(0);
+ server->subsystem = shadow_subsystem_new(NULL);
if (!server->subsystem)
return -1;
server->listener = NULL;
}
- if (server->subsystem)
- {
- server->subsystem->Free(server->subsystem);
- server->subsystem = NULL;
- }
-
if (server->CertificateFile)
{
free(server->CertificateFile);
return 1;
}
-int shadow_enum_monitors(MONITOR_DEF* monitors, int maxMonitors, UINT32 flags)
-{
- int numMonitors = 0;
- rdpShadowSubsystem* subsystem;
-
- subsystem = shadow_subsystem_new(flags);
-
- if (!subsystem)
- return -1;
-
- if (!subsystem->EnumMonitors)
- return -1;
-
- numMonitors = subsystem->EnumMonitors(subsystem, monitors, maxMonitors);
-
- shadow_subsystem_free(subsystem);
-
- return numMonitors;
-}
-
rdpShadowServer* shadow_server_new()
{
rdpShadowServer* server;
server->clients = NULL;
}
- shadow_server_uninit(server);
+ shadow_subsystem_free(server->subsystem);
free(server);
}
#include "shadow_subsystem.h"
+struct _RDP_SHADOW_SUBSYSTEM
+{
+ const char* name;
+ pfnShadowSubsystemEntry entry;
+};
+typedef struct _RDP_SHADOW_SUBSYSTEM RDP_SHADOW_SUBSYSTEM;
+
+
#ifdef WITH_SHADOW_X11
-extern rdpShadowSubsystem* X11_ShadowCreateSubsystem(rdpShadowServer* server);
+extern int X11_ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints);
#endif
#ifdef WITH_SHADOW_MAC
-extern rdpShadowSubsystem* Mac_ShadowCreateSubsystem(rdpShadowServer* server);
+extern int Mac_ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints);
#endif
#ifdef WITH_SHADOW_WIN
-extern rdpShadowSubsystem* Win_ShadowCreateSubsystem(rdpShadowServer* server);
+extern int Win_ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints);
#endif
-rdpShadowSubsystem* shadow_subsystem_new(UINT32 flags)
+
+static RDP_SHADOW_SUBSYSTEM g_Subsystems[] =
{
- rdpShadowSubsystem* subsystem = NULL;
- pfnShadowCreateSubsystem CreateSubsystem = NULL;
#ifdef WITH_SHADOW_X11
- CreateSubsystem = X11_ShadowCreateSubsystem;
+ { "X11", X11_ShadowSubsystemEntry },
#endif
#ifdef WITH_SHADOW_MAC
- CreateSubsystem = Mac_ShadowCreateSubsystem;
+ { "Mac", Mac_ShadowSubsystemEntry },
#endif
#ifdef WITH_SHADOW_WIN
- CreateSubsystem = Win_ShadowCreateSubsystem;
+ { "Win", Win_ShadowSubsystemEntry },
#endif
- if (CreateSubsystem)
- subsystem = CreateSubsystem(NULL);
+ { "", NULL }
+};
+
+static int g_SubsystemCount = (sizeof(g_Subsystems) / sizeof(g_Subsystems[0]));
+
+pfnShadowSubsystemEntry shadow_subsystem_load_static_entry(const char* name)
+{
+ int index;
+
+ if (!name)
+ {
+ for (index = 0; index < g_SubsystemCount; index++)
+ {
+ if (g_Subsystems[index].name)
+ return g_Subsystems[index].entry;
+ }
+ }
+
+ for (index = 0; index < g_SubsystemCount; index++)
+ {
+ if (strcmp(name, g_Subsystems[index].name) == 0)
+ return g_Subsystems[index].entry;
+ }
+
+ return NULL;
+}
+
+int shadow_subsystem_load_entry_points(RDP_SHADOW_ENTRY_POINTS* pEntryPoints, const char* name)
+{
+ pfnShadowSubsystemEntry entry;
+
+ entry = shadow_subsystem_load_static_entry(name);
+
+ if (!entry)
+ return -1;
+
+ ZeroMemory(pEntryPoints, sizeof(RDP_SHADOW_ENTRY_POINTS));
+
+ if (entry(pEntryPoints) < 0)
+ return -1;
+
+ return 1;
+}
+
+rdpShadowSubsystem* shadow_subsystem_new(const char* name)
+{
+ RDP_SHADOW_ENTRY_POINTS ep;
+ rdpShadowSubsystem* subsystem = NULL;
+
+ shadow_subsystem_load_entry_points(&ep, name);
+
+ if (!ep.New)
+ return NULL;
+
+ subsystem = ep.New();
+
+ if (!subsystem)
+ return NULL;
+
+ CopyMemory(&(subsystem->ep), &ep, sizeof(RDP_SHADOW_ENTRY_POINTS));
return subsystem;
}
void shadow_subsystem_free(rdpShadowSubsystem* subsystem)
{
- if (subsystem->Free)
- subsystem->Free(subsystem);
+ if (subsystem->ep.Free)
+ subsystem->ep.Free(subsystem);
}
int shadow_subsystem_init(rdpShadowSubsystem* subsystem, rdpShadowServer* server)
subsystem->MsgPipe = MessagePipe_New();
region16_init(&(subsystem->invalidRegion));
- if (!subsystem->Init)
+ if (!subsystem->ep.Init)
return -1;
- if (subsystem->Init)
- status = subsystem->Init(subsystem);
+ if (subsystem->ep.Init)
+ status = subsystem->ep.Init(subsystem);
return status;
}
void shadow_subsystem_uninit(rdpShadowSubsystem* subsystem)
{
- if (subsystem->Uninit)
- subsystem->Uninit(subsystem);
+ if (subsystem->ep.Uninit)
+ subsystem->ep.Uninit(subsystem);
if (subsystem->updateEvent)
{
region16_uninit(&(subsystem->invalidRegion));
}
}
+
+int shadow_subsystem_start(rdpShadowSubsystem* subsystem)
+{
+ int status;
+
+ if (!subsystem->ep.Start)
+ return -1;
+
+ status = subsystem->ep.Start(subsystem);
+
+ return status;
+}
+
+int shadow_subsystem_stop(rdpShadowSubsystem* subsystem)
+{
+ int status;
+
+ if (!subsystem->ep.Stop)
+ return -1;
+
+ status = subsystem->ep.Stop(subsystem);
+
+ return status;
+}
+
+int shadow_enum_monitors(MONITOR_DEF* monitors, int maxMonitors, const char* name)
+{
+ int numMonitors = 0;
+ RDP_SHADOW_ENTRY_POINTS ep;
+
+ if (shadow_subsystem_load_entry_points(&ep, name) < 0)
+ return -1;
+
+ numMonitors = ep.EnumMonitors(monitors, maxMonitors);
+
+ return numMonitors;
+}
extern "C" {
#endif
-rdpShadowSubsystem* shadow_subsystem_new(UINT32 flags);
+rdpShadowSubsystem* shadow_subsystem_new(const char* name);
void shadow_subsystem_free(rdpShadowSubsystem* subsystem);
int shadow_subsystem_init(rdpShadowSubsystem* subsystem, rdpShadowServer* server);
void shadow_subsystem_uninit(rdpShadowSubsystem* subsystem);
+int shadow_subsystem_start(rdpShadowSubsystem* subsystem);
+int shadow_subsystem_stop(rdpShadowSubsystem* subsystem);
+
#ifdef __cplusplus
}
#endif