Tips for Writing ACM Drivers
This section provides some guidelines for writing ACM drivers.
- Allocate driver-instance data in response to the DRV_OPEN message. You will usually need some data throughout the life of the driver; for example, you need the module-instance handle in order to load resource strings. Define a structure containing this data, and allocate it in response to DRV_OPEN. Do not save this structure as a global variable. Instead, return a pointer to the structure as the return value for the DRV_OPEN message. This pointer will be passed back to the driver in every subsequent message, as the first parameter of the DriverProc function. Remember to free this driver-instance data in response to the DRV_CLOSE message.
- Allocate stream-instance data in response to the ACMDM_STREAM_OPEN message. You will usually need some instance data for each open stream. Since there could be several streams open at the same time, you shouldn't store this data as a global variable. Instead, define a structure containing the required data, and allocate it in response to ACMDM_STREAM_OPEN. In that message, the driver is passed a pointer to an ACMDRVSTREAMINSTANCE structure. Store a pointer to the stream-instance data in the dwDriver member, and it will be available on every call involving that stream. Remember to free the stream-instance data in response to the ACMDM_STREAM_CLOSE message.
- Avoid using global variables. Defining a single DWORD of global data will use up 4K of memory in every process which uses the ACM, because your driver is loaded into each process. There is no need to use global data; instead, use the instance data, as described earlier.
- Make sure that your driver processes the ACMDM_STREAM_CONVERT message as quickly as possible. Perform as much processing as possible in the ACMDM_STREAM_OPEN message.
- Don't link to CRTDLL.DLL. This DLL cannot be loaded into all contexts, and therefore your codec will not function correctly. In particular, your codec may not work correctly for system sounds produced using the MessageBeep function. Use Win32 functions or link to a static C runtime library such as LIBC.LIB or LIBCMT.LIB.
- Handle Win32 error conditions correctly. You cannot always depend on the success of calls to the USER module (such as LoadString and LoadIcon). In particular, when your codec is used to play system sounds, it may be loaded into a context in which these calls are unable to succeed. Although there will be no opportunity for your codec to display icons or strings in this context, your code must be prepared handle this situation.
- Store configuration data on a per-user basis. Each user should be able to configure an ACM driver according to personal preferences. Therefore, configuration information should be stored in the HKEY_CURRENT_USER section of the registry.
- Provide a valid default configuration. Configuration data will normally be stored on a per-user basis; however, in some contexts (such as when playing system sounds) there will be no defined current user. In these situations, calls to the registry will fail. You must provide a reasonable default configuration to handle this failure.