Implemented DosBeep in doscalls and a simple audio mixer in lib2ine.
This commit is contained in:
1 parent
8c5d43f997
commit
490702cc45
7 files changed
+324
-7
No files matched your search
@@ -96,8 +96,10 @@ target_link_libraries(viocalls ncursesw)
|
||||
|
||||
# !!! FIXME: clean this up/
|
||||
if(LX_LEGACY)
|
||||
target_link_libraries(2ine "${CMAKE_CURRENT_SOURCE_DIR}/libSDL2-2.0.so.0")
|
||||
target_link_libraries(pmwin "${CMAKE_CURRENT_SOURCE_DIR}/libSDL2-2.0.so.0")
|
||||
else()
|
||||
target_link_libraries(2ine "SDL2")
|
||||
target_link_libraries(pmwin "SDL2")
|
||||
endif()
|
||||
|
||||
|
||||
@@ -23,8 +23,10 @@
|
||||
#include <pthread.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "lib2ine.h"
|
||||
#include "SDL.h"
|
||||
|
||||
extern char **environ;
|
||||
|
||||
@@ -640,6 +642,157 @@ static void prepOs2Drives(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
typedef struct LxAudioGeneratorInfo
|
||||
{
|
||||
LxAudioGeneratorFn fn;
|
||||
void *data;
|
||||
struct LxAudioGeneratorInfo *next;
|
||||
} LxAudioGeneratorInfo;
|
||||
|
||||
static LxAudioGeneratorInfo *audio_generators = NULL;
|
||||
static SDL_AudioDeviceID sdl_audio_device = 0;
|
||||
static SDL_AudioSpec sdl_audio_spec;
|
||||
static Uint32 no_audio_generators_timeout = 0;
|
||||
|
||||
static int SDLCALL closeAudioDeviceThread(void *arg)
|
||||
{
|
||||
const SDL_AudioDeviceID dev = (SDL_AudioDeviceID) (size_t) arg;
|
||||
//printf("2ine: Closing idle audio device %u.\n", (uint) dev);
|
||||
SDL_CloseAudioDevice(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void closeAudioDeviceFromAnotherThread(void)
|
||||
{
|
||||
FIXME("Make this atomic");
|
||||
const SDL_AudioDeviceID dev = sdl_audio_device;
|
||||
if (!sdl_audio_device) {
|
||||
return;
|
||||
}
|
||||
sdl_audio_device = 0;
|
||||
|
||||
SDL_Thread *thread = SDL_CreateThread(closeAudioDeviceThread, "2ine_close_audio_device", (void *) (size_t) dev);
|
||||
if (thread) {
|
||||
SDL_DetachThread(thread);
|
||||
} else {
|
||||
sdl_audio_device = dev; // oh well.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void SDLCALL audioCallback(void *userdata, Uint8 *stream, int len)
|
||||
{
|
||||
memset(stream, '\0', len);
|
||||
LxAudioGeneratorInfo *generator = audio_generators;
|
||||
if (!generator) {
|
||||
if (!no_audio_generators_timeout) {
|
||||
no_audio_generators_timeout = SDL_GetTicks() + 5000;
|
||||
} else if (SDL_TICKS_PASSED(SDL_GetTicks(), no_audio_generators_timeout)) {
|
||||
closeAudioDeviceFromAnotherThread();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
no_audio_generators_timeout = 0;
|
||||
|
||||
const int samples = len / sizeof (float);
|
||||
LxAudioGeneratorInfo *prev = NULL;
|
||||
while (generator) {
|
||||
LxAudioGeneratorInfo *next = generator->next;
|
||||
if (generator->fn(generator->data, (float *) stream, samples, sdl_audio_spec.freq)) {
|
||||
prev = generator;
|
||||
} else {
|
||||
// remove this generator, it's done.
|
||||
if (prev) {
|
||||
prev->next = next;
|
||||
} else {
|
||||
assert(generator == audio_generators);
|
||||
audio_generators = next;
|
||||
}
|
||||
free(generator);
|
||||
}
|
||||
generator = next;
|
||||
}
|
||||
}
|
||||
|
||||
static int registerAudioGenerator_lib2ine(LxAudioGeneratorFn fn, void *data, const int singleton)
|
||||
{
|
||||
if (!sdl_audio_device) {
|
||||
SDL_Init(SDL_INIT_AUDIO);
|
||||
SDL_AudioSpec spec;
|
||||
SDL_zero(spec);
|
||||
spec.freq = 48000;
|
||||
spec.format = AUDIO_F32SYS;
|
||||
spec.channels = 1;
|
||||
spec.samples = 1024;
|
||||
spec.callback = audioCallback;
|
||||
sdl_audio_device = SDL_OpenAudioDevice(NULL, 0, &spec, &sdl_audio_spec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE);
|
||||
if (!sdl_audio_device) {
|
||||
SDL_QuitSubSystem(SDL_INIT_AUDIO);
|
||||
return 0;
|
||||
}
|
||||
no_audio_generators_timeout = 0;
|
||||
SDL_PauseAudioDevice(sdl_audio_device, 0);
|
||||
}
|
||||
|
||||
LxAudioGeneratorInfo *info = (LxAudioGeneratorInfo *) malloc(sizeof (LxAudioGeneratorInfo *));
|
||||
if (!info) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
info->fn = fn;
|
||||
info->data = data;
|
||||
|
||||
SDL_LockAudioDevice(sdl_audio_device);
|
||||
|
||||
if (singleton) {
|
||||
for (LxAudioGeneratorInfo *i = audio_generators; i != NULL; i = i->next) {
|
||||
if (i->fn == fn) {
|
||||
SDL_UnlockAudioDevice(sdl_audio_device);
|
||||
free(info);
|
||||
return 2; // already added.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
no_audio_generators_timeout = 0;
|
||||
info->next = audio_generators;
|
||||
audio_generators = info;
|
||||
SDL_UnlockAudioDevice(sdl_audio_device);
|
||||
return 1;
|
||||
} // registerAudioGenerator_lib2ine
|
||||
|
||||
|
||||
static void lib2ine_shutdown(void)
|
||||
{
|
||||
if (sdl_audio_device) {
|
||||
// let the audio callback run about two more times, to let any last queued things fully render.
|
||||
SDL_Delay(((sdl_audio_spec.samples * 1000) / sdl_audio_spec.freq) * 2);
|
||||
SDL_CloseAudioDevice(sdl_audio_device);
|
||||
SDL_QuitSubSystem(SDL_INIT_AUDIO);
|
||||
sdl_audio_device = 0;
|
||||
}
|
||||
|
||||
LxAudioGeneratorInfo *generator = audio_generators;
|
||||
audio_generators = NULL;
|
||||
while (generator) {
|
||||
LxAudioGeneratorInfo *next = generator->next;
|
||||
free(generator);
|
||||
generator = next;
|
||||
}
|
||||
|
||||
for (int i = 0; i < (sizeof (GLoaderState.disks) / sizeof (GLoaderState.disks[0])); i++) {
|
||||
free(GLoaderState.disks[i]);
|
||||
GLoaderState.disks[i] = NULL;
|
||||
}
|
||||
|
||||
free(GLoaderState.pib.pib_pchenv);
|
||||
GLoaderState.pib.pib_pchenv = NULL;
|
||||
|
||||
memset(&GLoaderState, '\0', sizeof (GLoaderState));
|
||||
pthread_key_delete(tlskey);
|
||||
}
|
||||
|
||||
LX_NATIVE_CONSTRUCTOR(lib2ine)
|
||||
{
|
||||
if (pthread_key_create(&tlskey, NULL) != 0) {
|
||||
@@ -662,6 +815,8 @@ LX_NATIVE_CONSTRUCTOR(lib2ine)
|
||||
GLoaderState.loadModule = loadModule_lib2ine;
|
||||
GLoaderState.makeUnixPath = makeUnixPath_lib2ine;
|
||||
GLoaderState.terminate = terminate_lib2ine;
|
||||
GLoaderState.registerAudioGenerator = registerAudioGenerator_lib2ine;
|
||||
GLoaderState.lib2ine_shutdown = lib2ine_shutdown;
|
||||
|
||||
cfgLoadFiles();
|
||||
prepOs2Drives();
|
||||
@@ -689,13 +844,7 @@ LX_NATIVE_CONSTRUCTOR(lib2ine)
|
||||
|
||||
LX_NATIVE_DESTRUCTOR(lib2ine)
|
||||
{
|
||||
for (int i = 0; i < (sizeof (GLoaderState.disks) / sizeof (GLoaderState.disks[0])); i++) {
|
||||
free(GLoaderState.disks[i]);
|
||||
GLoaderState.disks[i] = NULL;
|
||||
}
|
||||
free(GLoaderState.pib.pib_pchenv);
|
||||
memset(&GLoaderState, '\0', sizeof (GLoaderState));
|
||||
pthread_key_delete(tlskey);
|
||||
lib2ine_shutdown();
|
||||
}
|
||||
|
||||
// end of lib2ine.c ...
|
||||
|
||||
@@ -273,6 +273,13 @@ typedef struct LxPostTIB
|
||||
void *anchor_block;
|
||||
} LxPostTIB;
|
||||
|
||||
// There are a few things that need access to the sound hardware:
|
||||
// DosBeep(), MMOS/2, DART, basic system sounds, etc. We unify all this
|
||||
// into a single SDL audio device open where possible, so that we don't
|
||||
// have to deal with multiple devices, but that means it has to move into
|
||||
// lib2ine so multiple libraries can access it.
|
||||
typedef int (*LxAudioGeneratorFn)(void *data, float *stream, int len, int freq);
|
||||
|
||||
#define LXTIBSIZE (sizeof (LxTIB) + sizeof (LxTIB2) + sizeof (LxPostTIB))
|
||||
|
||||
#define LX_MAX_LDT_SLOTS 8192
|
||||
@@ -318,6 +325,8 @@ typedef struct LxLoaderState
|
||||
LxModule *(*loadModule)(const char *modname);
|
||||
char *(*makeUnixPath)(const char *os2path, uint32 *err);
|
||||
void __attribute__((noreturn)) (*terminate)(const uint32 exitcode);
|
||||
int (*registerAudioGenerator)(LxAudioGeneratorFn fn, void *data, const int singleton);
|
||||
void (*lib2ine_shutdown)(void);
|
||||
} LxLoaderState;
|
||||
|
||||
typedef const LxExport *(*LxNativeModuleInitEntryPoint)(uint32 *lx_num_exports);
|
||||
|
||||
@@ -667,6 +667,8 @@ static void freeLxModule(LxModule *lxmod);
|
||||
|
||||
static __attribute__((noreturn)) void lxTerminate(const uint32 exitcode)
|
||||
{
|
||||
GLoaderState.lib2ine_shutdown();
|
||||
|
||||
// free the actual .exe
|
||||
freeLxModule(GLoaderState.main_module);
|
||||
|
||||
|
||||
@@ -72,6 +72,12 @@ static APIRET16 bridge16to32_Dos16GetMachineMode(uint8 *args) {
|
||||
return Dos16GetMachineMode(pmode);
|
||||
}
|
||||
|
||||
static APIRET16 bridge16to32_Dos16Beep(uint8 *args) {
|
||||
LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, dur);
|
||||
LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, freq);
|
||||
return Dos16Beep(freq, dur);
|
||||
}
|
||||
|
||||
static APIRET16 bridge16to32_Dos16ChDir(uint8 *args) {
|
||||
LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(ULONG, res);
|
||||
LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PSZ, pszDir);
|
||||
@@ -264,6 +270,7 @@ LX_NATIVE_MODULE_16BIT_SUPPORT()
|
||||
LX_NATIVE_MODULE_16BIT_API(Dos16FreeSeg)
|
||||
LX_NATIVE_MODULE_16BIT_API(Dos16GetHugeShift)
|
||||
LX_NATIVE_MODULE_16BIT_API(Dos16GetMachineMode)
|
||||
LX_NATIVE_MODULE_16BIT_API(Dos16Beep)
|
||||
LX_NATIVE_MODULE_16BIT_API(Dos16ChDir)
|
||||
LX_NATIVE_MODULE_16BIT_API(Dos16ChgFilePtr)
|
||||
LX_NATIVE_MODULE_16BIT_API(Dos16Close)
|
||||
@@ -308,6 +315,7 @@ static int init16_doscalls(void) {
|
||||
LX_NATIVE_INIT_16BIT_BRIDGE(Dos16FreeSeg, 2)
|
||||
LX_NATIVE_INIT_16BIT_BRIDGE(Dos16GetHugeShift, 4)
|
||||
LX_NATIVE_INIT_16BIT_BRIDGE(Dos16GetMachineMode, 4)
|
||||
LX_NATIVE_INIT_16BIT_BRIDGE(Dos16Beep, 4)
|
||||
LX_NATIVE_INIT_16BIT_BRIDGE(Dos16ChDir, 8)
|
||||
LX_NATIVE_INIT_16BIT_BRIDGE(Dos16ChgFilePtr, 12)
|
||||
LX_NATIVE_INIT_16BIT_BRIDGE(Dos16Close, 2)
|
||||
@@ -349,6 +357,7 @@ LX_NATIVE_MODULE_INIT({ if (!init16_doscalls()) return 0; })
|
||||
LX_NATIVE_EXPORT16(Dos16FreeSeg, 39),
|
||||
LX_NATIVE_EXPORT16(Dos16GetHugeShift, 41),
|
||||
LX_NATIVE_EXPORT16(Dos16GetMachineMode, 49),
|
||||
LX_NATIVE_EXPORT16(Dos16Beep, 50),
|
||||
LX_NATIVE_EXPORT16(Dos16ChDir, 57),
|
||||
LX_NATIVE_EXPORT16(Dos16ChgFilePtr, 58),
|
||||
LX_NATIVE_EXPORT16(Dos16Close, 59),
|
||||
@@ -404,6 +413,7 @@ LX_NATIVE_MODULE_INIT({ if (!init16_doscalls()) return 0; })
|
||||
LX_NATIVE_EXPORT(DosRead, 281),
|
||||
LX_NATIVE_EXPORT(DosWrite, 282),
|
||||
LX_NATIVE_EXPORT(DosExecPgm, 283),
|
||||
LX_NATIVE_EXPORT(DosBeep, 286),
|
||||
LX_NATIVE_EXPORT(DosSetProcessCp, 289),
|
||||
LX_NATIVE_EXPORT(DosQueryCp, 291),
|
||||
LX_NATIVE_EXPORT(DosExitList, 296),
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "doscalls-lx.h"
|
||||
|
||||
static pthread_mutex_t GMutexDosCalls;
|
||||
static pthread_mutex_t GMutexDosBeep;
|
||||
|
||||
typedef struct ExitListItem
|
||||
{
|
||||
@@ -3133,6 +3134,132 @@ APIRET DosDupHandle(HFILE hFile, PHFILE pHfile)
|
||||
return DosDupHandle_implementation(hFile, pHfile);
|
||||
} // DosDupHandle
|
||||
|
||||
|
||||
typedef struct DosBeepGeneratorInfo
|
||||
{
|
||||
ULONG samples_remaining;
|
||||
ULONG positive;
|
||||
ULONG square_remaining;
|
||||
ULONG square_length;
|
||||
ULONG square_remainder;
|
||||
ULONG accumulator;
|
||||
ULONG next_freq;
|
||||
ULONG next_duration;
|
||||
} DosBeepGeneratorInfo;
|
||||
|
||||
static DosBeepGeneratorInfo dos_beep_info;
|
||||
|
||||
static int DosBeepGenerator(void *userdata, float *stream, int samples, int freq)
|
||||
{
|
||||
DosBeepGeneratorInfo *info = &dos_beep_info;
|
||||
assert(userdata == &dos_beep_info);
|
||||
|
||||
while (samples > 0) {
|
||||
if (!info->samples_remaining) { // current beep command is finished?
|
||||
if (!info->next_freq) {
|
||||
return 0; // out of things to play, remove ourselves from the mixer.
|
||||
}
|
||||
|
||||
// set up next beep command.
|
||||
info->square_length = ((ULONG) freq) / info->next_freq;
|
||||
info->square_remainder = ((ULONG) freq) % info->next_freq;
|
||||
info->samples_remaining = ((ULONG) ((info->next_duration / 1000.0) * ((ULONG) freq))) * 1;
|
||||
info->accumulator = 0;
|
||||
info->next_freq = 0;
|
||||
info->next_duration = 0;
|
||||
} else if (!info->square_remaining) { // this part of the square wave is finished, flip it and start the next part.
|
||||
info->positive = !info->positive;
|
||||
info->square_remaining = info->square_length;
|
||||
info->accumulator += info->square_remainder;
|
||||
if (info->accumulator >= info->square_length) {
|
||||
info->accumulator -= info->square_length;
|
||||
info->square_remaining++;
|
||||
}
|
||||
} else { // still generating the current piece of the square wave, mix it into the stream.
|
||||
// VMware emulates the PC Speaker on a sound card _really_ quietly.
|
||||
const float val = info->positive ? 0.05f : -0.05f;
|
||||
int total = info->square_remaining;
|
||||
if (info->samples_remaining < total) total = info->samples_remaining;
|
||||
if (samples < total) total = samples;
|
||||
|
||||
FIXME("good candidate for SSE");
|
||||
for (int i = 0; i < total; i++) {
|
||||
stream[i] += val;
|
||||
}
|
||||
|
||||
samples -= total;
|
||||
info->samples_remaining -= total;
|
||||
info->square_remaining -= total;
|
||||
stream += total;
|
||||
}
|
||||
}
|
||||
|
||||
return 1; // remain in the mixer to keep generating audio.
|
||||
} // DosBeepGenerator
|
||||
|
||||
static APIRET DosBeep_implementation(ULONG freq, ULONG duration)
|
||||
{
|
||||
if ((freq < 0x25) || (freq > 0x7FFF)) {
|
||||
return ERROR_INVALID_FREQUENCY;
|
||||
} else if (duration == 0) {
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
// Either OS/2 or Vmware seems to be doubling the frequency requested, I
|
||||
// think, as this sounds closer to what DosBeep() generates there.
|
||||
//FIXME("sanity check this");
|
||||
//freq *= 2;
|
||||
|
||||
// assuming OS/2 ran the PC Speaker off the BIOS timer, firing 18.2 times
|
||||
// a second (about 55 milliseconds), we'll round up the requested
|
||||
// duration to match.
|
||||
FIXME("sanity check this");
|
||||
const ULONG duration_diff = duration % 55;
|
||||
const ULONG mix_duration = duration + (duration_diff ? (55 - duration_diff) : 0);
|
||||
|
||||
// we chain beep commands together and return a little before they'll
|
||||
// end, so the caller can queue another without a gap in playback if
|
||||
// they're making multiple calls to DosBeep to make a cute little tune.
|
||||
|
||||
// OS/2's implementation appears to hold a mutex while driving the PC
|
||||
// speaker; if you DosBeep() from two threads at once, one will block
|
||||
// until the other finishes playing.
|
||||
grabLock(&GMutexDosBeep);
|
||||
|
||||
FIXME("should be atomic");
|
||||
while (*((volatile ULONG *) &dos_beep_info.next_freq) != 0) {
|
||||
usleep(1000);
|
||||
}
|
||||
|
||||
dos_beep_info.next_duration = mix_duration;
|
||||
dos_beep_info.next_freq = freq;
|
||||
|
||||
// wait about the time this was requested to play, but since there is
|
||||
// variance on when the audio thread will run again, and we padded out
|
||||
// the play time to 55 milliseconds, chances are good that the next
|
||||
// DosBeep call will queue more sound to play seamlessly.
|
||||
// If less than 50 milliseconds, don't sleep at all; if they call DosBeep
|
||||
// again, it'll block until it can queue the command anyhow.
|
||||
if (duration > 55) {
|
||||
usleep((duration-55) * 1000);
|
||||
}
|
||||
|
||||
const int rc = GLoaderState.registerAudioGenerator(DosBeepGenerator, &dos_beep_info, 1);
|
||||
if (!rc) {
|
||||
memset(&dos_beep_info, '\0', sizeof (dos_beep_info)); // oh well.
|
||||
}
|
||||
|
||||
ungrabLock(&GMutexDosBeep);
|
||||
|
||||
return NO_ERROR;
|
||||
} // DosBeep_implementation
|
||||
|
||||
APIRET DosBeep(ULONG freq, ULONG duration)
|
||||
{
|
||||
TRACE_NATIVE("DosBeep(%u, %u)", freq, duration);
|
||||
return DosBeep_implementation(freq, duration);
|
||||
} // DosBeep
|
||||
|
||||
APIRET16 Dos16GetVersion(PUSHORT pver)
|
||||
{
|
||||
TRACE_NATIVE("Dos16GetVersion(%p)", pver);
|
||||
@@ -3486,6 +3613,12 @@ APIRET16 Dos16ChgFilePtr(USHORT handle, LONG distance, USHORT whence, PULONG new
|
||||
return (APIRET16) DosSetFilePtr_implementation(handle, distance, whence, newoffset);
|
||||
} // Dos16ChgFilePtr
|
||||
|
||||
APIRET16 Dos16Beep(USHORT freq, USHORT duration)
|
||||
{
|
||||
TRACE_NATIVE("Dos16Beep(%u, %u)", freq, duration);
|
||||
return DosBeep_implementation(freq, duration);
|
||||
} // Dos16Beep
|
||||
|
||||
|
||||
LX_NATIVE_CONSTRUCTOR(doscalls)
|
||||
{
|
||||
@@ -3496,10 +3629,17 @@ LX_NATIVE_CONSTRUCTOR(doscalls)
|
||||
abort();
|
||||
} // if
|
||||
|
||||
if (pthread_mutex_init(&GMutexDosBeep, NULL) == -1) {
|
||||
pthread_mutex_destroy(&GMutexDosCalls);
|
||||
fprintf(stderr, "pthread_mutex_init failed!\n");
|
||||
abort();
|
||||
} // if
|
||||
|
||||
MaxHFiles = 20; // seems to be OS/2's default.
|
||||
HFiles = (HFileInfo *) malloc(sizeof (HFileInfo) * MaxHFiles);
|
||||
if (!HFiles) {
|
||||
pthread_mutex_destroy(&GMutexDosCalls);
|
||||
pthread_mutex_destroy(&GMutexDosBeep);
|
||||
fprintf(stderr, "Out of memory!\n");
|
||||
abort();
|
||||
} // if
|
||||
@@ -3532,6 +3672,8 @@ LX_NATIVE_CONSTRUCTOR(doscalls)
|
||||
ginfo = (GINFOSEG *) GLoaderState.allocSegment(&ginfosel, 0);
|
||||
linfo = (LINFOSEG *) GLoaderState.allocSegment(&linfosel, 0);
|
||||
if ((!ginfo) || (!linfo)) {
|
||||
pthread_mutex_destroy(&GMutexDosCalls);
|
||||
pthread_mutex_destroy(&GMutexDosBeep);
|
||||
fprintf(stderr, "Failed to allocate info segments!\n");
|
||||
abort();
|
||||
}
|
||||
@@ -3589,6 +3731,7 @@ LX_NATIVE_DESTRUCTOR(doscalls)
|
||||
GLoaderState.freeSelector(ginfosel);
|
||||
GLoaderState.freeSelector(linfosel);
|
||||
pthread_mutex_destroy(&GMutexDosCalls);
|
||||
pthread_mutex_destroy(&GMutexDosBeep);
|
||||
}
|
||||
|
||||
// end of doscalls.c ...
|
||||
|
||||
@@ -544,6 +544,7 @@ OS2EXPORT APIRET16 OS2API16 Dos16Read(USHORT hFile, PVOID pBuffer, USHORT cbRead
|
||||
OS2EXPORT APIRET16 OS2API16 Dos16ExecPgm(PCHAR pObjname, SHORT cbObjname, USHORT execFlag, PSZ pArg, PSZ pEnv, PRESULTCODES16 pRes, PSZ pName) OS2APIINFO(144);
|
||||
OS2EXPORT APIRET16 OS2API16 Dos16CWait(USHORT action, USHORT option, PRESULTCODES16 pres, PUSHORT ppid, USHORT pid) OS2APIINFO(2);
|
||||
OS2EXPORT APIRET16 OS2API16 Dos16ChgFilePtr(USHORT handle, LONG distance, USHORT whence, PULONG newoffset) OS2APIINFO(58);
|
||||
OS2EXPORT APIRET16 OS2API16 Dos16Beep(USHORT freq, USHORT dur) OS2APIINFO(50);
|
||||
|
||||
// !!! FIXME: these should probably get sorted alphabetically and/or grouped
|
||||
// !!! FIXME: into areas of functionality, but for now, I'm just listing them
|
||||
@@ -619,6 +620,7 @@ OS2EXPORT APIRET OS2API DosSetProcessCp(ULONG cp) OS2APIINFO(289);
|
||||
OS2EXPORT APIRET OS2API DosQueryFSAttach(PSZ pszDeviceName, ULONG ulOrdinal, ULONG ulFSAInfoLevel, PFSQBUFFER2 pfsqb, PULONG pcbBuffLength) OS2APIINFO(277);
|
||||
OS2EXPORT APIRET OS2API DosSetFileSize(HFILE hFile, ULONG cbSize) OS2APIINFO(272);
|
||||
OS2EXPORT APIRET OS2API DosSetCurrentDir(PSZ pszName) OS2APIINFO(255);
|
||||
OS2EXPORT APIRET OS2API DosBeep(ULONG freq, ULONG dur) OS2APIINFO(286);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user