[Bug 28898] Blizzard Launcher/Installer needs AcceptEx improvements (Affects WoW, D3...)
wine-bugs at winehq.org
wine-bugs at winehq.org
Mon May 14 15:44:36 CDT 2012
http://bugs.winehq.org/show_bug.cgi?id=28898
Jerome Leclanche <adys.wh at gmail.com> changed:
What |Removed |Added
----------------------------------------------------------------------------
Attachment #38954|0 |1
is obsolete| |
--- Comment #100 from Jerome Leclanche <adys.wh at gmail.com> 2012-05-14 15:44:36 CDT ---
Comment on attachment 38954
--> http://bugs.winehq.org/attachment.cgi?id=38954
Try to hack together a solution for the D3 installer
>diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c
>index 2a3285f..88946ba 100644
>--- a/dlls/iphlpapi/iphlpapi_main.c
>+++ b/dlls/iphlpapi/iphlpapi_main.c
>@@ -1883,15 +1883,36 @@ DWORD WINAPI GetTcpTable(PMIB_TCPTABLE pTcpTable, PDWORD pdwSize, BOOL bOrder)
> DWORD WINAPI GetExtendedTcpTable(PVOID pTcpTable, PDWORD pdwSize, BOOL bOrder,
> ULONG ulAf, TCP_TABLE_CLASS TableClass, ULONG Reserved)
> {
>+ DWORD table_size;
>+ VOID *table;
>+ DWORD ret;
>+
> TRACE("pTcpTable %p, pdwSize %p, bOrder %d, ulAf %u, TableClass %u, Reserved %u\n",
> pTcpTable, pdwSize, bOrder, ulAf, TableClass, Reserved);
>
>- if (ulAf == AF_INET6 || TableClass != TCP_TABLE_BASIC_ALL)
>+ if (!pdwSize) return ERROR_INVALID_PARAMETER;
>+
>+ if (ulAf == AF_INET6)
> {
>- FIXME("ulAf = %u, TableClass = %u not supportted\n", ulAf, TableClass);
>+ FIXME("AF_INET6 not supported\n");
> return ERROR_NOT_SUPPORTED;
> }
>- return GetTcpTable(pTcpTable, pdwSize, bOrder);
>+
>+ ret = tcp_build_table(GetProcessHeap(), 0, &table, &table_size, bOrder, TableClass);
>+ if (!ret) {
>+ if (!pTcpTable || *pdwSize < table_size) {
>+ *pdwSize = table_size;
>+ ret = ERROR_INSUFFICIENT_BUFFER;
>+ }
>+ else {
>+ *pdwSize = table_size;
>+ memcpy(pTcpTable, table, table_size);
>+ }
>+ HeapFree(GetProcessHeap(), 0, table);
>+ }
>+
>+ TRACE("returning %d\n", ret);
>+ return ret;
> }
>
> /******************************************************************
>diff --git a/dlls/iphlpapi/ipstats.c b/dlls/iphlpapi/ipstats.c
>index db475fb..8d81b92 100644
>--- a/dlls/iphlpapi/ipstats.c
>+++ b/dlls/iphlpapi/ipstats.c
>@@ -1617,15 +1617,17 @@ DWORD WINAPI AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE *ppUdpTable, BOOL bOr
> }
>
>
>-static MIB_TCPTABLE *append_tcp_row( HANDLE heap, DWORD flags, MIB_TCPTABLE *table,
>- DWORD *count, const MIB_TCPROW *row )
>+static VOID *append_tcp_row( HANDLE heap, DWORD flags, VOID *table, DWORD *count,
>+ const VOID *row, DWORD row_size, DWORD table_struct_size )
> {
>- if (table->dwNumEntries >= *count)
>+ DWORD dwNumEntries = *(DWORD *)table;
>+
>+ if (dwNumEntries >= *count)
> {
>- MIB_TCPTABLE *new_table;
>- DWORD new_count = table->dwNumEntries * 2;
>+ VOID *new_table;
>+ DWORD new_count = dwNumEntries * 2;
>
>- if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_TCPTABLE, table[new_count] ))))
>+ if (!(new_table = HeapReAlloc( heap, flags, table, table_struct_size + row_size*new_count )))
> {
> HeapFree( heap, 0, table );
> return NULL;
>@@ -1633,7 +1635,8 @@ static MIB_TCPTABLE *append_tcp_row( HANDLE heap, DWORD flags, MIB_TCPTABLE *tab
> *count = new_count;
> table = new_table;
> }
>- memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
>+ memcpy( (CHAR *)table + sizeof(DWORD) + dwNumEntries*row_size, row, row_size );
>+ *(DWORD *)table = dwNumEntries+1;
> return table;
> }
>
>@@ -1674,38 +1677,34 @@ static int compare_tcp_rows(const void *a, const void *b)
> }
>
>
>-/******************************************************************
>- * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
>- *
>- * Get the TCP connection table.
>- * Like GetTcpTable(), but allocate the returned table from heap.
>- *
>- * PARAMS
>- * ppTcpTable [Out] pointer into which the MIB_TCPTABLE is
>- * allocated and returned.
>- * bOrder [In] whether to sort the table
>- * heap [In] heap from which the table is allocated
>- * flags [In] flags to HeapAlloc
>- *
>- * RETURNS
>- * ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
>- * returns otherwise.
>- */
>-DWORD WINAPI AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE *ppTcpTable, BOOL bOrder,
>- HANDLE heap, DWORD flags)
>+#include "wine/server.h"
>+#define STATUS_SUCCESS 0
>+DWORD tcp_build_table(HANDLE heap, DWORD flags, VOID **table, DWORD *table_size, BOOL bOrder,
>+ TCP_TABLE_CLASS TableClass)
> {
>- MIB_TCPTABLE *table;
>- MIB_TCPROW row;
>- DWORD ret = NO_ERROR, count = 16;
>-
>- TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppTcpTable, bOrder, heap, flags);
>+ DWORD ret = NO_ERROR, row_size, table_struct_size;
>+ MIB_TCPROW_OWNER_PID row;
>+ DWORD count = 16;
>
>- if (!ppTcpTable) return ERROR_INVALID_PARAMETER;
>+ switch(TableClass)
>+ {
>+ case TCP_TABLE_BASIC_ALL:
>+ row_size = sizeof(MIB_TCPROW);
>+ table_struct_size = sizeof(MIB_TCPTABLE)-row_size;
>+ break;
>+ case TCP_TABLE_OWNER_PID_ALL:
>+ row_size = sizeof(MIB_TCPROW_OWNER_PID);
>+ table_struct_size = sizeof(MIB_TCPTABLE_OWNER_PID)-row_size;
>+ break;
>+ default:
>+ FIXME("TableClass = %u not supported\n", TableClass);
>+ return ERROR_NOT_SUPPORTED;
>+ }
>
>- if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_TCPTABLE, table[count] ))))
>+ if (!(*table = HeapAlloc( heap, flags, table_struct_size+row_size*count )))
> return ERROR_OUTOFMEMORY;
>
>- table->dwNumEntries = 0;
>+ *(DWORD *)*table = 0;
>
> #ifdef __linux__
> {
>@@ -1720,13 +1719,43 @@ DWORD WINAPI AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE *ppTcpTable, BOOL bO
> ptr = fgets(buf, sizeof(buf), fp);
> while ((ptr = fgets(buf, sizeof(buf), fp)))
> {
>- if (sscanf( ptr, "%x: %x:%x %x:%x %x", &dummy, &row.dwLocalAddr, &row.dwLocalPort,
>- &row.dwRemoteAddr, &row.dwRemotePort, &row.u.dwState ) != 6)
>+ int inode;
>+
>+ if (sscanf( ptr, "%x: %x:%x %x:%x %x %*s %*s %*s %*s %*s %d", &dummy, &row.dwLocalAddr, &row.dwLocalPort,
>+ &row.dwRemoteAddr, &row.dwRemotePort, &row.dwState, &inode ) != 7)
> continue;
>+ if (inode)
>+ {
>+ char cmd[200], ret[200];
>+ FILE *handle;
>+ size_t r = 0;
>+
>+ ret[0] = 0;
>+ snprintf(cmd, sizeof(cmd), "lsof +c 0 -i :%d | grep '\\.exe' | grep ' %d ' | sed 's/[^ ]* *//' | sed 's/ .*//'", row.dwRemotePort, inode);
>+ handle = popen(cmd, "r");
>+ while(!feof(handle))
>+ r = fread(ret, 1, sizeof(ret), handle);
>+ if(r)
>+ {
>+ int unix_pid, status;
>+
>+ sscanf(ret, "%d", &unix_pid);
>+ SERVER_START_REQ( find_process )
>+ {
>+ req->unix_pid = unix_pid;
>+ status = wine_server_call( req );
>+ if (status == STATUS_SUCCESS)
>+ row.dwOwningPid = reply->pid;
>+ }
>+ SERVER_END_REQ;
>+FIXME("found pid %d\n", row.dwOwningPid);
>+ }
>+ pclose(handle);
>+ }
> row.dwLocalPort = htons( row.dwLocalPort );
> row.dwRemotePort = htons( row.dwRemotePort );
>- row.u.State = TCPStateToMIBState( row.u.dwState );
>- if (!(table = append_tcp_row( heap, flags, table, &count, &row )))
>+ row.dwState = TCPStateToMIBState( row.dwState );
>+ if (!(*table = append_tcp_row( heap, flags, *table, &count, &row, row_size, table_struct_size )))
> break;
> }
> fclose( fp );
>@@ -1749,8 +1778,8 @@ DWORD WINAPI AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE *ppTcpTable, BOOL bO
> row.dwLocalPort = htons( entry->tcpConnLocalPort );
> row.dwRemoteAddr = entry->tcpConnRemAddress;
> row.dwRemotePort = htons( entry->tcpConnRemPort );
>- row.u.dwState = entry->tcpConnState;
>- if (!(table = append_tcp_row( heap, flags, table, &count, &row ))) break;
>+ row.dwState = entry->tcpConnState;
>+ if (!(*table = append_tcp_row( heap, flags, *table, &count, &row, row_size, table_struct_size ))) break;
> }
> HeapFree( GetProcessHeap(), 0, data );
> }
>@@ -1828,8 +1857,8 @@ DWORD WINAPI AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE *ppTcpTable, BOOL bO
> row.dwLocalPort = pINData->inp_lport;
> row.dwRemoteAddr = pINData->inp_faddr.s_addr;
> row.dwRemotePort = pINData->inp_fport;
>- row.u.State = TCPStateToMIBState (pTCPData->t_state);
>- if (!(table = append_tcp_row( heap, flags, table, &count, &row ))) break;
>+ row.dwState = TCPStateToMIBState (pTCPData->t_state);
>+ if (!(*table = append_tcp_row( heap, flags, *table, &count, &row, row_size, table_struct_size ))) break;
> }
>
> done:
>@@ -1840,14 +1869,51 @@ DWORD WINAPI AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE *ppTcpTable, BOOL bO
> ret = ERROR_NOT_SUPPORTED;
> #endif
>
>- if (!table) return ERROR_OUTOFMEMORY;
>+ if (!*table) return ERROR_OUTOFMEMORY;
> if (!ret)
> {
>- if (bOrder && table->dwNumEntries)
>- qsort( table->table, table->dwNumEntries, sizeof(row), compare_tcp_rows );
>- *ppTcpTable = table;
>+ DWORD dwNumEntries = *(DWORD *)*table;
>+ if (bOrder && dwNumEntries)
>+ qsort( (CHAR*)(*table) + sizeof(DWORD), dwNumEntries, row_size, compare_tcp_rows );
>+ if (table_size)
>+ *table_size = table_struct_size + row_size*dwNumEntries;
> }
>- else HeapFree( heap, flags, table );
>+ else HeapFree( heap, flags, *table );
>+ return ret;
>+}
>+
>+
>+/******************************************************************
>+ * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
>+ *
>+ * Get the TCP connection table.
>+ * Like GetTcpTable(), but allocate the returned table from heap.
>+ *
>+ * PARAMS
>+ * ppTcpTable [Out] pointer into which the MIB_TCPTABLE is
>+ * allocated and returned.
>+ * bOrder [In] whether to sort the table
>+ * heap [In] heap from which the table is allocated
>+ * flags [In] flags to HeapAlloc
>+ *
>+ * RETURNS
>+ * ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
>+ * returns otherwise.
>+ */
>+DWORD WINAPI AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE *ppTcpTable, BOOL bOrder,
>+ HANDLE heap, DWORD flags)
>+{
>+ MIB_TCPTABLE *table;
>+ DWORD ret;
>+
>+ TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppTcpTable, bOrder, heap, flags);
>+
>+ if (!ppTcpTable) return ERROR_INVALID_PARAMETER;
>+
>+ ret = tcp_build_table(heap, flags, (VOID **)&table, NULL, bOrder, TCP_TABLE_BASIC_ALL);
>+ if (ret == NO_ERROR)
>+ *ppTcpTable = table;
>+
> TRACE( "returning ret %u table %p\n", ret, table );
> return ret;
> }
>diff --git a/dlls/iphlpapi/ipstats.h b/dlls/iphlpapi/ipstats.h
>index 3522716..c546512 100644
>--- a/dlls/iphlpapi/ipstats.h
>+++ b/dlls/iphlpapi/ipstats.h
>@@ -27,6 +27,8 @@
> #include "winbase.h"
> #include "iprtrmib.h"
>
>+DWORD tcp_build_table(HANDLE heap, DWORD flags, VOID **table, DWORD *table_size, BOOL bOrder, TCP_TABLE_CLASS TableClass);
>+
> /* Fills in entry's interface stats, using name to find them.
> * Returns ERROR_INVALID_PARAMETER if name or entry is NULL, NO_ERROR otherwise.
> */
>diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
>index 0ff19d6..0aa6596 100644
>--- a/dlls/ws2_32/socket.c
>+++ b/dlls/ws2_32/socket.c
>@@ -1707,7 +1707,7 @@ static NTSTATUS WS2_async_accept( void *arg, IO_STATUS_BLOCK *iosb, NTSTATUS sta
> if (status != STATUS_PENDING)
> goto finish;
>
>- return STATUS_SUCCESS;
>+ return STATUS_ALERTED;
>
> finish:
> iosb->u.Status = status;
>@@ -1715,8 +1715,6 @@ finish:
>
> if (wsa->user_overlapped->hEvent)
> SetEvent(wsa->user_overlapped->hEvent);
>- if (wsa->cvalue)
>- WS_AddCompletion( HANDLE2SOCKET(wsa->listen_socket), wsa->cvalue, iosb->u.Status, iosb->Information );
>
> *apc = ws2_async_accept_apc;
> return status;
>@@ -2047,7 +2045,9 @@ static BOOL WINAPI WS2_AcceptEx(SOCKET listener, SOCKET acceptor, PVOID dest, DW
> req->async.callback = wine_server_client_ptr( WS2_async_accept );
> req->async.iosb = wine_server_client_ptr( overlapped );
> req->async.arg = wine_server_client_ptr( wsa );
>- /* We don't set event or completion since we may also have to read */
>+ req->async.cvalue = cvalue;
>+ /* We don't set event since we may also have to read, completion returns STATUS_ALERTED
>+ * to indicate that no completion should be queued. */
> status = wine_server_call( req );
> }
> SERVER_END_REQ;
>diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
>index 0e989da..9851cbb 100644
>--- a/include/wine/server_protocol.h
>+++ b/include/wine/server_protocol.h
>@@ -716,6 +716,20 @@ struct init_thread_reply
>
>
>
>+struct find_process_request
>+{
>+ struct request_header __header;
>+ int unix_pid;
>+};
>+struct find_process_reply
>+{
>+ struct reply_header __header;
>+ process_id_t pid;
>+ char __pad_12[4];
>+};
>+
>+
>+
> struct terminate_process_request
> {
> struct request_header __header;
>@@ -4897,6 +4911,7 @@ enum request
> REQ_get_startup_info,
> REQ_init_process_done,
> REQ_init_thread,
>+ REQ_find_process,
> REQ_terminate_process,
> REQ_terminate_thread,
> REQ_get_process_info,
>@@ -5151,6 +5166,7 @@ union generic_request
> struct get_startup_info_request get_startup_info_request;
> struct init_process_done_request init_process_done_request;
> struct init_thread_request init_thread_request;
>+ struct find_process_request find_process_request;
> struct terminate_process_request terminate_process_request;
> struct terminate_thread_request terminate_thread_request;
> struct get_process_info_request get_process_info_request;
>@@ -5403,6 +5419,7 @@ union generic_reply
> struct get_startup_info_reply get_startup_info_reply;
> struct init_process_done_reply init_process_done_reply;
> struct init_thread_reply init_thread_reply;
>+ struct find_process_reply find_process_reply;
> struct terminate_process_reply terminate_process_reply;
> struct terminate_thread_reply terminate_thread_reply;
> struct get_process_info_reply get_process_info_reply;
>@@ -5646,6 +5663,6 @@ union generic_reply
> struct set_suspend_context_reply set_suspend_context_reply;
> };
>
>-#define SERVER_PROTOCOL_VERSION 431
>+#define SERVER_PROTOCOL_VERSION 432
>
> #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
>diff --git a/server/async.c b/server/async.c
>index dd28dff..b8be5cd 100644
>--- a/server/async.c
>+++ b/server/async.c
>@@ -256,10 +256,12 @@ void async_set_result( struct object *obj, unsigned int status, unsigned int tot
> else
> {
> if (async->timeout) remove_timeout_user( async->timeout );
>+ if (async->completion && async->data.cvalue && status != STATUS_ALERTED)
>+ add_completion( async->completion, async->comp_key, async->data.cvalue, status, total );
>+ else if (async->completion && async->data.cvalue && status == STATUS_ALERTED)
>+ status = STATUS_SUCCESS;
> async->timeout = NULL;
> async->status = status;
>- if (async->completion && async->data.cvalue)
>- add_completion( async->completion, async->comp_key, async->data.cvalue, status, total );
> if (apc)
> {
> apc_call_t data;
>diff --git a/server/process.c b/server/process.c
>index de3b594..7fe50c9 100644
>--- a/server/process.c
>+++ b/server/process.c
>@@ -989,6 +989,24 @@ DECL_HANDLER(new_process)
> release_object( info );
> }
>
>+/* Find a process from the Unix pid */
>+DECL_HANDLER(find_process)
>+{
>+ struct process *process;
>+ int i;
>+
>+ for(i=0; i<used_ptid_entries; i++)
>+ {
>+ process = (struct process *) ptid_entries[i + PTID_OFFSET].ptr;
>+ if (process && process->unix_pid == req->unix_pid)
>+ {
>+ reply->pid = get_process_id( process );
>+ return;
>+ }
>+ }
>+ set_error( STATUS_INVALID_PARAMETER );
>+}
>+
> /* Retrieve information about a newly started process */
> DECL_HANDLER(get_new_process_info)
> {
>diff --git a/server/protocol.def b/server/protocol.def
>index 80c0cd3..b36b878 100644
>--- a/server/protocol.def
>+++ b/server/protocol.def
>@@ -695,6 +695,14 @@ typedef union
> @END
>
>
>+/* Find a process from the Unix pid */
>+ at REQ(find_process)
>+ int unix_pid; /* Unix pid of the process */
>+ at REPLY
>+ process_id_t pid; /* Wine process id of the process */
>+ at END
>+
>+
> /* Terminate a process */
> @REQ(terminate_process)
> obj_handle_t handle; /* process handle to terminate */
>diff --git a/server/request.h b/server/request.h
>index 5b45cf9..8d59a46 100644
>--- a/server/request.h
>+++ b/server/request.h
>@@ -117,6 +117,7 @@ DECL_HANDLER(new_thread);
> DECL_HANDLER(get_startup_info);
> DECL_HANDLER(init_process_done);
> DECL_HANDLER(init_thread);
>+DECL_HANDLER(find_process);
> DECL_HANDLER(terminate_process);
> DECL_HANDLER(terminate_thread);
> DECL_HANDLER(get_process_info);
>@@ -370,6 +371,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
> (req_handler)req_get_startup_info,
> (req_handler)req_init_process_done,
> (req_handler)req_init_thread,
>+ (req_handler)req_find_process,
> (req_handler)req_terminate_process,
> (req_handler)req_terminate_thread,
> (req_handler)req_get_process_info,
>@@ -696,6 +698,10 @@ C_ASSERT( FIELD_OFFSET(struct init_thread_reply, info_size) == 24 );
> C_ASSERT( FIELD_OFFSET(struct init_thread_reply, version) == 28 );
> C_ASSERT( FIELD_OFFSET(struct init_thread_reply, all_cpus) == 32 );
> C_ASSERT( sizeof(struct init_thread_reply) == 40 );
>+C_ASSERT( FIELD_OFFSET(struct find_process_request, unix_pid) == 12 );
>+C_ASSERT( sizeof(struct find_process_request) == 16 );
>+C_ASSERT( FIELD_OFFSET(struct find_process_reply, pid) == 8 );
>+C_ASSERT( sizeof(struct find_process_reply) == 16 );
> C_ASSERT( FIELD_OFFSET(struct terminate_process_request, handle) == 12 );
> C_ASSERT( FIELD_OFFSET(struct terminate_process_request, exit_code) == 16 );
> C_ASSERT( sizeof(struct terminate_process_request) == 24 );
>diff --git a/server/trace.c b/server/trace.c
>index cfef963..5b0c85e 100644
>--- a/server/trace.c
>+++ b/server/trace.c
>@@ -1100,6 +1100,16 @@ static void dump_init_thread_reply( const struct init_thread_reply *req )
> fprintf( stderr, ", all_cpus=%08x", req->all_cpus );
> }
>
>+static void dump_find_process_request( const struct find_process_request *req )
>+{
>+ fprintf( stderr, " unix_pid=%d", req->unix_pid );
>+}
>+
>+static void dump_find_process_reply( const struct find_process_reply *req )
>+{
>+ fprintf( stderr, " pid=%04x", req->pid );
>+}
>+
> static void dump_terminate_process_request( const struct terminate_process_request *req )
> {
> fprintf( stderr, " handle=%04x", req->handle );
>@@ -3920,6 +3930,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
> (dump_func)dump_get_startup_info_request,
> (dump_func)dump_init_process_done_request,
> (dump_func)dump_init_thread_request,
>+ (dump_func)dump_find_process_request,
> (dump_func)dump_terminate_process_request,
> (dump_func)dump_terminate_thread_request,
> (dump_func)dump_get_process_info_request,
>@@ -4170,6 +4181,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
> (dump_func)dump_get_startup_info_reply,
> NULL,
> (dump_func)dump_init_thread_reply,
>+ (dump_func)dump_find_process_reply,
> (dump_func)dump_terminate_process_reply,
> (dump_func)dump_terminate_thread_reply,
> (dump_func)dump_get_process_info_reply,
>@@ -4420,6 +4432,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
> "get_startup_info",
> "init_process_done",
> "init_thread",
>+ "find_process",
> "terminate_process",
> "terminate_thread",
> "get_process_info",
--
Configure bugmail: http://bugs.winehq.org/userprefs.cgi?tab=email
Do not reply to this email, post in Bugzilla using the
above URL to reply.
------- You are receiving this mail because: -------
You are watching all bug changes.
More information about the wine-bugs
mailing list