289 lines
8.1 KiB
C
289 lines
8.1 KiB
C
/****************************************************************************
|
|
*
|
|
* util.c
|
|
*
|
|
* Copyright (c) 1992-1999 Microsoft Corporation
|
|
*
|
|
***************************************************************************/
|
|
|
|
#include "winmmi.h"
|
|
|
|
//
|
|
// Assist with unicode conversions
|
|
//
|
|
|
|
|
|
// This function translates from Unicode strings to multibyte strings.
|
|
// It will automatically munge down the Unicode string until the translation
|
|
// is guaranteed to succeed with the buffer space available in the multibyte
|
|
// buffer. Then it performs the conversion.
|
|
|
|
|
|
int Iwcstombs(LPSTR lpstr, LPCWSTR lpwstr, int len)
|
|
{
|
|
|
|
int wlength;
|
|
|
|
wlength=wcslen(lpwstr)+1;
|
|
|
|
while (WideCharToMultiByte(GetACP(), 0, lpwstr, wlength, NULL, 0, NULL, NULL)>len && wlength>0) {
|
|
wlength--;
|
|
}
|
|
|
|
return WideCharToMultiByte(GetACP(), 0, lpwstr, wlength, lpstr, len, NULL, NULL);
|
|
}
|
|
|
|
int Imbstowcs(LPWSTR lpwstr, LPCSTR lpstr, int len)
|
|
{
|
|
return MultiByteToWideChar(GetACP(),
|
|
MB_PRECOMPOSED,
|
|
lpstr,
|
|
-1,
|
|
lpwstr,
|
|
len);
|
|
}
|
|
|
|
#if 0
|
|
BOOL HugePageLock(LPVOID lpArea, DWORD dwLength)
|
|
{
|
|
PVOID BaseAddress = lpArea;
|
|
ULONG RegionSize = dwLength;
|
|
NTSTATUS Status;
|
|
|
|
Status =
|
|
NtLockVirtualMemory(NtCurrentProcess(),
|
|
&BaseAddress,
|
|
&RegionSize,
|
|
MAP_PROCESS);
|
|
|
|
//
|
|
// People without the right priviledge will not have the luxury
|
|
// of having their pages locked
|
|
// (maybe we should do something else to commit it ?)
|
|
//
|
|
|
|
if (!NT_SUCCESS(Status) && Status != STATUS_PRIVILEGE_NOT_HELD) {
|
|
dprintf2(("Failed to lock virtual memory - code %X", Status));
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void HugePageUnlock(LPVOID lpArea, DWORD dwLength)
|
|
{
|
|
PVOID BaseAddress = lpArea;
|
|
ULONG RegionSize = dwLength;
|
|
NTSTATUS Status;
|
|
|
|
Status =
|
|
NtUnlockVirtualMemory(NtCurrentProcess(),
|
|
&BaseAddress,
|
|
&RegionSize,
|
|
MAP_PROCESS);
|
|
|
|
//
|
|
// People without the right priviledge will not have the luxury
|
|
// of having their pages locked
|
|
// (maybe we should do something else to commit it ?)
|
|
//
|
|
|
|
if (!NT_SUCCESS(Status) && Status != STATUS_PRIVILEGE_NOT_HELD) {
|
|
dprintf2(("Failed to unlock virtual memory - code %X", Status));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
*
|
|
* @doc DDK MMSYSTEM
|
|
*
|
|
* @api BOOL | DriverCallback | This function notifies a client
|
|
* application by sending a message to a window or callback
|
|
* function or by unblocking a task.
|
|
*
|
|
* @parm DWORD | dwCallBack | Specifies either the address of
|
|
* a callback function, a window handle, or a task handle, depending on
|
|
* the flags specified in the <p wFlags> parameter.
|
|
*
|
|
* @parm DWORD | dwFlags | Specifies how the client
|
|
* application is notified, according to one of the following flags:
|
|
*
|
|
* @flag DCB_FUNCTION | The application is notified by
|
|
* sending a message to a callback function. The <p dwCallback>
|
|
* parameter specifies a procedure-instance address.
|
|
* @flag DCB_WINDOW | The application is notified by
|
|
* sending a message to a window. The low-order word of the
|
|
* <p dwCallback> parameter specifies a window handle.
|
|
* @flag DCB_TASK | The application is notified by
|
|
* calling mmTaskSignal
|
|
* @flag DCB_EVENT | The application is notified by
|
|
* calling SetEvent on the (assumed) event handle
|
|
*
|
|
* @parm HANDLE | hDevice | Specifies a handle to the device
|
|
* associated with the notification. This is the handle assigned by
|
|
* MMSYSTEM when the device was opened.
|
|
*
|
|
* @parm DWORD | dwMsg | Specifies a message to send to the
|
|
* application.
|
|
*
|
|
* @parm DWORD | dwUser | Specifies the DWORD of user instance
|
|
* data supplied by the application when the device was opened.
|
|
*
|
|
* @parm DWORD | dwParam1 | Specifies a message-dependent parameter.
|
|
* @parm DWORD | dwParam2 | Specifies a message-dependent parameter.
|
|
*
|
|
* @rdesc Returns TRUE if the callback was performed, else FALSE if an invalid
|
|
* parameter was passed, or the task's message queue was full.
|
|
*
|
|
* @comm This function can be called from an APC routine.
|
|
*
|
|
* The flags DCB_FUNCTION and DCB_WINDOW are equivalent to the
|
|
* high-order word of the corresponding flags CALLBACK_FUNCTION
|
|
* and CALLBACK_WINDOW specified when the device was opened.
|
|
*
|
|
* If notification is done with a callback function, <p hDevice>,
|
|
* <p wMsg>, <p dwUser>, <p dwParam1>, and <p dwParam2> are passed to
|
|
* the callback. If notification is done with a window, only <p wMsg>,
|
|
* <p hDevice>, and <p dwParam1> are passed to the window.
|
|
***************************************************************************/
|
|
|
|
BOOL APIENTRY DriverCallback(DWORD_PTR dwCallBack,
|
|
DWORD dwFlags,
|
|
HDRVR hDrv,
|
|
DWORD dwMsg,
|
|
DWORD_PTR dwUser,
|
|
DWORD_PTR dw1,
|
|
DWORD_PTR dw2)
|
|
{
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
|
|
// if this is a MIM_DATA message, and thruing is enabled for this
|
|
// device, pass the data on the the thru device
|
|
// NOTE: we do this BEFORE we check for NULL callback type on purpose!
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
|
|
|
|
//
|
|
// if this is not a MIM_DATA message, or if we have no
|
|
// thruing handle installed in the midi in device,
|
|
// we can skip all of the midi thruing code
|
|
//
|
|
if ((dwMsg == MIM_DATA) && (HtoPT(PMIDIDEV,hDrv)->pmThru))
|
|
{
|
|
MMRESULT mmr;
|
|
|
|
mmr = midiOutShortMsg((HMIDIOUT)HtoPT(PMIDIDEV,hDrv)->pmThru, (DWORD)dw1);
|
|
|
|
if (MIDIERR_DONT_CONTINUE == mmr)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (MMSYSERR_INVALHANDLE == mmr)
|
|
{
|
|
HtoPT(PMIDIDEV,hDrv)->pmThru = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the callback routine is null or erroneous flags are set return
|
|
// at once
|
|
//
|
|
|
|
if (dwCallBack == 0L) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Test what type of callback we're to make
|
|
//
|
|
|
|
switch (dwFlags & DCB_TYPEMASK) {
|
|
|
|
case DCB_WINDOW:
|
|
//
|
|
// Send message to window
|
|
//
|
|
|
|
return PostMessage(*(HWND *)&dwCallBack, dwMsg, (WPARAM)hDrv, (LPARAM)dw1);
|
|
|
|
case DCB_TASK:
|
|
//
|
|
// Send message to task
|
|
//
|
|
PostThreadMessage((DWORD)dwCallBack, dwMsg, (WPARAM)hDrv, (LPARAM)dw1);
|
|
return mmTaskSignal((DWORD)dwCallBack);
|
|
|
|
case DCB_FUNCTION:
|
|
//
|
|
// Call back the user's callback
|
|
//
|
|
(**(PDRVCALLBACK *)&dwCallBack)(hDrv, dwMsg, dwUser, dw1, dw2);
|
|
return TRUE;
|
|
|
|
case DCB_EVENT:
|
|
//
|
|
// Signal the user's event
|
|
//
|
|
SetEvent((HANDLE)dwCallBack);
|
|
return TRUE;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* @doc INTERNAL MCI
|
|
* @api PVOID | mciAlloc | Allocate memory from our heap and zero it
|
|
*
|
|
* @parm DWORD | cb | The amount of memory to allocate
|
|
*
|
|
* @rdesc returns pointer to the new memory
|
|
*
|
|
*/
|
|
|
|
PVOID winmmAlloc(DWORD cb)
|
|
{
|
|
PVOID ptr;
|
|
|
|
ptr = (PVOID)HeapAlloc(hHeap, 0, cb);
|
|
|
|
if (ptr == NULL) {
|
|
return NULL;
|
|
} else {
|
|
ZeroMemory(ptr, cb);
|
|
return ptr;
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
* @doc INTERNAL MCI
|
|
* @api PVOID | mciReAlloc | ReAllocate memory from our heap and zero extra
|
|
*
|
|
* @parm DWORD | cb | The new size
|
|
*
|
|
* @rdesc returns pointer to the new memory
|
|
*
|
|
*/
|
|
|
|
PVOID winmmReAlloc(PVOID ptr, DWORD cb)
|
|
{
|
|
PVOID newptr;
|
|
DWORD oldcb;
|
|
|
|
newptr = (PVOID)HeapAlloc(hHeap, 0, cb);
|
|
|
|
if (newptr != NULL) {
|
|
oldcb = (DWORD)HeapSize(hHeap, 0, ptr);
|
|
if (oldcb<cb) { // Block is being expanded
|
|
ZeroMemory((PBYTE)newptr+oldcb, cb-oldcb);
|
|
cb = oldcb;
|
|
}
|
|
CopyMemory(newptr, ptr, cb);
|
|
HeapFree(hHeap, 0, ptr);
|
|
}
|
|
return newptr;
|
|
}
|
|
|