/*
* mswin.cxx
*
* General class implementations for 16 bit Windows.
*
* Portable Windows Library
*
* Copyright (c) 1993-1998 Equivalence Pty. Ltd.
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Portable Windows Library.
*
* The Initial Developer of the Original Code is Equivalence Pty. Ltd.
*
* Portions are Copyright (C) 1993 Free Software Foundation, Inc.
* All Rights Reserved.
*
* Contributor(s): ______________________________________.
*
* $Log: mswin.cxx,v $
* Revision 1.18 2001/08/07 03:20:39 robertj
* Fixed close of DLL so flagged as closed, thanks Stefan Ditscheid.
*
* Revision 1.17 1998/09/24 03:30:51 robertj
* Added open software license.
*
* Revision 1.16 1996/02/15 14:55:02 robertj
* Win16 compatibility
*
* Revision 1.15 1996/01/28 02:55:33 robertj
* WIN16 support.
*
* Revision 1.14 1995/12/10 11:58:37 robertj
* Added WIN32 registry support for PConfig objects.
*
* Revision 1.13 1995/08/24 12:40:52 robertj
* Changed PChannel so not a PContainer.
*
* Revision 1.12 1995/07/02 01:24:45 robertj
* Added running of hidden VM for DOS program in PPipeChannel.
*
* Revision 1.11 1995/06/17 00:59:23 robertj
* Moved PPipeChannel::Execute from common dos/windows to individual files.
*
* Revision 1.10 1995/03/12 05:00:06 robertj
* Re-organisation of DOS/WIN16 and WIN32 platforms to maximise common code.
* Used built-in equate for WIN32 API (_WIN32).
*
* Revision 1.9 1995/01/09 12:28:00 robertj
* Added implementation for PConfig::Environment
*
* Revision 1.8 1994/10/23 05:41:29 robertj
* Fixed config file bugs.
*
* Revision 1.7 1994/08/22 00:18:02 robertj
* Fixed bug in serial comms timers.
*
* Revision 1.6 1994/08/04 13:24:27 robertj
* Added DCB so can set paraemters on closed channel.
*
* Revision 1.5 1994/07/27 06:00:10 robertj
* Backup
*
* Revision 1.4 1994/07/21 12:35:18 robertj
* *** empty log message ***
*
* Revision 1.3 1994/07/17 11:01:04 robertj
* Ehancements, implementation, bug fixes etc.
*
* Revision 1.2 1994/07/02 03:18:09 robertj
* Multi-threading implementation.
*
* Revision 1.1 1994/06/25 12:13:01 robertj
* Initial revision
*
// Revision 1.1 1994/04/01 14:39:35 robertj
// Initial revision
//
*/
#include "ptlib.h"
#include <errno.h>
#include <fcntl.h>
#include <stdresid.h>
extern "C" HINSTANCE _hInstance;
///////////////////////////////////////////////////////////////////////////////
// PTime
PString PTime::GetTimeSeparator()
{
PString str;
GetProfileString("intl", "sTime", ":", str.GetPointer(100), 99);
str.MakeMinimumSize();
return str;
}
BOOL PTime::GetTimeAMPM()
{
return GetProfileInt("intl", "iTime", 0) != 0;
}
PString PTime::GetTimeAM()
{
PString str;
GetProfileString("intl", "s1159", "am", str.GetPointer(100), 99);
str.MakeMinimumSize();
return str;
}
PString PTime::GetTimePM()
{
PString str;
GetProfileString("intl", "s2359", "pm", str.GetPointer(100), 99);
str.MakeMinimumSize();
return str;
}
PString PTime::GetDayName(Weekdays dayOfWeek, NameType type)
{
static const char * const weekdays[] = {
"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"
};
static const char * const abbrev_weekdays[] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
PString str;
if (LoadString(_hInstance, dayOfWeek+
(type != FullName ? PSTD_ID_STR_ABBREV_WEEKDAYS : PSTD_ID_STR_WEEKDAYS),
str.GetPointer(100), 99) == 0)
return (type != FullName ? abbrev_weekdays : weekdays)[dayOfWeek];
str.MakeMinimumSize();
return str;
}
PString PTime::GetDateSeparator()
{
PString str;
GetProfileString("intl", "sDate", "-", str.GetPointer(100), 99);
str.MakeMinimumSize();
return str;
}
PString PTime::GetMonthName(Months month, NameType type)
{
static const char * const months[] = { "",
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
};
static const char * const abbrev_months[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
PString str;
if (LoadString(_hInstance, month+
(UINT)(type != FullName ? PSTD_ID_STR_ABBREV_MONTHS : PSTD_ID_STR_MONTHS),
str.GetPointer(100), 99) == 0)
return (type != FullName ? abbrev_months : months)[month];
str.MakeMinimumSize();
return str;
}
PTime::DateOrder PTime::GetDateOrder()
{
return (DateOrder)GetProfileInt("intl", "iDate", 0);
}
BOOL PTime::IsDaylightSavings()
{
return FALSE;
}
int PTime::GetTimeZone(TimeZoneType type)
{
return 0;
}
PString PTime::GetTimeZoneString(TimeZoneType type)
{
return "";
}
///////////////////////////////////////////////////////////////////////////////
// PSerialChannel
void PSerialChannel::Construct()
{
char str[50];
strcpy(str, "com1");
GetProfileString("ports", str, "9600,n,8,1,x", &str[5], sizeof(str)-6);
str[4] = ':';
if (!BuildCommDCB(str, &deviceControlBlock)) {
osError = EINVAL;
lastError = BadParameter;
}
}
PString PSerialChannel::GetName() const
{
if (IsOpen())
return psprintf("COM%i", os_handle+1);
return PString();
}
BOOL PSerialChannel::IsReadBlocked(PObject * obj)
{
PSerialChannel & chan = *(PSerialChannel *)PAssertNULL(obj);
COMSTAT stat;
GetCommError(chan.os_handle, &stat);
return stat.cbInQue <= 0 &&
(chan.readTimeout == PMaxTimeInterval || chan.readTimer.IsRunning());
}
BOOL PSerialChannel::Read(void * buf, PINDEX len)
{
lastReadCount = 0;
if (!IsOpen()) {
PThread::Yield();
osError = EBADF;
lastError = NotOpen;
return FALSE;
}
if (readTimeout != PMaxTimeInterval)
readTimer = readTimeout;
if (IsReadBlocked(this))
PThread::Current()->Block(&PSerialChannel::IsReadBlocked, this);
lastReadCount = ReadComm(os_handle, buf, len);
if (lastReadCount > 0)
return TRUE;
COMSTAT stat;
GetCommError(os_handle, &stat);
osError = EFAULT;
lastReadCount = -lastReadCount;
return lastReadCount > 0;
}
BOOL PSerialChannel::IsWriteBlocked(PObject * obj)
{
PSerialChannel & chan = *(PSerialChannel *)PAssertNULL(obj);
COMSTAT stat;
GetCommError(chan.os_handle, &stat);
return stat.cbOutQue >= OutputQueueSize &&
(chan.writeTimeout == PMaxTimeInterval || chan.writeTimer.IsRunning());
}
BOOL PSerialChannel::Write(const void * buf, PINDEX len)
{
lastWriteCount = 0;
if (!IsOpen()) {
osError = EBADF;
lastError = NotOpen;
return FALSE;
}
if (writeTimeout != PMaxTimeInterval)
writeTimer = writeTimeout;
if (IsWriteBlocked(this))
PThread::Current()->Block(&PSerialChannel::IsWriteBlocked, this);
lastWriteCount = WriteComm(os_handle, buf, len);
if (lastWriteCount <= 0) {
COMSTAT stat;
GetCommError(os_handle, &stat);
osError = EFAULT;
lastWriteCount = -lastWriteCount;
}
return lastWriteCount >= len;
}
BOOL PSerialChannel::Close()
{
if (!IsOpen()) {
osError = EBADF;
lastError = NotOpen;
return FALSE;
}
BOOL retVal = CloseComm(os_handle) == 0;
os_handle = -1;
return retVal;
}
BOOL PSerialChannel::SetCommsParam(DWORD speed, BYTE data, Parity parity,
BYTE stop, FlowControl inputFlow, FlowControl outputFlow)
{
if (IsOpen())
PAssert(GetCommState(os_handle, &deviceControlBlock) == 0,
POperatingSystemError);
switch (speed) {
case 0 :
break;
case 14400 :
deviceControlBlock.BaudRate = CBR_14400;
break;
case 19200 :
deviceControlBlock.BaudRate = CBR_19200;
break;
case 38400 :
deviceControlBlock.BaudRate = CBR_38400;
break;
case 56000 :
deviceControlBlock.BaudRate = CBR_56000;
break;
case 128000 :
deviceControlBlock.BaudRate = CBR_128000;
break;
case 256000 :
deviceControlBlock.BaudRate = CBR_256000;
break;
default :
if (speed > 9600) {
osError = EINVAL;
return FALSE;
}
deviceControlBlock.BaudRate = (UINT)speed;
}
if (data > 0)
deviceControlBlock.ByteSize = data;
switch (parity) {
case NoParity :
deviceControlBlock.Parity = NOPARITY;
break;
case OddParity :
deviceControlBlock.Parity = ODDPARITY;
break;
case EvenParity :
deviceControlBlock.Parity = EVENPARITY;
break;
case MarkParity :
deviceControlBlock.Parity = MARKPARITY;
break;
case SpaceParity :
deviceControlBlock.Parity = SPACEPARITY;
break;
}
switch (stop) {
case 1 :
deviceControlBlock.StopBits = ONESTOPBIT;
break;
case 2 :
deviceControlBlock.StopBits = TWOSTOPBITS;
break;
}
switch (inputFlow) {
case NoFlowControl :
deviceControlBlock.fRtsflow = FALSE;
deviceControlBlock.fInX = FALSE;
break;
case XonXoff :
deviceControlBlock.fRtsflow = FALSE;
deviceControlBlock.fInX = TRUE;
break;
case RtsCts :
deviceControlBlock.fRtsflow = TRUE;
deviceControlBlock.fInX = FALSE;
break;
}
switch (outputFlow) {
case NoFlowControl :
deviceControlBlock.fOutxCtsFlow = FALSE;
deviceControlBlock.fOutxDsrFlow = FALSE;
deviceControlBlock.fOutX = FALSE;
break;
case XonXoff :
deviceControlBlock.fOutxCtsFlow = FALSE;
deviceControlBlock.fOutxDsrFlow = FALSE;
deviceControlBlock.fOutX = TRUE;
break;
case RtsCts :
deviceControlBlock.fOutxCtsFlow = TRUE;
deviceControlBlock.fOutxDsrFlow = FALSE;
deviceControlBlock.fOutX = FALSE;
break;
}
if (!IsOpen()) {
osError = EBADF;
lastError = NotOpen;
lastError = BadParameter;
return FALSE;
}
if (SetCommState(&deviceControlBlock) < 0) {
osError = EINVAL;
return FALSE;
}
PAssert(GetCommState(os_handle, &deviceControlBlock) == 0,
POperatingSystemError);
return TRUE;
}
BOOL PSerialChannel::Open(const PString & port, DWORD speed, BYTE data,
Parity parity, BYTE stop, FlowControl inputFlow, FlowControl outputFlow)
{
Close();
os_handle = OpenComm(port, InputQueueSize, OutputQueueSize);
if (os_handle < 0) {
switch (os_handle) {
case IE_BADID :
case IE_HARDWARE :
osError = ENOENT;
lastError = NotFound;
break;
case IE_OPEN :
osError = EBUSY;
lastError = DeviceInUse;
break;
case IE_MEMORY :
osError = ENOMEM;
lastError = NoMemory;
break;
case IE_BAUDRATE :
case IE_BYTESIZE :
osError = EINVAL;
lastError = BadParameter;
break;
default :
osError = EFAULT;
lastError = Miscellaneous;
}
os_handle = -1;
return FALSE;
}
deviceControlBlock.Id = (BYTE)os_handle;
SetCommState(&deviceControlBlock);
if (!SetCommsParam(speed, data, parity, stop, inputFlow, outputFlow)) {
CloseComm(os_handle);
return FALSE;
}
SetCommEventMask(os_handle, EV_CTSS|EV_DSR|EV_RING|EV_RLSDS);
return TRUE;
}
BOOL PSerialChannel::SetSpeed(DWORD speed)
{
return SetCommsParam(speed,
0, DefaultParity, 0, DefaultFlowControl, DefaultFlowControl);
}
DWORD PSerialChannel::GetSpeed() const
{
switch (deviceControlBlock.BaudRate) {
case CBR_110 :
return 110;
case CBR_300 :
return 300;
case CBR_600 :
return 600;
case CBR_1200 :
return 1200;
case CBR_2400 :
return 2400;
case CBR_4800 :
return 4800;
case CBR_9600 :
return 9600;
case CBR_14400 :
return 14400;
case CBR_19200 :
return 19200;
case CBR_38400 :
return 38400;
case CBR_56000 :
return 56000;
case CBR_128000 :
return 128000;
case CBR_256000 :
return 256000;
}
return deviceControlBlock.BaudRate;
}
BOOL PSerialChannel::SetDataBits(BYTE data)
{
return SetCommsParam(0,
data, DefaultParity, 0, DefaultFlowControl, DefaultFlowControl);
}
BYTE PSerialChannel::GetDataBits() const
{
return deviceControlBlock.ByteSize;
}
BOOL PSerialChannel::SetParity(Parity parity)
{
return SetCommsParam(0,0, parity, 0, DefaultFlowControl, DefaultFlowControl);
}
PSerialChannel::Parity PSerialChannel::GetParity() const
{
switch (deviceControlBlock.Parity) {
case ODDPARITY :
return OddParity;
case EVENPARITY :
return EvenParity;
case MARKPARITY :
return MarkParity;
case SPACEPARITY :
return SpaceParity;
}
return NoParity;
}
BOOL PSerialChannel::SetStopBits(BYTE stop)
{
return SetCommsParam(0,
0, DefaultParity, stop, DefaultFlowControl, DefaultFlowControl);
}
BYTE PSerialChannel::GetStopBits() const
{
return (BYTE)(deviceControlBlock.StopBits == ONESTOPBIT ? 1 : 2);
}
BOOL PSerialChannel::SetInputFlowControl(FlowControl flowControl)
{
return SetCommsParam(0,0, DefaultParity, 0, flowControl, DefaultFlowControl);
}
PSerialChannel::FlowControl PSerialChannel::GetInputFlowControl() const
{
if (deviceControlBlock.fRtsflow)
return RtsCts;
if (deviceControlBlock.fInX != 0)
return XonXoff;
return NoFlowControl;
}
BOOL PSerialChannel::SetOutputFlowControl(FlowControl flowControl)
{
return SetCommsParam(0,0, DefaultParity, 0, DefaultFlowControl, flowControl);
}
PSerialChannel::FlowControl PSerialChannel::GetOutputFlowControl() const
{
if (deviceControlBlock.fOutxCtsFlow != 0)
return RtsCts;
if (deviceControlBlock.fOutX != 0)
return XonXoff;
return NoFlowControl;
}
void PSerialChannel::SetDTR(BOOL state)
{
if (!IsOpen()) {
osError = EBADF;
lastError = NotOpen;
return;
}
PAssert(EscapeCommFunction(os_handle, state ? SETDTR : CLRDTR) == 0,
POperatingSystemError);
}
void PSerialChannel::SetRTS(BOOL state)
{
if (!IsOpen()) {
osError = EBADF;
lastError = NotOpen;
return;
}
PAssert(EscapeCommFunction(os_handle, state ? SETRTS : CLRRTS) == 0,
POperatingSystemError);
}
void PSerialChannel::SetBreak(BOOL state)
{
if (!IsOpen()) {
osError = EBADF;
lastError = NotOpen;
return;
}
if (state)
PAssert(SetCommBreak(os_handle), POperatingSystemError);
else
PAssert(ClearCommBreak(os_handle), POperatingSystemError);
}
BOOL PSerialChannel::GetCTS()
{
if (!IsOpen()) {
osError = EBADF;
lastError = NotOpen;
return FALSE;
}
return (GetCommEventMask(os_handle, 0)&EV_CTSS) != 0;
}
BOOL PSerialChannel::GetDSR()
{
if (!IsOpen()) {
osError = EBADF;
lastError = NotOpen;
return FALSE;
}
return (GetCommEventMask(os_handle, 0)&EV_DSR) != 0;
}
BOOL PSerialChannel::GetDCD()
{
if (!IsOpen()) {
osError = EBADF;
lastError = NotOpen;
return FALSE;
}
return (GetCommEventMask(os_handle, 0)&EV_RLSDS) != 0;
}
BOOL PSerialChannel::GetRing()
{
if (!IsOpen()) {
osError = EBADF;
lastError = NotOpen;
return FALSE;
}
return (GetCommEventMask(os_handle, 0)&EV_RING) != 0;
}
PStringList PSerialChannel::GetPortNames()
{
static char buf[] = "COM ";
PStringList ports;
for (char p = '1'; p <= '4'; p++) {
buf[3] = p;
ports.Append(new PString(buf));
}
return ports;
}
///////////////////////////////////////////////////////////////////////////////
// PPipeChannel
BOOL PPipeChannel::Execute()
{
if (hasRun)
return FALSE;
flush();
if (os_handle >= 0) {
_close(os_handle);
os_handle = -1;
}
static struct {
DWORD pifFlags;
DWORD displayFlags;
struct {
DWORD offset;
WORD selector;
} exePath, programArguments, workingDirectory;
WORD desiredV86Pages;
WORD minimumV86Pages;
WORD foregroundPriority;
WORD backgroundPriority;
WORD maximumEMS;
WORD minimumEMS;
WORD maximumXMS;
WORD minimumXMS;
DWORD unknown;
char windowTitle[128];
} seb = {
0x40000006, // Runs in background, runs in window, close on exit
0x0000001f, // Emulate text mode, no monitor ports
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
0xffff, // desired memory
0xffff, // minimum memory
100, // foreground priority
50, // background priority
0x0400, // maximum EMS
0, // minimum EMS
0x4000, // maximum XMS
0, // minimum XMS
0, // unknown
"PWLib Pipe Channel Process"
};
char * commandDotCom = getenv("COMSPEC");
if (commandDotCom == NULL)
commandDotCom = "C:\\COMMAND.COM";
seb.exePath.selector = SELECTOROF(commandDotCom);
seb.exePath.offset = OFFSETOF (commandDotCom);
PString commandArguments = " /c " + subProgName;
const char * argumentPointer = commandArguments;
seb.programArguments.selector = SELECTOROF(argumentPointer);
seb.programArguments.offset = OFFSETOF (argumentPointer);
static char * currentDirectory = ".";
seb.workingDirectory.selector = SELECTOROF(currentDirectory);
seb.workingDirectory.offset = OFFSETOF (currentDirectory);
void (FAR * shellEntry)();
_asm mov ax,1684h; //Get Shell VXDs protected mode entry point
_asm mov bx,0017h;
_asm int 2fh;
_asm mov word ptr [shellEntry], di;
_asm mov word ptr [shellEntry+2], es;
if (shellEntry == NULL)
return FALSE;
_asm lea di, word ptr seb;
_asm mov dx, 3;
_asm push es;
_asm push ss;
_asm pop es;
shellEntry();
_asm pop es;
DWORD hVirtualMachine;
#if defined(_MSC_VER)
_asm _emit 66h;
#else
_asm db 66h;
#endif
_asm mov word ptr hVirtualMachine, ax; // Really EAX
if (hVirtualMachine == 0)
return FALSE;
if (fromChild.IsEmpty())
return TRUE;
// Wait for child to complete
os_handle = _open(fromChild, _O_RDONLY);
return ConvertOSError(os_handle);
}
///////////////////////////////////////////////////////////////////////////////
// Configuration files
void PConfig::Construct(Source src)
{
switch (src) {
case System :
location = "WIN.INI";
break;
case Application :
PFilePath appFile = PProcess::Current()->GetFile();
location = appFile.GetDirectory() + appFile.GetTitle() + ".INI";
break;
}
source = src;
}
void PConfig::Construct(const PFilePath & filename)
{
location = filename;
source = NumSources;
}
PStringList PConfig::GetSections()
{
PStringList sections;
if (source != Environment) {
PString buf;
char * ptr = buf.GetPointer(10000);
GetPrivateProfileString(NULL, NULL, "", ptr, 9999, location);
while (*ptr != '\0') {
sections.AppendString(ptr);
ptr += strlen(ptr)+1;
}
}
return sections;
}
PStringList PConfig::GetKeys(const PString & section) const
{
PStringList keys;
if (source == Environment) {
char ** ptr = _environ;
while (*ptr != NULL) {
PString buf = *ptr++;
keys.AppendString(buf.Left(buf.Find('=')));
}
}
else {
PString buf;
char * ptr = buf.GetPointer(10000);
GetPrivateProfileString(section, NULL, "", ptr, 9999, location);
while (*ptr != '\0') {
keys.AppendString(ptr);
ptr += strlen(ptr)+1;
}
}
return keys;
}
void PConfig::DeleteSection(const PString & section)
{
if (source == Environment)
return;
PAssert(!section.IsEmpty(), PInvalidParameter);
PAssertOS(WritePrivateProfileString(section, NULL, NULL, location));
}
void PConfig::DeleteKey(const PString & section, const PString & key)
{
PAssert(!key.IsEmpty(), PInvalidParameter);
if (source == Environment) {
PString str = key;
PAssert(str.Find('=') == P_MAX_INDEX, PInvalidParameter);
_putenv(str + "=");
}
else {
PAssert(!section.IsEmpty(), PInvalidParameter);
PAssertOS(WritePrivateProfileString(section, key, NULL, location));
}
}
PString PConfig::GetString(const PString & section,
const PString & key, const PString & dflt)
{
PString str;
PAssert(!key.IsEmpty(), PInvalidParameter);
if (source == Environment) {
PAssert(key.Find('=') == P_MAX_INDEX, PInvalidParameter);
char * env = getenv(key);
if (env != NULL)
str = env;
else
str = dflt;
}
else {
PAssert(!section.IsEmpty(), PInvalidParameter);
GetPrivateProfileString(section, key, dflt,
str.GetPointer(1000), 999, location);
str.MakeMinimumSize();
}
return str;
}
void PConfig::SetString(const PString & section,
const PString & key, const PString & value)
{
PAssert(!key.IsEmpty(), PInvalidParameter);
if (source == Environment) {
PString str = key;
PAssert(str.Find('=') == P_MAX_INDEX, PInvalidParameter);
_putenv(str + "=" + value);
}
else {
PAssert(!section.IsEmpty(), PInvalidParameter);
PAssertOS(WritePrivateProfileString(section, key, value, location));
}
}
///////////////////////////////////////////////////////////////////////////////
// Threads
static char NEAR * NEAR * const StackBase = (char NEAR * NEAR *)0xa;
static char NEAR * NEAR * const StackUsed = (char NEAR * NEAR *)0xc;
static char NEAR * NEAR * const StackTop = (char NEAR * NEAR *)0xe;
void PThread::SwitchContext(PThread * from)
{
if (from == this) // Switching to itself, ie is only thread
return;
if (setjmp(from->context) != 0) // Are being reactivated from previous yield
return;
// Save some magic global variables in MS-Windows DGROUP segment
from->stackBase = *StackBase;
from->stackTop = *StackTop;
from->stackUsed = *StackTop - *StackUsed;
if (status == Starting) {
if (setjmp(context) != 0)
BeginThread();
context[3] = (int)stackTop-16; // Change the stack pointer in jmp_buf
}
// Restore those MS-Windows magic global for the next context
*StackBase = stackBase;
*StackTop = stackTop;
*StackUsed = stackTop - stackUsed;
longjmp(context, TRUE);
PAssertAlways("longjmp failed"); // Should never get here
}
///////////////////////////////////////////////////////////////////////////////
// PDynaLink
PDynaLink::PDynaLink()
{
_hDLL = NULL;
}
PDynaLink::PDynaLink(const PString & name)
{
Open(name);
}
PDynaLink::~PDynaLink()
{
Close();
}
BOOL PDynaLink::Open(const PString & name)
{
if ((_hDLL = LoadLibrary(name)) < HINSTANCE_ERROR)
_hDLL = NULL;
return _hDLL != NULL;
}
void PDynaLink::Close()
{
if (_hDLL != NULL) {
FreeLibrary(_hDLL);
_hDLL = NULL;
}
}
BOOL PDynaLink::IsLoaded() const
{
return _hDLL != NULL;
}
BOOL PDynaLink::GetFunction(PINDEX index, Function & func)
{
if (_hDLL == NULL)
return FALSE;
FARPROC p = GetProcAddress(_hDLL, (LPSTR)(DWORD)LOWORD(index));
if (p == NULL)
return FALSE;
func = (Function)p;
return TRUE;
}
BOOL PDynaLink::GetFunction(const PString & name, Function & func)
{
if (_hDLL == NULL)
return FALSE;
FARPROC p = GetProcAddress(_hDLL, name);
if (p == NULL)
return FALSE;
func = (Function)p;
return TRUE;
}
// End Of File ///////////////////////////////////////////////////////////////
syntax highlighted by Code2HTML, v. 0.9.1