206 lines
5.2 KiB
C
206 lines
5.2 KiB
C
|
/* Copyright (c) 1998 Microsoft Corporation */
|
||
|
/*
|
||
|
* @Doc DMusic
|
||
|
*
|
||
|
* @Module DMusic16.c - Startup code |
|
||
|
*
|
||
|
* 16-bit Dll for DirectMusic sequencing on legacy devices (Win95/Win98 non-WDM drivers)
|
||
|
*
|
||
|
* This Dll is the 16-bit thunk peer for DMusic32.Dll
|
||
|
*
|
||
|
* @globalv HINSTANCE | ghInst | The instance handle for the DLL.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include <windowsx.h>
|
||
|
#include <mmsystem.h>
|
||
|
|
||
|
#include "dmusic16.h"
|
||
|
#include "debug.h"
|
||
|
|
||
|
HINSTANCE ghInst;
|
||
|
HDRVR ghDrvr;
|
||
|
UINT guReferenceCount = 0;
|
||
|
|
||
|
/* @func LibMain system entry point
|
||
|
*
|
||
|
* @comm
|
||
|
*
|
||
|
* This entry point is called when the DLL is first loaded (NOT every time).
|
||
|
*
|
||
|
* Saves the global instance handle and initializes all the other modules.
|
||
|
*
|
||
|
*/
|
||
|
int PASCAL
|
||
|
LibMain(
|
||
|
HINSTANCE hInst, /* @parm Instance handle for the DLL */
|
||
|
WORD cbHeap, /* @parm Initial size of the local heap */
|
||
|
LPSTR lpszCmdLine) /* @parm Command-line parameters */
|
||
|
{
|
||
|
UINT uLev;
|
||
|
char szFilename[260];
|
||
|
|
||
|
if (GetModuleFileName(hInst, szFilename, sizeof(szFilename)))
|
||
|
{
|
||
|
DPF(2, "%s", (LPSTR)szFilename);
|
||
|
}
|
||
|
|
||
|
ghDrvr = OpenDriver(szFilename, NULL, 0L);
|
||
|
|
||
|
DPF(1, "DMusic16.DLL task %04X hdrvr %04X", GetCurrentTask(), (WORD)ghDrvr);
|
||
|
|
||
|
|
||
|
ghInst = hInst;
|
||
|
uLev = DbgInitialize(TRUE);
|
||
|
DPF(0, "DMusic16: Debug level is %u", uLev);
|
||
|
|
||
|
if (uLev > 2)
|
||
|
{
|
||
|
DPF(0, "DMusic16: Break in LibMain");
|
||
|
DebugBreak();
|
||
|
}
|
||
|
|
||
|
DeviceOnLoad();
|
||
|
AllocOnLoad();
|
||
|
MidiOutOnLoad();
|
||
|
|
||
|
#if 0
|
||
|
// This causes problems at terminate time. Find out later if we really need it.
|
||
|
//
|
||
|
if (!CreateTimerTask())
|
||
|
{
|
||
|
DPF(0, "CreateTimerTask() failed");
|
||
|
}
|
||
|
|
||
|
|
||
|
if (NULL == (LoadLibrary("dmusic16")))
|
||
|
{
|
||
|
DPF(0, "Could not LoadLibrary ourselves!");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
/* @func LibExit system call
|
||
|
*
|
||
|
* @comm
|
||
|
*
|
||
|
* This entry point is called just before the DLL is unloaded.
|
||
|
*
|
||
|
* Uninitialize all the other modules
|
||
|
*/
|
||
|
|
||
|
VOID PASCAL __loadds
|
||
|
LibExit(VOID)
|
||
|
{
|
||
|
DPF(2, "LibExit start");
|
||
|
#if 0
|
||
|
DestroyTimerTask();
|
||
|
#endif
|
||
|
MidiOutOnExit();
|
||
|
AllocOnExit();
|
||
|
DPF(2, "LibExit end, going away now.");
|
||
|
}
|
||
|
|
||
|
extern BOOL FAR PASCAL dmthunk_ThunkConnect16(LPCSTR, LPCSTR, HINSTANCE, DWORD);
|
||
|
STATIC char pszDll16[] = "DMUSIC16.DLL";
|
||
|
STATIC char pszDll32[] = "DMUSIC.DLL";
|
||
|
|
||
|
/* @func DLLEntryPoint system entry point
|
||
|
*
|
||
|
* @comm
|
||
|
*
|
||
|
* This entry point is called each time the DLL is loaded or unloaded
|
||
|
*
|
||
|
* It is used here to initialize the peer connection for the thunk layer.
|
||
|
*/
|
||
|
#define PROCESS_DETACH 0
|
||
|
#define PROCESS_ATTACH 1
|
||
|
|
||
|
BOOL WINAPI
|
||
|
DllEntryPoint(
|
||
|
DWORD dwReason, /* @parm Is the DLL being loaded or unloaded? */
|
||
|
HINSTANCE hi, /* @parm The instance handle */
|
||
|
HGLOBAL hgDS, /* @parm The global handle of the DLL's (shared) DS */
|
||
|
WORD wHeapSize, /* @parm The initial size of the local heap */
|
||
|
LPCSTR lszCmdLine, /* @parm The command line (always NULL) */
|
||
|
WORD wCmdLine) /* @parm Unused */
|
||
|
{
|
||
|
// DllEntryPoint is called before LibEntry in a 4.x dll, so we have to LocalInit here if we're
|
||
|
// going to use LocalAlloc
|
||
|
//
|
||
|
if (guReferenceCount == 0 && wHeapSize)
|
||
|
{
|
||
|
LocalInit(0, 0, wHeapSize);
|
||
|
}
|
||
|
|
||
|
switch(dwReason)
|
||
|
{
|
||
|
case PROCESS_ATTACH:
|
||
|
DPF(2, "ProcessAttach task %04X", GetCurrentTask());
|
||
|
++guReferenceCount;
|
||
|
dmthunk_ThunkConnect16(pszDll16, pszDll32, ghInst, 1);
|
||
|
break;
|
||
|
|
||
|
case PROCESS_DETACH:
|
||
|
DPF(2, "ProcessDetach task %04X", GetCurrentTask());
|
||
|
|
||
|
/* Clean up after them if they didn't close handles. We must do this here as well as
|
||
|
* in DriverProc because on the last exit, we will go away before the DriverProc cleanup
|
||
|
* gets called if the process termination is normal.
|
||
|
*/
|
||
|
CloseDevicesForTask(GetCurrentTask());
|
||
|
|
||
|
/* NOTE: We close on reference count of 1 since the initial OpenDriver call
|
||
|
causes one more PROCESS_ATTACH to happen. */
|
||
|
if (1 == --guReferenceCount)
|
||
|
{
|
||
|
CloseDriver(ghDrvr, 0, 0);
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* @func DriverProc entry point for ourselves as a loadable driver.
|
||
|
*
|
||
|
* @comm This entry points allows us to know when a task has gone away and therefore to clean
|
||
|
* up after it even though we don't properly get notified that our thunk peer has gone away.
|
||
|
*/
|
||
|
LRESULT WINAPI DriverProc(
|
||
|
DWORD dwID,
|
||
|
HDRVR hdrvr,
|
||
|
UINT umsg,
|
||
|
LPARAM lParam1,
|
||
|
LPARAM lParam2)
|
||
|
{
|
||
|
//
|
||
|
// NOTE DS is not valid here.
|
||
|
//
|
||
|
switch (umsg)
|
||
|
{
|
||
|
case DRV_LOAD:
|
||
|
return(1L);
|
||
|
|
||
|
case DRV_FREE:
|
||
|
return(0L);
|
||
|
|
||
|
case DRV_OPEN:
|
||
|
case DRV_CLOSE:
|
||
|
return(1L);
|
||
|
|
||
|
case DRV_EXITAPPLICATION:
|
||
|
DPF(2, "Cleaning up handles for task %04X", GetCurrentTask());
|
||
|
CloseDevicesForTask(GetCurrentTask());
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
return(DefDriverProc(dwID, hdrvr, umsg, lParam1, lParam2));
|
||
|
}
|
||
|
} //** DriverProc()
|