[PD-cvs] pd/portmidi/pm_win README_WIN.txt, NONE, 1.1 copy-dll.bat, NONE, 1.1 debugging_dlls.txt, NONE, 1.1 pm_dll.dsp, NONE, 1.1 pmdll.c, NONE, 1.1 pmdll.h, NONE, 1.1 pmwin.c, NONE, 1.1 pmwinmm.c, NONE, 1.1 pmwinmm.h, NONE, 1.1

Hans-Christoph Steiner eighthave at users.sourceforge.net
Thu Dec 15 01:57:04 CET 2005


Update of /cvsroot/pure-data/pd/portmidi/pm_win
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7035/pm_win

Added Files:
	README_WIN.txt copy-dll.bat debugging_dlls.txt pm_dll.dsp 
	pmdll.c pmdll.h pmwin.c pmwinmm.c pmwinmm.h 
Log Message:
checking in missing files on behalf of Miller (cleared it with him first).  The files are from portmidi17nov04.zip

--- NEW FILE: debugging_dlls.txt ---
========================================================================================================================
Methods for Debugging DLLs
========================================================================================================================
If you have the source for both the DLL and the calling program, open the project for the calling executable file and 
debug the DLL from there. If you load a DLL dynamically, you must specify it in the Additional DLLs category of the 
Debug tab in the Project Settings dialog box. 

If you have the source for the DLL only, open the project that builds the DLL. Use the Debug tab in the Project 
Settings dialog box to specify the executable file that calls the DLL.

You can also debug a DLL without a project. For example, maybe you just picked up a DLL and source code but you 
don’t have an associated project or workspace. You can use the Open command on the File menu to select the .DLL 
file you want to debug. The debug information should be in either the .DLL or the related .PDB file. After 
Visual C++ opens the file, on the Build menu click Start Debug and Go to begin debugging.

To debug a DLL using the project for the executable file 

>From the Project menu, click Settings. 
The Project Settings dialog box appears.

Choose the Debug tab.


In the Category drop-down list box, select General. 


In the Program Arguments text box, type any command-line arguments required by the executable file.


In the Category drop-down list box, select Additional DLLs.


In the Local Name column, type the names of DLLs to debug. 
If you are debugging remotely, the Remote Name column appears. In this column, type the complete path for the 
remote module to map to the local module name.

In the Preload column, select the check box if you want to load the module before debugging begins.


Click OK to store the information in your project.


>From the Build menu, click Start Debug and Go to start the debugger. 
You can set breakpoints in the DLL or the calling program. You can open a source file for the DLL and set breakpoints 
in that file, even though it is not a part of the executable file’s project.

To debug a DLL using the project for the DLL 

>From the Project menu, click Settings. 
The Project Settings dialog box appears.

Choose the Debug tab.


In the Category drop-down list box, select General. 


In the Executable For Debug Session text box, type the name of the executable file that calls the DLL.


In the Category list box, select Additional DLLs.


In the Local Module Name column, type the name of the DLLs you want to debug.


Click OK to store the information in your project.


Set breakpoints as required in your DLL source files or on function symbols in the DLL.


>From the Build menu, click Start Debug and Go to start the debugger. 
To debug a DLL created with an external project 

>From the Project menu, click Settings. 
The Project Settings dialog box appears.

Choose the Debug tab.


In the Category drop-down list box, select General.


In the Executable For Debug Session text box, type the name of the DLL that your external makefile builds. 


Click OK to store the information in your project.


Build a debug version of the DLL with symbolic debugging information, if you don’t already have one.


Follow one of the two procedures immediately preceding this one to debug the DLL. 

========================================================================================================================
Why Don’t My DLL Breakpoints Work?
========================================================================================================================
Some reasons why your breakpoints don’t work as expected are listed here, along with solutions or work-arounds for each. 
If you follow the instructions in one topic and are still having breakpoint problems, look at some of the other topics. 
Often breakpoint problems result from a combination of conditions. 

You can't set a breakpoint in a source file when the corresponding symbolic information isn't loaded into memory by 
the debugger. 
You cannot set a breakpoint in any source file when the corresponding symbolic information will not be loaded into memory 
by the debugger. 
Symptoms include messages such as "the breakpoint cannot be set" or a simple, noninformational beep.

When setting breakpoints before the code to be debugged has been started, the debugger uses a breakpoint list to keep 
track of how and where to set breakpoints. When you actually begin the debugging session, the debugger loads the symbolic 
information for all the code to be debugged and then walks through its breakpoint list, attempting to set the 
breakpoints. 

However, if one or more of the code modules have not been designated to the debugger, there will be no symbolic 
information for the debugger to use when walking through its breakpoint list. Situations where this is likely to 
occur include: 

Attempts to set breakpoints in a DLL before the call to LoadLibrary.

Setting a breakpoint in an ActiveX server before the container has started the server.

Other similar cases. 

To prevent this behavior in Visual C++, specify all additional DLLs and COM servers in the Additional DLLs field 
in the Debug/Options dialog box to notify the debugger that you want it to load symbolic debug information for 
additional .DLL files. When this has been done, breakpoints set in code that has not yet been loaded into memory 
will be "virtual" breakpoints. When the code is actually loaded into memory by the loader, these become physical 
breakpoints. Make sure that these additional debugging processes are not already running when you start your 
debugging session. The debugging process and these additional processes must be sychronized at the same beginning 
point to work correctly, hitting all breakpoints. 

Breakpoints are missed when more than one copy of a DLL is on your hard disk. 
Having more than one copy of a DLL on your hard drive, especially if it is in your Windows directory, can cause 
debugger confusion. The debugger will load the symbolic information for the DLL specified to it at run time (with the 
Additional DLLs field in the Debug/Options dialog box), while Windows has actually loaded a different copy of the 
DLL itself into memory. Because there is no way to force the debugger to load a specific DLL, it is a good idea to 
keep only one version of a DLL at a time in your path, current directory, and Windows directory. 

You can’t set "Break When Expression Has Changed" breakpoints on a variable local to a DLL. 
Setting a "Break When Expression Has Changed" breakpoint on a variable local to a DLL function before the call 
to LoadLibrary causes the breakpoint to be virtual (there are no physical addresses for the DLL in memory yet). 
Virtual breakpoints involving expressions pose a special problem. The DLL must be specified to the debugger at 
startup (causing its symbolic information to be loaded). In addition, the DLL's executable code must also be loaded 
into memory before this kind of breakpoint can be set. This means that the calling application's code must be 
executed to the point after its call to LoadLibrary before the debugger will allow this type of breakpoint to be set. 

--- NEW FILE: pmdll.c ---
/*
====================================================================
DLL to perform action when program shuts down
====================================================================
*/

#include "windows.h"
#include "pmdll.h"

static close_fn_ptr_type close_function = NULL;


DLL_EXPORT pm_set_close_function(close_fn_ptr_type close_fn_ptr)
{
    close_function = close_fn_ptr;
}


static void Initialize( void ) {
    return;
}

static void Terminate( void ) {
    if (close_function) {
        (*close_function)();
    }
}


BOOL WINAPI DllMain(HINSTANCE hinstDLL, //DLL module handle
					DWORD fdwReason,	//for calling function
					LPVOID lbpvReserved)//reserved
{
	switch(fdwReason) {
		case DLL_PROCESS_ATTACH:
			/* when DLL starts, run this */
			Initialize();
			break;
		case DLL_PROCESS_DETACH:
			/* when DLL ends, this run (note: verified this	run */
			Terminate();
			break;
		default:
			break;
	}
	return TRUE;
}



--- NEW FILE: pm_dll.dsp ---
# Microsoft Developer Studio Project File - Name="pm_dll" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **

# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102

CFG=pm_dll - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE 
!MESSAGE NMAKE /f "pm_dll.mak".
!MESSAGE 
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE 
!MESSAGE NMAKE /f "pm_dll.mak" CFG="pm_dll - Win32 Debug"
!MESSAGE 
!MESSAGE Possible choices for configuration are:
!MESSAGE 
!MESSAGE "pm_dll - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "pm_dll - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE 

# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe

!IF  "$(CFG)" == "pm_dll - Win32 Release"

# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "pm_win\Release"
# PROP Intermediate_Dir "pm_win\Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PM_DLL_EXPORTS" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PM_DLL_EXPORTS" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386

!ELSEIF  "$(CFG)" == "pm_dll - Win32 Debug"

# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "pm_win\Debug"
# PROP Intermediate_Dir "pm_win\Debug"
# PROP Ignore_Export_Lib 1
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PM_DLL_EXPORTS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "pm_common" /D "_WINDOWS" /D "_USRDLL" /D "PM_DLL_EXPORTS" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "USE_DLL_FOR_CLEANUP" /FR /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /dll /debug /machine:I386 /pdbtype:sept

!ENDIF 

# Begin Target

# Name "pm_dll - Win32 Release"
# Name "pm_dll - Win32 Debug"
# Begin Group "Source Files"

# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File

SOURCE=.\pmdll.c
# End Source File
# End Group
# Begin Group "Header Files"

# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File

SOURCE=.\pmdll.h
# End Source File
# End Group
# End Target
# End Project

--- NEW FILE: pmdll.h ---
#define DLL_EXPORT __declspec( dllexport )

typedef void (*close_fn_ptr_type)();

DLL_EXPORT pm_set_close_function(close_fn_ptr_type close_fn_ptr);

--- NEW FILE: pmwinmm.c ---
/* pmwinmm.c -- system specific definitions */

#include "windows.h"
#include "mmsystem.h"
#include "portmidi.h"
#include "pminternal.h"
#include "pmwinmm.h"
#include "string.h"
#include "porttime.h"

/* asserts used to verify portMidi code logic is sound; later may want
    something more graceful */
#include <assert.h>

#ifdef DEBUG
/* this printf stuff really important for debugging client app w/host errors.
    probably want to do something else besides read/write from/to console
    for portability, however */
#define STRING_MAX 80
[...1508 lines suppressed...]
                /* report any host errors; this EXTEREMELY useful when
                   trying to debug client app */
                if (winmm_has_host_error(midi)) {
                    winmm_get_host_error(midi, msg, PM_HOST_ERROR_MSG_LEN);
                    printf(msg);
                }
#endif
                /* close all open ports */
                (*midi->dictionary->close)(midi);
            }
        }
    }
#ifdef DEBUG
    if (doneAny) {
        printf("warning: devices were left open. They have been closed.\n");
    }
    printf("pm_winmm_term exiting\n");
#endif
    pm_descriptor_index = 0;
}

--- NEW FILE: pmwin.c ---
/* pmwin.c -- PortMidi os-dependent code */

/* This file only needs to implement:
       pm_init(), which calls various routines to register the 
           available midi devices,
       Pm_GetDefaultInputDeviceID(), and
       Pm_GetDefaultOutputDeviceID().
   This file must
   be separate from the main portmidi.c file because it is system
   dependent, and it is separate from, say, pmwinmm.c, because it
   might need to register devices for winmm, directx, and others.
 */

#include "stdlib.h"
#include "portmidi.h"
#include "pminternal.h"
#include "pmwinmm.h"
#ifdef USE_DLL_FOR_CLEANUP
#include "pmdll.h" /* used to close ports on exit */
#endif
#ifdef DEBUG
#include "stdio.h"
#endif

/* pm_exit is called when the program exits.
   It calls pm_term to make sure PortMidi is properly closed.
   If DEBUG is on, we prompt for input to avoid losing error messages.
 */
static void pm_exit(void) {
    pm_term();
#ifdef DEBUG
#define STRING_MAX 80
    {
        char line[STRING_MAX];
        printf("Type ENTER...\n");
        /* note, w/o this prompting, client console application can not see one
           of its errors before closing. */
        fgets(line, STRING_MAX, stdin);
    }
#endif
}


/* pm_init is the windows-dependent initialization.*/
void pm_init(void)
{
#ifdef USE_DLL_FOR_CLEANUP
    /* we were hoping a DLL could offer more robust cleanup after errors,
       but the DLL does not seem to run after crashes. Thus, the atexit()
       mechanism is just as powerful, and simpler to implement.
     */
    pm_set_close_function(pm_exit);
#ifdef DEBUG
    printf("registered pm_term with cleanup DLL\n");
#endif
#else
    atexit(pm_exit);
#ifdef DEBUG
    printf("registered pm_exit with atexit()\n");
#endif
#endif
    pm_winmm_init();
    /* initialize other APIs (DirectX?) here */
}


void pm_term(void) {
    pm_winmm_term();
}


PmDeviceID Pm_GetDefaultInputDeviceID() {
    /* This routine should check the environment and the registry
       as specified in portmidi.h, but for now, it just returns
       the first device of the proper input/output flavor.
     */
    int i;
    Pm_Initialize(); /* make sure descriptors exist! */
    for (i = 0; i < pm_descriptor_index; i++) {
        if (descriptors[i].pub.input) {
            return i;
        }
    }
    return pmNoDevice;
}

PmDeviceID Pm_GetDefaultOutputDeviceID() {
    /* This routine should check the environment and the registry
       as specified in portmidi.h, but for now, it just returns
       the first device of the proper input/output flavor.
     */
    int i;
    Pm_Initialize(); /* make sure descriptors exist! */
    for (i = 0; i < pm_descriptor_index; i++) {
        if (descriptors[i].pub.output) {
            return i;
        }
    }
    return pmNoDevice;
    return 0;
}

#include "stdio.h" 

void *pm_alloc(size_t s) {
    return malloc(s); 
}


void pm_free(void *ptr) { 
    free(ptr); 
}


--- NEW FILE: copy-dll.bat ---
copy Debug\pm_dll.dll ..\pm_test\testDebug\pm_dll.dll
copy Debug\pm_dll.dll ..\pm_test\sysexDebug\pm_dll.dll
copy Debug\pm_dll.dll ..\pm_test\midithreadDebug\pm_dll.dll
copy Debug\pm_dll.dll ..\pm_test\latencyDebug\pm_dll.dll
copy Debug\pm_dll.dll ..\pm_test\midithruDebug\pm_dll.dll

copy Release\pm_dll.dll ..\pm_test\testRelease\pm_dll.dll
copy Release\pm_dll.dll ..\pm_test\sysexRelease\pm_dll.dll
copy Release\pm_dll.dll ..\pm_test\midithreadRelease\pm_dll.dll
copy Release\pm_dll.dll ..\pm_test\latencyRelease\pm_dll.dll
copy Release\pm_dll.dll ..\pm_test\midithruRelease\pm_dll.dll



--- NEW FILE: pmwinmm.h ---
/* midiwin32.h -- system-specific definitions */

void pm_winmm_init( void );
void pm_winmm_term( void );


--- NEW FILE: README_WIN.txt ---
File: PortMidi Win32 Readme
Author: Belinda Thom, June 16 2002
Revised by: Roger Dannenberg, June 2002, May 2004

=============================================================================
USING PORTMIDI:
=============================================================================

PortMidi has been created using a DLL because the Win32 MMedia API doesn't 
handle midiInput properly in the debugger. Specifically, it doesn't clean up
after itself if the user (i.e. you, a PortMidi application) hasn't explicitly
closed all open midi input devices. This lack of cleanup can lead to much
pain and agony, including the blue-screen-of-death. This situation becomes
increasingly unacceptable when you are debugging your code, so a portMidi DLL
seemed to be the most elegant solution.

Using Microsoft Visual C++ project files (provided with PortMidi), there
are two configurations of the PortMidi library. The Debug version is 
intended for debugging, especially in a console application. The Debug
version enables some extra error checking and outputs some text as well
as a prompt to type ENTER so that you don't lose any debugging text when
the program exits. You can turn off this extra debugging info by taking
out the compile-time definition for DEBUG. This debugging version also
defines PM_CHECK_ERRORS, which forces a check for error return codes from
every call to PortMidi. You can disable this checking (especially if you
want to handle error codes in your own way) by removing PM_CHECK_ERRORS
from the predefined symbols list in the Settings dialog box.

PortMidi is designed to run without a console and should work perfectly 
well within a graphical user interface application. The Release version
is both optimized and lacking the debugging printout code of the Debug
version.

Read the portmidi.h file for PortMidi API details on using the PortMidi API.
See <...>\pm_dll_test\test.c or <...>\multithread\test.c for usage examples.

=============================================================================
TO INSTALL PORTMIDI:
=============================================================================
1)  download portmidi.zip

2)  unzip portmidi.zip into directory: <...>\portmidi

=============================================================================
TO COMPILE PORTMIDI:
=============================================================================

3)  go to this directory

4)  click on the portmidi.dsw workspace

5)  the following projects exist within this workspace:
    - portmidi (the PortMidi library)
	- pm_dll (the dll library used to close midi ports on program exit)
	- porttime (a small portable library implementing timer facilities)
	- test (simple midi I/O testing)
	- multithread (an example illustrating low-latency MIDI processing
            using a dedicated low-latency thread)
	- sysex (simple sysex message I/O testing)
	- latency (uses porttime to measure system latency)

6)  verify that all project settings are for Win32 Debug release:
	- hit Alt-F7
	- highlight all three projects in left part of Project Settings window; 
	- "Settings For" should say "Win32 Debug"

7)  set pm_dll as the active project (e.g. Project->Select Active Project)

8)  use Build->Batch Build ... to build everything in the project

9)  The settings for these projects were distributed in the zip file, so
    compile should just work.

10) IMPORTANT! PortMidi uses a DLL, pm_dll.dll, but there is no simple way
    to set up projects to use pm_dll. THEREFORE, you need to copy DLLs
    as follows (you can do this with <...>\portmidi\pm_win\copy-dll.bat):
        copy <...>\portmidi\pm_win\Debug\pm_dll.dll to:
            <...>\portmidi\pm_test\latencyDebug\pm_dll.dll
            <...>\portmidi\pm_test\midithreadDebug\pm_dll.dll
            <...>\portmidi\pm_test\sysexDebug\pm_dll.dll
            <...>\portmidi\pm_test\testDebug\pm_dll.dll
            <...>\portmidi\pm_test\midithruDebug\pm_dll.dll
        and copy <...>\portmidi\pm_win\Release\pm_dll.dll to:
            <...>\portmidi\pm_test\latencyRelease\pm_dll.dll
            <...>\portmidi\pm_test\midithreadRelease\pm_dll.dll
            <...>\portmidi\pm_test\sysexRelease\pm_dll.dll
            <...>\portmidi\pm_test\testRelease\pm_dll.dll
            <...>\portmidi\pm_test\midithruRelease\pm_dll.dll
    each time you rebuild the pm_dll project, these copies must be redone!

    Since Windows will look in the executable directory for DLLs, we 
    recommend that you always install a copy of pm_dll.dll (either the
    debug version or the release version) in the same directory as the
    application using PortMidi. The release DLL is about 40KB. This will 
    ensure that the application uses the correct DLL.

11) run test project; use the menu that shows up from the command prompt to
    test that portMidi works on your system. tests include: 
		- verify midi output works
		- verify midi input works
		- verify midi input w/midi thru works

12) run other projects if you wish: sysex, latency, and midithread

============================================================================
TO CREATE YOUR OWN PORTMIDI CLIENT APPLICATION:
============================================================================

NOTE: this section needs to be reviewed and tested. My suggestion would
be to copy the test project file (test.dsp) and modify it. -RBD

The easiest way is to start a new project w/in the portMidi workspace:

1) To open new project: 
	- File->New->Projects
	- Location: <...>\portmidi\<yourProjectName>
	- check Add to current workspace
	- select Win32 Console Application (recommended for now)
	- do *NOT* select the "make dependency" box (you will explicitly do this
      in the next step)
	- Click OK
	- Select "An Empty Project" and click Finish

2) Now this project will be the active project. Make it explicitly depend
   on PortMidi dll:
	- Project->Dependencies
	- Click pm_dll

3) Important! in order to be able to use portMidi DLL from your new project
   and set breakpoints,	copy following files from <...>\pm_dll\Debug into 
   <...>\<yourProjectName>\Debug directory:
		pm_dll.lib
		pm_dll.dll
    each time you rebuild pm_dll, these copies must be redone!

4) add whatever files you wish to add to your new project, using portMidi
   calls as desired (see USING PORTMIDI at top of this readme)

5) when you include portMidi files, do so like this:
	- #include "..\pm_dll\portmidi.h"
	- etc.

6) build and run your project

============================================================================
DESIGN NOTES
============================================================================

The DLL is used so that PortMidi can (usually) close open devices when the
program terminates. Failure to close input devices under WinNT, Win2K, and
probably later systems causes the OS to crash.

This is accomplished with a .LIB/.DLL pair, linking to the .LIB
in order to access functions in the .DLL. 

PortMidi for Win32 exists as a simple library,
with Win32-specific code in pmwin.c and MM-specific code in pmwinmm.c.
pmwin.c uses a DLL in pmdll.c to call Pm_Terminate() when the program
exits to make sure that all MIDI ports are closed.

Orderly cleanup after errors are encountered is based on a fixed order of
steps and state changes to reflect each step. Here's the order:

To open input:
    initialize return value to NULL
    - allocate the PmInternal strucure (representation of PortMidiStream)
    return value is (non-null) PmInternal structure
    - allocate midi buffer
    set buffer field of PmInternal structure
    - call system-dependent open code
        - allocate midiwinmm_type for winmm dependent data
        set descriptor field of PmInternal structure
        - open device
        set handle field of midiwinmm_type structure
        - allocate buffer 1 for sysex
        buffer is added to input port
        - allocate buffer 2 for sysex
        buffer is added to input port
        - return
    - return








More information about the Pd-cvs mailing list