Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
ca1a7c6b
Commit
ca1a7c6b
authored
Oct 22, 2009
by
Eric Pouech
Committed by
Alexandre Julliard
Oct 23, 2009
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
winmm: Get rid of 16bit driver support.
parent
2a581444
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
41 additions
and
466 deletions
+41
-466
driver.c
dlls/winmm/driver.c
+24
-59
lolvldrv.c
dlls/winmm/lolvldrv.c
+15
-112
message16.c
dlls/winmm/message16.c
+0
-0
mmsystem.c
dlls/winmm/mmsystem.c
+0
-258
winemm.h
dlls/winmm/winemm.h
+2
-37
No files found.
dlls/winmm/driver.c
View file @
ca1a7c6b
...
...
@@ -53,10 +53,6 @@ static LPWINE_DRIVER lpDrvItemList /* = NULL */;
static
const
WCHAR
HKLM_BASE
[]
=
{
'S'
,
'o'
,
'f'
,
't'
,
'w'
,
'a'
,
'r'
,
'e'
,
'\\'
,
'M'
,
'i'
,
'c'
,
'r'
,
'o'
,
's'
,
'o'
,
'f'
,
't'
,
'\\'
,
'W'
,
'i'
,
'n'
,
'd'
,
'o'
,
'w'
,
's'
,
' '
,
'N'
,
'T'
,
'\\'
,
'C'
,
'u'
,
'r'
,
'r'
,
'e'
,
'n'
,
't'
,
'V'
,
'e'
,
'r'
,
's'
,
'i'
,
'o'
,
'n'
,
0
};
LPWINE_DRIVER
(
*
pFnOpenDriver16
)(
LPCWSTR
,
LPCWSTR
,
LPARAM
)
/* = NULL */
;
LRESULT
(
*
pFnCloseDriver16
)(
UINT16
,
LPARAM
,
LPARAM
)
/* = NULL */
;
LRESULT
(
*
pFnSendMessage16
)(
UINT16
,
UINT
,
LPARAM
,
LPARAM
)
/* = NULL */
;
static
void
DRIVER_Dump
(
const
char
*
comment
)
{
#if 0
...
...
@@ -90,7 +86,7 @@ static unsigned DRIVER_GetNumberOfModuleRefs(HMODULE hModule, WINE_DRIVER** foun
if
(
found
)
*
found
=
NULL
;
for
(
lpDrv
=
lpDrvItemList
;
lpDrv
;
lpDrv
=
lpDrv
->
lpNextItem
)
{
if
(
!
(
lpDrv
->
dwFlags
&
WINE_GDF_16BIT
)
&&
lpDrv
->
d
.
d32
.
hModule
==
hModule
)
if
(
lpDrv
->
hModule
==
hModule
)
{
if
(
found
&&
!*
found
)
*
found
=
lpDrv
;
count
++
;
...
...
@@ -121,7 +117,7 @@ LPWINE_DRIVER DRIVER_FindFromHDrvr(HDRVR hDrvr)
}
__ENDTRY
;
if
(
d
)
TRACE
(
"%p -> %p, %p
\n
"
,
hDrvr
,
d
->
d
.
d32
.
lpDrvProc
,
(
void
*
)
d
->
d
.
d32
.
dwDriverID
);
if
(
d
)
TRACE
(
"%p -> %p, %p
\n
"
,
hDrvr
,
d
->
lpDrvProc
,
(
void
*
)
d
->
dwDriverID
);
else
TRACE
(
"%p -> NULL
\n
"
,
hDrvr
);
return
d
;
...
...
@@ -135,18 +131,12 @@ static inline LRESULT DRIVER_SendMessage(LPWINE_DRIVER lpDrv, UINT msg,
{
LRESULT
ret
=
0
;
if
(
lpDrv
->
dwFlags
&
WINE_GDF_16BIT
)
{
/* no need to check mmsystem presence: the driver must have been opened as a 16 bit one,
*/
if
(
pFnSendMessage16
)
ret
=
pFnSendMessage16
(
lpDrv
->
d
.
d16
.
hDriver16
,
msg
,
lParam1
,
lParam2
);
}
else
{
TRACE
(
"Before call32 proc=%p drvrID=%08lx hDrv=%p wMsg=%04x p1=%08lx p2=%08lx
\n
"
,
lpDrv
->
d
.
d32
.
lpDrvProc
,
lpDrv
->
d
.
d32
.
dwDriverID
,
lpDrv
,
msg
,
lParam1
,
lParam2
);
ret
=
lpDrv
->
d
.
d32
.
lpDrvProc
(
lpDrv
->
d
.
d32
.
dwDriverID
,
(
HDRVR
)
lpDrv
,
msg
,
lParam1
,
lParam2
);
lpDrv
->
lpDrvProc
,
lpDrv
->
dwDriverID
,
lpDrv
,
msg
,
lParam1
,
lParam2
);
ret
=
lpDrv
->
lpDrvProc
(
lpDrv
->
dwDriverID
,
(
HDRVR
)
lpDrv
,
msg
,
lParam1
,
lParam2
);
TRACE
(
"After call32 proc=%p drvrID=%08lx hDrv=%p wMsg=%04x p1=%08lx p2=%08lx => %08lx
\n
"
,
lpDrv
->
d
.
d32
.
lpDrvProc
,
lpDrv
->
d
.
d32
.
dwDriverID
,
lpDrv
,
msg
,
lParam1
,
lParam2
,
ret
);
}
lpDrv
->
lpDrvProc
,
lpDrv
->
dwDriverID
,
lpDrv
,
msg
,
lParam1
,
lParam2
,
ret
);
return
ret
;
}
...
...
@@ -180,13 +170,11 @@ LRESULT WINAPI SendDriverMessage(HDRVR hDriver, UINT msg, LPARAM lParam1,
*/
static
BOOL
DRIVER_RemoveFromList
(
LPWINE_DRIVER
lpDrv
)
{
if
(
!
(
lpDrv
->
dwFlags
&
WINE_GDF_16BIT
))
{
/* last of this driver in list ? */
if
(
DRIVER_GetNumberOfModuleRefs
(
lpDrv
->
d
.
d32
.
hModule
,
NULL
)
==
1
)
{
if
(
DRIVER_GetNumberOfModuleRefs
(
lpDrv
->
hModule
,
NULL
)
==
1
)
{
DRIVER_SendMessage
(
lpDrv
,
DRV_DISABLE
,
0L
,
0L
);
DRIVER_SendMessage
(
lpDrv
,
DRV_FREE
,
0L
,
0L
);
}
}
EnterCriticalSection
(
&
mmdriver_lock
);
...
...
@@ -198,9 +186,8 @@ static BOOL DRIVER_RemoveFromList(LPWINE_DRIVER lpDrv)
lpDrv
->
lpNextItem
->
lpPrevItem
=
lpDrv
->
lpPrevItem
;
/* trash magic number */
lpDrv
->
dwMagic
^=
0xa5a5a5a5
;
lpDrv
->
d
.
d32
.
lpDrvProc
=
NULL
;
lpDrv
->
d
.
d32
.
dwDriverID
=
0
;
lpDrv
->
d
.
d16
.
hDriver16
=
0
;
lpDrv
->
lpDrvProc
=
NULL
;
lpDrv
->
dwDriverID
=
0
;
LeaveCriticalSection
(
&
mmdriver_lock
);
...
...
@@ -217,9 +204,8 @@ static BOOL DRIVER_AddToList(LPWINE_DRIVER lpNewDrv, LPARAM lParam1, LPARAM lPar
{
lpNewDrv
->
dwMagic
=
WINE_DI_MAGIC
;
/* First driver to be loaded for this module, need to load correctly the module */
if
(
!
(
lpNewDrv
->
dwFlags
&
WINE_GDF_16BIT
))
{
/* first of this driver in list ? */
if
(
DRIVER_GetNumberOfModuleRefs
(
lpNewDrv
->
d
.
d32
.
hModule
,
NULL
)
==
0
)
{
if
(
DRIVER_GetNumberOfModuleRefs
(
lpNewDrv
->
hModule
,
NULL
)
==
0
)
{
if
(
DRIVER_SendMessage
(
lpNewDrv
,
DRV_LOAD
,
0L
,
0L
)
!=
DRV_SUCCESS
)
{
TRACE
(
"DRV_LOAD failed on driver %p
\n
"
,
lpNewDrv
);
return
FALSE
;
...
...
@@ -229,14 +215,13 @@ static BOOL DRIVER_AddToList(LPWINE_DRIVER lpNewDrv, LPARAM lParam1, LPARAM lPar
}
/* Now just open a new instance of a driver on this module */
lpNewDrv
->
d
.
d32
.
dwDriverID
=
DRIVER_SendMessage
(
lpNewDrv
,
DRV_OPEN
,
lParam1
,
lParam2
);
lpNewDrv
->
dwDriverID
=
DRIVER_SendMessage
(
lpNewDrv
,
DRV_OPEN
,
lParam1
,
lParam2
);
if
(
lpNewDrv
->
d
.
d32
.
dwDriverID
==
0
)
if
(
lpNewDrv
->
dwDriverID
==
0
)
{
TRACE
(
"DRV_OPEN failed on driver %p
\n
"
,
lpNewDrv
);
return
FALSE
;
}
}
EnterCriticalSection
(
&
mmdriver_lock
);
...
...
@@ -313,18 +298,18 @@ LPWINE_DRIVER DRIVER_TryOpenDriver32(LPCWSTR fn, LPARAM lParam2)
if
((
hModule
=
LoadLibraryW
(
fn
))
==
0
)
{
cause
=
"Not a 32 bit lib"
;
goto
exit
;}
lpDrv
->
d
.
d32
.
lpDrvProc
=
(
DRIVERPROC
)
GetProcAddress
(
hModule
,
"DriverProc"
);
if
(
lpDrv
->
d
.
d32
.
lpDrvProc
==
NULL
)
{
cause
=
"no DriverProc"
;
goto
exit
;}
lpDrv
->
lpDrvProc
=
(
DRIVERPROC
)
GetProcAddress
(
hModule
,
"DriverProc"
);
if
(
lpDrv
->
lpDrvProc
==
NULL
)
{
cause
=
"no DriverProc"
;
goto
exit
;}
lpDrv
->
dwFlags
=
0
;
lpDrv
->
d
.
d32
.
hModule
=
hModule
;
lpDrv
->
d
.
d32
.
d
wDriverID
=
0
;
lpDrv
->
hModule
=
hModule
;
lpDrv
->
dwDriverID
=
0
;
/* Win32 installable drivers must support a two phase opening scheme:
* + first open with NULL as lParam2 (session instance),
* + then do a second open with the real non null lParam2)
*/
if
(
DRIVER_GetNumberOfModuleRefs
(
lpDrv
->
d
.
d32
.
hModule
,
NULL
)
==
0
&&
lParam2
)
if
(
DRIVER_GetNumberOfModuleRefs
(
lpDrv
->
hModule
,
NULL
)
==
0
&&
lParam2
)
{
LPWINE_DRIVER
ret
;
...
...
@@ -421,17 +406,6 @@ HDRVR WINAPI OpenDriver(LPCWSTR lpDriverName, LPCWSTR lpSectionName, LPARAM lPar
(
lpDrv
=
DRIVER_TryOpenDriver32
(
libName
,
lParam
)))
goto
the_end
;
/* now we will try a 16 bit driver (and add all the glue to make it work... which
* is located in our mmsystem implementation)
* so ensure, we can load our mmsystem, otherwise just fail
*/
WINMM_CheckForMMSystem
();
if
(
pFnOpenDriver16
&&
(
lpDrv
=
pFnOpenDriver16
(
lpDriverName
,
lpSectionName
,
lParam
)))
{
if
(
DRIVER_AddToList
(
lpDrv
,
0
,
lParam
))
goto
the_end
;
HeapFree
(
GetProcessHeap
(),
0
,
lpDrv
);
}
TRACE
(
"Failed to open driver %s from system.ini file, section %s
\n
"
,
debugstr_w
(
lpDriverName
),
debugstr_w
(
lpSectionName
));
...
...
@@ -458,33 +432,25 @@ LRESULT WINAPI CloseDriver(HDRVR hDrvr, LPARAM lParam1, LPARAM lParam2)
if
((
lpDrv
=
DRIVER_FindFromHDrvr
(
hDrvr
))
!=
NULL
)
{
if
(
lpDrv
->
dwFlags
&
WINE_GDF_16BIT
)
{
if
(
pFnCloseDriver16
)
pFnCloseDriver16
(
lpDrv
->
d
.
d16
.
hDriver16
,
lParam1
,
lParam2
);
}
else
LPWINE_DRIVER
lpDrv0
;
DRIVER_SendMessage
(
lpDrv
,
DRV_CLOSE
,
lParam1
,
lParam2
);
DRIVER_RemoveFromList
(
lpDrv
);
if
(
!
(
lpDrv
->
dwFlags
&
WINE_GDF_16BIT
))
{
LPWINE_DRIVER
lpDrv0
;
if
(
lpDrv
->
dwFlags
&
WINE_GDF_SESSION
)
FIXME
(
"WINE_GDF_SESSION: Shouldn't happen (%p)
\n
"
,
lpDrv
);
/* if driver has an opened session instance, we have to close it too */
if
(
DRIVER_GetNumberOfModuleRefs
(
lpDrv
->
d
.
d32
.
hModule
,
&
lpDrv0
)
==
1
&&
if
(
DRIVER_GetNumberOfModuleRefs
(
lpDrv
->
hModule
,
&
lpDrv0
)
==
1
&&
(
lpDrv0
->
dwFlags
&
WINE_GDF_SESSION
))
{
DRIVER_SendMessage
(
lpDrv0
,
DRV_CLOSE
,
0
,
0
);
DRIVER_RemoveFromList
(
lpDrv0
);
FreeLibrary
(
lpDrv0
->
d
.
d32
.
hModule
);
FreeLibrary
(
lpDrv0
->
hModule
);
HeapFree
(
GetProcessHeap
(),
0
,
lpDrv0
);
}
FreeLibrary
(
lpDrv
->
d
.
d32
.
hModule
);
}
FreeLibrary
(
lpDrv
->
hModule
);
HeapFree
(
GetProcessHeap
(),
0
,
lpDrv
);
ret
=
TRUE
;
}
...
...
@@ -537,8 +503,7 @@ HMODULE WINAPI GetDriverModuleHandle(HDRVR hDrvr)
TRACE
(
"(%p);
\n
"
,
hDrvr
);
if
((
lpDrv
=
DRIVER_FindFromHDrvr
(
hDrvr
))
!=
NULL
)
{
if
(
!
(
lpDrv
->
dwFlags
&
WINE_GDF_16BIT
))
hModule
=
lpDrv
->
d
.
d32
.
hModule
;
hModule
=
lpDrv
->
hModule
;
}
TRACE
(
"=> %p
\n
"
,
hModule
);
return
hModule
;
...
...
dlls/winmm/lolvldrv.c
View file @
ca1a7c6b
...
...
@@ -36,17 +36,11 @@
WINE_DEFAULT_DEBUG_CHANNEL
(
winmm
);
LRESULT
(
*
pFnCallMMDrvFunc16
)(
DWORD
,
WORD
,
WORD
,
LONG
,
LONG
,
LONG
)
/* = NULL */
;
unsigned
(
*
pFnLoadMMDrvFunc16
)(
LPCSTR
,
LPWINE_DRIVER
,
LPWINE_MM_DRIVER
)
/* = NULL */
;
/* each known type of driver has an instance of this structure */
typedef
struct
tagWINE_LLTYPE
{
/* those attributes depend on the specification of the type */
LPCSTR
typestr
;
/* name (for debugging) */
BOOL
bSupportMapper
;
/* if type is allowed to support mapper */
MMDRV_MAPFUNC
Map32WTo16
;
/* when hi-func (in mmsystem or winmm) and */
MMDRV_UNMAPFUNC
UnMap32WTo16
;
/* low-func (in .drv) do not match */
LPDRVCALLBACK
Callback
;
/* handles callback for a specified type */
/* those attributes reflect the loaded/current situation for the type */
UINT
wMaxId
;
/* number of loaded devices (sum across all loaded drivers) */
LPWINE_MLD
lpMlds
;
/* "static" mlds to access the part though device IDs */
...
...
@@ -58,7 +52,7 @@ static WINE_MM_DRIVER MMDrvs[8];
static
LPWINE_MLD
MM_MLDrvs
[
40
];
#define MAX_MM_MLDRVS (sizeof(MM_MLDrvs) / sizeof(MM_MLDrvs[0]))
#define A(_x,_y) {#_y, _x,
NULL, NULL, NULL,
0, NULL, -1}
#define A(_x,_y) {#_y, _x, 0, NULL, -1}
/* Note: the indices of this array must match the definitions
* of the MMDRV_???? manifest constants
*/
...
...
@@ -72,31 +66,6 @@ static WINE_LLTYPE llTypes[MMDRV_MAX] = {
};
#undef A
/******************************************************************
* MMDRV_InstallMap
*
*
*/
void
MMDRV_InstallMap
(
unsigned
int
drv
,
MMDRV_MAPFUNC
mp3216
,
MMDRV_UNMAPFUNC
um3216
,
LPDRVCALLBACK
cb
)
{
assert
(
drv
<
MMDRV_MAX
);
llTypes
[
drv
].
Map32WTo16
=
mp3216
;
llTypes
[
drv
].
UnMap32WTo16
=
um3216
;
llTypes
[
drv
].
Callback
=
cb
;
}
/******************************************************************
* MMDRV_Is32
*
*/
BOOL
MMDRV_Is32
(
unsigned
int
idx
)
{
TRACE
(
"(%d)
\n
"
,
idx
);
return
MMDrvs
[
idx
].
bIs32
;
}
/**************************************************************************
* MMDRV_GetNum [internal]
*/
...
...
@@ -117,7 +86,6 @@ DWORD MMDRV_Message(LPWINE_MLD mld, UINT wMsg, DWORD_PTR dwParam1,
DWORD
ret
;
WINE_MM_DRIVER_PART
*
part
;
WINE_LLTYPE
*
llType
=
&
llTypes
[
mld
->
type
];
WINMM_MapType
map
;
int
devID
;
TRACE
(
"(%s %u %u 0x%08lx 0x%08lx 0x%08lx)
\n
"
,
...
...
@@ -150,41 +118,13 @@ DWORD MMDRV_Message(LPWINE_MLD mld, UINT wMsg, DWORD_PTR dwParam1,
ERR("!(devID(%d) < part->nIDMax(%d))\n", devID, part->nIDMax);
#endif
if
(
lpDrv
->
bIs32
)
{
assert
(
part
->
u
.
fnMessage32
);
assert
(
part
->
fnMessage32
);
TRACE
(
"Calling message(dev=%u msg=%u usr=0x%08lx p1=0x%08lx p2=0x%08lx)
\n
"
,
mld
->
uDeviceID
,
wMsg
,
mld
->
dwDriverInstance
,
dwParam1
,
dwParam2
);
ret
=
part
->
u
.
fnMessage32
(
mld
->
uDeviceID
,
wMsg
,
mld
->
dwDriverInstance
,
dwParam1
,
dwParam2
);
ret
=
part
->
fnMessage32
(
mld
->
uDeviceID
,
wMsg
,
mld
->
dwDriverInstance
,
dwParam1
,
dwParam2
);
TRACE
(
"=> %s
\n
"
,
WINMM_ErrorToString
(
ret
));
}
else
{
assert
(
part
->
u
.
fnMessage16
&&
pFnCallMMDrvFunc16
);
map
=
llType
->
Map32WTo16
(
wMsg
,
&
mld
->
dwDriverInstance
,
&
dwParam1
,
&
dwParam2
);
switch
(
map
)
{
case
WINMM_MAP_NOMEM
:
ret
=
MMSYSERR_NOMEM
;
break
;
case
WINMM_MAP_MSGERROR
:
FIXME
(
"NIY: no conversion yet 32->16 (%u)
\n
"
,
wMsg
);
ret
=
MMSYSERR_ERROR
;
break
;
case
WINMM_MAP_OK
:
case
WINMM_MAP_OKMEM
:
TRACE
(
"Calling message(dev=%u msg=%u usr=0x%08lx p1=0x%08lx p2=0x%08lx)
\n
"
,
mld
->
uDeviceID
,
wMsg
,
mld
->
dwDriverInstance
,
dwParam1
,
dwParam2
);
ret
=
pFnCallMMDrvFunc16
((
DWORD
)
part
->
u
.
fnMessage16
,
mld
->
uDeviceID
,
wMsg
,
mld
->
dwDriverInstance
,
dwParam1
,
dwParam2
);
TRACE
(
"=> %s
\n
"
,
WINMM_ErrorToString
(
ret
));
if
(
map
==
WINMM_MAP_OKMEM
)
llType
->
UnMap32WTo16
(
wMsg
,
&
mld
->
dwDriverInstance
,
&
dwParam1
,
&
dwParam2
,
ret
);
break
;
default:
FIXME
(
"NIY
\n
"
);
ret
=
MMSYSERR_NOTSUPPORTED
;
break
;
}
}
return
ret
;
}
...
...
@@ -227,13 +167,6 @@ LPWINE_MLD MMDRV_Alloc(UINT size, UINT type, LPHANDLE hndl, DWORD* dwFlags,
mld
->
dwCallback
=
*
dwCallback
;
mld
->
dwClientInstance
=
*
dwInstance
;
if
(
llTypes
[
type
].
Callback
)
{
*
dwFlags
=
LOWORD
(
*
dwFlags
)
|
CALLBACK_FUNCTION
;
*
dwCallback
=
(
DWORD_PTR
)
llTypes
[
type
].
Callback
;
*
dwInstance
=
(
DWORD_PTR
)
mld
;
/* FIXME: wouldn't some 16 bit drivers only use the loword ? */
}
return
mld
;
}
...
...
@@ -442,29 +375,16 @@ static BOOL MMDRV_InitPerType(LPWINE_MM_DRIVER lpDrv, UINT type, UINT wMsg)
/* for DRVM_INIT and DRVM_ENABLE, dwParam2 should be PnP node */
/* the DRVM_ENABLE is only required when the PnP node is non zero */
if
(
lpDrv
->
bIs32
&&
part
->
u
.
fnMessage32
)
{
ret
=
part
->
u
.
fnMessage32
(
0
,
DRVM_INIT
,
0L
,
0L
,
0L
);
TRACE
(
"DRVM_INIT => %s
\n
"
,
WINMM_ErrorToString
(
ret
));
#if 0
ret = part->u.fnMessage32(0, DRVM_ENABLE, 0L, 0L, 0L);
TRACE("DRVM_ENABLE => %08lx\n", ret);
#endif
count
=
part
->
u
.
fnMessage32
(
0
,
wMsg
,
0L
,
0L
,
0L
);
}
else
if
(
!
lpDrv
->
bIs32
&&
part
->
u
.
fnMessage16
&&
pFnCallMMDrvFunc16
)
{
ret
=
pFnCallMMDrvFunc16
((
DWORD
)
part
->
u
.
fnMessage16
,
0
,
DRVM_INIT
,
0L
,
0L
,
0L
);
if
(
part
->
fnMessage32
)
{
ret
=
part
->
fnMessage32
(
0
,
DRVM_INIT
,
0L
,
0L
,
0L
);
TRACE
(
"DRVM_INIT => %s
\n
"
,
WINMM_ErrorToString
(
ret
));
#if 0
ret = pFnCallMMDrvFunc16((DWORD)part->u.fnMessage16,
0, DRVM_ENABLE, 0L, 0L, 0L);
ret = part->fnMessage32(0, DRVM_ENABLE, 0L, 0L, 0L);
TRACE("DRVM_ENABLE => %08lx\n", ret);
#endif
count
=
pFnCallMMDrvFunc16
((
DWORD
)
part
->
u
.
fnMessage16
,
0
,
wMsg
,
0L
,
0L
,
0L
);
}
else
{
return
FALSE
;
count
=
part
->
fnMessage32
(
0
,
wMsg
,
0L
,
0L
,
0L
);
}
else
return
FALSE
;
TRACE
(
"Got %u dev for (%s:%s)
\n
"
,
count
,
lpDrv
->
drvname
,
llTypes
[
type
].
typestr
);
...
...
@@ -529,6 +449,7 @@ static BOOL MMDRV_Install(LPCSTR drvRegName, LPCSTR drvFileName, BOOL bIsMapper)
int
i
,
count
=
0
;
LPWINE_MM_DRIVER
lpDrv
=
&
MMDrvs
[
MMDrvsHi
];
LPWINE_DRIVER
d
;
WINEMM_msgFunc32
func
;
TRACE
(
"('%s', '%s', mapper=%c);
\n
"
,
drvRegName
,
drvFileName
,
bIsMapper
?
'Y'
:
'N'
);
...
...
@@ -550,20 +471,16 @@ static BOOL MMDRV_Install(LPCSTR drvRegName, LPCSTR drvFileName, BOOL bIsMapper)
}
d
=
DRIVER_FindFromHDrvr
(
lpDrv
->
hDriver
);
lpDrv
->
bIs32
=
(
d
->
dwFlags
&
WINE_GDF_16BIT
)
?
FALSE
:
TRUE
;
/* Then look for xxxMessage functions */
#define AA(_h,_w,_x,_y,_z) \
func = (WINEMM_msgFunc##_y) _z ((_h), #_x); \
if (func != NULL) \
{ lpDrv->parts[_w].
u.
fnMessage##_y = func; count++; \
{ lpDrv->parts[_w].fnMessage##_y = func; count++; \
TRACE("Got %d bit func '%s'\n", _y, #_x); }
if
(
lpDrv
->
bIs32
)
{
WINEMM_msgFunc32
func
;
if
(
d
->
d
.
d32
.
hModule
)
{
#define A(_x,_y) AA(d->d.d32.hModule,_x,_y,32,GetProcAddress)
if
(
d
->
hModule
)
{
#define A(_x,_y) AA(d->hModule,_x,_y,32,GetProcAddress)
A
(
MMDRV_AUX
,
auxMessage
);
A
(
MMDRV_MIXER
,
mxdMessage
);
A
(
MMDRV_MIDIIN
,
midMessage
);
...
...
@@ -572,9 +489,6 @@ static BOOL MMDRV_Install(LPCSTR drvRegName, LPCSTR drvFileName, BOOL bIsMapper)
A
(
MMDRV_WAVEOUT
,
wodMessage
);
#undef A
}
}
else
if
(
WINMM_CheckForMMSystem
()
&&
pFnLoadMMDrvFunc16
)
{
count
+=
pFnLoadMMDrvFunc16
(
drvFileName
,
d
,
lpDrv
);
}
#undef AA
if
(
!
count
)
{
...
...
@@ -664,24 +578,13 @@ static BOOL MMDRV_ExitPerType(LPWINE_MM_DRIVER lpDrv, UINT type)
DWORD
ret
;
TRACE
(
"(%p, %04x)
\n
"
,
lpDrv
,
type
);
if
(
lpDrv
->
bIs32
&&
part
->
u
.
fnMessage32
)
{
if
(
part
->
fnMessage32
)
{
#if 0
ret = part->u.
fnMessage32(0, DRVM_DISABLE, 0L, 0L, 0L);
ret = part->
fnMessage32(0, DRVM_DISABLE, 0L, 0L, 0L);
TRACE("DRVM_DISABLE => %08lx\n", ret);
#endif
ret
=
part
->
u
.
fnMessage32
(
0
,
DRVM_EXIT
,
0L
,
0L
,
0L
);
ret
=
part
->
fnMessage32
(
0
,
DRVM_EXIT
,
0L
,
0L
,
0L
);
TRACE
(
"DRVM_EXIT => %s
\n
"
,
WINMM_ErrorToString
(
ret
));
}
else
if
(
!
lpDrv
->
bIs32
&&
part
->
u
.
fnMessage16
&&
pFnCallMMDrvFunc16
)
{
#if 0
ret = pFnCallMMDrvFunc16((DWORD)part->u.fnMessage16,
0, DRVM_DISABLE, 0L, 0L, 0L);
TRACE("DRVM_DISABLE => %08lx\n", ret);
#endif
ret
=
pFnCallMMDrvFunc16
((
DWORD
)
part
->
u
.
fnMessage16
,
0
,
DRVM_EXIT
,
0L
,
0L
,
0L
);
TRACE
(
"DRVM_EXIT => %s
\n
"
,
WINMM_ErrorToString
(
ret
));
}
else
{
return
FALSE
;
}
return
TRUE
;
...
...
dlls/winmm/message16.c
View file @
ca1a7c6b
This diff is collapsed.
Click to expand it.
dlls/winmm/mmsystem.c
View file @
ca1a7c6b
...
...
@@ -40,7 +40,6 @@
#include "wine/list.h"
#include "wine/winuser16.h"
#include "winemm.h"
#include "winemm16.h"
#include "wine/debug.h"
...
...
@@ -48,9 +47,6 @@
WINE_DEFAULT_DEBUG_CHANNEL
(
mmsys
);
static
WINE_MMTHREAD
*
WINMM_GetmmThread
(
HANDLE16
);
static
LPWINE_DRIVER
DRIVER_OpenDriver16
(
LPCWSTR
,
LPCWSTR
,
LPARAM
);
static
LRESULT
DRIVER_CloseDriver16
(
HDRVR16
,
LPARAM
,
LPARAM
);
static
LRESULT
DRIVER_SendMessage16
(
HDRVR16
,
UINT
,
LPARAM
,
LPARAM
);
static
CRITICAL_SECTION_DEBUG
mmdrv_critsect_debug
=
{
...
...
@@ -76,32 +72,6 @@ BOOL WINAPI MMSYSTEM_LibMain(DWORD fdwReason, HINSTANCE hinstDLL, WORD ds,
{
TRACE
(
"%p 0x%x
\n
"
,
hinstDLL
,
fdwReason
);
switch
(
fdwReason
)
{
case
DLL_PROCESS_ATTACH
:
/* need to load WinMM in order to:
* - initiate correctly shared variables (WINMM_Init())
*/
if
(
!
GetModuleHandleA
(
"WINMM.DLL"
))
{
ERR
(
"Could not load sibling WinMM.dll
\n
"
);
return
FALSE
;
}
/* hook in our 16 bit function pointers */
pFnOpenDriver16
=
DRIVER_OpenDriver16
;
pFnCloseDriver16
=
DRIVER_CloseDriver16
;
pFnSendMessage16
=
DRIVER_SendMessage16
;
MMDRV_Init16
();
break
;
case
DLL_PROCESS_DETACH
:
pFnOpenDriver16
=
NULL
;
pFnCloseDriver16
=
NULL
;
pFnSendMessage16
=
NULL
;
/* FIXME: add equivalent for MMDRV_Init16() */
break
;
case
DLL_THREAD_ATTACH
:
case
DLL_THREAD_DETACH
:
break
;
}
return
TRUE
;
}
...
...
@@ -2069,234 +2039,6 @@ void WINAPI WMMMidiRunOnce16(void)
FIXME
(
"(), stub!
\n
"
);
}
/* ###################################################
* # DRIVER #
* ###################################################
*/
/**************************************************************************
* DRIVER_MapMsg32To16 [internal]
*
* Map a 32 bit driver message to a 16 bit driver message.
*/
static
WINMM_MapType
DRIVER_MapMsg32To16
(
WORD
wMsg
,
LPARAM
*
lParam1
,
LPARAM
*
lParam2
)
{
WINMM_MapType
ret
=
WINMM_MAP_MSGERROR
;
switch
(
wMsg
)
{
case
DRV_LOAD
:
case
DRV_ENABLE
:
case
DRV_DISABLE
:
case
DRV_FREE
:
case
DRV_QUERYCONFIGURE
:
case
DRV_REMOVE
:
case
DRV_EXITSESSION
:
case
DRV_EXITAPPLICATION
:
case
DRV_POWER
:
case
DRV_CLOSE
:
/* should be 0/0 */
case
DRV_OPEN
:
/* pass through */
/* lParam1 and lParam2 are not used */
ret
=
WINMM_MAP_OK
;
break
;
case
DRV_CONFIGURE
:
case
DRV_INSTALL
:
/* lParam1 is a handle to a window (conf) or to a driver (inst) or not used,
* lParam2 is a pointer to DRVCONFIGINFO
*/
if
(
*
lParam2
)
{
LPDRVCONFIGINFO16
dci16
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
*
dci16
)
);
LPDRVCONFIGINFO
dci32
=
(
LPDRVCONFIGINFO
)(
*
lParam2
);
if
(
dci16
)
{
LPSTR
str1
=
NULL
,
str2
;
INT
len
;
dci16
->
dwDCISize
=
sizeof
(
DRVCONFIGINFO16
);
if
(
dci32
->
lpszDCISectionName
)
{
len
=
WideCharToMultiByte
(
CP_ACP
,
0
,
dci32
->
lpszDCISectionName
,
-
1
,
NULL
,
0
,
NULL
,
NULL
);
str1
=
HeapAlloc
(
GetProcessHeap
(),
0
,
len
);
if
(
str1
)
{
WideCharToMultiByte
(
CP_ACP
,
0
,
dci32
->
lpszDCISectionName
,
-
1
,
str1
,
len
,
NULL
,
NULL
);
dci16
->
lpszDCISectionName
=
MapLS
(
str1
);
}
else
{
HeapFree
(
GetProcessHeap
(),
0
,
dci16
);
return
WINMM_MAP_NOMEM
;
}
}
else
{
dci16
->
lpszDCISectionName
=
0L
;
}
if
(
dci32
->
lpszDCIAliasName
)
{
len
=
WideCharToMultiByte
(
CP_ACP
,
0
,
dci32
->
lpszDCIAliasName
,
-
1
,
NULL
,
0
,
NULL
,
NULL
);
str2
=
HeapAlloc
(
GetProcessHeap
(),
0
,
len
);
if
(
str2
)
{
WideCharToMultiByte
(
CP_ACP
,
0
,
dci32
->
lpszDCIAliasName
,
-
1
,
str2
,
len
,
NULL
,
NULL
);
dci16
->
lpszDCIAliasName
=
MapLS
(
str2
);
}
else
{
HeapFree
(
GetProcessHeap
(),
0
,
str1
);
HeapFree
(
GetProcessHeap
(),
0
,
dci16
);
return
WINMM_MAP_NOMEM
;
}
}
else
{
dci16
->
lpszDCISectionName
=
0L
;
}
}
else
{
return
WINMM_MAP_NOMEM
;
}
*
lParam2
=
MapLS
(
dci16
);
ret
=
WINMM_MAP_OKMEM
;
}
else
{
ret
=
WINMM_MAP_OK
;
}
break
;
default:
if
(
!
((
wMsg
>=
0x800
&&
wMsg
<
0x900
)
||
(
wMsg
>=
0x4000
&&
wMsg
<
0x4100
)))
{
FIXME
(
"Unknown message 0x%04x
\n
"
,
wMsg
);
}
ret
=
WINMM_MAP_OK
;
}
return
ret
;
}
/**************************************************************************
* DRIVER_UnMapMsg32To16 [internal]
*
* UnMap a 32 bit driver message to a 16 bit driver message.
*/
static
WINMM_MapType
DRIVER_UnMapMsg32To16
(
WORD
wMsg
,
DWORD
lParam1
,
DWORD
lParam2
)
{
WINMM_MapType
ret
=
WINMM_MAP_MSGERROR
;
switch
(
wMsg
)
{
case
DRV_LOAD
:
case
DRV_ENABLE
:
case
DRV_DISABLE
:
case
DRV_FREE
:
case
DRV_QUERYCONFIGURE
:
case
DRV_REMOVE
:
case
DRV_EXITSESSION
:
case
DRV_EXITAPPLICATION
:
case
DRV_POWER
:
case
DRV_OPEN
:
case
DRV_CLOSE
:
/* lParam1 and lParam2 are not used */
break
;
case
DRV_CONFIGURE
:
case
DRV_INSTALL
:
/* lParam1 is a handle to a window (or not used), lParam2 is a pointer to DRVCONFIGINFO, lParam2 */
if
(
lParam2
)
{
LPDRVCONFIGINFO16
dci16
=
MapSL
(
lParam2
);
HeapFree
(
GetProcessHeap
(),
0
,
MapSL
(
dci16
->
lpszDCISectionName
)
);
HeapFree
(
GetProcessHeap
(),
0
,
MapSL
(
dci16
->
lpszDCIAliasName
)
);
UnMapLS
(
lParam2
);
UnMapLS
(
dci16
->
lpszDCISectionName
);
UnMapLS
(
dci16
->
lpszDCIAliasName
);
HeapFree
(
GetProcessHeap
(),
0
,
dci16
);
}
ret
=
WINMM_MAP_OK
;
break
;
default:
if
(
!
((
wMsg
>=
0x800
&&
wMsg
<
0x900
)
||
(
wMsg
>=
0x4000
&&
wMsg
<
0x4100
)))
{
FIXME
(
"Unknown message 0x%04x
\n
"
,
wMsg
);
}
ret
=
WINMM_MAP_OK
;
}
return
ret
;
}
/**************************************************************************
* DRIVER_TryOpenDriver16 [internal]
*
* Tries to load a 16 bit driver whose DLL's (module) name is lpFileName.
*/
static
LPWINE_DRIVER
DRIVER_OpenDriver16
(
LPCWSTR
fn
,
LPCWSTR
sn
,
LPARAM
lParam2
)
{
LPWINE_DRIVER
lpDrv
=
NULL
;
LPCSTR
cause
=
NULL
;
LPSTR
fnA
=
NULL
,
snA
=
NULL
;
unsigned
len
;
TRACE
(
"(%s, %s, %08lX);
\n
"
,
debugstr_w
(
fn
),
debugstr_w
(
sn
),
lParam2
);
lpDrv
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
WINE_DRIVER
));
if
(
lpDrv
==
NULL
)
{
cause
=
"OOM"
;
goto
exit
;}
if
(
fn
)
{
len
=
WideCharToMultiByte
(
CP_ACP
,
0
,
fn
,
-
1
,
NULL
,
0
,
NULL
,
NULL
);
fnA
=
HeapAlloc
(
GetProcessHeap
(),
0
,
len
);
if
(
fnA
==
NULL
)
{
cause
=
"OOM"
;
goto
exit
;}
WideCharToMultiByte
(
CP_ACP
,
0
,
fn
,
-
1
,
fnA
,
len
,
NULL
,
NULL
);
}
if
(
sn
)
{
len
=
WideCharToMultiByte
(
CP_ACP
,
0
,
sn
,
-
1
,
NULL
,
0
,
NULL
,
NULL
);
snA
=
HeapAlloc
(
GetProcessHeap
(),
0
,
len
);
if
(
snA
==
NULL
)
{
cause
=
"OOM"
;
goto
exit
;}
WideCharToMultiByte
(
CP_ACP
,
0
,
sn
,
-
1
,
snA
,
len
,
NULL
,
NULL
);
}
/* FIXME: shall we do some black magic here on sn ?
* drivers32 => drivers
* mci32 => mci
* ...
*/
lpDrv
->
d
.
d16
.
hDriver16
=
OpenDriver16
(
fnA
,
snA
,
lParam2
);
if
(
lpDrv
->
d
.
d16
.
hDriver16
==
0
)
{
cause
=
"Not a 16 bit driver"
;
goto
exit
;}
lpDrv
->
dwFlags
=
WINE_GDF_16BIT
;
exit:
HeapFree
(
GetProcessHeap
(),
0
,
fnA
);
HeapFree
(
GetProcessHeap
(),
0
,
snA
);
if
(
cause
)
{
TRACE
(
"Unable to load 16 bit module %s[%s]: %s
\n
"
,
debugstr_w
(
fn
),
debugstr_w
(
sn
),
cause
);
HeapFree
(
GetProcessHeap
(),
0
,
lpDrv
);
return
NULL
;
}
TRACE
(
"=> %p
\n
"
,
lpDrv
);
return
lpDrv
;
}
/******************************************************************
* DRIVER_SendMessage16
*
*
*/
static
LRESULT
DRIVER_SendMessage16
(
HDRVR16
hDrv16
,
UINT
msg
,
LPARAM
lParam1
,
LPARAM
lParam2
)
{
LRESULT
ret
=
0
;
WINMM_MapType
map
;
TRACE
(
"Before sdm16 call hDrv=%04x wMsg=%04x p1=%08lx p2=%08lx
\n
"
,
hDrv16
,
msg
,
lParam1
,
lParam2
);
switch
(
map
=
DRIVER_MapMsg32To16
(
msg
,
&
lParam1
,
&
lParam2
))
{
case
WINMM_MAP_OKMEM
:
case
WINMM_MAP_OK
:
ret
=
SendDriverMessage16
(
hDrv16
,
msg
,
lParam1
,
lParam2
);
if
(
map
==
WINMM_MAP_OKMEM
)
DRIVER_UnMapMsg32To16
(
msg
,
lParam1
,
lParam2
);
default:
break
;
}
return
ret
;
}
/******************************************************************
* DRIVER_CloseDriver16
*
*
*/
static
LRESULT
DRIVER_CloseDriver16
(
HDRVR16
hDrv16
,
LPARAM
lParam1
,
LPARAM
lParam2
)
{
return
CloseDriver16
(
hDrv16
,
lParam1
,
lParam2
);
}
/**************************************************************************
* DrvOpen [MMSYSTEM.1100]
*/
...
...
dlls/winmm/winemm.h
View file @
ca1a7c6b
...
...
@@ -29,13 +29,6 @@
#define WINE_DEFAULT_WINMM_MAPPER "msacm32.drv"
#define WINE_DEFAULT_WINMM_MIDI "midimap.dll"
typedef
enum
{
WINMM_MAP_NOMEM
,
/* ko, memory problem */
WINMM_MAP_MSGERROR
,
/* ko, unknown message */
WINMM_MAP_OK
,
/* ok, no memory allocated. to be sent to the proc. */
WINMM_MAP_OKMEM
,
/* ok, some memory allocated, need to call UnMapMsg. to be sent to the proc. */
}
WINMM_MapType
;
/* Who said goofy boy ? */
#define WINE_DI_MAGIC 0x900F1B01
...
...
@@ -44,22 +37,14 @@ typedef struct tagWINE_DRIVER
DWORD
dwMagic
;
/* as usual LPWINE_DRIVER == hDriver32 */
DWORD
dwFlags
;
union
{
struct
{
HMODULE
hModule
;
DRIVERPROC
lpDrvProc
;
DWORD_PTR
dwDriverID
;
}
d32
;
struct
{
UINT16
hDriver16
;
}
d16
;
}
d
;
struct
tagWINE_DRIVER
*
lpPrevItem
;
struct
tagWINE_DRIVER
*
lpNextItem
;
}
WINE_DRIVER
,
*
LPWINE_DRIVER
;
typedef
DWORD
(
CALLBACK
*
WINEMM_msgFunc16
)(
UINT16
,
WORD
,
DWORD
,
DWORD
,
DWORD
);
typedef
DWORD
(
CALLBACK
*
WINEMM_msgFunc32
)(
UINT
,
UINT
,
DWORD_PTR
,
DWORD_PTR
,
DWORD_PTR
);
typedef
DWORD
(
CALLBACK
*
WINEMM_msgFunc32
)(
UINT
,
UINT
,
DWORD_PTR
,
DWORD_PTR
,
DWORD_PTR
);
/* for each loaded driver and each known type of driver, this structure contains
* the information needed to access it
...
...
@@ -67,10 +52,7 @@ typedef DWORD (CALLBACK *WINEMM_msgFunc32)(UINT , UINT, DWORD_PTR, DWORD_PTR, D
typedef
struct
tagWINE_MM_DRIVER_PART
{
int
nIDMin
;
/* lower bound of global indexes for this type */
int
nIDMax
;
/* hhigher bound of global indexes for this type */
union
{
WINEMM_msgFunc32
fnMessage32
;
/* pointer to function */
WINEMM_msgFunc16
fnMessage16
;
}
u
;
}
WINE_MM_DRIVER_PART
;
#define MMDRV_AUX 0
...
...
@@ -85,8 +67,7 @@ typedef struct tagWINE_MM_DRIVER_PART {
typedef
struct
tagWINE_MM_DRIVER
{
HDRVR
hDriver
;
LPSTR
drvname
;
/* name of the driver */
unsigned
bIs32
:
1
,
/* TRUE if 32 bit driver, FALSE for 16 */
bIsMapper
:
1
;
/* TRUE if mapper */
unsigned
bIsMapper
:
1
;
/* TRUE if mapper */
WINE_MM_DRIVER_PART
parts
[
MMDRV_MAX
];
/* Information for all known types */
}
WINE_MM_DRIVER
,
*
LPWINE_MM_DRIVER
;
...
...
@@ -151,9 +132,6 @@ typedef struct tagWINE_MMIO {
/* function prototypes */
typedef
WINMM_MapType
(
*
MMDRV_MAPFUNC
)(
UINT
wMsg
,
DWORD_PTR
*
lpdwUser
,
DWORD_PTR
*
lpParam1
,
DWORD_PTR
*
lpParam2
);
typedef
WINMM_MapType
(
*
MMDRV_UNMAPFUNC
)(
UINT
wMsg
,
DWORD_PTR
*
lpdwUser
,
DWORD_PTR
*
lpParam1
,
DWORD_PTR
*
lpParam2
,
MMRESULT
ret
);
LPWINE_DRIVER
DRIVER_FindFromHDrvr
(
HDRVR
hDrvr
);
BOOL
DRIVER_GetLibName
(
LPCWSTR
keyName
,
LPCWSTR
sectName
,
LPWSTR
buf
,
int
sz
);
LPWINE_DRIVER
DRIVER_TryOpenDriver32
(
LPCWSTR
fn
,
LPARAM
lParam2
);
...
...
@@ -171,15 +149,12 @@ LPWINE_MLD MMDRV_Get(HANDLE hndl, UINT type, BOOL bCanBeID);
LPWINE_MLD
MMDRV_GetRelated
(
HANDLE
hndl
,
UINT
srcType
,
BOOL
bSrcCanBeID
,
UINT
dstTyped
);
DWORD
MMDRV_Message
(
LPWINE_MLD
mld
,
UINT
wMsg
,
DWORD_PTR
dwParam1
,
DWORD_PTR
dwParam2
);
UINT
MMDRV_PhysicalFeatures
(
LPWINE_MLD
mld
,
UINT
uMsg
,
DWORD_PTR
dwParam1
,
DWORD_PTR
dwParam2
);
BOOL
MMDRV_Is32
(
unsigned
int
);
void
MMDRV_InstallMap
(
unsigned
int
,
MMDRV_MAPFUNC
,
MMDRV_UNMAPFUNC
,
LPDRVCALLBACK
);
const
char
*
MCI_MessageToString
(
UINT
wMsg
);
DWORD
MCI_SendCommand
(
UINT
wDevID
,
UINT16
wMsg
,
DWORD_PTR
dwParam1
,
DWORD_PTR
dwParam2
);
LPWSTR
MCI_strdupAtoW
(
LPCSTR
str
);
LPSTR
MCI_strdupWtoA
(
LPCWSTR
str
);
BOOL
WINMM_CheckForMMSystem
(
void
);
const
char
*
WINMM_ErrorToString
(
MMRESULT
error
);
void
TIME_MMTimeStop
(
void
);
...
...
@@ -190,19 +165,9 @@ extern HINSTANCE hWinMM32Instance;
extern
HANDLE
psLastEvent
;
extern
HANDLE
psStopEvent
;
/* pointers to 16 bit functions (if sibling MMSYSTEM.DLL is loaded
* NULL otherwise
*/
extern
LPWINE_DRIVER
(
*
pFnOpenDriver16
)(
LPCWSTR
,
LPCWSTR
,
LPARAM
);
extern
LRESULT
(
*
pFnCloseDriver16
)(
UINT16
,
LPARAM
,
LPARAM
);
extern
LRESULT
(
*
pFnSendMessage16
)(
UINT16
,
UINT
,
LPARAM
,
LPARAM
);
extern
LRESULT
(
*
pFnCallMMDrvFunc16
)(
DWORD
/* in fact FARPROC16 */
,
WORD
,
WORD
,
LONG
,
LONG
,
LONG
);
extern
unsigned
(
*
pFnLoadMMDrvFunc16
)(
LPCSTR
,
LPWINE_DRIVER
,
LPWINE_MM_DRIVER
);
/* GetDriverFlags() returned bits is not documented (nor the call itself)
* Here are Wine only definitions of the bits
*/
#define WINE_GDF_EXIST 0x80000000
#define WINE_GDF_16BIT 0x10000000
#define WINE_GDF_EXTERNAL_MASK 0xF0000000
#define WINE_GDF_SESSION 0x00000001
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment