diff --git a/lsteamclient/steamclient_main.c b/lsteamclient/steamclient_main.c
index 123e5dbb..9c1631da 100644
--- a/lsteamclient/steamclient_main.c
+++ b/lsteamclient/steamclient_main.c
@@ -352,6 +352,10 @@ static void execute_pending_callbacks(void)
                    params.callback->warning_message_hook.severity, wine_dbgstr_a( params.callback->warning_message_hook.msg ) );
             params.callback->warning_message_hook.pFunction( params.callback->warning_message_hook.severity, params.callback->warning_message_hook.msg );
             break;
+        case CALL_CDECL_FUNC_DATA:
+            TRACE( "CALL_CDECL_FUNC_DATA func %p, data %p.\n", params.callback->call_cdecl_func_data.pFunc, params.callback->call_cdecl_func_data.data );
+            params.callback->call_cdecl_func_data.pFunc( params.callback->call_cdecl_func_data.data );
+            break;
         case CALL_IFACE_VTABLE_0:
             TRACE( "CALL_IFACE_VTABLE_0 iface %p, arg0 %#jx, arg1 %#jx, arg2 %#jx.\n", params.callback->call_iface_vtable.iface,
                    params.callback->call_iface_vtable.arg0, params.callback->call_iface_vtable.arg1, params.callback->call_iface_vtable.arg2 );
diff --git a/lsteamclient/unix_private.h b/lsteamclient/unix_private.h
index 9273650f..150c801e 100644
--- a/lsteamclient/unix_private.h
+++ b/lsteamclient/unix_private.h
@@ -23,6 +23,9 @@ extern void queue_vtable_callback( struct w_steam_iface *w_iface, enum callback_
 extern void queue_vtable_callback_0_add_player_to_list( struct w_steam_iface *w_iface, const char *pchName, int nScore, float flTimePlayed );
 extern void queue_vtable_callback_0_rules_responded( struct w_steam_iface *w_iface, const char *pchRule, const char *pchValue );
 
+typedef void (*W_CDECL w_cdecl_func)( void * );
+extern void queue_cdecl_func_callback( w_cdecl_func func, void *data, uint32_t data_size );
+
 extern uint32_t manual_convert_nNativeKeyCode( uint32_t win_vk );
 
 typedef void (U_CDECL *u_SteamAPIWarningMessageHook_t)( int32_t, const char * );
diff --git a/lsteamclient/unix_steam_networking_manual.cpp b/lsteamclient/unix_steam_networking_manual.cpp
index 7dfc785c..f40d96d8 100644
--- a/lsteamclient/unix_steam_networking_manual.cpp
+++ b/lsteamclient/unix_steam_networking_manual.cpp
@@ -296,55 +296,42 @@ NTSTATUS ISteamNetworkingUtils_SteamNetworkingUtils003_AllocateMessage( void *ar
     return 0;
 }
 
-typedef void (*CDECL win_FnSteamNetConnectionStatusChanged)( w_SteamNetConnectionStatusChangedCallback_t_151 * );
-static win_FnSteamNetConnectionStatusChanged win_SteamNetConnectionStatusChanged;
-static void lin_SteamNetConnectionStatusChanged( u_SteamNetConnectionStatusChangedCallback_t_151 *u_dat )
+static void (*W_CDECL w_SteamNetConnectionStatusChanged)( w_SteamNetConnectionStatusChangedCallback_t_151 * );
+static void U_CDECL u_SteamNetConnectionStatusChanged( u_SteamNetConnectionStatusChangedCallback_t_151 *u_dat )
 {
-    win_FnSteamNetConnectionStatusChanged fn = win_SteamNetConnectionStatusChanged;
-    if (fn)
-    {
-        w_SteamNetConnectionStatusChangedCallback_t_151 w_dat = *u_dat;
-        fn( &w_dat );
-    }
+    w_SteamNetConnectionStatusChangedCallback_t_151 w_dat = *u_dat;
+    if (w_SteamNetConnectionStatusChanged) queue_cdecl_func_callback( (w_cdecl_func)w_SteamNetConnectionStatusChanged, &w_dat, sizeof(w_dat) );
 }
 
-typedef void (*CDECL win_FnSteamNetAuthenticationStatusChanged)( SteamNetAuthenticationStatus_t * );
-static win_FnSteamNetAuthenticationStatusChanged win_SteamNetAuthenticationStatusChanged;
-static void lin_SteamNetAuthenticationStatusChanged( SteamNetAuthenticationStatus_t *dat )
+static void (*W_CDECL w_SteamNetAuthenticationStatusChanged)( SteamNetAuthenticationStatus_t * );
+static void U_CDECL u_SteamNetAuthenticationStatusChanged( SteamNetAuthenticationStatus_t *dat )
 {
-    win_FnSteamNetAuthenticationStatusChanged fn = win_SteamNetAuthenticationStatusChanged;
-    if (fn) fn( dat );
+    if (w_SteamNetAuthenticationStatusChanged) queue_cdecl_func_callback( (w_cdecl_func)w_SteamNetAuthenticationStatusChanged, dat, sizeof(*dat) );
 }
 
-typedef void (*CDECL win_FnSteamRelayNetworkStatusChanged)( SteamRelayNetworkStatus_t * );
-static win_FnSteamRelayNetworkStatusChanged win_SteamRelayNetworkStatusChanged;
-static void lin_SteamRelayNetworkStatusChanged( SteamRelayNetworkStatus_t *dat )
+static void (*W_CDECL w_SteamRelayNetworkStatusChanged)( SteamRelayNetworkStatus_t * );
+static void U_CDECL u_SteamRelayNetworkStatusChanged( SteamRelayNetworkStatus_t *dat )
 {
-    win_FnSteamRelayNetworkStatusChanged fn = win_SteamRelayNetworkStatusChanged;
-    if (fn) fn( dat );
+    if (w_SteamRelayNetworkStatusChanged) queue_cdecl_func_callback( (w_cdecl_func)w_SteamRelayNetworkStatusChanged, dat, sizeof(*dat) );
 }
 
-typedef void (*CDECL win_FnSteamNetworkingMessagesSessionRequest)( SteamNetworkingMessagesSessionRequest_t_151 * );
-static win_FnSteamNetworkingMessagesSessionRequest win_SteamNetworkingMessagesSessionRequest;
-static void lin_SteamNetworkingMessagesSessionRequest( SteamNetworkingMessagesSessionRequest_t_151 *dat )
+static void (*W_CDECL w_SteamNetworkingMessagesSessionRequest)( SteamNetworkingMessagesSessionRequest_t_151 * );
+static void U_CDECL u_SteamNetworkingMessagesSessionRequest( SteamNetworkingMessagesSessionRequest_t_151 *dat )
 {
-    win_FnSteamNetworkingMessagesSessionRequest fn = win_SteamNetworkingMessagesSessionRequest;
-    if (fn) fn( dat );
+    if (w_SteamNetworkingMessagesSessionRequest) queue_cdecl_func_callback( (w_cdecl_func)w_SteamNetworkingMessagesSessionRequest, dat, sizeof(*dat) );
 }
 
-typedef void (*CDECL win_FnSteamNetworkingMessagesSessionFailed)( SteamNetworkingMessagesSessionFailed_t_151 * );
-static win_FnSteamNetworkingMessagesSessionFailed win_SteamNetworkingMessagesSessionFailed;
-static void lin_SteamNetworkingMessagesSessionFailed( SteamNetworkingMessagesSessionFailed_t_151 *dat )
+static void (*W_CDECL w_SteamNetworkingMessagesSessionFailed)( SteamNetworkingMessagesSessionFailed_t_151 * );
+static void U_CDECL u_SteamNetworkingMessagesSessionFailed( SteamNetworkingMessagesSessionFailed_t_151 *dat )
 {
-    win_FnSteamNetworkingMessagesSessionFailed fn = win_SteamNetworkingMessagesSessionFailed;
-    if (fn) fn( dat );
+    if (w_SteamNetworkingMessagesSessionFailed) queue_cdecl_func_callback( (w_cdecl_func)w_SteamNetworkingMessagesSessionFailed, dat, sizeof(*dat) );
 }
 
 NTSTATUS ISteamNetworkingUtils_SteamNetworkingUtils003_SetConfigValue( void *args )
 {
     struct ISteamNetworkingUtils_SteamNetworkingUtils003_SetConfigValue_params *params = (struct ISteamNetworkingUtils_SteamNetworkingUtils003_SetConfigValue_params *)args;
     struct u_ISteamNetworkingUtils_SteamNetworkingUtils003 *iface = (struct u_ISteamNetworkingUtils_SteamNetworkingUtils003 *)params->linux_side;
-    void *lin_fn; /* api requires passing pointer-to-pointer */
+    void *u_fn; /* api requires passing pointer-to-pointer */
 
     switch (params->eValue)
     {
@@ -356,11 +343,11 @@ NTSTATUS ISteamNetworkingUtils_SteamNetworkingUtils003_SetConfigValue( void *arg
     }                                                                                              \
     else                                                                                           \
     {                                                                                              \
-        if (*(void **)params->pArg == NULL) lin_fn = NULL;                                         \
-        else lin_fn = (void *)&lin_##y;                                                            \
+        if (*(void **)params->pArg == NULL) u_fn = NULL;                                           \
+        else u_fn = (void *)&u_##y;                                                                \
         params->_ret = iface->SetConfigValue( params->eValue, params->eScopeType,                  \
-                                              params->scopeObj, params->eDataType, &lin_fn );      \
-        if (params->_ret) win_##y = *(win_Fn##y *)params->pArg;                                    \
+                                              params->scopeObj, params->eDataType, &u_fn );        \
+        if (params->_ret) w_##y = *(decltype(w_##y) *)params->pArg;                                \
     }
 
     case 201 /*ConnectionStatusChanged*/: CASE( SteamNetConnectionStatusChanged )
@@ -548,24 +535,17 @@ NTSTATUS ISteamNetworkingUtils_SteamNetworkingUtils004_AllocateMessage( void *ar
     return 0;
 }
 
-typedef void (*CDECL win_FnSteamNetConnectionStatusChanged_153a)( w_SteamNetConnectionStatusChangedCallback_t_153a * );
-static win_FnSteamNetConnectionStatusChanged_153a win_SteamNetConnectionStatusChanged_153a;
-static void lin_SteamNetConnectionStatusChanged_153a( u_SteamNetConnectionStatusChangedCallback_t_153a *u_dat )
+static void (*W_CDECL w_SteamNetConnectionStatusChanged_153a)( w_SteamNetConnectionStatusChangedCallback_t_153a * );
+static void U_CDECL u_SteamNetConnectionStatusChanged_153a( u_SteamNetConnectionStatusChangedCallback_t_153a *u_dat )
 {
-    win_FnSteamNetConnectionStatusChanged_153a fn = win_SteamNetConnectionStatusChanged_153a;
-    if (fn)
-    {
-        w_SteamNetConnectionStatusChangedCallback_t_153a w_dat = *u_dat;
-        fn( &w_dat );
-    }
+    w_SteamNetConnectionStatusChangedCallback_t_153a w_dat = *u_dat;
+    if (w_SteamNetConnectionStatusChanged_153a) queue_cdecl_func_callback( (w_cdecl_func)w_SteamNetConnectionStatusChanged_153a, &w_dat, sizeof(w_dat) );
 }
 
-typedef void (*CDECL win_FnSteamNetworkingMessagesSessionFailed_153a)( SteamNetworkingMessagesSessionFailed_t_153a * );
-static win_FnSteamNetworkingMessagesSessionFailed_153a win_SteamNetworkingMessagesSessionFailed_153a;
-static void lin_SteamNetworkingMessagesSessionFailed_153a( SteamNetworkingMessagesSessionFailed_t_153a *dat )
+static void (*W_CDECL w_SteamNetworkingMessagesSessionFailed_153a)( SteamNetworkingMessagesSessionFailed_t_153a * );
+static void U_CDECL u_SteamNetworkingMessagesSessionFailed_153a( SteamNetworkingMessagesSessionFailed_t_153a *dat )
 {
-    win_FnSteamNetworkingMessagesSessionFailed_153a fn = win_SteamNetworkingMessagesSessionFailed_153a;
-    if (fn) fn( dat );
+    if (w_SteamNetworkingMessagesSessionFailed_153a) queue_cdecl_func_callback( (w_cdecl_func)w_SteamNetworkingMessagesSessionFailed_153a, dat, sizeof(*dat) );
 }
 
 NTSTATUS ISteamNetworkingUtils_SteamNetworkingUtils004_SetConfigValue( void *args )
@@ -573,7 +553,7 @@ NTSTATUS ISteamNetworkingUtils_SteamNetworkingUtils004_SetConfigValue( void *arg
     struct ISteamNetworkingUtils_SteamNetworkingUtils004_SetConfigValue_params *params = (struct ISteamNetworkingUtils_SteamNetworkingUtils004_SetConfigValue_params *)args;
     struct u_ISteamNetworkingUtils_SteamNetworkingUtils004 *iface = (struct u_ISteamNetworkingUtils_SteamNetworkingUtils004 *)params->linux_side;
     bool ret;
-    void *lin_fn; /* api requires passing pointer-to-pointer */
+    void *u_fn; /* api requires passing pointer-to-pointer */
 
     switch (params->eValue)
     {
@@ -586,11 +566,11 @@ NTSTATUS ISteamNetworkingUtils_SteamNetworkingUtils004_SetConfigValue( void *arg
     }                                                                                              \
     else                                                                                           \
     {                                                                                              \
-        if (*(void **)params->pArg == NULL) lin_fn = NULL;                                         \
-        else lin_fn = (void *)&lin_##y;                                                            \
+        if (*(void **)params->pArg == NULL) u_fn = NULL;                                           \
+        else u_fn = (void *)&u_##y;                                                                \
         params->_ret = iface->SetConfigValue( params->eValue, params->eScopeType,                  \
-                                              params->scopeObj, params->eDataType, &lin_fn );      \
-        if (params->_ret) win_##y = *(win_Fn##y *)params->pArg;                                    \
+                                              params->scopeObj, params->eDataType, &u_fn );        \
+        if (params->_ret) w_##y = *(decltype(w_##y) *)params->pArg;                                \
     }
 
     case 201 /*ConnectionStatusChanged*/: CASE( SteamNetConnectionStatusChanged_153a )
diff --git a/lsteamclient/unixlib.cpp b/lsteamclient/unixlib.cpp
index 36b1ab23..34f82624 100644
--- a/lsteamclient/unixlib.cpp
+++ b/lsteamclient/unixlib.cpp
@@ -103,6 +103,26 @@ static void u_steam_networking_socket_debug_output( uint32_t nType, const char *
     pthread_mutex_unlock( &callbacks_lock );
 }
 
+void queue_cdecl_func_callback( w_cdecl_func func, void *data, uint32_t data_size )
+{
+    uint32_t size = data_size;
+    struct callback_entry *entry;
+
+    size += sizeof(struct callback_entry);
+    if (!(entry = (struct callback_entry *)malloc( size ))) return;
+
+    entry->callback.type = CALL_CDECL_FUNC_DATA;
+    size -= offsetof( struct callback_entry, callback );
+    entry->callback.size = size;
+
+    entry->callback.call_cdecl_func_data.pFunc = func;
+    memcpy( (char *)entry->callback.call_cdecl_func_data.data, data, data_size );
+
+    pthread_mutex_lock( &callbacks_lock );
+    list_add_tail( &callbacks, &entry->entry );
+    pthread_mutex_unlock( &callbacks_lock );
+}
+
 u_FSteamNetworkingSocketsDebugOutput manual_convert_SetDebugOutputFunction_pfnFunc( w_FSteamNetworkingSocketsDebugOutput w_func )
 {
     w_steam_networking_socket_debug_output = w_func;
diff --git a/lsteamclient/unixlib.h b/lsteamclient/unixlib.h
index 90307ffb..c3521006 100644
--- a/lsteamclient/unixlib.h
+++ b/lsteamclient/unixlib.h
@@ -34,6 +34,7 @@ enum callback_type
 {
     SOCKETS_DEBUG_OUTPUT = 1,
     WARNING_MESSAGE_HOOK,
+    CALL_CDECL_FUNC_DATA,
     CALL_IFACE_VTABLE_0,
     CALL_IFACE_VTABLE_1,
     CALL_IFACE_VTABLE_2,
@@ -62,6 +63,12 @@ struct callback
             const char msg[1];
         } warning_message_hook;
 
+        struct
+        {
+            void (*W_CDECL pFunc)( void * );
+            unsigned char data[1];
+        } call_cdecl_func_data;
+
         struct
         {
             struct w_steam_iface *iface;