diff --git a/AdDispLog.inc b/AdDispLog.inc new file mode 100644 index 0000000..ab0d3cb --- /dev/null +++ b/AdDispLog.inc @@ -0,0 +1,371 @@ +(***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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 TurboPower Async Professional + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1991-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* ADDISPLOG.INC 4.06 *} +{*********************************************************} +{* String resources for the dispatcher log *} +{*********************************************************} + + + { Logging - It is unlikely that these should change, these strings are } + { used in the dispatcher log. Translating them into another language } + { could make it difficult for TurboPower Tech Support to decipher it. } + { Dispatch type } + sdtNone {15001} = 'No event'; + sdtDispatch {15002} = 'Dispatch'; + sdtTrigger {15003} = 'Trigger'; + sdtError {15004} = 'Error'; + sdtThread {15005} = 'Thread'; + sdtTriggerAlloc {15006} = 'TrigAllc'; + sdtTriggerDispose {15007} = 'TrigDisp'; + sdtTriggerHandlerAlloc {15008} = 'TrgHdAlc'; + sdtTriggerHandlerDispose {15009} = 'TrgHdDsp'; + sdtTriggerDataChange {15010} = 'TrDatChg'; + sdtTelnet {15011} = 'Telnet'; + sdtFax {15012} = 'Fax'; + sdtXModem {15013} = 'XModem'; + sdtYModem {15014} = 'YModem'; + sdtZModem {15015} = 'ZModem'; + sdtKermit {15016} = 'Kermit'; + sdtAscii {15017} = 'Ascii'; + sdtBPlus {15018} = 'BPlus'; + sdtPacket {15019} = 'Packet'; + sdtUser {15020} = 'User'; + sdtScript {15021} = 'Script'; + { Dispatch subtype } + sdstNone {15100} = ''; + sdstReadCom {15101} = 'ReadCom'; + sdstWriteCom {15102} = 'WriteCom'; + sdstLineStatus {15103} = 'Line status'; + sdstModemStatus {15104} = 'Modem status'; + sdstAvail {15105} = 'Avail'; + sdstTimer {15106} = 'Timer'; + sdstData {15107} = 'Data'; + sdstStatus {15108} = 'Status'; + sdstThreadStart {15109} = 'Start'; + sdstThreadExit {15110} = 'Exit'; + sdstThreadSleep {15111} = 'Sleep'; + sdstThreadWake {15112} = 'Wake'; + sdstDataTrigger {15113} = 'Data'; + sdstTimerTrigger {15114} = 'Timer'; + sdstStatusTrigger {15115} = 'Status'; + sdstAvailTrigger {15116} = 'Avail'; + sdstWndHandler {15117} = 'Window'; + sdstProcHandler {15118} = 'Procedure'; + sdstEventHandler {15119} = 'Method'; + sdstSWill {15120} = 'Sent WILL'; + sdstSWont {15121} = 'Sent WON''T'; + sdstSDo {15122} = 'Sent DO'; + sdstSDont {15123} = 'Sent DON''T'; + sdstRWill {15124} = 'Recv WILL'; + sdstRWont {15125} = 'Recv WON''T'; + sdstRDo {15126} = 'Recv DO'; + sdstRDont {15127} = 'Recv DON''T'; + sdstCommand {15128} = 'Command'; + sdstSTerm {15129} = 'Sent Term'; + sdsttfNone {15130} = 'tfNone'; + sdsttfGetEntry {15131} = 'tfGetEntry'; + sdsttfInit {15132} = 'tfInit'; + sdsttf1Init1 {15133} = 'tf1Init1'; + sdsttf2Init1 {15134} = 'tf2Init1'; + sdsttf2Init1A {15135} = 'tf2Init1A'; + sdsttf2Init1B {15136} = 'tf2Init1B'; + sdsttf2Init2 {15137} = 'tf2Init2'; + sdsttf2Init3 {15138} = 'tf2Init3'; + sdsttfDial {15139} = 'tfDial'; + sdsttfRetryWait {15140} = 'tfRetryWait'; + sdsttf1Connect {15141} = 'tf1Connect'; + sdsttf1SendTSI {15142} = 'tf1SendTSI'; + sdsttf1TSIResponse {15143} = 'tf1TSIRespns'; + sdsttf1DCSResponse {15144} = 'tf1DCSRspns'; + sdsttf1TrainStart {15145} = 'tf1TrainStrt'; + sdsttf1TrainFinish {15146} = 'tf1TrainFnsh'; + sdsttf1WaitCFR {15147} = 'tf1WaitCFR'; + sdsttf1WaitPageConnect {15148} = 'tf1WaitPgCn'; + sdsttf2Connect {15149} = 'tf2Connect'; + sdsttf2GetParams {15150} = 'tf2GetParams'; + sdsttfWaitXon {15151} = 'tfWaitXon'; + sdsttfWaitFreeHeader {15152} = 'tfWaitFrHead'; + sdsttfSendPageHeader {15153} = 'tfSndPgeHdr'; + sdsttfOpenCover {15154} = 'tfOpenCover'; + sdsttfSendCover {15155} = 'tfSendCover'; + sdsttfPrepPage {15156} = 'tfPrepPage'; + sdsttfSendPage {15157} = 'tfSendPage'; + sdsttfDrainPage {15158} = 'tfDrainPage'; + sdsttf1PageEnd {15159} = 'tf1PageEnd'; + sdsttf1PrepareEOP {15160} = 'tf1PrepEOP'; + sdsttf1SendEOP {15161} = 'tf1SendEOP'; + sdsttf1WaitMPS {15162} = 'tf1WaitMPS'; + sdsttf1WaitEOP {15163} = 'tf1WaitEOP'; + sdsttf1WaitMCF {15164} = 'tf1WaitMCF'; + sdsttf1SendDCN {15165} = 'tf1SendDCN'; + sdsttf1Hangup {15166} = 'tf1Hangup'; + sdsttf1WaitHangup {15167} = 'tf1WaitHngp'; + sdsttf2SendEOP {15168} = 'tf2SendEOP'; + sdsttf2WaitFPTS {15169} = 'tf2WaitFPTS'; + sdsttf2WaitFET {15170} = 'tf2WaitFET'; + sdsttf2WaitPageOK {15171} = 'tf2WaitPgOK'; + sdsttf2SendNewParams {15172} = 'tf2SndNwPrm'; + sdsttf2NextPage {15173} = 'tf2NextPage'; + sdsttf20CheckPage {15174} = 'tf20ChckPg'; + sdsttfClose {15175} = 'tfClose'; + sdsttfCompleteOK {15176} = 'tfCompleteOK'; + sdsttfAbort {15177} = 'tfAbort'; + sdsttfDone {15178} = 'tfDone'; + sdstrfNone {15179} = 'rfNone'; + sdstrfInit {15180} = 'rfInit'; + sdstrf1Init1 {15181} = 'rf1Init1'; + sdstrf2Init1 {15182} = 'rf2Init1'; + sdstrf2Init1A {15183} = 'rf2Init1A'; + sdstrf2Init1B {15184} = 'rf2Init1B'; + sdstrf2Init2 {15185} = 'rf2Init2'; + sdstrf2Init3 {15186} = 'rf2Init3'; + sdstrfWaiting {15187} = 'rfWaiting'; + sdstrfAnswer {15188} = 'rfAnswer'; + sdstrf1SendCSI {15189} = 'rf1SendCSI'; + sdstrf1SendDIS {15190} = 'rf1SendDIS'; + sdstrf1CollectFrames {15191} = 'rf1CollFrms'; + sdstrf1CollectRetry1 {15192} = 'rf1CollRtry1'; + sdstrf1CollectRetry2 {15193} = 'rf1CollRtry2'; + sdstrf1StartTrain {15194} = 'rf1StrtTrn'; + sdstrf1CollectTrain {15195} = 'rf1CollTrn'; + sdstrf1Timeout {15196} = 'rf1Timeout'; + sdstrf1Retrain {15197} = 'rf1Retrain'; + sdstrf1FinishTrain {15198} = 'rf1FinTrn'; + sdstrf1SendCFR {15199} = 'rf1SendCFR'; + sdstrf1WaitPageConnect {15200} = 'rf1WtPgCnnct'; + sdstrf2ValidConnect {15201} = 'rf2ValCnnct'; + sdstrf2GetSenderID {15202} = 'rf2GtSndID'; + sdstrf2GetConnect {15203} = 'rf2GtCnnct'; + sdstrfStartPage {15204} = 'rfStartPage'; + sdstrfGetPageData {15205} = 'rfGtPgDta'; + sdstrf1FinishPage {15206} = 'rf1FinPage'; + sdstrf1WaitEOP {15207} = 'rf1WaitEOP'; + sdstrf1WritePage {15208} = 'rf1WritePage'; + sdstrf1SendMCF {15209} = 'rf1SendMCF'; + sdstrf1WaitDCN {15210} = 'rf1WaitDCN'; + sdstrf1WaitHangup {15211} = 'rf1WtHngp'; + sdstrf2GetPageResult {15212} = 'rf2GtPgRslt'; + sdstrf2GetFHNG {15213} = 'rf2GetFHNG'; + sdstrfComplete {15214} = 'rfComplete'; + sdstrfAbort {15215} = 'rfAbort'; + sdstrfDone {15216} = 'rfDone'; + sdsttxInitial {15217} = 'txInitial'; + sdsttxHandshake {15218} = 'txHandshake'; + sdsttxGetBlock {15219} = 'txGetBlock'; + sdsttxWaitFreeSpace {15220} = 'txWtFreeSpc'; + sdsttxSendBlock {15221} = 'txSendBlock'; + sdsttxDraining {15222} = 'txDraining'; + sdsttxReplyPending {15223} = 'txRplyPnding'; + sdsttxEndDrain {15224} = 'txEndDrain'; + sdsttxFirstEndOfTransmit {15225} = 'txFirstEOT'; + sdsttxRestEndOfTransmit {15226} = 'txRestEOT'; + sdsttxEotReply {15227} = 'txEotReply'; + sdsttxFinished {15228} = 'txFinished'; + sdsttxDone {15229} = 'txDone'; + sdstrxInitial {15230} = 'rxInitial'; + sdstrxWaitForHSReply {15231} = 'rxWtFrHSRply'; + sdstrxWaitForBlockStart {15232} = 'rxWtFrBlStrt'; + sdstrxCollectBlock {15233} = 'rxCollBlock'; + sdstrxProcessBlock {15234} = 'rxProcBlck'; + sdstrxFinishedSkip {15235} = 'rxFinSkip'; + sdstrxFinished {15236} = 'rxFinished'; + sdstrxDone {15237} = 'rxDone'; + sdsttyInitial {15238} = 'tyInitial'; + sdsttyHandshake {15239} = 'tyHandshake'; + sdsttyGetFileName {15240} = 'tyGetFlName'; + sdsttySendFileName {15241} = 'tySndFlName'; + sdsttyDraining {15242} = 'tyDraining'; + sdsttyReplyPending {15243} = 'tyRplyPndng'; + sdsttyPrepXmodem {15244} = 'tyPrpXmdm'; + sdsttySendXmodem {15245} = 'tySndXmdm'; + sdsttyFinished {15246} = 'tyFinishd'; + sdsttyFinishDrain {15247} = 'tyFinDrain'; + sdsttyDone {15248} = 'tyDone'; + sdstryInitial {15249} = 'ryInitial'; + sdstryDelay {15250} = 'ryDelay'; + sdstryWaitForHSReply {15251} = 'ryWtFrHSRply'; + sdstryWaitForBlockStart {15252} = 'ryWtFBlkStrt'; + sdstryCollectBlock {15253} = 'ryCollBlck'; + sdstryProcessBlock {15254} = 'ryProcBlck'; + sdstryOpenFile {15255} = 'ryOpenFile'; + sdstryPrepXmodem {15256} = 'ryPrepXmdm'; + sdstryReceiveXmodem {15257} = 'ryRcvXmodem'; + sdstryFinished {15258} = 'ryFinished'; + sdstryDone {15259} = 'ryDone'; + sdsttzInitial {15260} = 'tzInitial'; + sdsttzHandshake {15261} = 'tzHandshake'; + sdsttzGetFile {15262} = 'tzGetFile'; + sdsttzSendFile {15263} = 'tzSendFile'; + sdsttzCheckFile {15264} = 'tzCheckFile'; + sdsttzStartData {15265} = 'tzStartData'; + sdsttzEscapeData {15266} = 'tzEscapeData'; + sdsttzSendData {15267} = 'tzSendData'; + sdsttzWaitAck {15268} = 'tzWaitAck'; + sdsttzSendEof {15269} = 'tzSendEof'; + sdsttzDrainEof {15270} = 'tzDrainEof'; + sdsttzCheckEof {15271} = 'tzCheckEof'; + sdsttzSendFinish {15272} = 'tzSendFinish'; + sdsttzCheckFinish {15273} = 'tzChkFinish'; + sdsttzError {15274} = 'tzError'; + sdsttzCleanup {15275} = 'tzCleanup'; + sdsttzDone {15276} = 'tzDone'; + sdstrzRqstFile {15277} = 'rzRqstFile'; + sdstrzDelay {15278} = 'rzDelay'; + sdstrzWaitFile {15279} = 'rzWaitFile'; + sdstrzCollectFile {15280} = 'rzCollFile'; + sdstrzSendInit {15281} = 'rzSendInit'; + sdstrzSendBlockPrep {15282} = 'rzSndBlkPrp'; + sdstrzSendBlock {15283} = 'rzSendBlock'; + sdstrzSync {15284} = 'rzSync'; + sdstrzStartFile {15285} = 'rzStartFile'; + sdstrzStartData {15286} = 'rzStartData'; + sdstrzCollectData {15287} = 'rzCollData'; + sdstrzGotData {15288} = 'rzGotData'; + sdstrzWaitEof {15289} = 'rzWaitEof'; + sdstrzEndOfFile {15290} = 'rzEndOfFile'; + sdstrzSendFinish {15291} = 'rzSendFinish'; + sdstrzCollectFinish {15292} = 'rzCollFin'; + sdstrzError {15293} = 'rzError'; + sdstrzWaitCancel {15294} = 'rzWaitCancel'; + sdstrzCleanup {15295} = 'rzCleanup'; + sdstrzDone {15296} = 'rzDone'; + sdsttkInit {15297} = 'tkInit'; + sdsttkInitReply {15298} = 'tkInitReply'; + sdsttkCollectInit {15299} = 'tkCollInit'; + sdsttkOpenFile {15300} = 'tkOpenFile'; + sdsttkSendFile {15301} = 'tkSendFile'; + sdsttkFileReply {15302} = 'tkFileReply'; + sdsttkCollectFile {15303} = 'tkCollFile'; + sdsttkCheckTable {15304} = 'tkCheckTable'; + sdsttkSendData {15305} = 'tkSendData'; + sdsttkBlockReply {15306} = 'tkBlockReply'; + sdsttkCollectBlock {15307} = 'tkCollBlock'; + sdsttkSendEof {15308} = 'tkSendEof'; + sdsttkEofReply {15309} = 'tkEofReply'; + sdsttkCollectEof {15310} = 'tkCollectEof'; + sdsttkSendBreak {15311} = 'tkSendBreak'; + sdsttkBreakReply {15312} = 'tkBreakReply'; + sdsttkCollectBreak {15313} = 'tkCollBreak'; + sdsttkComplete {15314} = 'tkComplete'; + sdsttkWaitCancel {15315} = 'tkWaitCancel'; + sdsttkError {15316} = 'tkError'; + sdsttkDone {15317} = 'tkDone'; + sdstrkInit {15318} = 'rkInit'; + sdstrkGetInit {15319} = 'rkGetInit'; + sdstrkCollectInit {15320} = 'rkCollInit'; + sdstrkGetFile {15321} = 'rkGetFile'; + sdstrkCollectFile {15322} = 'rkCollFile'; + sdstrkGetData {15323} = 'rkGetData'; + sdstrkCollectData {15324} = 'rkCollData'; + sdstrkComplete {15325} = 'rkComplete'; + sdstrkWaitCancel {15326} = 'rkWaitCancel'; + sdstrkError {15327} = 'rkError'; + sdstrkDone {15328} = 'rkDone'; + sdsttaInitial {15329} = 'taInitial'; + sdsttaGetBlock {15330} = 'taGetBlock'; + sdsttaWaitFreeSpace {15331} = 'taWaitFrSpc'; + sdsttaSendBlock {15332} = 'taSendBlock'; + sdsttaSendDelay {15333} = 'taSendDelay'; + sdsttaFinishDrain {15334} = 'taFinDrain'; + sdsttaFinished {15335} = 'taFinished'; + sdsttaDone {15336} = 'taDone'; + sdstraInitial {15337} = 'raInitial'; + sdstraCollectBlock {15338} = 'raCollBlock'; + sdstraProcessBlock {15339} = 'raProcBlock'; + sdstraFinished {15340} = 'raFinished'; + sdstraDone {15341} = 'raDone'; + sdstEnable {15342} = 'Enable'; + sdstDisable {15343} = 'Disable'; + sdstStringPacket {15344} = 'StringPacket'; + sdstSizePacket {15345} = 'SizePacket'; + sdstPacketTimeout {15346} = 'PcktTimeout'; + sdstStartStr {15347} = 'StartStr'; + sdstEndStr {15348} = 'EndStr'; + sdstIdle {15349} = 'Idle'; + sdstWaiting {15350} = 'Waiting'; + sdstCollecting {15351} = 'Collecting'; + sdstThreadStatusQueued {15352} = 'Status Queued'; // SWB + sdstThreadDataQueued {15353} = 'Data Queued'; // SWB + sdstThreadDataWritten {15354} = 'Data Written'; // SWB + sdsttzSInit {15355} = 'ZSInit'; // SWB + sdsttzCheckSInit {15356} = 'CheckSInit'; // SWB + {log headers} + sdispHeader {15501} = 'Time Type SubType Data OtherData'; + sdispHeaderLine {15502} = '-------- -------- ------------ -------- ---------'; + {modem tags} + sdispmdmtagDCTS {15601} = 'DCTS '; + sdispmdmtagDDSR {15602} = 'DDSR '; + sdispmdmtagTERI {15603} = 'TERI '; + sdispmdmtagDDCD {15604} = 'DDCD '; + sdispmdmtagCTS {15605} = 'CTS '; + sdispmdmtagDSR {15606} = 'DSR '; + sdispmdmtagRI {15607} = 'RI '; + sdispmdmtagDCD {15608} = 'DCD '; + {Telnet tags} + sdispTelnetBinary {15700} = 'Binary'; + sdispTelnetEcho {15701} = 'Echo'; + sdispTelnetReconnection {15702} = 'Reconnection'; + sdispTelnetSupressGoAhead {15703} = 'Supress Go Ahead'; + sdispTelnetApproxMsgSize {15704} = 'Approx Msg Size'; + sdispTelnetStatus {15705} = 'Status'; + sdispTelnetTimingMark {15706} = 'Timing Mark'; + sdispTelnetRemoteTransEcho {15707} = 'Remote Trans & Echo'; + sdispTelnetOutputLineWidth {15708} = 'Output Line Width'; + sdispTelnetOutputPageSize {15709} = 'Output Page Size'; + sdispTelnetOutputCRDisp {15710} = 'Output C/R Disp'; + sdispTelnetOutputHorzTabs {15711} = 'Output Horz Tabs'; + sdispTelnetOutputHorzTabDisp {15712} = 'Output Horz Tab Disp'; + sdispTelnetOutputFFDisp {15713} = 'Output FF Disp'; + sdispTelnetOutputVertTabs {15714} = 'Output Vert Tabs'; + sdispTelnetOutputVertTabDisp {15715} = 'Output Vert Tab Disp'; + sdispTelnetOutputLinefeedDisp {15716} = 'Output Linefeed Disp'; + sdispTelnetExtendedASCII {15717} = 'Extended ASCII'; + sdispTelnetLogout {15718} = 'Logout'; + sdispTelnetByteMacro {15719} = 'Byte Macro'; + sdispTelnetDataEntryTerminal {15720} = 'Data Entry Terminal'; + sdispTelnetSUPDUP {15721} = 'SUPDUP'; + sdispTelnetSUPDUPOutput {15722} = 'SUPDUP Output'; + sdispTelnetSendLocation {15723} = 'Send Location'; + sdispTelnetTerminalType {15724} = 'Terminal Type'; + sdispTelnetEndofRecord {15725} = 'End of Record'; + sdispTelnetTACACSUserID {15726} = 'TACACS User ID'; + sdispTelnetOutputMarking {15727} = 'Output Marking'; + sdispTelnetTerminalLocNum {15728} = 'Terminal Loc Num'; + sdispTelnetTelnet3270Regime {15729} = 'Telnet3270 Regime'; + sdispTelnetX3PAD {15730} = 'X.3 PAD'; + sdispTelnetNegWindowSize {15731} = 'Neg Window Size'; + sdispTelnetTerminalSpeed {15732} = 'Terminal Speed'; + sdispTelnetFlowControl {15733} = 'Flow Control'; + sdispTelnetLineMode {15734} = 'LineMode'; + sdispTelnetXDisplayLocation {15735} = 'X Display Location'; + sdispTelnetEnvironment {15736} = 'Environment'; + sdispTelnetAuthentication {15737} = 'Authentication'; + sdispTelnetTelnetcode38 {15738} = 'Telnet code 38'; + sdispTelnetNewEnvironment {15739} = 'New Environment'; + sdispTelnetTelnetcode40 {15740} = 'Telnet code 40'; + sdispTelnetTelnetcode41 {15741} = 'Telnet code 41'; + sdispTelnetCharacterSet {15742} = 'Character Set'; diff --git a/AdExcept.fra b/AdExcept.fra new file mode 100644 index 0000000..74a5ea4 --- /dev/null +++ b/AdExcept.fra @@ -0,0 +1,833 @@ +(***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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 TurboPower Async Professional + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1991-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* ADEXCEPT.FRA 4.04 *} +{* French string resources for errors and status *} +{*********************************************************} + +(* + All string resources have been moved into this resourcestring file in + APRO 4.03. The APRO String Resource Manager is still available, but + not used by default. Disable the {$DEFINE UseResourceStrings} define + in AwDefine.inc to revert back to the string resource manager if desired. + AdExcept.inc contains English strings + AdExcept.fra contains French strings + AdExcept.deu contains German strings + AdExcept.esp contains Spanish strings + AdExcept.sw contains Swedish strings + AdExcept.nor constains Norwegian strings + AdExcept.dk contains Danish strings + + Where a translation was not available, the English version was used. + If you have a translation for the strings, please send them to us + through the mailsupport@turbopower.com email address, or through + the turbopower.public.third-party.internationalization newsgroup. + We will include the translation in the next release of APRO. Thanks. +*) + +resourcestring +{ Numbers in the comments correspond to the ErrorCode passed in many of our } +{ events. Strings without the numbers do not have corresponding ErrorCodes } + {No error} + secOK { 0} = 'OK'; + + {egDOS} + secFileNotFound { 2} = 'Fichier introuvable'; + secPathNotFound { 3} = 'Chemin introuvable'; + secTooManyFiles { 4} = 'Trop de fichiers ouverts'; + secAccessDenied { 5} = 'Accès au fichier refusé'; + secInvalidHandle { 6} = 'Handle de fichier incorrect'; + secOutOfMemory { 8} = 'Mémoire insuffisante'; + secInvalidDrive { 15} = 'Lecteur incorrect'; + secNoMoreFiles { 18} = 'Plus de fichiers'; + secDiskRead { 100} = 'Tentative de lire au-delà de la fin de fichier'; + secDiskFull { 101} = 'Disque plein'; + secNotAssigned { 102} = 'Fichier/périphérique non assigné'; + secNotOpen { 103} = 'Fichier/périphérique non ouvert'; + secNotOpenInput { 104} = 'Fichier/périphérique non ouvert en entrée'; + secNotOpenOutput { 105} = 'Fichier/périphérique non ouvert en sortie'; + secWriteProtected { 150} = 'Le disque est protégé en écriture'; + secUnknownUnit { 151} = 'Unité de disque inconnue'; + secDriveNotReady { 152} = 'Lecteur non prêt'; + secUnknownCommand { 153} = 'Commande inconnue'; + secCrcError { 154} = 'Erreur de données'; + secBadStructLen { 155} = 'Mauvaise longueur de structure de requête'; + secSeekError { 156} = 'Erreur de recherche'; + secUnknownMedia { 157} = 'Type de support inconnu'; + secSectorNotFound { 158} = 'Secteur du disque introuvable'; + secOutOfPaper { 159} = 'Plus de papier'; + secDeviceWrite { 160} = 'Erreur d''écriture sur le périphérique'; + secDeviceRead { 161} = 'Erreur de lecture sur le périphérique'; + secHardwareFailure { 162} = 'Echec général'; + + {egGeneral} + secBadHandle {1001} = 'Mauvais handle passé à la fonction de communication'; + secBadArgument {1002} = 'Mauvais argument passé à la fonction'; + secGotQuitMsg {1003} = 'Reçu un message d''arrêt'; + secBufferTooBig {1004} = 'Tampon du terminal buffer supérieur à 65521'; + secPortNotAssigned {1005} = 'Composant ComPort non assigné'; + secInternal {1006} = 'Erreur interne lors de la création de la classe de fenêtre'; + secModemNotAssigned {1007} = 'Composant Modem non assigné'; + secPhonebookNotAssigned {1008} = 'Composant répertoire non assigné'; + secCannotUseWithWinSock {1009} = 'Composant incompatible avec WinSock'; + + {egOpenComm} + secBadId {2001} = 'ie_BadId - le port Com spécifié n''existe pas'; + secBaudRate {2002} = 'ie_Baudrate - vitesse en baud non supportée'; + secByteSize {2003} = 'ie_Bytesize - taille en octets incorrecte'; + secDefault {2004} = 'ie_Default - erreur dans les paramètres par défaut'; + secHardware {2005} = 'ie_Hardware - le port Com spécifié est en cours d''utilisation'; + secMemory {2006} = 'ie_Memory - impossible d''allouer des files'; + secCommNotOpen {2007} = 'ie_NOpen - périphérique non ouvert'; + secAlreadyOpen {2008} = 'ie_Open - périphérique déjà open'; + secNoHandles {2009} = 'Plus de handles, impossible d''ouvrir le port'; + secNoTimers {2010} = 'Aucun timer disponible'; + secNoPortSelected {2011} = 'La propriété ComNumber de TApdComPort n''a pas été initialisée'; + secNotOpenedByTapi {2012} = 'Comport was not opened by Tapi'; + + {egSerialIO} + secNullApi {3001} = 'Aucune couche de périphérique spécifiée'; + secNotSupported {3002} = 'Fonction non supporté par le pilote'; + secRegisterHandlerFailed {3003} = 'Echec de EnableCommNotification'; + secPutBlockFail {3004} = 'Echec d''écriture du bloc entier'; + secGetBlockFail {3005} = 'Echec de lecture du bloc entier'; + secOutputBufferTooSmall {3006} = 'Tampon de sortie trop petit pour le bloc'; + secBufferIsEmpty {3007} = 'Le tampon est vide'; + secTracingNotEnabled {3008} = 'Mode trace non activé'; + secLoggingNotEnabled {3009} = 'Journalisation non activée'; + secBaseAddressNotSet {3010} = 'Adresse de base non initialisée'; + + {Modem/Pager} + secModemNotStarted {4001} = 'StartModem n''a pas été appelée'; + secModemBusy {4002} = 'Le modem est occupé ailleurs'; + secModemNotDialing {4003} = 'Le modem ne compose pas le numéro'; + secNotDialing {4004} = 'Le numéroteur ne numérote pas'; + secAlreadyDialing {4005} = 'Le numéroteur numérote déjà'; + secModemNotResponding {4006} = 'Le modem ne répond pas'; + secModemRejectedCommand {4007} = 'Commande incorrecte envoyée au modem'; + secModemStatusMismatch {4008} = 'Le statut de modem demandé est erroné'; + + secDeviceNotSelected {4009} = 'Device not selected'; + secModemDetectedBusy {4010} = 'Called number is busy'; + secModemNoDialtone {4011} = 'No dialtone'; + secModemNoCarrier {4012} = 'No carrier'; + secModemNoAnswer {4013} = 'No answer'; + + { Pager } + secInitFail {4014} = 'Modem Initialization Failure'; + secLoginFail {4015} = 'Failed to Login'; + secMinorSrvErr {4016} = 'Minor Server Error'; + secFatalSrvErr {4017} = 'Fatal Server Error'; + + {LibModem} + secModemNotFound {4020} = 'Modem not found'; + secInvalidFile {4021} = 'Invalid modemcap file'; + + {deprecated, duplicate values different names} + {TApdPhoneBookEditor} + spbeDeleteQuery {4101} = 'Etes-vous sûr(e) de vouloir supprimer cette entrée ?'; + {TApdSModem} + sdsmMsgBase {4200} = ''; + sdsmMsgReady {4201} = 'Prêt'; + sdsmMsgInitialize {4202} = 'Initialisation du modem'; + sdsmMsgInitializeTimeout {4203} = 'Initialisation hors délais'; + sdsmMsgAutoAnswerBackground {4204} = 'AutoAnswer en arrière-plan'; + sdsmMsgAutoAnswerWait {4205} = 'Attente d''appel entrant'; + sdsmMsgAnswerWait {4206} = 'Réponse à l''appel'; + sdsmMsgDialWait {4207} = 'Numérotation'; + sdsmMsgDialCycle {4208} = 'Attente de renumérotation'; + sdsmMsgNoDialtone {4209} = 'Pas de tonalité'; + sdsmMsgConnectWait {4210} = 'Connecté en attente'; + sdsmMsgConnected {4211} = 'Connecté'; + sdsmMsgHangup {4212} = 'Déconnection'; + sdsmMsgCancel {4213} = 'Annulation'; + {TApdDialerDialog} + sdddCycling {4301} = 'Tentative de numérotation répétée . . .'; + sdddRetryWaiting {4302} = 'Attente . . .'; + sdddRetryWaitOver {4303} = 'Attente terminée, renumérotation . . .'; + sdddDialing {4304} = 'Numérotation . . .'; + sdddModemConnect {4305} = 'Modem connecté !'; + sdddModemConnectAt {4306} = 'Connecté à %d bauds'; + sdddModemVoice {4307} = 'Résultat de la connection : liaison ''voix'''; + sdddModemError {4308} = 'Résultat de la connection : le modem retourne une erreur'; + sdddModemNoCarrier {4309} = 'Résultat de la connection : pas de porteuse, échec de la connection'; + sdddModemBusy {4310} = 'Résultat de la connection : correspondant occupé'; + sdddModemNoDialTone {4311} = 'Résultat de la connection : pas de porteuse, vérifiez les connections'; + sdddDialTimedOut {4312} = 'Tentative de numérotation hors délais'; + {TPhoneBookEntryForm} + sdpeMustEnterName {4401} = 'Vous devez saisir un nom d''entrée'; + sdpeMustEnterNumber {4402} = 'Vous devez saisir un numéro de téléphone'; + sdpeNameExists {4403} = 'Une entrée de répertoire existe déjà sous ce nom'; + + {RAS connection status codes} + scsOpenPort {4500} = 'OpenPort'; + scsPortOpened {4501} = 'PortOpened'; + scsConnectDevice {4502} = 'ConnectDevice'; + scsDeviceConnected {4503} = 'DeviceConnected'; + scsAllDevicesConnected {4504} = 'AllDevicesConnected'; + scsAuthenticate {4505} = 'Authenticate'; + scsAuthNotify {4506} = 'AuthNotify'; + scsAuthRetry {4507} = 'AuthRetry'; + scsAuthCallback {4508} = 'AuthCallback'; + scsAuthChangePassword {4509} = 'AuthChangePassword'; + scsAuthProject {4510} = 'AuthProject'; + scsAuthLinkSpeed {4511} = 'AuthLinkSpeed'; + scsAuthAck {4512} = 'AuthAck'; + scsReAuthenticate {4513} = 'ReAuthenticate'; + scsAuthenticated {4514} = 'Authenticated'; + scsPrepareForCallback {4515} = 'PrepareForCallback'; + scsWaitForModemReset {4516} = 'WaitForModemReset'; + scsWaitForCallback {4517} = 'WaitForCallback'; + scsProjected {4518} = 'Projected'; + scsStartAuthentication {4519} = 'StartAuthentication'; + scsCallbackComplete {4520} = 'CallbackComplete'; + scsLogonNetwork {4521} = 'LogonNetwork'; + scsSubEntryConnected {4522} = 'SubEntryConnected'; + scsSubEntryDisconnected {4523} = 'SubEntryDisconnected'; + scsRasInteractive {4550} = 'Interactive'; + scsRasRetryAuthentication {4551} = 'RetryAuthentication'; + scsRasCallbackSetByCaller {4552} = 'CallbackSetByCaller'; + scsRasPasswordExpired {4553} = 'PasswordExpired'; + scsRasDeviceConnected {4599} = 'DeviceConnected'; + + { Pager TDialingStatus } + sPDS_NONE {4600} = ''; + sPDS_OFFHOOK {4601} = 'Off Hook'; + sPDS_DIALING {4602} = 'Dialing'; + sPDS_RINGING {4603} = 'Ringing'; + sPDS_WAITFORCONNECT {4604} = 'Wait For Connect'; + sPDS_CONNECTED {4605} = 'Connected'; + sPDS_WAITINGTOREDIAL {4606} = 'Waiting To Redial'; + sPDS_REDIALING {4607} = 'Redialing'; + sPDS_MSGNOTSENT {4608} = 'Message Not Sent'; + sPDS_CANCELLING {4609} = 'Cancelling'; + sPDS_DISCONNECT {4610} = 'Disconnect'; + sPDS_CLEANUP {4611} = 'Cleanup'; + + { PDialingError } + sPDE_NONE {4630} = ''; + sPDE_NODIALTONE {4631} = 'No Dial Tone'; + sPDE_LINEBUSY {4632} = 'Busy'; + sPDE_NOCONNECTION {4633} = 'No Connection'; + + { TTapStatus } + sTAPS_NONE {4660} = ''; + sTAPS_LOGINPROMPT {4661} = 'Login Prompt'; + sTAPS_LOGGEDIN {4662} = 'Logged In'; + sTAPS_LOGINERR {4663} = 'Login Error'; + sTAPS_LOGINFAIL {4664} = 'Login Fail'; + sTAPS_MSGOKTOSEND {4665} = 'Message Ok To Send'; + sTAPS_SENDINGMSG {4666} = 'Sending Message'; + sTAPS_MSGACK {4667} = 'Message Acknowledged'; + sTAPS_MSGNAK {4668} = 'Message Not Acknowledged'; + sTAPS_MSGRS {4669} = 'Message Error'; + sTAPS_MSGCOMPLETED {4670} = 'Message Completed'; + sTAPS_DONE {4671} = 'Done'; + + { Protocol status } + spsOK {4700} = 'OK'; + spsProtocolHandshake {4701} = 'Protocole de transfert en cours'; + spsInvalidDate {4702} = 'Mauvais horodatage reçu et ignoré'; + spsFileRejected {4703} = 'Fichier refusé'; + spsFileRenamed {4704} = 'Fichier renommé'; + spsSkipFile {4705} = 'Fichier ignoré'; + spsFileDoesntExist {4706} = 'Le fichier n''existe pas localement, ignoré'; + spsCantWriteFile {4707} = 'Fichier ignoré'; + spsTimeout {4708} = 'Dépassement de délai dans le protocole'; + spsBlockCheckError {4709} = 'Somme de contrôle ou CRC erroné'; + spsLongPacket {4710} = 'Bloc trop long'; + spsDuplicateBlock {4711} = 'Bloc reçu en double et ignoré '; + spsProtocolError {4712} = 'Erreur dans le protocole'; + spsCancelRequested {4713} = 'Annulation demandée'; + spsEndFile {4714} = 'En fin de fichier'; + spsResumeBad {4715} = 'L''hôte B+ a refusé la demande de reprise'; + spsSequenceError {4716} = 'Bloc hors séquence'; + spsAbortNoCarrier {4717} = 'Abandon sur perte de porteuse'; + + {Specific to certain protocols} + spsGotCrcE {4718} = 'Reçu paquet CrcE (Zmodem)'; + spsGotCrcG {4719} = 'Reçu paquet CrcG (Zmodem)'; + spsGotCrcW {4720} = 'Reçu paquet CrcW (Zmodem)'; + spsGotCrcQ {4721} = 'Reçu paquet CrcQ (Zmodem)'; + spsTryResume {4722} = 'B+ tente de reprendre le téléchargement'; + spsHostResume {4723} = 'L''hôte B+ reprend'; + spsWaitAck {4724} = 'Waiting for B+ ACK'; + + {Internal protocol codes} + spsNoHeader {4725} = ''; + spsGotHeader {4726} = ''; + spsGotData {4727} = ''; + spsNoData {4728} = ''; + spsAbort {4730} = ''; + + {Fax progress codes, sending} + sfpInitModem {4801} = 'Initialisation du modem pour l''envoi de fax'; + sfpDialing {4802} = 'Numérotation'; + sfpBusyWait {4803} = 'Occupé, attente de renumérotation...'; + sfpSendPage {4804} = 'Envoi des données de la page'; + sfpSendPageStatus {4805} = 'Envoi de EOP'; + sfpPageError {4806} = 'Erreur d''envoi de la page'; + sfpPageOK {4807} = 'Page acceptée par le correspondant'; + sfpConnecting {4808} = 'Connection...'; + + {Fax progress codes, receiving} + sfpWaiting {4820} = 'Attente d''appel entrant'; + sfpNoConnect {4821} = 'Pas de connection sur cet appel'; + sfpAnswer {4822} = 'Réponse à l''appel entrant'; + sfpIncoming {4823} = 'Appel entrant reconnu comme fax'; + sfpGetPage {4824} = 'Réception des données de la page'; + sfpGetPageResult {4825} = 'Réception du signal de fin de page'; + sfpCheckMorePages {4826} = 'Réception du statut de fin de document'; + sfpGetHangup {4827} = 'Réception de commande de raccrochage'; + sfpGotHangup {4828} = 'Reçu code de classe 2 FHNG'; + + {Fax server codes } + sfpSwitchModes {4830} = 'Switching modes'; + sfpMonitorEnabled {4831} = 'Monitoring for incoming faxes'; + sfpMonitorDisabled {4832} = 'Not monitoring for incoming faxes'; + + {Fax progress codes, common} + sfpSessionParams {4840} = 'Réception des paramètres de connection'; + sfpGotRemoteID {4841} = 'Reçu l''ID de l''appelé'; + sfpCancel {4842} = 'Abandonné par l''utilisateur'; + sfpFinished {4843} = 'Terminé'; + + {Trigger errors} + secNoMoreTriggers {5001} = 'Plus trigger slots'; + secTriggerTooLong {5002} = 'Data trigger trop long'; + secBadTriggerHandle {5003} = 'Bad trigger handle'; + + {Packet errors} + secStartStringEmpty {5501} = 'La chaîne de start est vide'; + secPacketTooSmall {5502} = 'La taille de paquet ne peut pas être plus petite que la chaîne de start'; + secNoEndCharCount {5503} = 'Les paquets CharCount doivent avoir une condition de fin'; + secEmptyEndString {5504} = 'La chaîne de fin est vide'; + secZeroSizePacket {5505} = 'Le taille de paquet ne peut pas être nulle'; + secPacketTooLong {5506} = 'Paquet trop long'; + + {Protocol errors} + secBadFileList {6001} = 'Mauvais format dans la liste de fichiers'; + secNoSearchMask {6002} = 'Aucun masque de recherche spécifié pendant la transmission'; + secNoMatchingFiles {6003} = 'Aucun fichier ne correspond au masque de recherche'; + secDirNotFound {6004} = 'Le répertoire dans le masque de recherche n''existe pas'; + secCancelRequested {6005} = 'Annulation demandée'; + secTimeout {6006} = 'Dépassement de délai fatal'; + secProtocolError {6007} = 'Evènement irrécupérable pendant le protocole'; + secTooManyErrors {6008} = 'Trop d''erreurs pendant le protocole'; + secSequenceError {6009} = 'Erreur de séquence de blocs dans Xmodem'; + secNoFilename {6010} = 'Nom de fichier non spécifié dans le protocole reçu'; + secFileRejected {6011} = 'Le fichier a été refusé'; + secCantWriteFile {6012} = 'Impossible d''écrire le fichier'; + secTableFull {6013} = 'La table de fenêtre Kermit est pleine, erreur fatale'; + secAbortNoCarrier {6014} = 'Abandon par perte de porteuse'; + secBadProtocolFunction {6015} = 'Fonction non supportée par le protocole'; + secProtocolAbort {6016} = 'Protocol aborted'; + + {INI database} + secKeyTooLong {7001} = 'Chaîne clé trop longue'; + secDataTooLarge {7002} = 'Chaîne de données trop longue'; + secNoFieldsDefined {7003} = 'Aucun champ dans la base de données'; + secIniWrite {7004} = 'Erreur d''écriture dans le fichier INI générique'; + secIniRead {7005} = 'Erreur de lecture dans le fichier INI générique'; + secNoIndexKey {7006} = 'Aucun index dans la base de données'; + secRecordExists {7007} = 'L''enregistrement existe déjà'; + secRecordNotFound {7008} = 'Enregistrement introuvable dans la base de données'; + secMustHaveIdxVal {7009} = 'Nom de clé d''index incorrect'; + secDatabaseFull {7010} = 'Nombre maximum (999) d''enregistrements de base de données atteint'; + secDatabaseEmpty {7011} = 'Pas d''enregistrements dans la base de données'; + secDatabaseNotPrepared {7012} = 'iPrepareIniDatabase non appelé'; + secBadFieldList {7013} = 'Mauvaise liste de champs dans le composant INI'; + secBadFieldForIndex {7014} = 'Mauvais index de champ dans le composant INI'; + + {State Machine} + secNoStateMachine {7500} = 'No state machine specified'; + secNoStartState {7501} = 'StartState not set'; + secNoSapiEngine {7502} = 'No SAPI engine specified'; + + { fax codes } + secFaxBadFormat {8001} = 'Le fichier n''est pas du type APF'; + secBadGraphicsFormat {8002} = 'Format de fichier graphique non supporté'; + secConvertAbort {8003} = 'Conversion de fax abandonnée par l''utilisateur'; + secUnpackAbort {8004} = 'Décompactage de fax abandonné par l''utilisateur'; + secCantMakeBitmap {8005} = 'Echec de l''API CreateBitmapIndirect'; + secNoImageLoaded {8050} = 'Aucune image chargée dans le visualisateur'; + secNoImageBlockMarked {8051} = 'Aucun bloc de l''image marqué'; + secFontFileNotFound {8052} = 'APFAX.FNT introuvable ou mauvaise ressource'; + secInvalidPageNumber {8053} = 'Le numéro de page de fax spécifié est incorrect'; + secBmpTooBig {8054} = 'La taille du BMP dépasse la hauteur maximale Windows'' de 32767'; + secEnhFontTooBig {8055} = 'La police sélectionnée pour le convertisseur de texte est trop grande'; + + secFaxBadMachine {8060} = 'Fax incompatible avec celui du correspondant'; + secFaxBadModemResult {8061} = 'Mauvaise réponse du modem'; + secFaxTrainError {8062} = 'Echec de formation des modems'; + secFaxInitError {8063} = 'Erreurpendant l''initialisation du modem'; + secFaxBusy {8064} = 'Le numéro de fax appelé est occupé'; + secFaxVoiceCall {8065} = 'Le numéro appelé est un numéro vocal'; + secFaxDataCall {8066} = 'Appel données entrant'; + secFaxNoDialTone {8067} = 'Pas de tonalité'; + secFaxNoCarrier {8068} = 'Echec de la conection au fax distant'; + secFaxSessionError {8069} = 'Echec du fax en cours de session'; + secFaxPageError {8070} = 'Echec du fax en fin de page'; + secFaxGDIPrintError {8071} = 'Erreur NextBand GDI dans le pilote d''impression fax'; + secFaxMixedResolution {8072} = 'Résolutions multiples dans une même session non supportées'; + secFaxConverterInitFail {8073} = 'Echec de l''initialisation du convertisseur de fax'; + secNoAnswer {8074} = 'Le fax distant ne répond pas'; + secAlreadyMonitored {8075} = 'Directory already being monitored'; + + { Printer driver installation codes } + secUniAlreadyInstalled {8080} = 'Support des fichiers Unidrv déjà installé'; + secUniCannotGetSysDir {8081} = 'Répertoire système Windows indéterminé'; + secUniCannotGetWinDir {8082} = 'Répertoire Windows indéterminé'; + secUniUnknownLayout {8083} = 'Environnement de fichier d''installation indéterminé'; + secUniCannotInstallFile {8085} = 'Impossible d''installer les fichiers Unidrv dans le répertoire système'; + secDrvCopyError {8087} = 'Erreur pendant la copie du pilote d''imprimante'; + secCannotAddPrinter {8088} = 'Echec de l''appel 32-bit à AddPrinter'; + secDrvBadResources {8089} = 'Ressources défectueuses ou manquantes dans le pilote'; + secDrvDriverNotFound {8090} = 'Fichier du pilote introuvable'; + secUniCannotGetPrinterDriverDir {8091} = 'Répertoire du pilote d''impression Win NT indéterminé'; + secInstallDriverFailed {8092} = 'Echec de l''API AddPrinterDriver'; + + { TApdGSMPhone error codes } + secSMSBusy {8100} = 'Busy with another command'; + secSMSTimedOut {8101} = 'Timed out, no response back'; + secSMSTooLong {8102} = 'SMS message too long'; + secSMSUnknownStatus {8103} = 'Status unknown'; + secMEFailure {8300} = 'Mobile equipment failure'; + secServiceRes {8301} = 'SMS service of ME reserved'; + secBadOperation {8302} = 'Operation not allowed'; + secUnsupported {8303} = 'Operation not supported'; + secInvalidPDU {8304} = 'Invalid PDU mode parameter'; + secInvalidText {8305} = 'Invalid Text mode parameter'; + secSIMInsert {8310} = 'SIM card not inserted'; + secSIMPin {8311} = 'SIM PIN required'; + secSIMPH {8312} = 'PH-SIM PIN required'; + secSIMFailure {8313} = 'SIM failure'; + secSIMBusy {8314} = 'SIM busy'; + secSIMWrong {8315} = 'SIM wrong'; + secSIMPUK {8316} = 'SIM PUK required'; + secSIMPIN2 {8317} = 'SIM PIN2 required'; + secSIMPUK2 {8318} = 'SIM PUK2 required'; + secMemFail {8320} = 'Memory failure'; + secInvalidMemIndex {8321} = 'Invalid memory index'; + secMemFull {8322} = 'Memory is full'; + secSMSCAddUnknown {8330} = 'SMS Center Address unknown'; + secNoNetwork {8331} = 'No network service'; + secNetworkTimeout {8332} = 'Network timeout'; + secCNMAAck {8340} = 'No +CNMA acknowledgement expected'; + secUnknown {8500} = 'Unknown error'; + + { Winsock codes } + secADWSERROR {9001} = 'Erreur Async Professional'; + secADWSLOADERROR {9002} = 'Erreur au chargement de la DLL Winsock'; + secADWSVERSIONERROR {9003} = 'Version de Winsock incorrecte'; + secADWSNOTINIT {9004} = 'Winsock non initialisé - %s'; + secADWSINVPORT {9005} = 'Le port spécifié n''est pas valide'; + secADWSCANTCHANGE {9006} = 'Impossible de changer le paramètre pendant que le socket est connecté'; + secADWSCANTRESOLVE {9007} = 'Impossible de résoudre l''adresse de destination'; + + { All Windows Sockets error constants are biased by 10000 from the ';normal'; } + swsaBaseErr {10000} = ''; + { Windows Sockets definitions of regular Microsoft C error constants } + swsaEIntr {10004} = 'Interrupted function call'; + swsaEBadF {10009} = 'Bad file number'; + swsaEAcces {10013} = 'Permission denied'; + swsaEFault {10014} = 'Unknown error'; + swsaEInVal {10022} = 'Invalid argument'; + swsaEMFile {10024} = 'Too many open files'; + + { Windows Sockets definitions of regular Berkeley error constants } + swsaEWouldBlock {10035} = 'Warning : the socket would block on this call'; + swsaEInProgress {10036} = 'A blocking call is in progress'; + swsaEAlReady {10037} = 'WSAEALREADY: watch out, Al is ready'; + swsaENotSock {10038} = 'Socket descriptor is (1) not a socket, or (2) is of wrong type'; + swsaEDestAddrReq {10039} = 'The destination address is required for this operation'; + swsaEMsgSize {10040} = 'The datagram was too large to fit into the buffer and was truncated'; + swsaEPrototype {10041} = 'WSAEPROTOTYPE'; + swsaENoProtoOpt {10042} = 'The option is unknown or not supported'; + swsaEProtoNoSupport {10043} = 'Either (1) not enough buffer space to create socket (2) protocol not supported'; + swsaESocktNoSupport {10044} = 'Specified socket type not supported in this address family'; + swsaEOpNotSupp {10045} = 'Operation is not supported by this socket'; + swsaEPfNoSupport {10046} = 'Specified protocol family is not supported'; + swsaEAfNoSupport {10047} = 'Specified address family is not supported by this protocol'; + swsaEAddrInUse {10048} = 'The address is already in use for this operation'; + swsaEAddrNotAvail {10049} = 'The address is not available from this machine'; + swsaENetDown {10050} = 'The network subsystem has failed'; + swsaENetUnreach {10051} = 'The network is unreachable from this machine at this time'; + swsaENetReset {10052} = 'The network has been reset'; + swsaEConnAborted {10053} = 'The virtual circuit has been aborted due to timeout, etc'; + swsaEConnReset {10054} = 'The virtual circuit has been reset by the partner'; + swsaENoBufs {10055} = 'The descriptor is not a socket, or no buffer space is available'; + swsaEIsConn {10056} = 'The socket is already connected'; + swsaENotConn {10057} = 'The socket is not connected'; + swsaEShutDown {10058} = 'The socket has been shutdown'; + swsaETooManyRefs {10059} = 'WSAETOOMANYREFS'; + swsaETimedOut {10060} = 'The operation timed out'; + swsaEConnRefused {10061} = 'The attempt to connect was forcibly refused'; + swsaELoop {10062} = 'WSAELOOP: see WSAELOOP'; + swsaENameTooLong {10063} = 'The name is too long'; + swsaEHostDown {10064} = 'The host machine is down'; + swsaEHostUnreach {10065} = 'The host machine is unreachable'; + swsaENotEmpty {10066} = 'WSAENOTEMPTY'; + swsaEProcLim {10067} = 'WSAEPROCLIM'; + swsaEUsers {10068} = 'WSAEUSERS'; + swsaEDQuot {10069} = 'WSAEDQUOT'; + swsaEStale {10070} = 'WSAESTALE'; + swsaERemote {10071} = 'WSAEREMOTE'; + + { Extended Windows Sockets error constant definitions } + swsaSysNotReady {10091} = 'Network subsystem unusable'; + swsaVerNotSupported {10092} = 'Version requested by WSAStartUp not supported by loaded Winsock DLL'; + swsaNotInitialised {10093} = 'WSAStartUp not yet called'; + swsaEDiscOn {10101} = 'WSAEDISCON'; + swsaHost_Not_Found {11001} = 'Host not found'; + swsaTry_Again {11002} = 'Host not found, or SERVERFAIL, can try again'; + swsaNo_Recovery {11003} = 'Non recoverable errors, FORMERR, REFUSED, NOTIMP'; + swsaNo_Data {11004} = 'Valid name, but no data record of requested type'; + + { The string resource range 13500 - 13800 is used for TAPI } + { status messages, which do not require constants here } + {TAPI CallState} + stcs_Idle {13501} = 'Line is idle'; + stcs_Offering {13502} = 'Offering line...'; + stcs_Accepted {13503} = 'Accepting call...'; + stcs_Dialtone {13504} = 'Dialtone detected'; + stcs_Dialing {13505} = 'Dialing...'; + stcs_Ringback {13506} = 'Ringback detected'; + stcs_Busy {13507} = 'Called number is busy'; + stcs_SpecialInfo {13508} = 'Special info'; + stcs_Connected {13509} = 'Connected!'; + stcs_Proceeding {13510} = 'Proceeding...'; + stcs_OnHold {13511} = 'On hold...'; + stcs_Conferenced {13512} = 'Call conferenced'; + stcs_OnHoldPendConf {13513} = 'On hold pending conference...'; + stcs_OnHoldPendTransfer {13514} = 'On hold pending transfer...'; + stcs_Disconnected {13515} = 'Call disconnected (%s)'; + stcs_Unknown {13516} = 'Unknown state'; + {TAPI DevState} + stds_Other {13533} = 'Other'; + stds_Ringing {13534} = 'Ringing'; + stds_Connected {13535} = 'Connected'; + stds_Disconnected {13536} = 'Disconnected'; + stds_MsgWaitOn {13537} = 'Message wait on'; + stds_MsgWaitOff {13538} = 'Message wait off'; + stds_InService {13539} = 'In service'; + stds_OutOfService {13540} = 'Out of service'; + stds_Maintenance {13541} = 'Maintenance change'; + stds_Open {13542} = 'Ppen change'; + stds_Close {13543} = 'Closed'; + stds_NumCalls {13544} = 'Number of calls changed'; + stds_NumCompletions {13545} = 'Number of completions changed'; + stds_Terminals {13546} = 'Terminals changed'; + stds_RoamMode {13547} = 'Roam mode changed'; + stds_Battery {13548} = 'Battery changed'; + stds_Signal {13549} = 'Signal changed'; + stds_DevSpecific {13550} = 'Device specific change'; + stds_ReInit {13551} = 'Re-initialized'; + stds_Lock {13552} = 'Lock change'; + stds_CapsChange {13553} = 'Caps change'; + stds_ConfigChange {13554} = 'Configuration change'; + stds_TranslateChange {13555} = 'Translate change'; + stds_ComplCancel {13556} = 'Compltion cancel'; + stds_Removed {13557} = 'Removed'; + + { TAPI APRO-specific } + sTAPILineReply {13565} = 'TAPI line reply'; + sTAPIStateChange {13597} = 'TAPI state change'; + sTAPICalledBusy {13598} = 'Called number is busy'; + sTAPIDialFail {13599} = 'Dial failed/no connection'; + sTAPIRetryWait {13600} = 'Waiting for retry in %d seconds'; + sTAPIDeviceInUse {13601} = 'Device is in use by another application'; + + { TAPI Disconnect Reasons } + sTAPIDisconnect_Unspecified {13650} = 'Reason Unspecified'; + sTAPIDisconnect_Normal {13651} = 'Normal Hangup by Remote'; + sTAPIDisconnect_Unknown {13652} = 'Reason Unknown'; + sTAPIDisconnect_Reject {13653} = 'Remote Rejected Call'; + sTAPIDisconnect_PickUp {13654} = 'Call Picked Up Elsewhere'; + sTAPIDisconnect_Forwarded {13655} = 'Call was Forwarded'; + sTAPIDisconnect_Busy {13656} = 'Line was Busy'; + sTAPIDisconnect_NoAnswer {13657} = 'No Answer by Remote'; + sTAPIDisconnect_BadAddress {13658} = 'Invalid Destination Address'; + sTAPIDisconnect_Unreachable {13659} = 'Remote Unreachable'; + sTAPIDisconnect_Congestion {13660} = 'Network Congestion'; + sTAPIDisconnect_Incompatible {13661} = 'Remote Equipment Incompatible'; + sTAPIDisconnect_Unavail {13662} = 'Reason Unavailable'; + sTAPIDisconnect_NoDialtone {13663} = 'No Dialtone'; + sTAPIDisconnect_NumberChanged {13664} = 'Number Changed'; + sTAPIDisconnect_OutOfOrder {13665} = 'Out of Order'; + sTAPIDisconnect_TempFailure {13666} = 'Temporary Failure'; + sTAPIDisconnect_QOSUnavail {13667} = 'Quality of Service Unavail'; + sTAPIDisconnect_Blocked {13668} = 'Blocked'; + sTAPIDisconnect_DoNotDisturb {13669} = 'Do Not Disturb'; + sTAPIDisconnect_Cancelled {13670} = 'Cancelled'; + + {Adjusted TAPI error codes} + secAllocated {13801} = 'Already allocated'; + secBadDeviceID {13802} = 'Bad device ID'; + secBearerModeUnavail {13803} = 'Bearer mode unavailable'; + secCallUnavail {13805} = 'Call unavailable'; + secCompletionOverrun {13806} = 'Completion overrun'; + secConferenceFull {13807} = 'Conference full'; + secDialBilling {13808} = 'Dial failed'; + secDialDialtone {13809} = 'Dial failed, no dialtone'; + secDialPrompt {13810} = 'Dial failed'; + secDialQuiet {13811} = 'Dial failed'; + secIncompatibleApiVersion {13812} = 'Incompatible API version'; + secIncompatibleExtVersion {13813} = 'Incompatible EXT version'; + secIniFileCorrupt {13814} = 'INI file corrupt'; + secInUse {13815} = 'Resource in use'; + secInvalAddress {13816} = 'Invalid address'; + secInvalAddressID {13817} = 'Invalid address ID'; + secInvalAddressMode {13818} = 'Invalid address mode'; + secInvalAddressState {13819} = 'Invalid address state'; + secInvalAppHandle {13820} = 'Invalid application handle'; + secInvalAppName {13821} = 'Invalid Application name'; + secInvalBearerMode {13822} = 'Invalid bearer mode'; + secInvalCallComplMode {13823} = 'Invalid call completion mode'; + secInvalCallHandle {13824} = 'Invalid call handle'; + secInvalCallParams {13825} = 'Invalid call parameters'; + secInvalCallPrivilege {13826} = 'Invalid call privilege'; + secInvalCallSelect {13827} = 'Invalid call select'; + secInvalCallState {13828} = 'Invalid call state'; + secInvalCallStatelist {13829} = 'Invalid call state list'; + secInvalCard {13830} = 'Invalid card'; + secInvalCompletionID {13831} = 'Invalid completion ID'; + secInvalConfCallHandle {13832} = 'Invalid conference call handle'; + secInvalConsultCallHandle {13833} = 'Invalid consultation call handle'; + secInvalCountryCode {13834} = 'Invalid country code'; + secInvalDeviceClass {13835} = 'Invalid device class'; + secInvalDeviceHandle {13836} = 'Invalid device handle'; + secInvalDialParams {13837} = 'Invalid dial params'; + secInvalDigitList {13838} = 'Invalid digit list'; + secInvalDigitMode {13839} = 'Invalid digit mode'; + secInvalDigits {13840} = 'Invalid digits'; + secInvalExtVersion {13841} = 'Invalid ext version'; + secInvalGroupID {13842} = 'Invalid group ID'; + secInvalLineHandle {13843} = 'Invalid line handle'; + secInvalLineState {13844} = 'Invalid line state'; + secInvalLocation {13845} = 'Invalid location'; + secInvalMediaList {13846} = 'Invalid media list'; + secInvalMediaMode {13847} = 'Invalid media mode'; + secInvalMessageID {13848} = 'Invalid message ID'; + secInvalParam {13850} = 'Invalid parameter'; + secInvalParkID {13851} = 'Invalid park ID'; + secInvalParkMode {13852} = 'Invalid park mode'; + secInvalPointer {13853} = 'Invalid pointer'; + secInvalPrivSelect {13854} = 'Invalid privilege select'; + secInvalRate {13855} = 'Invalid rate'; + secInvalRequestMode {13856} = 'Invalid request mode'; + secInvalTerminalID {13857} = 'Invalid terminal ID'; + secInvalTerminalMode {13858} = 'Invalid terminal mode'; + secInvalTimeout {13859} = 'Invalid timeout'; + secInvalTone {13860} = 'Invalid tone'; + secInvalToneList {13861} = 'Invalid tone list'; + secInvalToneMode {13862} = 'Invalid tone mode'; + secInvalTransferMode {13863} = 'Invalid transfer mode'; + secLineMapperFailed {13864} = 'Line mapper failed'; + secNoConference {13865} = 'No conference'; + secNoDevice {13866} = 'No device'; + secNoDriver {13867} = 'No driver'; + secNoMem {13868} = 'No memory'; + secNoRequest {13869} = 'No request'; + secNotOwner {13870} = 'Not owner'; + secNotRegistered {13871} = 'Not registered'; + secOperationFailed {13872} = 'Operation failed'; + secOperationUnavail {13873} = 'Operation unavailable'; + secRateUnavail {13874} = 'Rate unavailable'; + secResourceUnavail {13875} = 'Resource unavailable'; + secRequestOverrun {13876} = 'Request overrun'; + secStructureTooSmall {13877} = 'Structure too small'; + secTargetNotFound {13878} = 'Target not found'; + secTargetSelf {13879} = 'Target is self'; + secUninitialized {13880} = 'Uninitialized'; + secUserUserInfoTooBig {13881} = 'User info too big'; + secReinit {13882} = 'Reinit failed'; + secAddressBlocked {13883} = 'Address blocked'; + secBillingRejected {13884} = 'Billing rejected'; + secInvalFeature {13885} = 'Invalid feature'; + secNoMultipleInstance {13886} = 'No multiple instance'; + + {Apro encounters a few of its own TAPI errors, place these error + codes after the native TAPI error codes, but leave a little bit + of room for expansion of the TAPI error codes.} + secTapiBusy {13928} = 'TAPI already open, dialing or answering'; + secTapiNotSet {13929} = 'TapiMode not set in TApdComPort'; + secTapiNoSelect {13930} = 'No TAPI device selected'; + secTapiLoadFail {13931} = 'Failed to find/load TAPI.DLL'; + secTapiGetAddrFail {13932} = 'Failed to get TAPI address'; + sTAPIdisabled16bit {13933} = 'TAPI disabled for 16-bit environments'; + secTapiUnexpected {13934} = 'Unexpected TAPI error'; + secTapiVoiceNotSupported {13935} = 'TAPI device does not support voice extensions'; + secTapiWaveFail {13936} = 'TAPI wave file error'; + secTapiCIDBlocked {13937} = 'Caller ID Blocked'; + secTapiCIDOutOfArea {13938} = 'Out of Area Call'; + secTapiWaveFormatError {13939} = 'The selected file is not a wave file'; + secTapiWaveReadError {13940} = 'Unable to read wave file data'; + secTapiWaveBadFormat {13941} = 'Unsupported wave format'; + secTapiTranslateFail {13942} = 'Unable to translate address'; + secTapiWaveDeviceInUse {13943} = 'Wave device in use'; + secTapiWaveFileExists {13944} = 'Wave file already exists'; + secTapiWaveNoData {13945} = 'No wave data available'; + + secVoIPNotSupported {13950} = 'Voice over IP not available (requires Windows 2000 and above)'; + secVoIPCallBusy {13951} = 'Remote was busy'; + secVoIPBadAddress {13952} = 'Destination address bad'; + secVoIPNoAnswer {13953} = 'Remote did not answer'; + secVoIPCancelled {13954} = 'Cancelled'; + secVoIPRejected {13955} = 'Remote rejected the call'; + secVoIPFailed {13956} = 'General failure'; + secVoIPTapi3NotInstalled {13957} = 'ITTapi interface failure'; + secVoIPH323NotFound {13958} = 'H.323 line not found'; + secVoIPTapi3EventFailure {13959} = 'Event notify failure'; + + {RAS error codes} + secRasLoadFail {13980} = 'Failed to find/load RASAPI32.DLL'; + + { Logging - It is unlikely that these should change, these strings are } + { used in the dispatcher log. Translating them into another language } + { could make it difficult for TurboPower Tech Support to decipher it. } + { Dispatch type. Instead of duplicating the strings in the different } + { language include files, we'll just include a common file here. } + {$I AdDispLog.inc} + + {XML strings} + sIENotInstalled = 'Cannot open WININET, Microsoft IE required'; + sOpenFileFailed = 'Impossible d''ouvrir le fichier '; + sFileNotFound = 'File %s could not be found'; + sAllocSrcMemFailed = 'Impossible d''allouer la mémoire pour la source XML'; + sHttpReadReqFailed = 'Impossible de lire la requête HTTP'; + sHttpDataNotAvail = 'Données Http non disponibles'; + sHttpReqSendFailed = 'Impossible d''envoyer la requête HTTP'; + sHttpReqOpenFailed = 'Impossible d''ouvrir la requête HTTP'; + sInetConnectFailed = 'Impossible d''établir la connexion Internet'; + sInetOpenFailed = 'Impossible d''accéder à Internet'; + sInvalidFtpLoc = 'Localisation FTP incorrecte'; + sInvalidFtpDir = 'Répertoire FTP incorrect'; + sFtpReadReqFailed = 'Impossible de lire la requête FTP'; + sFtpDataNotAvail = 'Données FTP non disponibles'; + sFtpOpenFileFailed = 'Impossible d''ouvrir le fichier FTP'; + sFtpPutFileFailed = 'Could not save file via ftp to %s'; + sSrcLoadFailed = 'Impossible de charger la source '; + sInvalidMemPtr = 'Pointeur incorrect'; + sFmtErrorMsg = 'Ligne: %d Colonne: %d Erreur: %s'; + sIndexOutOfBounds = 'ERREUR - INDEX HORS BORNES'; + sExpMarkupDecl = 'Markup de déclaration attendu'; + sIllAttrType = 'Type d''attribut invalide'; + sIllAttrDefKeyw = 'Valeur par défaut incorrecte'; + sSysIdMissing = 'Identificateur système manquant '; + sExtModifMissing = 'Modificateur externe manquant '; + sIllCondSectStart = 'Une section conditionnelle doit débuter par INCLUDE ou IGNORE'; + sBadSepInModel = 'Mauvais séparateur dans un modèle de contenu'; + sExpCommentOrCDATA = 'Commentaire ou section CDATA attendu '; + sUnexpectedEof = 'Fin de fichier inattendue'; + sMismatchEndTag = 'Tag de fin sans correspondance '; + sIllCharInRef = 'Caractère illegal dans la référence'; + sUndeclaredEntity = 'Référence à une entité non déclarée '; + sExpectedString = 'Chaîne attendue '; + sSpaceExpectedAt = 'Espace attendu en position '; + sUnexpEndOfInput = 'Fin de données pendant la recherche du délimiteur '; + sQuoteExpected = '" ou '' attendu'; + sInvalidXMLVersion = 'XMLPartner does not support XML specification greater than %s'; + sUnableCreateStr = 'Unable to create stream for input.'; + sInvalidName = 'Invalid XML name'; + sInvalidCommentText = 'Invalid comment text'; + sCommentBeforeXMLDecl = 'Document cannot start with a comment if it also contains an XML declaration'; + sInvalidCDataSection = 'Invalid characters in CDATA section'; + sRedefinedAttr = 'Attributes cannot be redefined in a start tag'; + sCircularEntRef = 'Circular reference to: '; + sInvAttrChar = 'Invalid character in attribute value: '; + sInvPCData = 'Invalid characters in element''s character data: '; + sDataAfterValDoc = 'There is invalid data after valid XML document'; + sNoIntConditional = 'Conditional sections not allowed in internal subset of document type declaration'; + sNotationNotDeclared = 'Notation not declared: '; + sInvPubIDChar = 'Invalid PublicID character: '; + sNoNDATAInPeDecl = 'NDATA not allowed in parameter entity declaration.'; + sInvStandAloneVal = 'Standalone value must equal ''yes'' or ''no'''; + sInvEncName = 'Invalid encoding declaration: '; + sInvVerNum = 'Invalid XML version number: '; + sInvEntityValue = 'Invalid character in entity value: '; + sNoCommentInMarkup = 'Comments can not be placed within other markup'; + sNoPEInIntDTD = 'Parameter entities not allowed in DTD internal subset'; + sXMLDecNotAtBeg = 'The XML declaration must appear before the first element'; + sInvalidElementName = 'Invalid element name: '; + sBadParamEntNesting = 'Parameter-entity text must be properly nested: '; + sInvalidCharEncoding = 'Invalid character encoding specified.'; + sAttrNotNum = 'Attribute %s of element %s does not have an integer value.'; + + {xpchrstm related errors} + sInvalidXMLChar = 'Invalid XML Character found'; + sInvalidBEChar = 'Invalid (big-endian) UTF-16 character encoding'; + sInvalidLEChar = 'Invalid (little-endian) UTF-16 character encoding'; + sBadUTF8Char = 'Badly formed UTF-8 character in stream'; + sErrEndOfDocument = 'Unexpected end of document stream'; + sUCS_ISOConvertErr = 'Cannot convert UCS-4 character to ISO-8859-1'; + sUCS_U16ConvertErr = 'Cannot convert UCS-4 character to UTF-16'; + sUCS_U8ConverErr = 'Cannot convert UCS-4 character to UTF-8'; + + {EModem error string resource} + sModemDetectedBusy = 'Line is Busy'; + sModemNoDialtone = 'No Dialtone'; + sModemNoCarrier = 'No Carrier'; + + {TApdPager string resource} + sInitFail = 'Modem Initialization Failure'; + sLoginFail = 'Failed to Login'; + sMinorSrvErr = 'Minor Server Error'; + sFatalSrvErr = 'Fatal Server Error'; + sConnected = 'Modem Connected'; + sCancelled = 'Cancel Requested'; + sLineBusy = 'Line Busy'; + sDisconnect = 'Disconnecing'; + sNoDialtone = 'No Dialtone'; + sMsgNotSent = 'Message not sent'; + sWaitingToRedial = 'Waiting to Redial'; + sLoginPrompt = 'Received Prompt for Login'; + sLoggedIn = 'Successful Login'; + sDialing = 'Now Dialing'; + sRedialing = 'Now Redialing'; + sLoginRetry = 'Retry Password for Login'; + sMsgOkToSend = 'Ready to Send Message'; + sSendingMsg = 'Now sending Message'; + sMsgAck = 'Received, Send next block or end'; + sMsgNak = 'Received Error, Resend Message'; + sMsgRs = 'Unable to Send Page'; + sMsgCompleted = 'Page Complete - Logging out if done'; + sSendTimedOut = 'Timed Out - No Response'; + sLoggingOut = 'Logging Out'; + sDone = 'Done with Page'; + + {TApdVoIP error string resource} + sVoIPNotAvailable = 'Voice over IP not available (requires Windows 2000 and above)'; + + {TFaxLogCode description strings, used by TApdAbstractFax.LogMsg method} + slfaxNone = 'none'; + slfaxTransmitStart = 'transmit started'; + slfaxTransmitOk = 'transmit finished okay'; + slfaxTransmitFail = 'transmit failed'; + slfaxReceiveStart = 'receive started'; + slfaxReceiveOk = 'receive finished okay'; + slfaxReceiveSkip = 'receive skipped on request'; + slfaxReceiveFail = 'receive failed'; diff --git a/AdExcept.pas b/AdExcept.pas new file mode 100644 index 0000000..9adb410 --- /dev/null +++ b/AdExcept.pas @@ -0,0 +1,760 @@ +(***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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 TurboPower Async Professional + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1991-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Sulaiman Mah + * Sean B. Durkin + * Sebastian Zierer + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* ADEXCEPT.PAS 5.00 *} +{*********************************************************} + +{Global defines potentially affecting this unit} +{$I AWDEFINE.INC} + +{Options required for this unit} +{$G+,X+,F-,V-,P-,T-,B-} + +unit AdExcept; + {-Apro exceptions} + +interface + +uses + Messages, + Windows, + SysUtils, + Classes, + OoMisc; + +{ The design of the string resources has changed for APRO 4.04. We no longer } +{ use the string resource manager (AdSrmgr.pas), we now use resourcestrings. } +{ To use a different language, specify the language below. Only select one } +{ language when compiling. Selecting multiple languages will result in } +{ duplicate identifiers. If you need to support multiple langauages, use the } +{ separate string resource units to create your own language DLLs or other } +{ techniques. See the comments in the applicable language include file for } +{ more details (in English). } + + +{Select English by default, only one can be enabled at any given time } + +{*** English ***} + {.$I AdExcept.inc} +{*** French ***} + {$I AdExcept.fra} +{*** German ***} + {.$I AdExcept.deu} +{*** Spanish ***} + {.$I AdExcept.esp} +{*** Swedish ***} + {.$I AdExcept.sw} +{*** Norwegian ***} + {.$I AdExcept.nor} +{*** Danish ***} + {.$I AdExcept.dk} + + +type + {General Apro exception class} + EAPDException = class(Exception) + private + FErrorCode : Integer; + + public + constructor Create(const EC : Integer; PassThru : Boolean); + constructor CreateUnknown(const Msg : String; Dummy : Byte); + + class function MapCodeToStringID(const Code : Integer) : Word; + {-Return a string table index for Code} + + property ErrorCode : Integer + read FErrorCode write FErrorCode; + end; + + {Apro exception groups} + EGeneral = class(EAPDException); + EOpenComm = class(EAPDException); + ESerialIO = class(EAPDException); + EModem = class(EAPDException); + ETrigger = class(EAPDException); + EPacket = class(EAPDException); + EProtocol = class(EAPDException); + EINI = class(EAPDException); + EFax = class(EAPDException); + ETapi = class(EAPDException); + ERas = class(EAPDException); + EAdTerminal = class(EAPDException); + EXML = class(EAPDException); + EStateMachine = class(EAPDException); + + {Specific general exceptions} + EBadArgument = class(EGeneral); + EGotQuitMsg = class(EGeneral); + EBufferTooBig = class(EGeneral); + EPortNotAssigned = class(EGeneral); + EInternal = class(EGeneral); + EModemNotAssigned = class(EGeneral); + EPhonebookNotAssigned = class(EGeneral); + ECannotUseWithWinSock = class(EGeneral); + + {Specific OpenComm exceptions} + EBadId = class(EOpenComm); + EBaudRate = class(EOpenComm); + EByteSize = class(EOpenComm); + EDefault = class(EOpenComm); + EHardware = class(EOpenComm); + EMemory = class(EOpenComm); + ECommNotOpen = class(EOpenComm); + EAlreadyOpen = class(EOpenComm); + ENoHandles = class(EOpenComm); + ENoTimers = class(EOpenComm); + ENoPortSelected = class(EOpenComm); + ENotOpenedByTapi = class(EOpenComm); + + {Specific serial I/O exceptions} + ENullApi = class(ESerialIO); + ERegisterHandlerFailed= class(ESerialIO); + EPutBlockFail = class(ESerialIO); + EGetBlockFail = class(ESerialIO); + EOutputBufferTooSmall = class(ESerialIO); + EBufferIsEmpty = class(ESerialIO); + ETracingNotEnabled = class(ESerialIO); + ELoggingNotEnabled = class(ESerialIO); + EBaseAddressNotSet = class(ESerialIO); + + {Specific modem exceptions} + EModemNotStarted = class(EModem); + EModemBusy = class(EModem); + EModemNotDialing = class(EModem); + EModemNotResponding = class(EModem); + EModemRejectedCommand = class(EModem); + EModemStatusMismatch = class(EModem); + + {Specific dialer exceptions} + EAlreadyDialing = class(EModem); + ENotDialing = class(EModem); + + EDeviceNotSelected = class(EModem); + EModemDetectedBusy = class(EModem); + ENoDialtone = class(EModem); + ENoCarrier = class(EModem); + ENoAnswer = class(EModem); + + {Specific trigger exceptions} + ENoMoreTriggers = class(ETrigger); + ETriggerTooLong = class(ETrigger); + EBadTriggerHandle = class(ETrigger); + + {Specific packet exceptions} + EInvalidProperty = class(EPacket); + EStringSizeError = class(EPacket); + + {Specific protocol exceptions} + ETimeout = class(EProtocol); + ETooManyErrors = class(EProtocol); + ESequenceError = class(EProtocol); + + {Specific INI database exceptions} + EKeyTooLong = class(EINI); + EDataTooLarge = class(EINI); + EIniWrite = class(EINI); + EIniRead = class(EINI); + ERecordExists = class(EINI); + ERecordNotFound = class(EINI); + EDatabaseFull = class(EINI); + EDatabaseEmpty = class(EINI); + EBadFieldList = class(EINI); + EBadFieldForIndex = class(EINI); + + {.Z+} + {Specific FAX exceptions} + EFaxBadFormat = class(EFax); + EBadGraphicsFormat = class(EFax); + EConvertAbort = class(EFax); + EUnpackAbort = class(EFax); + ECantMakeBitmap = class(EFax); + ENoImageLoaded = class(EFax); + ENoImageBlockMarked = class(EFax); + EInvalidPageNumber = class(EFax); + + EFaxBadMachine = class(EFax); + EFaxBadModemResult = class(EFax); + EFaxTrainError = class(EFax); + EFaxInitError = class(EFax); + EFaxBusy = class(EFax); + EFaxVoiceCall = class(EFax); + EFaxDataCall = class(EFax); + EFaxNoDialTone = class(EFax); + EFaxNoCarrier = class(EFax); + EFaxSessionError = class(EFax); + EFaxPageError = class(EFax); + + EAlreadyMonitored = class(EFax); + + ETapiAllocated = class(ETapi); + ETapiBadDeviceID = class(ETapi); + ETapiBearerModeUnavail = class(ETapi); + ETapiCallUnavail = class(ETapi); + ETapiCompletionOverrun = class(ETapi); + ETapiConferenceFull = class(ETapi); + ETapiDialBilling = class(ETapi); + ETapiDialDialtone = class(ETapi); + ETapiDialPrompt = class(ETapi); + ETapiDialQuiet = class(ETapi); + ETapiIncompatibleApiVersion = class(ETapi); + ETapiIncompatibleExtVersion = class(ETapi); + ETapiIniFileCorrupt = class(ETapi); + ETapiInUse = class(ETapi); + ETapiInvalAddress = class(ETapi); + ETapiInvalAddressID = class(ETapi); + ETapiInvalAddressMode = class(ETapi); + ETapiInvalAddressState = class(ETapi); + ETapiInvalAppHandle = class(ETapi); + ETapiInvalAppName = class(ETapi); + ETapiInvalBearerMode = class(ETapi); + ETapiInvalCallComplMode = class(ETapi); + ETapiInvalCallHandle = class(ETapi); + ETapiInvalCallParams = class(ETapi); + ETapiInvalCallPrivilege = class(ETapi); + ETapiInvalCallSelect = class(ETapi); + ETapiInvalCallState = class(ETapi); + ETapiInvalCallStatelist = class(ETapi); + ETapiInvalCard = class(ETapi); + ETapiInvalCompletionID = class(ETapi); + ETapiInvalConfCallHandle = class(ETapi); + ETapiInvalConsultCallHandle = class(ETapi); + ETapiInvalCountryCode = class(ETapi); + ETapiInvalDeviceClass = class(ETapi); + ETapiInvalDeviceHandle = class(ETapi); + ETapiInvalDialParams = class(ETapi); + ETapiInvalDigitList = class(ETapi); + ETapiInvalDigitMode = class(ETapi); + ETapiInvalDigits = class(ETapi); + ETapiInvalExtVersion = class(ETapi); + ETapiInvalGroupID = class(ETapi); + ETapiInvalLineHandle = class(ETapi); + ETapiInvalLineState = class(ETapi); + ETapiInvalLocation = class(ETapi); + ETapiInvalMediaList = class(ETapi); + ETapiInvalMediaMode = class(ETapi); + ETapiInvalMessageID = class(ETapi); + ETapiInvalParam = class(ETapi); + ETapiInvalParkID = class(ETapi); + ETapiInvalParkMode = class(ETapi); + ETapiInvalPointer = class(ETapi); + ETapiInvalPrivSelect = class(ETapi); + ETapiInvalRate = class(ETapi); + ETapiInvalRequestMode = class(ETapi); + ETapiInvalTerminalID = class(ETapi); + ETapiInvalTerminalMode = class(ETapi); + ETapiInvalTimeout = class(ETapi); + ETapiInvalTone = class(ETapi); + ETapiInvalToneList = class(ETapi); + ETapiInvalToneMode = class(ETapi); + ETapiInvalTransferMode = class(ETapi); + ETapiLineMapperFailed = class(ETapi); + ETapiNoConference = class(ETapi); + ETapiNoDevice = class(ETapi); + ETapiNoDriver = class(ETapi); + ETapiNoMem = class(ETapi); + ETapiNoRequest = class(ETapi); + ETapiNotOwner = class(ETapi); + ETapiNotRegistered = class(ETapi); + ETapiOperationFailed = class(ETapi); + ETapiOperationUnavail = class(ETapi); + ETapiRateUnavail = class(ETapi); + ETapiResourceUnavail = class(ETapi); + ETapiRequestOverrun = class(ETapi); + ETapiStructureTooSmall = class(ETapi); + ETapiTargetNotFound = class(ETapi); + ETapiTargetSelf = class(ETapi); + ETapiUninitialized = class(ETapi); + ETapiUserUserInfoTooBig = class(ETapi); + ETapiReinit = class(ETapi); + ETapiAddressBlocked = class(ETapi); + ETapiBillingRejected = class(ETapi); + ETapiInvalFeature = class(ETapi); + ETapiNoMultipleInstance = class(ETapi); + + {Tapi exceptions that don't simply mirror TAPI error codes} + ETapiBusy = class(ETapi); + ETapiNotSet = class(ETapi); + ETapiNoSelect = class(ETapi); + ETapiLoadFail = class(ETapi); + ETapiGetAddrFail = class(ETapi); + ETapiUnexpected = class(ETapi); + ETapiVoiceNotSupported = class(ETapi); + ETapiWaveFail = class(ETapi); + ETapiTranslateFail = class(ETapi); + + {VoIP specific errors} + EVoIPNotSupported = class(ETapi); + + {Ras exceptions} + ERasLoadFail = class(ERas); + + {Terminal exceptions} + EAdTerminalClass = class of EAdTerminal; + EAdTermRangeError = class(EAdTerminal); + EAdTermInvalidParameter = class(EAdTerminal); + EAdTermTooLarge = class(EAdTerminal); + + {TApdPager Exceptions} + {$M+} + EApdPagerException = class (Exception) + private + FErrorCode : Integer; + public + { Parameters to the construtor are reversed to prevent problems with + C++ Builder } + constructor Create (const ErrCode : Integer; const Msg : string); + published + property ErrorCode : Integer read FErrorCode; + end; + {$M-} + + {TApdGSMPhone Exceptions} + {$M+} + EApdGSMPhoneException = class (Exception) + private + FErrorCode : Integer; + public + { Parameters to the construtor are reversed to prevent problems with + C++ Builder } + constructor Create (const ErrCode : Integer; const Msg : string); + published + property ErrorCode : Integer read FErrorCode; + end; + {$M-} + + { XML exceptions } + {$M+} + EAdStreamError = class(EXML) + private + seFilePos : Integer; + public + constructor CreateError(const FilePos : Integer; + const Reason : DOMString); + property FilePos : Integer + read seFilePos; + end; + {$M-} + + EAdFilterError = class(EAdStreamError) + private + feReason : DOMString; + feLine : Integer; + feLinePos : Integer; + public + constructor CreateError(const FilePos, Line, LinePos : Integer; + const Reason : DOMString); + property Reason : DOMString + read feReason; + property Line : Integer + read feLine; + property LinePos : Integer + read feLinePos; + end; + + EAdParserError = class(EAdFilterError) + protected + public + constructor CreateError(Line, LinePos : Integer; + const Reason : DOMString); + end; + + function CheckException(const Ctl : TComponent; + const Res : Integer) : Integer; + function XlatException(const E : Exception) : Integer; + {-Translate an exception into an error code} + + function AproLoadStr(const ErrorCode : SmallInt) : string; + function AproLoadAnsiStr(const ErrorCode : SmallInt) : AnsiString; + + function AproLoadZ(P : PAnsiChar; Code : Integer) : PAnsiChar; // --sm ansi + + function ErrorMsg(const ErrorCode : SmallInt) : string; + function MessageNumberToString(MessageNumber : SmallInt) : string; + {.Z-} + + +implementation + +{ include AdStrMap here to prevent circular references in AdStrMap } +uses + AnsiStrings, AdStrMap; + + function AproLoadZ(P : PAnsiChar; Code : Integer) : PAnsiChar; + begin + Result := AnsiStrings.StrPCopy(P, AproLoadAnsiStr(Code)); + end; + + function AproLoadStr(const ErrorCode : SmallInt) : string; + {-Return an error message for ErrorCode} + begin + Result := MessageNumberToString(ErrorCode); + + if Result = '' then + Result := SysErrorMessage(ErrorCode); + end; + + function AproLoadAnsiStr(const ErrorCode : SmallInt) : AnsiString; + begin + Result := AnsiString(AproLoadStr(ErrorCode)); + end; + + {Alias for function above} + function ErrorMsg(const ErrorCode : SmallInt) : string; + {-Return an error message for ErrorCode} + begin + Result := AproLoadStr(ErrorCode); + end; + + function MessageNumberToString(MessageNumber : SmallInt) : string; + var + Middle : integer; + Min : integer; + Max : integer; + begin + Result := ''; + + Min := 0; + Max := AdMaxMessages; + MessageNumber := abs(MessageNumber); + while (Min <= Max) do begin + Middle := Round ((Min + Max) / 2); + if abs(AdMessageNumberLookup[Middle].MessageNumber) = abs(MessageNumber) then begin + { found it } + Result := AdMessageNumberLookup[Middle].MessageString; + Exit; + end else if abs(MessageNumber) < abs(AdMessageNumberLookup[Middle].MessageNumber) then + Max := Middle - 1 + else + Min := Middle + 1; + end; + + end; + + constructor EAPDException.Create(const EC : Integer; PassThru : Boolean); + begin + FErrorCode := EC; + inherited Create(AproLoadStr(Abs(EC))); + end; + + constructor EAPDException.CreateUnknown(const Msg : String; Dummy : Byte); + begin + ErrorCode := 0; + + inherited Create(Msg); + end; + + class function EAPDException.MapCodeToStringID(const Code : Integer) : Word; + begin + Result := Abs(Code); + end; + + function CheckException(const Ctl : TComponent; const Res : Integer) : Integer; + {-Check Res, raise appropriate exception if non-zero} + var + ErrorMsg : String; + FileIO : EInOutError; + + begin + Result := Res; + if (Res < ecOk) then + if not (csLoading in Ctl.ComponentState) then begin + case Res of + ecHardwareFailure..ecFileNotFound: + begin + {find the error message for the error} + ErrorMsg := AproLoadStr(Abs(Res)); + + {if we've run out of memory, raise that exception} + if (Res = ecOutOfMemory) then + OutOfMemoryError + + {otherwise, raise a file I/O exception} + else begin + FileIO := EInOutError.Create(ErrorMsg); + FileIO.ErrorCode := Abs(Res); + raise FileIO; + end; + end; + + {EGeneral} + ecBadArgument : raise EBadArgument.Create(Res, False); + ecGotQuitMsg : raise EGotQuitMsg.Create(Res, False); + ecBufferTooBig : raise EBufferTooBig.Create(Res, False); + ecPortNotAssigned : raise EPortNotAssigned.Create(Res, False); + ecInternal, + ecNoFieldsDefined, + ecNoIndexKey, + ecDatabaseNotPrepared : raise EInternal.Create(Res, False); + ecModemNotAssigned : raise EModemNotAssigned.Create(Res, False); + ecPhonebookNotAssigned : raise EPhonebookNotAssigned.Create(Res, False); + ecCannotUseWithWinSock : raise ECannotUseWithWinsock.Create(Res, False); + + {EOpenComm} + ecBadId : raise EBadId.Create(Res, False); + ecBaudRate : raise EBaudRate.Create(Res, False); + ecByteSize : raise EByteSize.Create(Res, False); + ecDefault : raise EDefault.Create(Res, False); + ecHardware : raise EHardware.Create(Res, False); + ecMemory : raise EMemory.Create(Res, False); + ecCommNotOpen : raise ECommNotOpen.Create(Res, False); + ecAlreadyOpen : raise EAlreadyOpen.Create(Res, False); + ecNoHandles : raise ENoHandles.Create(Res, False); + ecNoTimers : raise ENoTimers.Create(Res, False); + ecNoPortSelected : raise ENoPortSelected.Create(Res, False); + ecNotOpenedByTapi : raise ENotOpenedByTapi.Create(Res, False); + + {ESerialIO} + ecNullApi : raise ENullApi.Create(Res, False); + ecRegisterHandlerFailed : raise ERegisterHandlerFailed.Create(Res, False); + ecPutBlockFail : raise EPutBlockFail.Create(Res, False); + ecGetBlockFail : raise EGetBlockFail.Create(Res, False); + ecOutputBufferTooSmall : raise EOutputBufferTooSmall.Create(Res, False); + ecBufferIsEmpty : raise EBufferIsEmpty.Create(Res, False); + ecTracingNotEnabled : raise ETracingNotEnabled.Create(Res, False); + ecLoggingNotEnabled : raise ELoggingNotEnabled.Create(Res, False); + ecBaseAddressNotSet : raise EBaseAddressNotSet.Create(Res, False); + + {EModem} + ecModemNotStarted : raise EModemNotStarted.Create(Res, False); + ecModemBusy : raise EModemBusy.Create(Res, False); + ecModemNotDialing : raise EModemNotDialing.Create(Res, False); + ecNotDialing : raise ENotDialing.Create(Res, False); + ecAlreadyDialing : raise EAlreadyDialing.Create(Res, False); + ecModemNotResponding : raise EModemNotResponding.Create(Res, False); + ecModemRejectedCommand : raise EModemRejectedCommand.Create(Res, False); + ecModemStatusMismatch : raise EModemStatusMismatch.Create(Res, False); + + {ETrigger} + ecNoMoreTriggers : raise ENoMoreTriggers.Create(Res, False); + ecTriggerTooLong : raise ETriggerTooLong.Create(Res, False); + ecBadTriggerHandle : raise EBadTriggerHandle.Create(Res, False); + + {EProtocol} + ecTimeout : raise EProtocol.Create(Res, False); + ecTooManyErrors : raise EProtocol.Create(Res, False); + ecSequenceError : raise EProtocol.Create(Res, False); + + {EIni} + ecKeyTooLong : raise EKeyTooLong.Create(Res, False); + ecDataTooLarge : raise EDataTooLarge.Create(Res, False); + ecIniWrite : raise EIniWrite.Create(Res, False); + ecIniRead : raise EIniRead.Create(Res, False); + ecRecordExists : raise ERecordExists.Create(Res, False); + ecRecordNotFound : raise ERecordNotFound.Create(Res, False); + ecDatabaseFull : raise EDatabaseFull.Create(Res, False); + ecDatabaseEmpty : raise EDatabaseEmpty.Create(Res, False); + ecBadFieldList : raise EBadFieldList.Create(Res, False); + ecBadFieldForIndex : raise EBadFieldForIndex.Create(Res, False); + + {EFax} + ecFaxBadFormat : raise EFaxBadFormat.Create(Res, False); + ecBadGraphicsFormat : raise EBadGraphicsFormat.Create(Res, False); + ecConvertAbort : raise EConvertAbort.Create(Res, False); + ecUnpackAbort : raise EUnpackAbort.Create(Res, False); + ecCantMakeBitmap : raise ECantMakeBitmap.Create(Res, False); + ecInvalidPageNumber : raise EInvalidPageNumber.Create(Res, False); + + ecFaxBadMachine : raise EFaxBadMachine.Create(Res, False); + ecFaxBadModemResult : raise EFaxBadModemResult.Create(Res, False); + ecFaxTrainError : raise EFaxTrainError.Create(Res, False); + ecFaxInitError : raise EFaxInitError.Create(Res, False); + ecFaxBusy : raise EFaxBusy.Create(Res, False); + ecFaxVoiceCall : raise EFaxVoiceCall.Create(Res, False); + ecFaxDataCall : raise EFaxDataCall.Create(Res, False); + ecFaxNoDialTone : raise EFaxNoDialTone.Create(Res, False); + ecFaxNoCarrier : raise EFaxNoCarrier.Create(Res, False); + ecFaxSessionError : raise EFaxSessionError.Create(Res, False); + ecFaxPageError : raise EFaxPageError.Create(Res, False); + + ecAllocated : raise ETapiAllocated.Create(Res, False); + ecBadDeviceID : raise ETapiBadDeviceID.Create(Res, False); + ecBearerModeUnavail : raise ETapiBearerModeUnavail.Create(Res, False); + ecCallUnavail : raise ETapiCallUnavail.Create(Res, False); + ecCompletionOverrun : raise ETapiCompletionOverrun.Create(Res, False); + ecConferenceFull : raise ETapiConferenceFull.Create(Res, False); + ecDialBilling : raise ETapiDialBilling.Create(Res, False); + ecDialDialtone : raise ETapiDialDialtone.Create(Res, False); + ecDialPrompt : raise ETapiDialPrompt.Create(Res, False); + ecDialQuiet : raise ETapiDialQuiet.Create(Res, False); + ecIncompatibleApiVersion: raise ETapiIncompatibleApiVersion.Create(Res, False); + ecIncompatibleExtVersion: raise ETapiIncompatibleExtVersion.Create(Res, False); + ecIniFileCorrupt : raise ETapiIniFileCorrupt.Create(Res, False); + ecInUse : raise ETapiInUse.Create(Res, False); + ecInvalAddress : raise ETapiInvalAddress.Create(Res, False); + ecInvalAddressID : raise ETapiInvalAddressID.Create(Res, False); + ecInvalAddressMode : raise ETapiInvalAddressMode.Create(Res, False); + ecInvalAddressState : raise ETapiInvalAddressState.Create(Res, False); + ecInvalAppHandle : raise ETapiInvalAppHandle.Create(Res, False); + ecInvalAppName : raise ETapiInvalAppName.Create(Res, False); + ecInvalBearerMode : raise ETapiInvalBearerMode.Create(Res, False); + ecInvalCallComplMode : raise ETapiInvalCallComplMode.Create(Res, False); + ecInvalCallHandle : raise ETapiInvalCallHandle.Create(Res, False); + ecInvalCallParams : raise ETapiInvalCallParams.Create(Res, False); + ecInvalCallPrivilege : raise ETapiInvalCallPrivilege.Create(Res, False); + ecInvalCallSelect : raise ETapiInvalCallSelect.Create(Res, False); + ecInvalCallState : raise ETapiInvalCallState.Create(Res, False); + ecInvalCallStatelist : raise ETapiInvalCallStatelist.Create(Res, False); + ecInvalCard : raise ETapiInvalCard.Create(Res, False); + ecInvalCompletionID : raise ETapiInvalCompletionID.Create(Res, False); + ecInvalConfCallHandle : raise ETapiInvalConfCallHandle.Create(Res, False); + ecInvalConsultCallHandle: raise ETapiInvalConsultCallHandle.Create(Res, False); + ecInvalCountryCode : raise ETapiInvalCountryCode.Create(Res, False); + ecInvalDeviceClass : raise ETapiInvalDeviceClass.Create(Res, False); + ecInvalDeviceHandle : raise ETapiInvalDeviceHandle.Create(Res, False); + ecInvalDialParams : raise ETapiInvalDialParams.Create(Res, False); + ecInvalDigitList : raise ETapiInvalDigitList.Create(Res, False); + ecInvalDigitMode : raise ETapiInvalDigitMode.Create(Res, False); + ecInvalDigits : raise ETapiInvalDigits.Create(Res, False); + ecInvalExtVersion : raise ETapiInvalExtVersion.Create(Res, False); + ecInvalGroupID : raise ETapiInvalGroupID.Create(Res, False); + ecInvalLineHandle : raise ETapiInvalLineHandle.Create(Res, False); + ecInvalLineState : raise ETapiInvalLineState.Create(Res, False); + ecInvalLocation : raise ETapiInvalLocation.Create(Res, False); + ecInvalMediaList : raise ETapiInvalMediaList.Create(Res, False); + ecInvalMediaMode : raise ETapiInvalMediaMode.Create(Res, False); + ecInvalMessageID : raise ETapiInvalMessageID.Create(Res, False); + ecInvalParam : raise ETapiInvalParam.Create(Res, False); + ecInvalParkID : raise ETapiInvalParkID.Create(Res, False); + ecInvalParkMode : raise ETapiInvalParkMode.Create(Res, False); + ecInvalPointer : raise ETapiInvalPointer.Create(Res, False); + ecInvalPrivSelect : raise ETapiInvalPrivSelect.Create(Res, False); + ecInvalRate : raise ETapiInvalRate.Create(Res, False); + ecInvalRequestMode : raise ETapiInvalRequestMode.Create(Res, False); + ecInvalTerminalID : raise ETapiInvalTerminalID.Create(Res, False); + ecInvalTerminalMode : raise ETapiInvalTerminalMode.Create(Res, False); + ecInvalTimeout : raise ETapiInvalTimeout.Create(Res, False); + ecInvalTone : raise ETapiInvalTone.Create(Res, False); + ecInvalToneList : raise ETapiInvalToneList.Create(Res, False); + ecInvalToneMode : raise ETapiInvalToneMode.Create(Res, False); + ecInvalTransferMode : raise ETapiInvalTransferMode.Create(Res, False); + ecLineMapperFailed : raise ETapiLineMapperFailed.Create(Res, False); + ecNoConference : raise ETapiNoConference.Create(Res, False); + ecNoDevice : raise ETapiNoDevice.Create(Res, False); + ecNoDriver : raise ETapiNoDriver.Create(Res, False); + ecNoMem : raise ETapiNoMem.Create(Res, False); + ecNoRequest : raise ETapiNoRequest.Create(Res, False); + ecNotOwner : raise ETapiNotOwner.Create(Res, False); + ecNotRegistered : raise ETapiNotRegistered.Create(Res, False); + ecOperationFailed : raise ETapiOperationFailed.Create(Res, False); + ecOperationUnavail : raise ETapiOperationUnavail.Create(Res, False); + ecRateUnavail : raise ETapiRateUnavail.Create(Res, False); + ecResourceUnavail : raise ETapiResourceUnavail.Create(Res, False); + ecRequestOverrun : raise ETapiRequestOverrun.Create(Res, False); + ecStructureTooSmall : raise ETapiStructureTooSmall.Create(Res, False); + ecTargetNotFound : raise ETapiTargetNotFound.Create(Res, False); + ecTargetSelf : raise ETapiTargetSelf.Create(Res, False); + ecUninitialized : raise ETapiUninitialized.Create(Res, False); + ecUserUserInfoTooBig : raise ETapiUserUserInfoTooBig.Create(Res, False); + ecReinit : raise ETapiReinit.Create(Res, False); + ecAddressBlocked : raise ETapiAddressBlocked.Create(Res, False); + ecBillingRejected : raise ETapiBillingRejected.Create(Res, False); + ecInvalFeature : raise ETapiInvalFeature.Create(Res, False); + ecNoMultipleInstance : raise ETapiNoMultipleInstance.Create(Res, False); + ecTapiBusy : raise ETapiBusy.Create(Res, False); + ecTapiNotSet : raise ETapiNotSet.Create(Res, False); + ecTapiNoSelect : raise ETapiNoSelect.Create(Res, False); + ecTapiLoadFail : raise ETapiLoadFail.Create(Res, False); + ecTapiGetAddrFail : raise ETapiGetAddrFail.Create(Res, False); + ecTapiVoiceNotSupported : raise ETapiVoiceNotSupported.Create(Res, False); + ecTapiWaveFail : raise ETapiWaveFail.Create(Res, False); + ecTapiTranslateFail : raise ETapiTranslateFail.Create(Res, False); + + {ERas} + ecRasLoadFail : raise ERasLoadFail.Create(Res, False); + + {Couldn't find error message} + else raise EAPDException.CreateUnknown('Apro exception', 0); + end; + end; + end; + + function XlatException(const E : Exception) : Integer; + {-Translate an exception into an error code} + begin + if (E is EApdException) then + Result := EApdException(E).ErrorCode + else if (E is EInOutError) then + Result := -EInOutError(E).ErrorCode + else if (E is EOutOfMemory) then + Result := ecOutOfMemory + else + Result := -9999; + end; + +{ EAdStreamError } + +constructor EAdStreamError.CreateError(const FilePos: Integer; + const Reason: DOMString); +begin + inherited CreateUnknown(Reason, 0); + seFilePos := FilePos; +end; + +{ EAdFilterError } + +constructor EAdFilterError.CreateError(const FilePos, Line, + LinePos: Integer; const Reason: DOMString); +begin + inherited CreateError(FilePos, Reason); + + feLine := Line; + feLinePos := LinePos; + feReason := Reason; +end; + +{ EAdParserError } + +constructor EAdParserError.CreateError(Line, LinePos: Integer; + const Reason: DOMString); +begin + inherited CreateError(FilePos, Line, LinePos, Reason); +end; + +{ EApdGSMPhoneException } + +constructor EApdGSMPhoneException.Create(const ErrCode: Integer; + const Msg: string); +begin + inherited Create (Msg); + + FErrorCode := ErrCode; +end; + +{ EApdPagerException } + +constructor EApdPagerException.Create(const ErrCode: Integer; + const Msg: string); +begin + inherited Create (Msg); + + FErrorCode := ErrCode; +end; + +end. diff --git a/AdPort.pas b/AdPort.pas new file mode 100644 index 0000000..ecde003 --- /dev/null +++ b/AdPort.pas @@ -0,0 +1,3016 @@ +(***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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 TurboPower Async Professional + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1991-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Stephen W Boyd - Introduced a new log/trace state, tlAppendAndContinue + * September 2005 which appends the current contents of the trace / + * log buffer to the given file and leaves the log / + * trace in the state which it was in before setting + * the state to tlAppendAndContinue. This allows + * you to flush the buffer to disk without having + * to issue a Logging := tlAppend followed by + * Logging := tlOn. This also closes a timing window + * where log entries could be lost between setting + * Logging to tlAppend and then tlOn. + * Sebastian Zierer + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* ADPORT.PAS 5.00 *} +{*********************************************************} +{* TApdComPort component *} +{*********************************************************} + +{ + This unit defines the TApdCustomComPort and TApdComPort components. Both + of these are interfaces to the dispatcher, which is what does the actual + port communication. The base dispatcher is defined in AwUser.pas, serial + port dispatcher (Win32) is in AwWin32.pas, Winsock dispatcher is in + AwWnSock.pas The term dispatcher is used for the code that interfaces with + the device. +} + +{Global defines potentially affecting this unit} +{$I AWDEFINE.INC} + +{Options required for this unit} +{$G+,X+,F+. $J+} + +{$C MOVEABLE,DEMANDLOAD,DISCARDABLE} + +{!!.02} { removed Win16 references } +unit AdPort; + {-Delphi serial port component} + +interface + +uses + Windows, + SysUtils, + Classes, + Messages, + Controls, + Forms, + OoMisc, + AwUser, +{$IFNDEF UseAwWin32} + LnsWin32, +{$ELSE} + AwWin32, +{$ENDIF} + AdExcept, + AdSelCom; + +type + {Parity type} + TParity = (pNone, pOdd, pEven, pMark, pSpace); + + {Activation procedure type} + TActivationProcedure = function(Owner : TObject) : TApdBaseDispatcher; + + {Device layer types} + TDeviceLayer = (dlWin32, dlWinsock); + + TDeviceLayers = set of TDeviceLayer; + + {Baud type} + TBaudRate = Integer; + + {Tapi modes} + TTapiMode = (tmNone, tmAuto, tmOn, tmOff); + + {Port state} + TPortState = (psClosed, psShuttingDown, psOpen); + + {Hardware flow control types} + THWFlowOptions = ( + hwfUseDTR, {Use DTR for receive flow control} + hwfUseRTS, {Use RTS for receive flow control} + hwfRequireDSR, {Require DSR before transmitting} + hwfRequireCTS); {Require CTS before transmitting} + + THWFlowOptionSet = set of THWFlowOptions; + + {Software flow control types} + TSWFlowOptions = (swfNone, swfReceive, swfTransmit, swfBoth); + + {For reporting flow states, note: no rcv hardware flow status is provided} + TFlowControlState = (fcOff, {No flow control is in use} + fcOn, {Transmit blocked} + fcDsrHold, {Transmit blocked by low DSR} + fcCtsHold, {Transmit blocked by low CTS} + fcDcdHold, {Transmit blocked by low DCD} + fcXOutHold, {Transmit blocked by Xoff} + fcXInHold, {Receive blocked by Xoff} + fcXBothHold); {Both are blocked by Xoff} + + {Tracing/logging states} + TTraceLogState = (tlOff, tlOn, tlDump, tlAppend, tlClear, tlPause, // SWB + tlAppendAndContinue); // SWB + + {General trigger event handler} + TTriggerEvent = procedure(CP : TObject; + Msg, TriggerHandle, Data : Word) of object; + + {Specific trigger event handlers} + TTriggerAvailEvent = procedure(CP : TObject; Count : Word) of object; + TTriggerDataEvent = procedure(CP : TObject; TriggerHandle : Word) of object; + TTriggerStatusEvent = procedure(CP : TObject; + TriggerHandle : Word) of object; + TTriggerTimerEvent = procedure(CP : TObject; TriggerHandle : Word) of object; + + {Status event handlers} + TTriggerLineErrorEvent = procedure(CP : TObject; + Error : Word; + LineBreak : Boolean) of object; + + {WaitChar event handler} + TWaitCharEvent = procedure(CP : TObject; C : AnsiChar) of object; + + + {Port open/close callbacks} + TPortCallback = procedure(CP : TObject; Opening : Boolean) of object; + + {Extended port open/closing/close callbacks} {!!.03} + TApdCallbackType = (ctOpen, ctClosing, ctClosed); + TPortCallbackEx = procedure(CP : TObject; CallbackType : TApdCallbackType) of object; + + {For keeping track of port users} + PUserListEntry = ^TUserListEntry; + TUserListEntry = record + Handle : THandle; + OpenClose : TPortCallback; + OpenCloseEx: TPortCallbackEx; {!!.03} + IsEx : Boolean; {!!.03} + end; + + TApThreadBoost = (tbNone, tbPlusOne, tbPlusTwo); + +const + {Parity strings} + ParityName : array[TParity] of string[5] = + ('None', 'Odd', 'Even', 'Mark', 'Space'); + + {Property defaults} + adpoDefDeviceLayer = dlWin32; + adpoDefPromptForPort = True; + adpoDefComNumber = 0; + adpoDefBaudRt = 19200; + adpoDefParity = pNone; + adpoDefDatabits = 8; + adpoDefStopbits = 1; + adpoDefInSize = 4096; + adpoDefOutSize = 4096; + adpoDefOpen = False; + adpoDefAutoOpen = True; + adpoDefBaseAddress = 0; + adpoDefTapiMode = tmAuto; + adpoDefDTR = True; + adpoDefRTS = True; + adpoDefTracing = tlOff; + adpoDefTraceSize = 10000; + adpoDefTraceName = 'APRO.TRC'; + adpoDefTraceHex = True; + adpoDefTraceAllHex = False; + adpoDefLogging = tlOff; + adpoDefLogSize = 10000; + adpoDefLogName = 'APRO.LOG'; + adpoDefLogHex = True; + adpoDefLogAllHex = False; + adpoDefUseMSRShadow = True; + adpoDefUseEventWord = True; + adpoDefSWFlowOptions = swfNone; + adpoDefXonChar = #17; + adpoDefXoffChar = #19; + adpoDefBufferFull = 0; + adpoDefBufferResume = 0; + adpoDefTriggerLength = 1; + adpoDefCommNotificationLevel = 10; + adpoDefRS485Mode = False; + +type + {Port component} + TApdCustomComPort = class(TApdBaseComponent) + private + function GetLastWinError: Integer; // SWB + protected {private} + {.Z+} + {Internal stuff} + Force : Boolean; {True to force property setting} + PortState : TPortState; {State of the physical port/dispatcher} + OpenPending : Boolean; {True if Open := True while shutting down} + ForceOpen : Boolean; {Force open after loading} + UserList : TList; {List of comport users} + CopyTriggers : Boolean; {Copy triggers on open} + SaveTriggerBuffer: TTriggerSave; {Triggers to copy} + BusyBeforeWait : Boolean; {True if EventBusy before Wait} + WaitPrepped : Boolean; {True if PrepareWait called} + fComWindow : THandle; {Hidden window handle} + fCustomDispatcher: TActivationProcedure;{Custom device layer activation} + FMasterTerminal : TWinControl; {The terminal that replies to requests} + + {Port info} + FDeviceLayer : TDeviceLayer; {Device layer for this port} + FDeviceLayers : TDeviceLayers; + FDispatcher : TApdBaseDispatcher; {Handle to comm object} + FComNumber : Word; {Com1 - ComWhatever} + FBaud : Integer; {Baud rate} + FParity : TParity; {Parity} + FDatabits : Word; {Data bits} + FStopbits : Word; {Stop bits} + FInSize : Word; {Input buffer size} + FOutSize : Word; {Output buffer size} + FOpen : Boolean; {True if the port is open} + FPromptForPort : Boolean; + {True to display the com port selection dialog if no port is selected} + FAutoOpen : Boolean; {True to do implicit opens} + FCommNotificationLevel : Word; {Comm notify level} + FTapiCid : Word; {Cid from TAPI} + FTapiMode : TTapiMode; {True if using TAPI} + FRS485Mode : Boolean; {True if in RS485 mode} + FThreadBoost : TApThreadBoost; {Boost for dispatcher threads} + + {Modem control/status} + FDTR : Boolean; {DTR control state} + FRTS : Boolean; {RTS control state} + + {Flow control} + FBufferFull : Word; {Flow control cutoff} + FBufferResume : Word; {Flow control resume} + FHWFlowOptions : THWFlowOptionSet; {Hardware flow control} + FSWFlowOptions : TSWFlowOptions; {Software flow control} + FXOnChar : AnsiChar; {Xon character} + FXOffChar : AnsiChar; {Xoff character} + + {Debugging} + FTracing : TTraceLogState; {Controls Tracing state} + FTraceSize : Cardinal; {Number of tracing entries} + FTraceName : string; {Name of trace file} + FTraceHex : Boolean; {True to dump trace non-printables in hex} + FTraceAllHex : Boolean; {True to dump all trace chars in hex} + FLogging : TTraceLogState; {Controls DispatchLogging state} + FLogSize : Cardinal; {Size, in bytes, of log buffer} + FLogName : string; {Name of log file} + FLogHex : Boolean; {True to dump log non-printables in hex} + FLogAllHex : Boolean; {True to dump all log chars in hex} + + {Options} + FUseMSRShadow : Boolean; {True to use MSR shadow reg} + FUseEventWord : Boolean; {True to use the EventWord} + + {Triggers} + FTriggerLength : Word; {Number of bytes for avail trigger} + + FOnTrigger : TTriggerEvent; {All-encompassing event handler} + FOnTriggerAvail : TTriggerAvailEvent; {APW_TRIGGERAVAIL events} + FOnTriggerData : TTriggerDataEvent; {APW_TRIGGERDATA events} + FOnTriggerStatus : TTriggerStatusEvent; {APW_TRIGGERSTATUS events} + FOnTriggerTimer : TTriggerTimerEvent; {APW_TRIGGERTIMER events} + FOnTriggerLineError : TTriggerLineErrorEvent; {Got line error} + FOnTriggerModemStatus : TNotifyEvent; {Got modem status change} + FOnTriggerOutbuffFree : TNotifyEvent; {Outbuff free above mark} + FOnTriggerOutbuffUsed : TNotifyEvent; {Outbuff used above mark} + FOnTriggerOutSent : TNotifyEvent; {Data was transmitted} + + FOnPortOpen : TNotifyEvent; {Port just opened} + FOnPortClose : TNotifyEvent; {Port just closed} + FOnWaitChar : TWaitCharEvent; {Received char during wait} + + {Property read/write methods} + procedure SetDeviceLayer(const NewDevice : TDeviceLayer); + procedure SetComNumber(const NewNumber : Word); + procedure SetBaud(const NewBaud : Integer); + procedure SetParity(const NewParity : TParity); + procedure SetDatabits(const NewBits : Word); + procedure SetStopbits(const NewBits : Word); + procedure SetInSize(const NewSize : Word); + procedure SetOutSize(const NewSize : Word); + procedure SetTracing(const NewState : TTraceLogState); + procedure SetTraceSize(const NewSize : Cardinal); + procedure SetLogging(const NewState : TTraceLogState); + procedure SetLogSize(const NewSize : Cardinal); + procedure SetOpen(const Enable : Boolean); + procedure SetHWFlowOptions(const NewOpts : THWFlowOptionSet); + function GetFlowState : TFlowControlState; + procedure SetSWFlowOptions(const NewOpts : TSWFlowOptions); + procedure SetXonChar(const NewChar : AnsiChar); + procedure SetXoffChar(const NewChar : AnsiChar); + procedure SetBufferFull(const NewFull : Word); + procedure SetBufferResume(const NewResume : Word); + procedure SetTriggerLength(const NewLength : Word); + procedure SetDTR(const NewDTR : Boolean); + procedure SetRTS(const NewRTS : Boolean); + + {Trigger write methods} + procedure SetOnTrigger(const Value : TTriggerEvent); + procedure SetOnTriggerAvail(const Value : TTriggerAvailEvent); + procedure SetOnTriggerData(const Value : TTriggerDataEvent); + procedure SetOnTriggerStatus(const Value : TTriggerStatusEvent); + procedure SetOnTriggerTimer(const Value : TTriggerTimerEvent); + procedure SetOnTriggerLineError(const Value : TTriggerLineErrorEvent); + procedure SetOnTriggerModemStatus(const Value : TNotifyEvent); + procedure SetOnTriggerOutbuffFree(const Value : TNotifyEvent); + procedure SetOnTriggerOutbuffUsed(const Value : TNotifyEvent); + procedure SetOnTriggerOutSent(const Value : TNotifyEvent); + + function GetBaseAddress : Word; + function GetDispatcher : TApdBaseDispatcher; + function GetModemStatus : Byte; + function GetDSR : Boolean; + function GetCTS : Boolean; + function GetRI : Boolean; + function GetDCD : Boolean; + function GetDeltaDSR : Boolean; + function GetDeltaCTS : Boolean; + function GetDeltaRI : Boolean; + function GetDeltaDCD : Boolean; + function GetLineError : Word; + function GetLineBreak : Boolean; + function GetInBuffUsed : Word; + function GetInBuffFree : Word; + function GetOutBuffUsed : Word; + function GetOutBuffFree : Word; + procedure SetUseEventWord(NewUse : Boolean); + procedure SetCommNotificationLevel(NewLevel : Word); + procedure SetRS485Mode(NewMode : Boolean); + procedure SetBaseAddress(NewBaseAddress : Word); + procedure SetThreadBoost(NewBoost : TApThreadBoost); + + protected + {Misc} + function ActivateDeviceLayer : TApdBaseDispatcher; virtual; + procedure DeviceLayerChanged; virtual; + function InitializePort : integer; virtual; + procedure Loaded; override; + procedure RegisterComPort(Enabling : Boolean); virtual; + procedure ValidateComport; virtual; + procedure SetUseMSRShadow(NewUse : Boolean); virtual; + + {Trigger event methods} + procedure Trigger(Msg, TriggerHandle, Data : Word); virtual; + procedure TriggerAvail(Count : Word); virtual; + procedure TriggerData(TriggerHandle : Word); virtual; + procedure TriggerStatus(TriggerHandle : Word); virtual; + procedure TriggerTimer(TriggerHandle : Word); virtual; + procedure UpdateHandlerFlag; virtual; + + {Port open/close/change event methods} + procedure PortOpen; dynamic; + procedure PortClose; dynamic; + procedure PortClosing; dynamic; {!!.03} + + {Status trigger methods} + procedure TriggerLineError(const Error : Word; + const LineBreak : Boolean); virtual; + procedure TriggerModemStatus; virtual; + procedure TriggerOutbuffFree; virtual; + procedure TriggerOutbuffUsed; virtual; + procedure TriggerOutSent; virtual; + + {Wait trigger method} + procedure WaitChar(C : AnsiChar); virtual; + + {Tracing} + procedure InitTracing(const NumEntries : Cardinal); + procedure DumpTrace(const FName : String; const InHex : Boolean); + procedure AppendTrace(const FName : String; // SWB + const InHex : Boolean; // SWB + const NewState : TTraceLogState); // SWB + procedure ClearTracing; + procedure AbortTracing; + procedure StartTracing; + procedure StopTracing; + + {DispatchLogging} + procedure InitLogging(const Size : Cardinal); + procedure DumpLog(const FName : string; const InHex : Boolean);// --sm check shortstring to sting + procedure AppendLog(const FName : string; // --sm check shortstring to sting // SWB + const InHex : Boolean; // SWB + const NewState : TTraceLogState); // SWB + procedure ClearLogging; + procedure AbortLogging; + procedure StartLogging; + procedure StopLogging; + + public + OverrideLine : Boolean; {True to override line parms} + {Creation/destruction} + constructor Create(AOwner : TComponent); override; + {-Create a TApdComPort component} + destructor Destroy; override; + {-Destroy a TApdComPort component} + + {General} + procedure InitPort; dynamic; + {-Physically open the serial port} + procedure DonePort; virtual; + {-Physically close the serial port} + procedure Assign(Source: TPersistent); override; + {-Assign fields from TApdComPort object specified by Source} + procedure ForcePortOpen; + {-Force the port open after it is loaded} + procedure SendBreak(Ticks : Word; Yield : Boolean); + {-Send a line break of ticks duration} + procedure SetBreak(BreakOn : Boolean); + {-Sets or clears line break condition} + + {.Z-} + procedure RegisterUser(const H : THandle); + {-Register a TApdComPort user to receive PortOpen/PortClose events} + procedure RegisterUserEx(const H : THandle); {!!.03} + {-Register a TApdComPort user to receive open/closing/close events} + procedure RegisterUserCallback(CallBack : TPortCallback); + {-Register a TApdComPort user to receive callbacks} + procedure RegisterUserCallbackEx(CallBackEx : TPortCallbackEx); {!!.03} + {-Register a TApdComPort user to receive extended callbacks} + procedure DeregisterUser(const H : THandle); + {-Deregister a TApdComPort user from receiving PortOpen/PortClose events} + procedure DeregisterUserCallback(CallBack : TPortCallback); + {-Deregister a TApdComPort user callback} + procedure DeregisterUserCallbackEx(CallBackEx : TPortCallbackEx); {!!.03} + {-Deregister a TApdComPort user callback} + + procedure ProcessCommunications; virtual; + {-Call the internal dispatcher} + procedure FlushInBuffer; + {-Discard the contents of the input buffer} + procedure FlushOutBuffer; + {-Discard the contents of the output buffer} + + {Trigger managment} + function AddDataTrigger(const Data : ShortString; + const IgnoreCase : Boolean) : Word; + {-Add a data trigger} + function AddTimerTrigger : Word; + {-Add a timer trigger} + function AddStatusTrigger(const SType : Word) : Word; + {-Add a status trigger} + procedure RemoveTrigger(const Handle : Word); + {-Remove a trigger} + procedure RemoveAllTriggers; + {-Remove all triggers} + procedure SetTimerTrigger(const Handle : Word; const Ticks : Integer; + const Activate : Boolean); + {-Activate or deactivate a timer trigger} + procedure SetStatusTrigger(const Handle : Word; const Value : Word; + const Activate : Boolean); + {-Activate or deactivate a status trigger} + + {I/O} + function CharReady : Boolean; + {-Return True if at least one character is in the input buffer} + function PeekChar(const Count : Word) : AnsiChar; + {-Return a received character other than the next one} + function GetChar : AnsiChar; + {-Return the next received character} + procedure PeekBlock(var Block; const Len : Word); + {-Return a block of data other than the next block} + + procedure GetBlock(var Block; const Len : Word); + {-Return the next block of data} + procedure PutChar(const C : AnsiChar); + {-Add C to the output buffer} + procedure PutString(const S : string); overload; + procedure PutString(const S : AnsiString); overload; + {-Add S to the output buffer} + function PutBlock(const Block; const Len : Word) : Integer; + {-Add Block to the output buffer} + + {Waits} + function CheckForString(var Index : Byte; C : AnsiChar; + const S : AnsiString; + IgnoreCase : Boolean) : Boolean; + {-Compare C against a sequence of chars, looking for S} + function WaitForString(const S : AnsiString; + const Timeout : Integer; + const Yield, IgnoreCase : Boolean) : Boolean; + {-Wait for S} + function WaitForMultiString(const S : AnsiString; const Timeout : Integer; + const Yield, IgnoreCase : Boolean; + const SepChar : AnsiChar) : Integer; + {-Wait for S, which contains several substrings separated by ^} + procedure PrepareWait; + {-Set EventBusy true to prevent triggers} + + property ComNumber : Word + read FComNumber write SetComNumber default adpoDefComNumber; + property CustomDispatcher : TActivationProcedure + read fCustomDispatcher write fCustomDispatcher; + property DeviceLayer : TDeviceLayer + read FDeviceLayer write SetDeviceLayer default adpoDefDeviceLayer; + property ComWindow : THandle + read fComWindow; + property Baud : Integer + read FBaud write SetBaud default adpoDefBaudRt; + property Parity : TParity + read FParity write SetParity default adpoDefParity; + property PromptForPort : Boolean + read FPromptForPort write FPromptForPort + default adpoDefPromptForPort; + property DataBits : Word + read FDatabits write SetDatabits default adpoDefDatabits; + property StopBits : Word + read FStopbits write SetStopbits default adpoDefStopbits; + + {Miscellaneous port properties} + property InSize : Word + read FInSize write SetInSize default adpoDefInSize; + property OutSize : Word + read FOutSize write SetOutSize default adpoDefOutSize; + property Open : Boolean + read FOpen write SetOpen default adpoDefOpen; + property AutoOpen : Boolean + read FAutoOpen write FAutoOpen default adpoDefAutoOpen; + property CommNotificationLevel : Word + read FCommNotificationLevel write SetCommNotificationLevel + default adpoDefCommNotificationLevel; + property TapiMode : TTapiMode + read FTapiMode write FTapiMode default adpoDefTapiMode; + property TapiCid : Word + read FTapiCid write FTapiCid; + property RS485Mode : Boolean + read FRS485Mode write SetRS485Mode default adpoDefRS485Mode; + property BaseAddress : Word + read GetBaseAddress write SetBaseAddress + default adpoDefBaseAddress; + property ThreadBoost : TApThreadBoost + read FThreadBoost write SetThreadBoost; + property MasterTerminal : TWinControl + read FMasterTerminal write FMasterTerminal; + + {Modem control/status} + property DTR : Boolean + read FDTR write SetDTR default adpoDefDTR; + property RTS : Boolean + read FRTS write SetRTS default adpoDefRTS; + + {Flow control properties} + property HWFlowOptions : THWFlowOptionSet + read FHWFlowOptions write SetHWFlowOptions default []; + property FlowState : TFlowControlState + read GetFlowState; + property SWFlowOptions : TSWFlowOptions + read FSWFlowOptions write SetSWFlowOptions default adpoDefSWFlowOptions; + property XOnChar : AnsiChar + read FXonChar write SetXonChar default adpoDefXOnChar; + property XOffChar : AnsiChar + read FXOffChar write SetXoffChar default adpoDefXOffChar; + property BufferFull : Word + read FBufferFull write SetBufferFull default adpoDefBufferFull; + property BufferResume : Word + read FBufferResume write SetBufferResume default adpoDefBufferResume; + + {Debugging} + property Tracing : TTraceLogState + read FTracing write SetTracing default adpoDefTracing; + property TraceSize : Cardinal + read FTraceSize write SetTraceSize default adpoDefTraceSize; + property TraceName : string + read FTraceName write FTraceName; + property TraceHex : Boolean + read FTraceHex write FTraceHex default adpoDefTraceHex; + property TraceAllHex : Boolean + read FTraceAllHex write FTraceAllHex default adpoDefTraceAllHex; + + property Logging : TTraceLogState + read FLogging write SetLogging default adpoDefLogging; + property LogSize : Cardinal + read FLogSize write SetLogSize default adpoDefLogSize; + property LogName : string + read FLogName write FLogName; + property LogHex : Boolean + read FLogHex write FLogHex default adpoDefLogHex; + property LogAllHex : Boolean + read FLogAllHex write FLogAllHex default adpoDefLogAllHex; + + {Options} + property UseMSRShadow : Boolean + read FUseMSRShadow write SetUseMSRShadow default adpoDefUseMSRShadow; + property UseEventWord : Boolean + read FUseEventWord write SetUseEventWord default adpoDefUseEventWord; + + {Tracing} + procedure AddTraceEntry(const CurEntry, CurCh : AnsiChar); + {-Add an entry to the trace buffer} + procedure AddStringToLog(S : Ansistring); + {-Add a string to the current LOG file} + + {Trigger events} + property TriggerLength : Word + read FTriggerLength write SetTriggerLength default adpoDefTriggerLength; + property OnTrigger : TTriggerEvent + read FOnTrigger write SetOnTrigger; + property OnTriggerAvail : TTriggerAvailEvent + read FOnTriggerAvail write SetOnTriggerAvail; + property OnTriggerData : TTriggerDataEvent + read FOnTriggerData write SetOnTriggerData; + property OnTriggerStatus : TTriggerStatusEvent + read FOnTriggerStatus write SetOnTriggerStatus; + property OnTriggerTimer : TTriggerTimerEvent + read FOnTriggerTimer write SetOnTriggerTimer; + + {Port open/close/change events} + property OnPortOpen : TNotifyEvent + read FOnPortOpen write FOnPortOpen; + property OnPortClose : TNotifyEvent + read FOnPortClose write FOnPortClose; + + {Status events} + property OnTriggerLineError : TTriggerLineErrorEvent + read FOnTriggerLineError write SetOnTriggerLineError; + property OnTriggerModemStatus : TNotifyEvent + read FOnTriggerModemStatus write SetOnTriggerModemStatus; + property OnTriggerOutbuffFree : TNotifyEvent + read FOnTriggerOutbuffFree write SetOnTriggerOutbuffFree; + property OnTriggerOutbuffUsed : TNotifyEvent + read FOnTriggerOutbuffUsed write SetOnTriggerOutbuffUsed; + property OnTriggerOutSent : TNotifyEvent + read FOnTriggerOutSent write SetOnTriggerOutSent; + + {WaitChar event} + property OnWaitChar : TWaitCharEvent + read FOnWaitchar write FOnWaitChar; + + {I/O properties} + property Output : AnsiString + write PutString; + property OutputUni : string write PutString; + + {TComHandle, read only} + property Dispatcher : TApdBaseDispatcher + read GetDispatcher; + function ValidDispatcher : TApdBaseDispatcher; + + {Modem status, read only} + property ModemStatus : Byte + read GetModemStatus; + property DSR : Boolean + read GetDSR; + property CTS : Boolean + read GetCTS; + property RI : Boolean + read GetRI; + property DCD : Boolean + read GetDCD; + property DeltaDSR : Boolean + read GetDeltaDSR; + property DeltaCTS : Boolean + read GetDeltaCTS; + property DeltaRI : Boolean + read GetDeltaRI; + property DeltaDCD : Boolean + read GetDeltaDCD; + + {Line errors} + property LineError : Word + read GetLineError; + property LineBreak : Boolean + read GetLineBreak; + + {Buffer info, readonly} + property InBuffUsed : Word + read GetInBuffUsed; + property InBuffFree : Word + read GetInBuffFree; + property OutBuffUsed : Word + read GetOutBuffUsed; + property OutBuffFree : Word + read GetOutBuffFree; + + property LastWinError: Integer read GetLastWinError; // SWB + end; + + {Port component} + TApdComPort = class(TApdCustomComPort) + published + property DeviceLayer; + property ComNumber; + property Baud; + property PromptForPort; + property Parity; + property DataBits; + property StopBits; + property InSize; + property OutSize; + property AutoOpen; + property Open; + property DTR; + property RTS; + property HWFlowOptions; + property SWFlowOptions; + property XOnChar; + property XOffChar; + property BufferFull; + property BufferResume; + property Tracing; + property TraceSize; + property TraceName; + property TraceHex; + property TraceAllHex; + property Logging; + property LogSize; + property LogName; + property LogHex; + property LogAllHex; + property UseMSRShadow; + property UseEventWord; + property CommNotificationLevel; + property TapiMode; + property RS485Mode; + property OnPortClose; + property OnPortOpen; + property OnTrigger; + property OnTriggerAvail; + property OnTriggerData; + property OnTriggerStatus; + property OnTriggerTimer; + property OnTriggerLineError; + property OnTriggerModemStatus; + property OnTriggerOutbuffFree; + property OnTriggerOutbuffUsed; + property OnTriggerOutSent; + property Tag; + end; + + function ComName(const ComNumber : Word) : string; + function SearchComPort(const C : TComponent) : TApdCustomComPort; + +implementation + +uses + Types, AnsiStrings; + +const + ComWindowClass = 'awComWindow'; + + {Main trigger handler} + + function ComWindowProc(AWindow: HWND; AMsg: UINT; AWParam: WPARAM; ALParam: LPARAM): Integer; stdcall; + + {-Receives all triggers, dispatches to event handlers} + type + lParamCast = record + Data : Word; + Dispatcher : Word; + end; + var + LP : lParamCast absolute ALParam; + TrigHandle : Word absolute AWParam; + Count : Word absolute AWParam; + CP : TApdCustomComPort; + D : Pointer; + begin + case AMsg of + APW_CLOSEPENDING, APW_TRIGGERAVAIL, APW_TRIGGERDATA, + APW_TRIGGERSTATUS, APW_TRIGGERTIMER : ; + else + ComWindowProc := DefWindowProc(AWindow, AMsg, AWParam, ALParam); + Exit; + end; + LockPortList; + try + ComWindowProc := ecOK; + if (PortList <> nil) and (LP.Dispatcher < PortList.Count) then begin + D := PortList[LP.Dispatcher]; + if D <> nil then + CP := TApdCustomComPort(TApdBaseDispatcher(D).Owner) + else + CP := nil; + if Assigned(CP) then with CP do begin + try + if AMsg = APW_TRIGGERAVAIL then + Trigger(AMsg, TrigHandle, Count) + else + Trigger(AMsg, TrigHandle, LP.Data); + case AMsg of + APW_CLOSEPENDING : + begin + if FDispatcher.Active then begin + PostMessage(FComWindow,APW_CLOSEPENDING, 0, ALParam); + end else begin + {Get rid of the trigger handler} + RegisterComPort(False); + FDispatcher.Free; + FDispatcher := nil; + PortState := psClosed; + FOpen := False; {!!.02} + if OpenPending then begin + InitPort; + OpenPending := False; + end; + end; + end; + APW_TRIGGERAVAIL : + TriggerAvail(Count); + APW_TRIGGERDATA : + TriggerData(TrigHandle); + APW_TRIGGERSTATUS : + begin + TriggerStatus(TrigHandle); + case Dispatcher.ClassifyStatusTrigger(TrigHandle) of + stModem : TriggerModemStatus; + stLine : TriggerLineError(LineError, LineBreak); + stOutBuffFree : TriggerOutbuffFree; + stOutBuffUsed : TriggerOutbuffUsed; + stOutSent : TriggerOutSent; + end; + end; + APW_TRIGGERTIMER : + TriggerTimer(TrigHandle); + end; + except + if GetCurrentThreadID = MainThreadID then + Application.HandleException(nil); + end; + end; + end; + finally + UnlockPortList; + end; + end; + +{Misc} + +var + Registered : Boolean = False; + + procedure RegisterComWindow; + {-Make sure the comwindow class is registered} + var + XClass: TWndClass; + begin + if Registered then + Exit; + Registered := True; + + with XClass do begin + Style := 0; + lpfnWndProc := @ComWindowProc; + cbClsExtra := 0; + cbWndExtra := SizeOf(Pointer); + if ModuleIsLib and not ModuleIsPackage then + { we're in a DLL, not a package } + hInstance := SysInit.hInstance + else + { we're a package or exe } + hInstance := System.MainInstance; + hIcon := 0; + hCursor := 0; + hbrBackground := 0; + lpszMenuName := nil; + lpszClassName := ComWindowClass; + end; + Windows.RegisterClass(XClass); + end; + + function TApdCustomComPort.ValidDispatcher : TApdBaseDispatcher; + {- return the current dispatcher object. Raise an exception if NIL } + begin + if Dispatcher = nil then + CheckException(Self,ecCommNotOpen); + Result := Dispatcher; + end; + + procedure TApdCustomComPort.SetDeviceLayer(const NewDevice : TDeviceLayer); + {-Set a new device layer, ignore if port is open} + begin + if (NewDevice <> FDeviceLayer) and (PortState = psClosed) then + if NewDevice in FDeviceLayers then begin + FDeviceLayer := NewDevice; + DeviceLayerChanged; + end; + end; + + procedure TApdCustomComPort.SetComNumber(const NewNumber : Word); + {-Set a new comnumber, close the old port if open} + var + WasOpen : Boolean; + OldTracing : TTraceLogState; + OldLogging : TTraceLogState; + begin + if FComNumber <> NewNumber then begin + WasOpen := (PortState = psOpen); + OldTracing := tlOff; + OldLogging := tlOff; + if (PortState = psOpen) then begin + Dispatcher.SaveTriggers(SaveTriggerBuffer); + OldTracing := Tracing; + OldLogging := Logging; + Open := False; + end; + FComNumber := NewNumber; + if WasOpen then begin + Tracing := OldTracing; + Logging := OldLogging; + Open := True; + Dispatcher.RestoreTriggers(SaveTriggerBuffer); + end; + end; + end; + + procedure TApdCustomComPort.SetBaud(const NewBaud : Integer); + {-Set a new baud rate} + begin + if NewBaud <> FBaud then begin + FBaud := NewBaud; + if (PortState = psOpen) then + CheckException(Self, + Dispatcher.SetLine(NewBaud, Ord(Parity), Databits, Stopbits)); + end; + end; + + procedure TApdCustomComPort.SetParity(const NewParity : TParity); + {-Set new parity} + begin + if NewParity <> FParity then begin + FParity := NewParity; + if (PortState = psOpen) then + CheckException(Self, + Dispatcher.SetLine(Baud, Ord(FParity), Databits, Stopbits)); + end; + end; + + procedure TApdCustomComPort.SetDatabits(const NewBits : Word); + {-Set new databits} + begin + if NewBits <> FDatabits then begin + FDatabits := NewBits; + if (PortState = psOpen) then + CheckException(Self, + Dispatcher.SetLine(Baud, Ord(Parity), FDatabits, Stopbits)); + end; + end; + + procedure TApdCustomComPort.SetStopbits(const NewBits : Word); + {-Set new stop bits} + begin + if NewBits <> FStopbits then begin + FStopbits := NewBits; + if (PortState = psOpen) then + CheckException(Self, + Dispatcher.SetLine(Baud, Ord(Parity), Databits, FStopbits)); + end; + end; + + procedure TApdCustomComPort.SetInSize(const NewSize : Word); + {-Set new insize, requires re-opening port if port was open} + begin + if NewSize <> FInSize then begin + FInSize := NewSize; + if (PortState = psOpen) then + Dispatcher.SetCommBuffers(NewSize, OutSize); + end; + end; + + procedure TApdCustomComPort.SetOutSize(const NewSize : Word); + {-Set new outsize, requires re-opening port if port was open} + begin + if NewSize <> FOutSize then begin + FOutSize := NewSize; + if (PortState = psOpen) then + Dispatcher.SetCommBuffers(InSize, NewSize); + end; + end; + + procedure TApdCustomComPort.SetTracing(const NewState : TTraceLogState); + {-Set Tracing state, FTracing is modified by called methods} + begin + if (FTracing <> NewState) or Force then begin + if (PortState = psOpen) then begin + {Port is open -- do it} + case NewState of + tlOff : if (FTracing = tlOn) or (FTracing = tlPause) then + AbortTracing; + tlOn : if FTracing = tlPause then + StartTracing + else + InitTracing(FTraceSize); + tlDump : if (FTracing = tlOn) or (FTracing = tlPause) then begin + StartTracing; + DumpTrace(FTraceName, FTraceHex); + end; + tlAppend : if (FTracing = tlOn) or (FTracing = tlPause) then begin + StartTracing; + AppendTrace(FTraceName, FTraceHex, tlOff); // SWB + end; + tlAppendAndContinue : // SWB + if (FTracing = tlOn) or (FTracing = tlPause) then begin// SWB + StartTracing; // SWB + AppendTrace(FTraceName, FTraceHex, FTracing); // SWB + end; // SWB + tlPause : if (FTracing = tlOn) then + StopTracing; + tlClear : if (FTracing = tlOn) or (FTracing = tlPause) then + ClearTracing; + end; + end else begin + {Port is closed, only acceptable values are tlOff and tlOn} + case NewState of + tlOff, tlOn : FTracing := NewState; + else FTracing := tlOff; + end; + end; + end; + end; + + procedure TApdCustomComPort.SetTraceSize(const NewSize : Cardinal); + {-Set trace size} + var + OldState : TTraceLogState; + begin + if NewSize <> FTraceSize then begin + if NewSize > HighestTrace then + FTraceSize := HighestTrace + else + FTraceSize := NewSize; + if (PortState = psOpen) and ((FTracing = tlOn) or (FTracing = tlPause)) then begin + {Trace file is open: abort, then restart to get new size} + OldState := Tracing; + AbortTracing; + Tracing := OldState; + end; + end; + end; + + procedure TApdCustomComPort.SetLogging(const NewState : TTraceLogState); + {-Set Logging state, FLogging is modified by called methods} + begin + if (FLogging <> NewState) or Force then begin + if (PortState = psOpen) then begin + case NewState of + tlOff : if (FLogging = tlOn) or (FLogging = tlPause) then + AbortLogging; + tlOn : if FLogging = tlPause then + StartLogging + else + InitLogging(FLogSize); + tlDump : if (FLogging = tlOn) or (FLogging = tlPause) then begin + StartLogging; + DumpLog(FLogName, FLogHex); + end; + tlAppend : if (FLogging = tlOn) or (FLogging = tlPause) then begin + StartLogging; + AppendLog(FLogName, FLogHex, tlOff); // SWB + end; + tlAppendAndContinue : // SWB + if (FLogging = tlOn) or (FLogging = tlPause) then begin// SWB + StartLogging; // SWB + AppendLog(FLogName, FLogHex, FLogging); // SWB + end; // SWB + tlPause : if (FLogging = tlOn) then + StopLogging; + tlClear : if (FLogging = tlOn) or (FLogging = tlPause) then + ClearLogging; + end; + end else begin + {Port is closed, only acceptable values are tlOff and tlOn} + case NewState of + tlOff, tlOn : FLogging := NewState; + else FLogging := tlOff; + end; + end; + end; + end; + + procedure TApdCustomComPort.SetLogSize(const NewSize : Cardinal); + {-Set log size} + var + OldState : TTraceLogState; + begin + if NewSize <> FLogSize then begin + if NewSize > MaxDLogQueueSize then + FLogSize := MaxDLogQueueSize + else + FLogSize := NewSize; + if (PortState = psOpen) and ((FLogging = tlOn) or (FLogging = tlPause)) then begin + {Log file is open: abort, then restart to get new size} + OldState := FLogging; + AbortLogging; + Logging := OldState; + end; + end; + end; + + procedure TApdCustomComPort.SetOpen(const Enable : Boolean); + {-Open/close the port} + begin + if FOpen <> Enable then begin + if not (csDesigning in ComponentState) and + not (csLoading in ComponentState) then begin + if Enable then begin + if (PortState = psClosed) then + { open the port } + InitPort + else + { wait until we're closed } + OpenPending := True; + end else + { close the port } + DonePort; + end else begin + { we're loading or designing, just set a flag } + FOpen := Enable; + if Enable then + ForceOpen := True; + end; + end; + end; + + procedure TApdCustomComPort.SetHWFlowOptions(const NewOpts : THWFlowOptionSet); + {-Set hardware flow options} + const + UseDTR : array[Boolean] of Word = (0, hfUseDTR); + UseRTS : array[Boolean] of Word = (0, hfUseRTS); + RequireDSR : array[Boolean] of Word = (0, hfRequireDSR); + RequireCTS : array[Boolean] of Word = (0, hfRequireCTS); + var + Opts : Word; + begin + if (FHWFlowOptions <> NewOpts) or Force then begin + Opts := UseDTR[hwfUseDTR in NewOpts] + + UseRTS[hwfUseRTS in NewOpts] + + RequireDSR[hwfRequireDSR in NewOpts] + + RequireCTS[hwfRequireCTS in NewOpts]; + + {Validate bufferfull and bufferresume if opts not zero} + if Opts <> 0 then begin + if (BufferFull = 0) or (BufferFull > InSize) then + FBufferFull := Trunc(InSize * 0.9); + if (BufferResume = 0) or (BufferResume > BufferFull) then + FBufferResume := Trunc(InSize * 0.1); + end; + + if (PortState = psOpen) then begin + CheckException(Self, Dispatcher.HWFlowOptions(FBufferFull, FBufferResume, Opts)) + end; + FHWFlowOptions := NewOpts; + {Force RS485 mode off if using RTS/CTS flow control} + if (hwfUseRTS in NewOpts) or + (hwfRequireCTS in NewOpts) then + RS485Mode := False; + end; + end; + + function TApdCustomComPort.GetFlowState : TFlowControlState; + {-Return the current state of flow control} + begin + if (PortState <> psShuttingDown) then begin + Result := TFlowControlState(Pred(CheckException(Self, + ValidDispatcher.HWFlowState))); + if Result = fcOff then + Result := TFlowControlState(Pred(CheckException(Self, + Dispatcher.SWFlowState))); + end else begin + Result := fcOff; + end; + end; + + procedure TApdCustomComPort.SetSWFlowOptions(const NewOpts : TSWFlowOptions); + var + Opts : Word; + begin + if (FSWFlowOptions <> NewOpts) or Force then begin + if NewOpts = swfBoth then + Opts := sfTransmitFlow + sfReceiveFlow + else if NewOpts = swfTransmit then + Opts := sfTransmitFlow + else if NewOpts = swfReceive then + Opts := sfReceiveFlow + else + Opts := 0; + + {Validate bufferfull and bufferresume if opts not zero} + if Opts <> 0 then begin + if (BufferFull = 0) or (BufferFull > InSize) then + FBufferFull := Trunc(InSize * 0.75); + if (BufferResume = 0) or (BufferResume > BufferFull) then + FBufferResume := Trunc(InSize * 0.25); + end; + + if (PortState = psOpen) then begin + if Opts <> 0 then + CheckException(Self, + Dispatcher.SWFlowEnable(FBufferFull, FBufferResume, Opts)) + else + CheckException(Self, Dispatcher.SWFlowDisable); + end; + FSWFlowOptions := NewOpts; + end; + end; + + procedure TApdCustomComPort.SetXonChar(const NewChar : AnsiChar); + {-Set new xon character} + begin + if (NewChar <> FXOnChar) or Force then begin + FXOnChar := NewChar; + if (PortState = psOpen) then + CheckException(Self, Dispatcher.SWFlowChars(FXOnChar, FXOffChar)); + end; + end; + + procedure TApdCustomComPort.SetXoffChar(const NewChar : AnsiChar); + {-Set new xoff character} + begin + if (NewChar <> FXOffChar) or Force then begin + FXOffChar := NewChar; + if (PortState = psOpen) then + CheckException(Self, Dispatcher.SWFlowChars(FXOnChar, FXOffChar)); + end; + end; + + procedure TApdCustomComPort.SetBufferFull(const NewFull : Word); + {-Set buffer full mark} + var + SaveForce : Boolean; + begin + if (NewFull <> FBufferFull) or Force then begin + if NewFull <= InSize then + FBufferFull := NewFull + else + FBufferFull := Trunc(NewFull * 0.9); + SaveForce := Force; + Force := True; + SetHWFlowOptions(HWFlowOptions); + SetSWFlowOptions(SWFlowOptions); + Force := SaveForce; + end; + end; + + procedure TApdCustomComPort.SetBufferResume(const NewResume : Word); + {-Set buffer resume mark} + var + SaveForce : Boolean; + begin + if (NewResume <> FBufferResume) or Force then begin + if NewResume > FBufferFull then + FBufferResume := Trunc(FBufferFull * 0.1) + else + FBufferResume := NewResume; + SaveForce := Force; + Force := True; + SetHWFlowOptions(HWFlowOptions); + SetSWFlowOptions(SWFlowOptions); + Force := SaveForce; + end; + end; + + procedure TApdCustomComPort.SetDTR(const NewDTR : Boolean); + {-Set a new DTR value} + begin + if (NewDTR <> FDTR) or Force then begin + if (PortState = psOpen) then begin + if CheckException(Self, Dispatcher.SetDTR(NewDTR)) = ecOK then + FDTR := NewDTR; + end else begin + FDTR := NewDTR; + end; + end; + end; + + procedure TApdCustomComPort.SetRTS(const NewRTS : Boolean); + {-Set new RTS value} + begin + if (NewRTS <> FRTS) or Force then begin + if (PortState = psOpen) then begin + if CheckException(Self, Dispatcher.SetRTS(NewRTS)) = ecOK then + FRTS := NewRTS; + end else begin + FRTS := NewRTS; + end; + end; + end; + + procedure TApdCustomComPort.SetOnTrigger(const Value : TTriggerEvent); + begin + FOnTrigger := Value; + UpdateHandlerFlag; + end; + + procedure TApdCustomComPort.SetOnTriggerAvail(const Value : TTriggerAvailEvent); + begin + FOnTriggerAvail := Value; + UpdateHandlerFlag; + end; + + procedure TApdCustomComPort.SetOnTriggerData(const Value : TTriggerDataEvent); + begin + FOnTriggerData := Value; + UpdateHandlerFlag; + end; + + procedure TApdCustomComPort.SetOnTriggerStatus(const Value : TTriggerStatusEvent); + begin + FOnTriggerStatus := Value; + UpdateHandlerFlag; + end; + + procedure TApdCustomComPort.SetOnTriggerTimer(const Value : TTriggerTimerEvent); + begin + FOnTriggerTimer := Value; + UpdateHandlerFlag; + end; + + procedure TApdCustomComPort.SetOnTriggerLineError(const Value : TTriggerLineErrorEvent); + begin + FOnTriggerLineError := Value; + UpdateHandlerFlag; + end; + + procedure TApdCustomComPort.SetOnTriggerModemStatus(const Value : TNotifyEvent); + begin + FOnTriggerModemStatus := Value; + UpdateHandlerFlag; + end; + + procedure TApdCustomComPort.SetOnTriggerOutbuffFree(const Value : TNotifyEvent); + begin + FOnTriggerOutbuffFree := Value; + UpdateHandlerFlag; + end; + + procedure TApdCustomComPort.SetOnTriggerOutbuffUsed(const Value : TNotifyEvent); + begin + FOnTriggerOutbuffUsed := Value; + UpdateHandlerFlag; + end; + + procedure TApdCustomComPort.SetOnTriggerOutSent(const Value : TNotifyEvent); + begin + FOnTriggerOutSent := Value; + UpdateHandlerFlag; + end; + + function TApdCustomComPort.GetDispatcher : TApdBaseDispatcher; + {-Return the current Dispatcher, opening the port if necessary} + begin + if FDispatcher = nil then + if not (csDesigning in ComponentState) then begin + if (PortState <> psOpen) and + (not (csLoading in ComponentState)) and + AutoOpen then + Open := True; + end; + Result := FDispatcher; + end; + + function TApdCustomComPort.GetModemStatus : Byte; + {-Return the current modem status register value} + begin + if (PortState = psShuttingDown) then + Result := 0 + else + Result := ValidDispatcher.GetModemStatus; + end; + + function TApdCustomComPort.GetDSR : Boolean; + {-Return the DSR bit state} + begin + if (PortState = psOpen) then + Result := Dispatcher.CheckDSR + else + Result := False; + end; + + function TApdCustomComPort.GetCTS : Boolean; + {-Return CTS bit state} + begin + if (PortState = psOpen) then + Result := Dispatcher.CheckCTS + else + Result := False; + end; + + function TApdCustomComPort.GetRI : Boolean; + {-Return RI bit state} + begin + if (PortState = psOpen) then + Result := Dispatcher.CheckRI + else + Result := False; + end; + + function TApdCustomComPort.GetDCD : Boolean; + {-Return DCD bit state} + begin + if (PortState = psOpen) then + Result := Dispatcher.CheckDCD + else + Result := False; + end; + + function TApdCustomComPort.GetDeltaDSR : Boolean; + {-Return delta DSR bit state} + begin + if (PortState = psOpen) then + Result := Dispatcher.CheckDeltaDSR + else + Result := False; + end; + + function TApdCustomComPort.GetDeltaCTS : Boolean; + {-Return delta CTS bit state} + begin + if (PortState = psOpen) then + Result := Dispatcher.CheckDeltaCTS + else + Result := False; + end; + + function TApdCustomComPort.GetDeltaRI : Boolean; + {-Return delta RI bit state} + begin + if (PortState = psOpen) then + Result := Dispatcher.CheckDeltaRI + else + Result := False; + end; + + function TApdCustomComPort.GetDeltaDCD : Boolean; + {-Return delta DCD bit state} + begin + if (PortState = psOpen) then + Result := Dispatcher.CheckDeltaDCD + else + Result := False; + end; + + function TApdCustomComPort.GetLineError : Word; + {-Return most severe current line error} + begin + if (PortState = psOpen) then + Result := Word(CheckException(Self, Word(Dispatcher.GetLineError))) + else + Result := leNoError; + end; + + function TApdCustomComPort.GetLineBreak : Boolean; + {-Return True if break received} + begin + if (PortState = psOpen) then + Result := Dispatcher.CheckLineBreak + else + Result := False; + end; + + procedure TApdCustomComPort.SetTriggerLength(const NewLength : Word); + {-Change the length trigger} + begin + if (FTriggerLength <> NewLength) or Force then begin + FTriggerLength := NewLength; + if (PortState = psOpen) then + Dispatcher.ChangeLengthTrigger(NewLength); + end; + end; + + function TApdCustomComPort.GetInBuffUsed : Word; + {-Return the number of used bytes in the input buffer} + begin + if (PortState = psOpen) then + Result := Dispatcher.InBuffUsed + else + Result := 0; + end; + + function TApdCustomComPort.GetInBuffFree : Word; + {-Return amount of freespace in inbuf} + begin + if (PortState = psOpen) then + Result := Dispatcher.InBuffFree + else + Result := DispatchBufferSize; + end; + + function TApdCustomComPort.GetOutBuffUsed : Word; + {-Return number of used bytes in output buffer} + begin + if (PortState = psOpen) then + Result := Dispatcher.OutBuffUsed + else + Result := 0; + end; + + function TApdCustomComPort.GetOutBuffFree : Word; + {-Return amount of free space in outbuff} + begin + if (PortState = psOpen) then + Result := Dispatcher.OutBuffFree + else + Result := FOutSize; + end; + + procedure TApdCustomComPort.SetUseMSRShadow(NewUse : Boolean); + {-Set the MSR shadow option} + begin + { UseMSRShadow is only applicable to 16-bit, ignore it } + end; + + procedure TApdCustomComPort.SetUseEventWord(NewUse : Boolean); + {-Set the UseEventWord option} + begin + if (FUseEventWord <> NewUse) or Force then begin + FUseEventWord := NewUse; + if (PortState = psOpen) then + if FUseEventWord then + Dispatcher.OptionsOn(poUseEventWord) + else + Dispatcher.OptionsOff(poUseEventWord); + end; + end; + + procedure TApdCustomComPort.SetCommNotificationLevel(NewLevel : Word); + {-Set the comm notification level} + begin + { 16-bit } + if (FCommNotificationLevel <> NewLevel) or Force then begin + FCommNotificationLevel := NewLevel; + end; + end; + + procedure TApdCustomComPort.SetRS485Mode(NewMode : Boolean); + {-Set the RS485 mode} + var + NewFlowOpts : THWFlowOptionSet; + begin + if (FRS485Mode <> NewMode) or Force then begin + FRS485Mode := NewMode; + if (PortState = psOpen) then + Dispatcher.SetRS485Mode(NewMode); + + if NewMode then begin + {Force rts/cts flow control off} + NewFlowOpts := FHWFlowOptions; + Exclude(NewFlowOpts, hwfUseRTS); + Exclude(NewFlowOpts, hwfRequireCTS); + SetHWFlowOptions(NewFlowOpts); + + {Force RTS off} + RTS := False; + end; + end; + end; + + procedure TApdCustomComPort.SetBaseAddress(NewBaseAddress : Word); + {-Set the base address} + begin + if (BaseAddress <> NewBaseAddress) or Force then begin + if (PortState = psOpen) then + Dispatcher.SetBaseAddress(NewBaseAddress); + end; + end; + + procedure TApdCustomComPort.SetThreadBoost(NewBoost : TApThreadBoost); + begin + if (FThreadBoost <> NewBoost) or Force then begin + FThreadBoost := NewBoost; + if (PortState = psOpen) then + Dispatcher.SetThreadBoost(Ord(NewBoost)); + end; + end; + + function TApdCustomComPort.GetBaseAddress : Word; + {-Get the base address} + begin + if (PortState = psOpen) then + Result := Dispatcher.GetBaseAddress + else + Result := 0; + end; + +{TApdComPort protected} + + function TApdCustomComPort.ActivateDeviceLayer : TApdBaseDispatcher; + begin + if Assigned(fCustomDispatcher) then + Result := CustomDispatcher(Self) + else case DeviceLayer of + dlWin32 : + if TapiMode = tmOn then + Result := TApdTAPI32Dispatcher.Create(Self,FTapiCID) + else + Result := TApdWin32Dispatcher.Create(Self); + else + raise ENullAPI.Create(ecNullAPI, False); + end; + end; + + procedure TApdCustomComPort.DeviceLayerChanged; + {-Notification that device layer has changed} + begin + { Do nothing at this level } + end; + + function TApdCustomComPort.InitializePort : Integer; + var + Temp : array[0..12] of Char; + FlowFlags : DWORD; + + function MakeComName(const ComNum : Word) : PChar; + {-Return a string like 'COMXX'} + begin + if TapiMode <> tmOn then begin + StrFmt(Temp, '\\.\COM%d', [ComNum]); + Result := Temp; + end else + Result := nil; + end; + + begin + { Set up initial flow control info } + FlowFlags := 0; + + { Manual settings } + if FDTR then FlowFlags := (FlowFlags or ipAssertDTR); + if FRTS then FlowFlags := (FlowFlags or ipAssertRTS); + + if (hwfUseDTR in FHWFlowOptions) then + FlowFlags := (FlowFlags or ipAutoDTR); + + if (hwfUseRTS in FHWFlowOptions) then + FlowFlags := (FlowFlags or ipAutoRTS); + + Result := Dispatcher.InitPort(MakeComName(FComNumber), FBaud, + Ord(FParity), FDatabits, FStopbits, FInSize, FOutSize, FlowFlags); + end; + + procedure TApdCustomComPort.Loaded; + {-Physically open the port if FOpen is True} + begin + inherited Loaded; + + if not (csDesigning in ComponentState) then begin + if ForceOpen then + FOpen := True; + if FOpen then begin + ForceOpen := False; + try + InitPort; + except + FOpen := False; + Application.HandleException(nil); + end; + end; + end; + end; + + procedure TApdCustomComPort.Trigger(Msg, TriggerHandle, Data : Word); + {-For internal processing of all triggers} + begin + if Assigned(FOnTrigger) then + FOnTrigger(Self, Msg, TriggerHandle, Data); + end; + + procedure TApdCustomComPort.TriggerAvail(Count : Word); + {-For internal triggeravail processing} + begin + if Assigned(FOnTriggerAvail) then + FOnTriggerAvail(Self, Count); + end; + + procedure TApdCustomComPort.TriggerData(TriggerHandle : Word); + {-For internal triggerdata processing} + begin + if Assigned(FOnTriggerData) then + FOnTriggerData(Self, TriggerHandle); + end; + + procedure TApdCustomComPort.TriggerStatus(TriggerHandle : Word); + {-For internal triggerstatus processing} + begin + if Assigned(FOnTriggerStatus) then + FOnTriggerStatus(Self, TriggerHandle); + end; + + procedure TApdCustomComPort.TriggerTimer(TriggerHandle : Word); + {-For internal triggertimer processing} + begin + if Assigned(FOnTriggerTimer) then + FOnTriggerTimer(Self, TriggerHandle); + end; + + procedure TApdCustomComPort.UpdateHandlerFlag; + begin + if (PortState <> psOpen) then Exit; + if Assigned(FOnTrigger) or Assigned(FOnTriggerAvail) or + Assigned(FOnTriggerData) or Assigned(FOnTriggerStatus) or + Assigned(FOnTriggerTimer) or Assigned(FOnTriggerLineError) or + Assigned(FOnTriggerModemStatus) or Assigned(FOnTriggerOutbuffFree) or + Assigned(FOnTriggerOutbuffUsed) or Assigned(FOnTriggerOutSent) then + FDispatcher.UpdateHandlerFlags(fuEnablePort) + else + FDispatcher.UpdateHandlerFlags(fuDisablePort); + end; + + procedure TApdCustomComPort.PortOpen; + {-Port open processing} + var + I : Word; + UL : PUserListEntry; + begin + {Tell all comport users that the port is now open} + if UserList.Count > 0 then begin + for I := UserList.Count-1 downto 0 do begin + UL := UserList.Items[I]; + with UL^ do begin + if Handle <> 0 then + SendMessage(Handle, APW_PORTOPEN, 0, 0) + else begin {!!.03} + if IsEx then {!!.03} + UL^.OpenCloseEx(Self, ctOpen) {!!.03} + else {!!.03} + UL^.OpenClose(Self, True); + end; {!!.03} + end; + end; + end; + + if Assigned(FOnPortOpen) then + FOnPortOpen(Self); + end; + + procedure TApdCustomComPort.PortClose; + {-Port close processing} + var + I : Word; + UL : PUserListEntry; + begin + {Tell all comport users that the port is now closed} + if UserList.Count > 0 then begin + for I := UserList.Count-1 downto 0 do begin + UL := UserList.Items[I]; + with UL^ do begin + if Handle <> 0 then + SendMessage(Handle, APW_PORTCLOSE, 0, 0) + else begin {!!.03} + if IsEx then {!!.03} + UL^.OpenCloseEx(Self, ctClosed) {!!.03} + else {!!.03} + UL^.OpenClose(Self, False); + end; {!!.03} + end; + end; + end; + + if Assigned(FOnPortClose) then + FOnPortClose(Self); + end; + + procedure TApdCustomComPort.PortClosing; {!!.03} + {-Port closing processing, sent to other controls to notify that the port } + { is starting to close for cleanup } + var + I : Word; + UL : PUserListEntry; + begin + { tell all users that the port is now being closed } + if UserList.Count > 0 then begin + for I := pred(UserList.Count) downto 0 do begin + UL := UserList.Items[I]; + { only notify if they are registered as extended } + if UL^.IsEx then + with UL^ do begin + if Handle <> 0 then + SendMessage(Handle, APW_CLOSEPENDING, 0, 0) + else + UL^.OpenCloseEx(Self, ctClosing); + end; + end; + end; + end; + + procedure TApdCustomComPort.TriggerLineError(const Error : Word; + const LineBreak : Boolean); + {-Received a line error} + begin + if Assigned(FOnTriggerLineError) then + FOnTriggerLineError(Self, Error, LineBreak); + end; + + procedure TApdCustomComPort.TriggerModemStatus; + {-Received a modem status change} + begin + if Assigned(FOnTriggerModemStatus) then + FOnTriggerModemStatus(Self); + end; + + procedure TApdCustomComPort.TriggerOutbuffFree; + {-Received and outbuff free trigger} + begin + if Assigned(FOnTriggerOutbuffFree) then + FOnTriggerOutbuffFree(Self); + end; + + procedure TApdCustomComPort.TriggerOutbuffUsed; + {-Received and outbuff used trigger} + begin + if Assigned(FOnTriggerOutbuffUsed) then + FOnTriggerOutbuffUsed(Self); + end; + + procedure TApdCustomComPort.TriggerOutSent; + {-Received an outsent trigger} + begin + if Assigned(FOnTriggerOutSent) then + FOnTriggerOutSent(Self); + end; + + procedure TApdCustomComPort.WaitChar(C : AnsiChar); + {-Received a character in WaitForString or WaitForMultiString} + begin + if Assigned(FOnWaitChar) then + FOnWaitChar(Self, C); + end; + + procedure TApdCustomComPort.RegisterComPort(Enabling : Boolean); + {-Use a hidden window to get triggers} + var + Instance : THandle; + begin + if Enabling then begin + {Make sure the window is registered} + RegisterComWindow; + + if ModuleIsLib and not ModuleIsPackage then + { we're a DLL, not a package } + Instance := SysInit.hInstance + else + {we're an exe or package } + Instance := System.MainInstance; + + {Create a window} + fComWindow := CreateWindow(ComWindowClass, {class name} + '', {caption} + ws_Overlapped, {window style} + 0, {X} + 0, {Y} + 0, {width} + 0, {height} + 0, {parent} + 0, {menu} + Instance, {instance} + nil); {parameter} + + {Register it} + FDispatcher.RegisterWndTriggerHandler(ComWindow); + end else begin + {Deregister it} + FDispatcher.DeregisterWndTriggerHandler(ComWindow); + DestroyWindow(ComWindow); + end; + end; + + procedure TApdCustomComPort.ValidateComport; + var + ComSelDlg : TComSelectForm; + begin + if (FComNumber = 0) then + if (not FPromptForPort) then + raise ENoPortSelected.Create(ecNoPortSelected, False) + else begin + ComSelDlg := TComSelectForm.Create(Application); + try + if (ComSelDlg.ShowModal = mrOk) then + ComNumber := ComSelDlg.SelectedComNum + else + raise ENoPortSelected.Create(ecNoPortSelected, False); + finally + ComSelDlg.Free; + end; + end; + end; + + constructor TApdCustomComPort.Create(AOwner : TComponent); + {-Create the object instance} + begin + + {Create the registration list before notification events are sent} + UserList := TList.Create; + + {No override by default} + OverrideLine := False; + + {This causes notification events for all other components} + inherited Create(AOwner); + + {Private inits} + Force := False; + PortState := psClosed; + ForceOpen := False; + CopyTriggers := False; + BusyBeforeWait := False; + WaitPrepped := False; + fComWindow := 0; + + {Data inits} + FDeviceLayers := [dlWin32]; + FPromptForPort := adpoDefPromptForPort; + FDeviceLayer := adpoDefDeviceLayer; + FDispatcher := nil; + FComNumber := adpoDefComNumber; + FOpen := adpoDefOpen; + FAutoOpen := adpoDefAutoOpen; + FDTR := adpoDefDTR; + FRTS := adpoDefRTS; + FSWFlowOptions := adpoDefSWFlowOptions; + FXonChar := adpoDefXOnChar; + FXOffChar := adpoDefXOffChar; + FBufferFull := adpoDefBufferFull; + FBufferResume := adpoDefBufferResume; + FTriggerLength := adpoDefTriggerLength; + FTracing := adpoDefTracing; + FTraceSize := adpoDefTraceSize; + FTraceName := adpoDefTraceName; + FTraceHex := adpoDefTraceHex; + TraceAllHex:= adpoDefTraceAllHex; + FLogging := adpoDefLogging; + FLogSize := adpoDefLogSize; + FLogName := adpoDefLogName; + FLogHex := adpoDefLogHex; + LogAllHex := adpoDefLogAllHex; + FUseMSRShadow := adpoDefUseMSRShadow; + FUseEventWord := adpoDefUseEventWord; + FCommNotificationLevel := adpoDefCommNotificationLevel; + FTapiMode := adpoDefTapiMode; + + + if not OverrideLine then begin + FBaud := adpoDefBaudRt; + FParity := adpoDefParity; + FDatabits := adpoDefDatabits; + FStopbits := adpoDefStopbits; + FInSize := adpoDefInSize; + FOutSize := adpoDefOutSize; + FHWFlowOptions := []; + end; + + {Event inits} + FOnTrigger := nil; + FOnTriggerAvail := nil; + FOnTriggerData := nil; + FOnTriggerStatus := nil; + FOnTriggerTimer := nil; + FOnTriggerLineError := nil; + FOnTriggerModemStatus := nil; + FOnTriggerOutbuffFree := nil; + FOnTriggerOutbuffUsed := nil; + FOnTriggerOutSent := nil; + FOnPortOpen := nil; + FOnPortClose := nil; + FOnWaitChar := nil; + + end; + + destructor TApdCustomComPort.Destroy; + {-Destroy the object instance} + var + I : Word; + UL : PUserListEntry; + begin + + {Close the port} + if (PortState = psOpen) then begin + DonePort; + end; + + {Get rid of the user list} + if Assigned(UserList) and (UserList.Count > 0) then begin {!!.02} + for I := UserList.Count-1 downto 0 do begin + UL := UserList.Items[I]; + UserList.Remove(UL); + Dispose(UL); + end; + end; + UserList.Free; + + TApdBaseDispatcher.ClearSaveBuffers(SaveTriggerBuffer); + inherited Destroy; + end; + + procedure TApdCustomComPort.InitPort; + {-Physically open the comport} + var + Res : Integer; + nBaud : Integer; + nParity : Word; + nDataBits : TDatabits; + nStopBits : TStopbits; + nHWOpts, nSWOpts, nBufferFull, nBufferResume : Cardinal; + nOnChar, nOffChar : AnsiChar; + begin + { Validate the comport -- not needed for Tapi } + if TapiMode <> tmOn then + ValidateComport; + + { Activate the specified device layer } + FDispatcher := ActivateDeviceLayer; + FDispatcher.DeviceName := Format('\\.\COM%d', [ComNumber]); // SWB + try + { Get line parameters that Tapi set } + if TapiMode = tmOn then begin + if ValidDispatcher.ComHandle = 0 then + CheckException(Self, ecNotOpenedByTapi); + FDispatcher.GetLine(nBaud, nParity, nDataBits, nStopBits); + FDispatcher.GetFlowOptions(nHWOpts, nSWOpts, nBufferFull, + nBufferResume, nOnChar, nOffChar); + + { Sync our properties with those set by Tapi } + FBaud := nBaud; + FParity := TParity(nParity); + FDataBits := Ord(nDataBits); + FStopBits := Ord(nStopBits); + + FHWFlowOptions := []; + if (nHWOpts and hfUseDTR) <> 0 then + Include(FHWFlowOptions, hwfUseDTR); + if (nHWOpts and hfUseRTS) <> 0 then + Include(FHWFlowOptions, hwfUseRTS); + if (nHWOpts and hfRequireDSR) <> 0 then + Include(FHWFlowOptions, hwfRequireDSR); + if (nHWOpts and hfRequireCTS) <> 0 then + Include(FHWFlowOptions, hwfRequireCTS); + + FSWFlowOptions := TSWFlowOptions(nSWOpts); + FXOnChar := nOnChar; + FXOffChar := nOffChar; + end; + + Res := InitializePort; + + {Remap access denied and file not found errors} + if Res = ecAccessDenied then + Res := ecAlreadyOpen + else if (Res = ecFileNotFound) or (Res = ecPathNotFound) then + Res := ecBadId; + + if (Res = ecOk) then begin + {Handle preset properties} + PortState := psOpen; + UpdateHandlerFlag; + Force := True; + SetTracing(Tracing); + SetLogging(Logging); + SetHWFlowOptions(HWFlowOptions); + SetSWFlowOptions(SWFlowOptions); + SetXOnChar(FXonChar); + SetXOffChar(FXoffChar); + SetTriggerLength(FTriggerLength); + SetDTR(FDTR); + SetRTS(FRTS); + {SetUseMSRShadow(FUseMSRShadow);} {16-bit} {!!.02} + SetUseEventWord(FUseEventWord); + {SetCommNotificationLevel(FCommNotificationLevel);} {16-bit} {!!.02} + SetRS485Mode(FRS485Mode); + SetThreadBoost(FThreadBoost); + Force := False; + FOpen := True; + + {Prepare for triggers} + RegisterComPort(True); + + {Add pending triggers} + if CopyTriggers then begin + CopyTriggers := False; + FDispatcher.RestoreTriggers(SaveTriggerBuffer); + end; + + {Send OnPortEvent} + PortOpen; + end else + CheckException(Self, Res); + except + FOpen := False; + PortState := psClosed; + FDispatcher.Free; + FDispatcher := nil; + raise; + end; + end; + + procedure TApdCustomComPort.DonePort; + {-Physically close the comport} + begin + {FOpen := False;} {!!.02} + if (PortState = psOpen) then begin + + { Force trace/log dumps if they were on } + Tracing := tlDump; + Logging := tlDump; + + { Port is shutting down } + PortState := psShuttingDown; + + { Send OnPortClose event } + {PortClose;} {!!.02} + PortClosing; {!!.03} + + { Save triggers in case this port is reopened } + Dispatcher.SaveTriggers(SaveTriggerBuffer); + CopyTriggers := True; + + { Close the port and clear ComTable } + Dispatcher.DonePort; + if Dispatcher.EventBusy then begin + PostMessage(fComWindow, apw_ClosePending, 0, + Dispatcher.Handle shl 16); + SafeYield; + end else begin + { Get rid of the trigger handler } + RegisterComPort(False); + FDispatcher.Free; + FDispatcher := nil; + PortState := psClosed; + FOpen := False; {!!.02} + end; + { Send OnPortClose event } + PortClose; {!!.02} + end; + end; + + procedure TApdCustomComPort.Assign(Source: TPersistent); + {-Assign values of Source to self} + var + SourcePort : TApdCustomComPort absolute Source; + I : Word; + UL : PUserListEntry; + begin + if Source is TApdCustomComPort then begin + {Discard existing userlist} + if UserList.Count > 0 then + for I := UserList.Count-1 downto 0 do begin + UL := UserList.Items[I]; + UserList.Remove(UL); + Dispose(UL); + end; + UserList.Free; + + {Copy Source's userlist} + UserList := TList.Create; + if SourcePort.UserList.Count > 0 then + for I := 0 to SourcePort.UserList.Count-1 do begin + New(UL); + Move(SourcePort.UserList.Items[I]^, UL^, + SizeOf(TUserListEntry)); + UserList.Add(UL); + end; + + {Copy triggers from Source} + if (SourcePort.PortState = psOpen) then begin + SourcePort.Dispatcher.SaveTriggers(SaveTriggerBuffer); + CopyTriggers := True; + end; + + {Copy all other fields} + Force := SourcePort.Force; + FDeviceLayer := SourcePort.FDeviceLayer; + FComNumber := SourcePort.FComNumber; + FBaud := SourcePort.FBaud; + FParity := SourcePort.FParity; + FDatabits := SourcePort.FDatabits; + FStopbits := SourcePort.FStopbits; + FInSize := SourcePort.FInSize; + FOutSize := SourcePort.FOutSize; + FOpen := False; + FAutoOpen := SourcePort.FAutoOpen; + FPromptForPort := SourcePort.FPromptForPort; + FRS485Mode := SourcePort.FRS485Mode; + FThreadBoost := SourcePort.FThreadBoost; + FDTR := SourcePort.FDTR; + FRTS := SourcePort.FRTS; + FBufferFull := SourcePort.FBufferFull; + FBufferResume := SourcePort.FBufferResume; + FHWFlowOptions := SourcePort.FHWFlowOptions; + FSWFlowOptions := SourcePort.FSWFlowOptions; + FXOnChar := SourcePort.FXOnChar; + FXOffChar := SourcePort.FXOffChar; + FTracing := SourcePort.FTracing; + FTraceSize := SourcePort.FTraceSize; + FTraceName := SourcePort.FTraceName; + FTraceHex := SourcePort.FTraceHex; + FTraceAllHex := SourcePort.FTraceAllHex; + FLogging := SourcePort.FLogging; + FLogSize := SourcePort.FLogSize; + FLogName := SourcePort.FLogName; + FLogHex := SourcePort.FLogHex; + FLogAllHex := SourcePort.FLogAllHex; + FTriggerLength := SourcePort.FTriggerLength; + {Must go through write method to ensure flag gets updated} + OnTrigger := SourcePort.FOnTrigger; + OnTriggerAvail := SourcePort.FOnTriggerAvail; + OnTriggerData := SourcePort.FOnTriggerData; + OnTriggerStatus := SourcePort.FOnTriggerStatus; + OnTriggerTimer := SourcePort.FOnTriggerTimer; + FOnPortOpen := SourcePort.FOnPortOpen; + FOnPortClose := SourcePort.FOnPortClose; + FTapiMode := SourcePort.FTapiMode; + end; + end; + + procedure TApdCustomComPort.RegisterUser(const H : THandle); + {-Register a user of this comport} + var + UL : PUserListEntry; + begin + New(UL); + with UL^ do begin + Handle := H; + OpenClose := nil; + OpenCloseEx := nil; {!!.03} + IsEx := False; {!!.03} + end; + UserList.Add(UL); + end; + + procedure TApdCustomComPort.RegisterUserEx(const H : THandle);{!!.03} + {-Register a TApdComPort user to receive open/closing/close events} + var + UL : PUserListEntry; + begin + New(UL); + with UL^ do begin + Handle := H; + OpenClose := nil; + OpenCloseEx := nil; + IsEx := True; + end; + UserList.Add(UL); + end; + + procedure TApdCustomComPort.RegisterUserCallback(CallBack : TPortCallback); + {-Register a user of this comport} + var + UL : PUserListEntry; + begin + New(UL); + with UL^ do begin + Handle := 0; + OpenClose := Callback; + OpenCloseEx := nil; {!!.03} + IsEx := False; {!!.03} + end; + UserList.Add(UL); + end; + + procedure TApdCustomComPort.RegisterUserCallbackEx( {!!.03} + CallBackEx : TPortCallbackEx); + {-Register a TApdComPort user to receive extended callbacks} + var + UL : PUserListEntry; + begin + New(UL); + with UL^ do begin + Handle := 0; + OpenClose := nil; + OpenCloseEx := CallbackEx; + IsEx := True; + end; + UserList.Add(UL); + end; + + procedure TApdCustomComPort.DeregisterUser(const H : THandle); + {-Deregister a user of this comport} + var + UL : PUserListEntry; + I : Word; + begin + if csDestroying in ComponentState then Exit; {!!.05} + if Assigned(UserList) and (UserList.Count > 0) then begin {!!.02} + for I := UserList.Count-1 downto 0 do begin + UL := UserList.Items[I]; + with UL^ do begin + if Handle = H then begin + UserList.Remove(UL); + Dispose(UL); + end; + end; + end; + end; + end; + + procedure TApdCustomComPort.DeregisterUserCallback(CallBack : TPortCallback); + {-Deregister a user of this comport} + var + UL : PUserListEntry; + I : Word; + begin + if csDestroying in ComponentState then Exit; {!!.05} + if Assigned(UserList) and (UserList.Count > 0) then begin {!!.02} + for I := UserList.Count-1 downto 0 do begin + UL := UserList.Items[I]; + with UL^ do begin + if @CallBack = @OpenClose then begin + UserList.Remove(UL); + Dispose(UL); + end; + end; + end; + end; + end; + + procedure TApdCustomComPort.DeregisterUserCallbackEx( {!!.03} + CallBackEx : TPortCallbackEx); + {-Deregister a TApdComPort user callback} + var + UL : PUserListEntry; + I : Word; + begin + if csDestroying in ComponentState then Exit; {!!.05} + if Assigned(UserList) and (UserList.Count > 0) then begin + for I := UserList.Count-1 downto 0 do begin + UL := UserList.Items[I]; + with UL^ do begin + if @CallBackEx = @OpenCloseEx then begin + UserList.Remove(UL); + Dispose(UL); + end; + end; + end; + end; + end; + + procedure TApdCustomComPort.ProcessCommunications; + {-Process communications receive events, but not triggers} + begin + if (PortState = psShuttingDown) then Exit; + CheckException(Self, ValidDispatcher.ProcessCommunications); + end; + + procedure TApdCustomComPort.FlushInBuffer; + {-Flush the input buffer} + begin + if (PortState = psShuttingDown) then Exit; + CheckException(Self, ValidDispatcher.FlushInBuffer); + end; + + procedure TApdCustomComPort.FlushOutBuffer; + {-Flush the output buffer} + begin + if (PortState = psShuttingDown) then Exit; + CheckException(Self, ValidDispatcher.FlushOutBuffer); + end; + + procedure TApdCustomComPort.InitTracing(const NumEntries : Cardinal); + {-Start tracing} + begin + if (PortState = psShuttingDown) then Exit; + if NumEntries <> 0 then + FTraceSize := NumEntries; + CheckException(Self, Dispatcher.InitTracing(NumEntries)); + FTracing := tlOn; + end; + + procedure TApdCustomComPort.DumpTrace(const FName : String; + const InHex : Boolean); + {-Dump the trace file} + var + Dest : array[0..255] of Char; + begin + if (PortState = psShuttingDown) then Exit; + CheckException(Self, Dispatcher.DumpTrace(StrPCopy(Dest, FName), + InHex, TraceAllHex)); + FTracing := tlOff; + end; + + procedure TApdCustomComPort.AppendTrace(const FName : string; + const InHex : Boolean; + const NewState : TTraceLogState); // SWB + {-Append the trace file} + var + Dest : array[0..255] of Char; + begin + if (PortState = psShuttingDown) then Exit; + CheckException(Self, + Dispatcher.AppendTrace(StrPCopy(Dest, FName), InHex, TraceAllHex)); + FTracing := NewState; // SWB + end; + + procedure TApdCustomComPort.ClearTracing; + {-Clear the trace buffer but keep tracing} + begin + if (PortState = psShuttingDown) then Exit; + CheckException(Self, Dispatcher.ClearTracing); + end; + + procedure TApdCustomComPort.AbortTracing; + {-Abort tracing without dumping the trace file} + begin + if (PortState = psShuttingDown) then Exit; + Dispatcher.AbortTracing; + FTracing := tlOff; + end; + + procedure TApdCustomComPort.AddTraceEntry(const CurEntry, CurCh : AnsiChar); + {-Add a trace entry} + begin + if (PortState = psShuttingDown) then Exit; + Dispatcher.AddTraceEntry(CurEntry, CurCh); + end; + + procedure TApdCustomComPort.AddStringToLog(S : AnsiString); + begin + if (PortState = psShuttingDown) then Exit; + ValidDispatcher.AddStringToLog(S); + end; + + procedure TApdCustomComPort.StartTracing; + {-Resume tracing after StopTracing} + begin + if (PortState = psShuttingDown) then Exit; + Dispatcher.StartTracing; + FTracing := tlOn; + end; + + procedure TApdCustomComPort.StopTracing; + {-Temporarily stop tracing} + begin + if (PortState = psShuttingDown) then Exit; + Dispatcher.StopTracing; + FTracing := tlPause; + end; + + procedure TApdCustomComPort.ForcePortOpen; + {-Ensure port is opened after loading} + begin + if AutoOpen then + ForceOpen := True; + end; + + procedure TApdCustomComPort.SendBreak(Ticks : Word; Yield : Boolean); + {-Send a line break of ticks duration} + begin + if (PortState = psShuttingDown) then Exit; + ValidDispatcher.SendBreak(Ticks, Yield); + end; + + procedure TApdCustomComPort.SetBreak(BreakOn: Boolean); + {-Sets or clears line break condition} + begin + if (PortState = psShuttingDown) then Exit; + ValidDispatcher.SetBreak(BreakOn); + end; + + procedure TApdCustomComPort.InitLogging(const Size : Cardinal); + {-Start dispatch logging} + begin + if (PortState = psShuttingDown) then Exit; + if Size <> 0 then + FLogSize := Size; + Dispatcher.InitDispatchLogging(FLogSize); + FLogging := tlOn; + end; + + procedure TApdCustomComPort.DumpLog(const FName : string; + const InHex : Boolean); + {-Dump the dispatch log} + var + Dest : array[0..255] of Char; + begin + if (PortState = psShuttingDown) then Exit; + CheckException(Self, + Dispatcher.DumpDispatchLog(StrPCopy(Dest, FName), InHex, LogAllHex)); + FLogging := tlOff; + end; + + procedure TApdCustomComPort.AppendLog(const FName : string; + const InHex : Boolean; + const NewState : TTraceLogState); // SWB + {-Dump the dispatch log} + var + Dest : array[0..255] of Char; + begin + if (PortState = psShuttingDown) then Exit; + CheckException(Self, + Dispatcher.AppendDispatchLog(StrPCopy(Dest, FName), InHex, LogAllHex)); + FLogging := NewState; // SWB + end; + + procedure TApdCustomComPort.ClearLogging; + {-Clear the log but keep logging} + begin + if (PortState = psShuttingDown) then Exit; + Dispatcher.ClearDispatchLogging; + end; + + procedure TApdCustomComPort.AbortLogging; + {-Abort logging without dumping the log} + begin + if (PortState = psShuttingDown) then Exit; + Dispatcher.AbortDispatchLogging; + FLogging := tlOff; + end; + + procedure TApdCustomComPort.StartLogging; + {-Resume logging after stopping} + begin + if (PortState = psShuttingDown) then Exit; + Dispatcher.StartDispatchLogging; + FLogging := tlOn; + end; + + procedure TApdCustomComPort.StopLogging; + {-Temporarily stop logging} + begin + if (PortState = psShuttingDown) then Exit; + Dispatcher.StopDispatchLogging; + FLogging := tlPause; + end; + + function TApdCustomComPort.AddDataTrigger(const Data : ShortString; + const IgnoreCase : Boolean) : Word; + {-Add a ShortString data trigger} + var + Len : Word; + P : array[0..255] of AnsiChar; + begin + if (PortState = psShuttingDown) then begin + Result := 0; + Exit; + end; + Len:=Length(data); + AnsiStrings.StrPLCopy(P, Data, Length(P) - 1); + Result := Word(CheckException(Self, + ValidDispatcher.AddDataTriggerLen(P, IgnoreCase, Len))); + end; + + function TApdCustomComPort.AddTimerTrigger : Word; + {-Add a timer trigger} + begin + if (PortState = psShuttingDown) then + Result := 0 + else + Result := Word(CheckException(Self, ValidDispatcher.AddTimerTrigger)); + end; + + function TApdCustomComPort.AddStatusTrigger(const SType : Word) : Word; + {-Add a status trigger of type SType} + begin + if (PortState = psShuttingDown) then + Result := 0 + else + Result := Word(CheckException(Self, + ValidDispatcher.AddStatusTrigger(SType))); + end; + + procedure TApdCustomComPort.RemoveTrigger(const Handle : Word); + {-Remove trigger with index Index} + begin + if (PortState = psOpen) then + CheckException(Self, Dispatcher.RemoveTrigger(Handle)); + end; + + procedure TApdCustomComPort.RemoveAllTriggers; + {-Remove all triggers} + begin + if (PortState = psOpen) then begin + Dispatcher.RemoveAllTriggers; + FTriggerLength := 0; + end; + end; + + procedure TApdCustomComPort.SetTimerTrigger(const Handle : Word; + const Ticks : Integer; + const Activate : Boolean); + {-Set the timer for trigger Index} + begin + if (PortState = psShuttingDown) then Exit; + CheckException(Self, ValidDispatcher.SetTimerTrigger(Handle, Ticks, Activate)); + end; + + procedure TApdCustomComPort.SetStatusTrigger(const Handle : Word; + const Value : Word; + const Activate : Boolean); + {-Set status trigger} + begin + if (PortState = psShuttingDown) then Exit; + CheckException(Self, + ValidDispatcher.SetStatusTrigger(Handle, Value, Activate)); + end; + +{I/O} + + function TApdCustomComPort.CharReady : Boolean; + {-Return the next character in the receive buffer} + begin + if (PortState = psShuttingDown) then + Result := False + else + Result := ValidDispatcher.CharReady; + end; + + function TApdCustomComPort.PeekChar(const Count : Word) : AnsiChar; + {-Peek at the Count'th character in the buffer (1=next)} + var + Res : Integer; + C : AnsiChar; + begin + if (PortState = psShuttingDown) then begin + Res := ecOk; + C := #0; + end else + Res := ValidDispatcher.PeekChar(C, Count); + if Res = ecOK then + Result := C + else begin + CheckException(Self, Res); + Result := #0; + end; + end; + + function TApdCustomComPort.GetChar : AnsiChar; + {-Retrieve the next character from the input queue} + var + Res : Integer; + C : AnsiChar; + begin + if (PortState = psShuttingDown) then begin + Res := ecOk; + C := #0; + end else + Res := ValidDispatcher.GetChar(C); + if Res = ecOK then + Result := C + else begin + CheckException(Self, Res); + Result := #0; + end; + end; + + procedure TApdCustomComPort.PeekBlock(var Block; const Len : Word); + {-Peek at the next Len characters, but don't remove from buffer} + begin + if (PortState = psShuttingDown) then Exit; + CheckException(Self, ValidDispatcher.PeekBlock(PAnsiChar(@Block), Len)); + end; + + procedure TApdCustomComPort.GetBlock(var Block; const Len : Word); + {-Return the next Len characters from the buffer} + begin + if (PortState = psShuttingDown) then Exit; + CheckException(Self, ValidDispatcher.GetBlock(PAnsiChar(@Block), Len)); + end; + + procedure TApdCustomComPort.PutChar(const C : AnsiChar); + {-Add C to the output buffer} + begin + if (PortState = psShuttingDown) then Exit; + CheckException(Self, ValidDispatcher.PutChar(C)); + end; + + procedure TApdCustomComPort.PutString(const S : string); + begin + PutString(AnsiString(S)); + end; + + procedure TApdCustomComPort.PutString(const S : AnsiString); + {-Add S to the output buffer} + begin + if (PortState = psShuttingDown) then Exit; + {$IFOPT H+} + CheckException(Self, ValidDispatcher.PutBlock(Pointer(S)^, Length(S))); + {$ELSE} + CheckException(Self, ValidDispatcher.PutString(S)); + {$ENDIF} + end; + + function TApdCustomComPort.PutBlock(const Block; const Len : Word) : Integer; + {-Add Block to the output buffer} + begin + PutBlock := 0; + if (PortState = psShuttingDown) then Exit; + CheckException(Self, ValidDispatcher.PutBlock(PByte(Block), Len)); + end; + +{Waits} + + function TApdCustomComPort.CheckForString(var Index : Byte; C : AnsiChar; + const S : AnsiString; + IgnoreCase : Boolean) : Boolean; + {-Compare C against a sequence of chars, looking for S} + var + CurChar : AnsiChar; + begin + CheckForString := False; + if (PortState = psShuttingDown) then Exit; + Inc(Index); + + {Upcase both data if ignoring case} + if IgnoreCase then begin + C := Upcase(C); + CurChar := Upcase(S[Index]); + end else + CurChar := S[Index]; + + {Compare...} + if C = CurChar then + {Got match, was it complete?} + if Index = Length(S) then begin + Index := 0; + CheckForString := True; + end else + else + {No match, reset Index} + if (IgnoreCase and (C = Upcase(S[1]))) or + (C = S[1]) then + Index := 1 + else + Index := 0; + end; + + function TApdCustomComPort.WaitForString(const S : AnsiString; + const Timeout : Integer; + const Yield, IgnoreCase : Boolean) + : Boolean; + {-Wait for data, generate ETimeout exception if not found} + var + ET : EventTimer; + C : AnsiChar; + CurChar : AnsiChar; + StartChar : AnsiChar; + Index : Byte; + Finished : Boolean; + WasBusy : Boolean; + Len : Word; + begin + Result := True; + + {Exit immediately if nothing to do} + if (S = '') or (PortState = psShuttingDown) then + Exit; + + {Set busy flag} + ValidDispatcher.SetEventBusy(WasBusy, True); + + {Note the length of the string} + Len := Length(S); + + {Prepare...} + NewTimer(ET, Timeout); + Index := 0; + Finished := False; + StartChar := S[1]; + if IgnoreCase then + StartChar := Upcase(StartChar); + + {Wait for data...} + repeat + if CharReady then begin + {Char is ready, go get it} + try // SWB + C := GetChar; + Inc(Index); + CurChar := S[Index]; + + {Report the character} + WaitChar(C); + + {If ignoring case then upcase both} + if IgnoreCase then begin + C := Upcase(C); + CurChar := Upcase(CurChar); + end; + + {Compare current character} + if C = CurChar then begin + if Index = Len then + Finished := True; + end else begin + {No match, reset...} + if C = StartChar then + Index := 1 + else + Index := 0; + end; + except // SWB + // There is a timing window between CharReady and GetChar where // SWB + // a call to FlushCom can cause 'buffer is empty' exceptions. So // SWB + // just ignore them. // SWB + on EBufferIsEmpty do // SWB + ; // SWB + else // SWB + raise; // SWB + end; // SWB + end; + + {Check for timeout if we're not otherwise finished} + if not Finished then begin + Finished := TimerExpired(ET); + + {Yield} + if Yield then + Application.ProcessMessages; + end; + until Finished or Application.Terminated; + + {Indicate timeout if we timed out} + if not Application.Terminated then + Result := not TimerExpired(ET); + + {Restore busy flag} + if WaitPrepped and not BusyBeforeWait then + Dispatcher.SetEventBusy(WasBusy, False) + else if not WasBusy then + Dispatcher.SetEventBusy(WasBusy, False); + WaitPrepped := False; + BusyBeforeWait := False; + end; + + function TApdCustomComPort.WaitForMultiString(const S : AnsiString; + const Timeout : Integer; + const Yield : Boolean; + const IgnoreCase : Boolean; + const SepChar : AnsiChar) : Integer; + {-Wait for S, which contains several substrings separated by ^} + const + MaxSubs = 127; + var + ET : EventTimer; + I, Total : Word; + C : AnsiChar; + CurChar : AnsiChar; + Finished : Boolean; + WasBusy : Boolean; + StartChar : array[1..MaxSubs] of AnsiChar; + StartIndex : array[1..MaxSubs] of Byte; + EndIndex : array[1..MaxSubs] of Byte; + Index : array[1..MaxSubs] of Byte; + Len : Word; + begin + Result := 0; + + {Exit immediately if nothing to do} + if (S = '') or (PortState = psShuttingDown) then + Exit; + + {Note the length of the string} + Len := Length(S); + + {Set busy flag} + ValidDispatcher.SetEventBusy(WasBusy, True); + + {Prepare to parse for substrings} + Total := 1; + I := 1; + StartIndex[Total] := I; + Index[Total] := I; + StartChar[Total] := S[I]; + if IgnoreCase then + StartChar[Total] := Upcase(StartChar[Total]); + + {Loop through S, noting start positions of each substring} + while (I <= Len) and (Total < MaxSubs) do begin + if S[I] = SepChar then begin + EndIndex[Total] := I-1; + Inc(I); + Inc(Total); + StartIndex[Total] := I; + Index[Total] := I; + StartChar[Total] := S[I]; + If IgnoreCase then + StartChar[Total] := Upcase(StartChar[Total]); + end else + Inc(I); + end; + + {Handle last string} + if S[Len] <> SepChar then + EndIndex[Total] := Len + else + Dec(Total); + + {Prepare to wait} + NewTimer(ET, Timeout); + Finished := False; + + {Wait for data...} + repeat + + if CharReady then begin + {Char is ready, go get it} + try // SWB + C := GetChar; + {Report the character} + WaitChar(C); + + {Handle case} + if IgnoreCase then + C := Upcase(C); + + {Compare against all substrings} + for I := 1 to Total do begin + CurChar := S[Index[I]]; + if IgnoreCase then + CurChar := Upcase(CurChar); + + {Compare current character} + if C = CurChar then begin + if Index[I] = EndIndex[I] then begin + Result := I; + Finished := True; + break; + end; + Inc(Index[I]); + end else begin + {No match, reset...} + if C = StartChar[I] then + Index[I] := StartIndex[I]+1 + else + Index[I] := StartIndex[I]; + end; + end; + except // SWB + // There is a timing window between CharReady and GetChar where // SWB + // a call to FlushCom can cause 'buffer is empty' exceptions. So // SWB + // just ignore them. // SWB + on EBufferIsEmpty do // SWB + ; // SWB + else // SWB + raise; // SWB + end; // SWB + end; + + {Check for timeout if we're not otherwise finished} + if not Finished then begin + Finished := TimerExpired(ET); + + {Yield} + if Yield then + Application.ProcessMessages; + end; + until Finished or Application.Terminated; + + {Restore busy flag} + if WaitPrepped and not BusyBeforeWait then + Dispatcher.SetEventBusy(WasBusy, False) + else if not WasBusy then + Dispatcher.SetEventBusy(WasBusy, False); + WaitPrepped := False; + BusyBeforeWait := False; + end; + + procedure TApdCustomComPort.PrepareWait; + {-Set EventBusy true to prevent triggers} + begin + if (PortState = psShuttingDown) then Exit; + WaitPrepped := True; + ValidDispatcher.SetEventBusy(BusyBeforeWait, True); + end; + +{Miscellaneous procedures} + + function SearchComPort(const C : TComponent) : TApdCustomComPort; + {-Search for a comport in the same form as TComponent} + + function FindComPort(const C : TComponent) : TApdCustomComPort; + var + I : Integer; + begin + Result := nil; + if not Assigned(C) then + Exit; + + {Look through all of the owned components} + for I := 0 to C.ComponentCount-1 do begin + if C.Components[I] is TApdCustomComPort then begin + Result := TApdCustomComPort(C.Components[I]); + Exit; + end; + + {If this isn't one, see if it owns other components} + Result := FindComPort(C.Components[I]); + end; + end; + + begin + {Search the entire form} + Result := FindComPort(C); + end; + + function ComName(const ComNumber : Word) : string; + {-Return a comname ShortString for ComNumber} + begin + Result := 'COM' + IntToStr(ComNumber); + end; + +function TApdCustomComPort.GetLastWinError: Integer; // SWB +begin // SWB + Result := Dispatcher.LastWinError; // SWB +end; // SWB + +end. diff --git a/AdSelCom.dfm b/AdSelCom.dfm new file mode 100644 index 0000000..08b8992 --- /dev/null +++ b/AdSelCom.dfm @@ -0,0 +1,74 @@ +object ComSelectForm: TComSelectForm + Left = 336 + Top = 234 + BorderIcons = [biSystemMenu] + BorderStyle = bsDialog + Caption = 'Select Port' + ClientHeight = 131 + ClientWidth = 220 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clBlack + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + OldCreateOrder = True + Position = poScreenCenter + OnCreate = FormCreate + PixelsPerInch = 96 + TextHeight = 13 + object Label1: TLabel + Left = 18 + Top = 14 + Width = 176 + Height = 13 + Caption = 'The configured serial port is not valid.' + end + object Label2: TLabel + Left = 18 + Top = 30 + Width = 133 + Height = 13 + Caption = 'Please choose another port.' + end + object Bevel1: TBevel + Left = 8 + Top = 8 + Width = 201 + Height = 42 + end + object OkBtn: TBitBtn + Left = 8 + Top = 95 + Width = 85 + Height = 27 + Caption = 'OK' + Default = True + DoubleBuffered = True + ModalResult = 1 + NumGlyphs = 2 + ParentDoubleBuffered = False + TabOrder = 0 + end + object AbortBtn: TBitBtn + Left = 124 + Top = 95 + Width = 85 + Height = 27 + Caption = 'Cancel' + DoubleBuffered = True + ModalResult = 3 + NumGlyphs = 2 + ParentDoubleBuffered = False + TabOrder = 1 + end + object PortsComboBox: TComboBox + Left = 8 + Top = 64 + Width = 201 + Height = 21 + Style = csDropDownList + ItemHeight = 0 + TabOrder = 2 + end +end diff --git a/AdSelCom.pas b/AdSelCom.pas new file mode 100644 index 0000000..e754a50 --- /dev/null +++ b/AdSelCom.pas @@ -0,0 +1,198 @@ +(***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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 TurboPower Async Professional + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1991-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Sebastian Zierer + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* ADSELCOM.PAS 5.00 *} +{*********************************************************} +{* Port selection dialog, IsPortAvailable method *} +{*********************************************************} + +{Global defines potentially affecting this unit} +{$I AWDEFINE.INC} + +{Options required for this unit} +{$G+,X+,F+,J+} +{$C MOVEABLE,DEMANDLOAD,DISCARDABLE} + +unit AdSelCom; + {-Com port selection dialog} +interface + +uses + Windows, + SysUtils, + Classes, + Messages, + Graphics, + Controls, + Forms, + Dialogs, + StdCtrls, + ExtCtrls, + Buttons, + OoMisc, + AwUser, +{$IFNDEF UseAwWin32} + LnsWin32; +{$ELSE} + AwWin32; +{$ENDIF} + +type + TComSelectForm = class(TForm) + Label1: TLabel; + Label2: TLabel; + OkBtn: TBitBtn; + AbortBtn: TBitBtn; + Bevel1: TBevel; + PortsComboBox: TComboBox; + procedure FormCreate(Sender: TObject); + private + public + function SelectedCom : String; + function SelectedComNum : Word; + end; + +function IsPortAvailable(ComNum : Cardinal) : Boolean; + +const + {True to create a dispatcher to validate the port; false to open the + port using direct API calls} + UseDispatcherForAvail : Boolean = True; + {True to return True even if the port is in use; False to return False + if the port is in use} + ShowPortsInUse : Boolean = True; +implementation + +{$R *.DFM} + +function IsPortAvailable(ComNum : Cardinal) : Boolean; + function MakeComName(const Dest : PChar; const ComNum : Cardinal) : PChar; + {-Return a string like 'COMXX'} + begin + StrFmt(Dest,'\\.\COM%d',[ComNum]); + MakeComName := Dest; + end; + +var + ComName : array[0..12] of Char; + Res : Integer; + DeviceLayer : TApdBaseDispatcher; + CC: TCommConfig; + Len: Cardinal; +begin + DeviceLayer := nil; + try + if (ComNum = 0) then + Result := False + else begin + if UseDispatcherForAvail then + begin + DeviceLayer := TApdWin32Dispatcher.Create(nil); + + if ShowPortsInUse then + begin + Result := DeviceLayer.CheckPort(MakeComName(ComName,ComNum)); + end + else + begin + Res := DeviceLayer.OpenCom(MakeComName(ComName,ComNum), 64, 64); + if (Res < 0) then + if ShowPortsInUse then + Result := GetLastError = DWORD(Abs(ecAccessDenied)) + else + Result := False + else begin + Result := True; + DeviceLayer.CloseCom; + end; + end; + end else + begin + if ShowPortsInUse then //SZ: optimize this one - otherwise bluetooth devices may request confirmation + begin + FillChar(CC, SizeOf(CC), 0); + CC.dwSize := SizeOf(CC); + Len := SizeOf(CC); + Result := GetDefaultCommConfig(MakeComName(ComName, ComNum) + 4, CC, Len); + end + else + begin + Res := CreateFile(MakeComName(ComName, ComNum), + GENERIC_READ or GENERIC_WRITE, + 0, + nil, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL or + FILE_FLAG_OVERLAPPED, + 0); + + if Res > 0 then begin + CloseHandle(Res); + Result := True; + end else begin + if ShowPortsInUse then + Result := GetLastError = DWORD(Abs(ecAccessDenied)) + else + Result := False; + end; + end; + end; + end; + finally + if UseDispatcherForAvail then + DeviceLayer.Free; + end; +end; + +procedure TComSelectForm.FormCreate(Sender: TObject); +var + I : Integer; + S : string; +begin + for I := 1 to MaxComHandles do + if IsPortAvailable(I) then begin + S := Format('COM%d', [I]); + PortsComboBox.Items.Add(S); + end; + PortsComboBox.ItemIndex := 0; +end; + +function TComSelectForm.SelectedCom : String; +begin + Result := PortsComboBox.Items[PortsComboBox.ItemIndex]; +end; + +function TComSelectForm.SelectedComNum : Word; +var + S : String; +begin + S := PortsComboBox.Items[PortsComboBox.ItemIndex]; + S := Copy(S, 4, 255); + Result := StrToInt(S); +end; + +end. diff --git a/AdStrMap.pas b/AdStrMap.pas new file mode 100644 index 0000000..2e02dfc --- /dev/null +++ b/AdStrMap.pas @@ -0,0 +1,959 @@ +(***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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 TurboPower Async Professional + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1991-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* ADSTRMAP.PAS 4.06 *} +{*********************************************************} +(* Defines the string mapping tables *) +{*********************************************************} + +{ + This replaces the string resource manager. Disable the + UseResourceStrings define in AwDefine.inc to use the string + resource manager instead if desired. +} +{Global defines potentially affecting this unit} +{$I AWDEFINE.INC} + +unit AdStrMap; + +interface + +uses + OOMisc, AdExcept; + +const + AdMaxMessages = 896; { the number of messages in the message map array } // SWB + +type + AdMessageNumberLookupRecord = record + MessageNumber : integer; + MessageString : string; + end; + +const + AdMessageNumberLookup : array [0..AdMaxMessages] of AdMessageNumberLookupRecord =( +{ # } {Error mnemonic or code} {Error string} +{ 0}(MessageNumber : ecOK; MessageString : secOK), +{ 2}(MessageNumber : ecFileNotFound; MessageString : secFileNotFound), +{ 3}(MessageNumber : ecPathNotFound; MessageString : secPathNotFound), +{ 4}(MessageNumber : ecTooManyFiles; MessageString : secTooManyFiles), +{ 5}(MessageNumber : ecAccessDenied; MessageString : secAccessDenied), +{ 6}(MessageNumber : ecInvalidHandle; MessageString : secInvalidHandle), +{ 8}(MessageNumber : ecOutOfMemory; MessageString : secOutOfMemory), +{ 15}(MessageNumber : ecInvalidDrive; MessageString : secInvalidDrive), +{ 18}(MessageNumber : ecNoMoreFiles; MessageString : secNoMoreFiles), +{ 100}(MessageNumber : ecDiskRead; MessageString : secDiskRead), +{ 101}(MessageNumber : ecDiskFull; MessageString : secDiskFull), +{ 102}(MessageNumber : ecNotAssigned; MessageString : secNotAssigned), +{ 103}(MessageNumber : ecNotOpen; MessageString : secNotOpen), +{ 104}(MessageNumber : ecNotOpenInput; MessageString : secNotOpenInput), +{ 105}(MessageNumber : ecNotOpenOutput; MessageString : secNotOpenOutput), +{ 150}(MessageNumber : ecWriteProtected; MessageString : secWriteProtected), +{ 151}(MessageNumber : ecUnknownUnit; MessageString : secUnknownUnit), +{ 152}(MessageNumber : ecDriveNotReady; MessageString : secDriveNotReady), +{ 153}(MessageNumber : ecUnknownCommand; MessageString : secUnknownCommand), +{ 154}(MessageNumber : ecCrcError; MessageString : secCrcError), +{ 155}(MessageNumber : ecBadStructLen; MessageString : secBadStructLen), +{ 156}(MessageNumber : ecSeekError; MessageString : secSeekError), +{ 157}(MessageNumber : ecUnknownMedia; MessageString : secUnknownMedia), +{ 158}(MessageNumber : ecSectorNotFound; MessageString : secSectorNotFound), +{ 159}(MessageNumber : ecOutOfPaper; MessageString : secOutOfPaper), +{ 160}(MessageNumber : ecDeviceWrite; MessageString : secDeviceWrite), +{ 161}(MessageNumber : ecDeviceRead; MessageString : secDeviceRead), +{ 162}(MessageNumber : ecHardwareFailure; MessageString : secHardwareFailure), +{ 1001}(MessageNumber : ecBadHandle; MessageString : secBadHandle), +{ 1002}(MessageNumber : ecBadArgument; MessageString : secBadArgument), +{ 1003}(MessageNumber : ecGotQuitMsg; MessageString : secGotQuitMsg), +{ 1004}(MessageNumber : ecBufferTooBig; MessageString : secBufferTooBig), +{ 1005}(MessageNumber : ecPortNotAssigned; MessageString : secPortNotAssigned), +{ 1006}(MessageNumber : ecInternal; MessageString : secInternal), +{ 1007}(MessageNumber : ecModemNotAssigned; MessageString : secModemNotAssigned), +{ 1008}(MessageNumber : ecPhonebookNotAssigned; MessageString : secPhonebookNotAssigned), +{ 1009}(MessageNumber : ecCannotUseWithWinSock; MessageString : secCannotUseWithWinSock), +{ 2001}(MessageNumber : ecBadId; MessageString : secBadId), +{ 2002}(MessageNumber : ecBaudRate; MessageString : secBaudRate), +{ 2003}(MessageNumber : ecByteSize; MessageString : secByteSize), +{ 2004}(MessageNumber : ecDefault; MessageString : secDefault), +{ 2005}(MessageNumber : ecHardware; MessageString : secHardware), +{ 2006}(MessageNumber : ecMemory; MessageString : secMemory), +{ 2007}(MessageNumber : ecCommNotOpen; MessageString : secCommNotOpen), +{ 2008}(MessageNumber : ecAlreadyOpen; MessageString : secAlreadyOpen), +{ 2009}(MessageNumber : ecNoHandles; MessageString : secNoHandles), +{ 2010}(MessageNumber : ecNoTimers; MessageString : secNoTimers), +{ 2011}(MessageNumber : ecNoPortSelected; MessageString : secNoPortSelected), +{ 2012}(MessageNumber : ecNotOpenedByTapi; MessageString : secNotOpenedByTapi), +{ 3001}(MessageNumber : ecNullApi; MessageString : secNullApi), +{ 3002}(MessageNumber : ecNotSupported; MessageString : secNotSupported), +{ 3003}(MessageNumber : ecRegisterHandlerFailed; MessageString : secRegisterHandlerFailed), +{ 3004}(MessageNumber : ecPutBlockFail; MessageString : secPutBlockFail), +{ 3005}(MessageNumber : ecGetBlockFail; MessageString : secGetBlockFail), +{ 3006}(MessageNumber : ecOutputBufferTooSmall; MessageString : secOutputBufferTooSmall), +{ 3007}(MessageNumber : ecBufferIsEmpty; MessageString : secBufferIsEmpty), +{ 3008}(MessageNumber : ecTracingNotEnabled; MessageString : secTracingNotEnabled), +{ 3009}(MessageNumber : ecLoggingNotEnabled; MessageString : secLoggingNotEnabled), +{ 3010}(MessageNumber : ecBaseAddressNotSet; MessageString : secBaseAddressNotSet), +{ 4001}(MessageNumber : ecModemNotStarted; MessageString : secModemNotStarted), +{ 4002}(MessageNumber : ecModemBusy; MessageString : secModemBusy), +{ 4003}(MessageNumber : ecModemNotDialing; MessageString : secModemNotDialing), +{ 4004}(MessageNumber : ecNotDialing; MessageString : secNotDialing), +{ 4005}(MessageNumber : ecAlreadyDialing; MessageString : secAlreadyDialing), +{ 4006}(MessageNumber : ecModemNotResponding; MessageString : secModemNotResponding), +{ 4007}(MessageNumber : ecModemRejectedCommand; MessageString : secModemRejectedCommand), +{ 4008}(MessageNumber : ecModemStatusMismatch; MessageString : secModemStatusMismatch), +{ 4009}(MessageNumber : ecDeviceNotSelected; MessageString : secDeviceNotSelected), +{ 4010}(MessageNumber : ecModemDetectedBusy; MessageString : secModemDetectedBusy), +{ 4011}(MessageNumber : ecModemNoDialtone; MessageString : secModemNoDialtone), +{ 4012}(MessageNumber : ecModemNoCarrier; MessageString : secModemNoCarrier), +{ 4013}(MessageNumber : ecModemNoAnswer; MessageString : secModemNoAnswer), +{ 4014}(MessageNumber : ecInitFail; MessageString : secInitFail), +{ 4015}(MessageNumber : ecLoginFail; MessageString : secLoginFail), +{ 4016}(MessageNumber : ecMinorSrvErr; MessageString : secMinorSrvErr), +{ 4017}(MessageNumber : ecFatalSrvErr; MessageString : secFatalSrvErr), +{ 4020}(MessageNumber : ecModemNotFound; MessageString : secModemNotFound), +{ 4021}(MessageNumber : ecInvalidFile; MessageString : secInvalidFile), +{ 4101}(MessageNumber : 4101; MessageString : spbeDeleteQuery), +{ 4200}(MessageNumber : 4200; MessageString : sdsmMsgBase), +{ 4201}(MessageNumber : 4201; MessageString : sdsmMsgReady), +{ 4202}(MessageNumber : 4202; MessageString : sdsmMsgInitialize), +{ 4203}(MessageNumber : 4203; MessageString : sdsmMsgInitializeTimeout), +{ 4204}(MessageNumber : 4204; MessageString : sdsmMsgAutoAnswerBackground), +{ 4205}(MessageNumber : 4205; MessageString : sdsmMsgAutoAnswerWait), +{ 4206}(MessageNumber : 4206; MessageString : sdsmMsgAnswerWait), +{ 4207}(MessageNumber : 4207; MessageString : sdsmMsgDialWait), +{ 4208}(MessageNumber : 4208; MessageString : sdsmMsgDialCycle), +{ 4209}(MessageNumber : 4209; MessageString : sdsmMsgNoDialtone), +{ 4210}(MessageNumber : 4210; MessageString : sdsmMsgConnectWait), +{ 4211}(MessageNumber : 4211; MessageString : sdsmMsgConnected), +{ 4212}(MessageNumber : 4212; MessageString : sdsmMsgHangup), +{ 4213}(MessageNumber : 4213; MessageString : sdsmMsgCancel), +{ 4301}(MessageNumber : 4301; MessageString : sdddCycling), +{ 4302}(MessageNumber : 4302; MessageString : sdddRetryWaiting), +{ 4303}(MessageNumber : 4303; MessageString : sdddRetryWaitOver), +{ 4304}(MessageNumber : 4304; MessageString : sdddDialing), +{ 4305}(MessageNumber : 4305; MessageString : sdddModemConnect), +{ 4306}(MessageNumber : 4306; MessageString : sdddModemConnectAt), +{ 4307}(MessageNumber : 4307; MessageString : sdddModemVoice), +{ 4308}(MessageNumber : 4308; MessageString : sdddModemError), +{ 4309}(MessageNumber : 4309; MessageString : sdddModemNoCarrier), +{ 4310}(MessageNumber : 4310; MessageString : sdddModemBusy), +{ 4311}(MessageNumber : 4311; MessageString : sdddModemNoDialTone), +{ 4312}(MessageNumber : 4312; MessageString : sdddDialTimedOut), +{ 4401}(MessageNumber : 4401; MessageString : sdpeMustEnterName), +{ 4402}(MessageNumber : 4402; MessageString : sdpeMustEnterNumber), +{ 4403}(MessageNumber : 4403; MessageString : sdpeNameExists), +{ 4500}(MessageNumber : csOpenPort; MessageString : scsOpenPort), +{ 4501}(MessageNumber : csPortOpened; MessageString : scsPortOpened), +{ 4502}(MessageNumber : csConnectDevice; MessageString : scsConnectDevice), +{ 4503}(MessageNumber : csDeviceConnected; MessageString : scsDeviceConnected), +{ 4504}(MessageNumber : csAllDevicesConnected; MessageString : scsAllDevicesConnected), +{ 4505}(MessageNumber : csAuthenticate; MessageString : scsAuthenticate), +{ 4506}(MessageNumber : csAuthNotify; MessageString : scsAuthNotify), +{ 4507}(MessageNumber : csAuthRetry; MessageString : scsAuthRetry), +{ 4508}(MessageNumber : csAuthCallback; MessageString : scsAuthCallback), +{ 4509}(MessageNumber : csAuthChangePassword; MessageString : scsAuthChangePassword), +{ 4510}(MessageNumber : csAuthProject; MessageString : scsAuthProject), +{ 4511}(MessageNumber : csAuthLinkSpeed; MessageString : scsAuthLinkSpeed), +{ 4512}(MessageNumber : csAuthAck; MessageString : scsAuthAck), +{ 4513}(MessageNumber : csReAuthenticate; MessageString : scsReAuthenticate), +{ 4514}(MessageNumber : csAuthenticated; MessageString : scsAuthenticated), +{ 4515}(MessageNumber : csPrepareForCallback; MessageString : scsPrepareForCallback), +{ 4516}(MessageNumber : csWaitForModemReset; MessageString : scsWaitForModemReset), +{ 4517}(MessageNumber : csWaitForCallback; MessageString : scsWaitForCallback), +{ 4518}(MessageNumber : csProjected; MessageString : scsProjected), +{ 4519}(MessageNumber : csStartAuthentication; MessageString : scsStartAuthentication), +{ 4520}(MessageNumber : csCallbackComplete; MessageString : scsCallbackComplete), +{ 4521}(MessageNumber : csLogonNetwork; MessageString : scsLogonNetwork), +{ 4522}(MessageNumber : csSubEntryConnected; MessageString : scsSubEntryConnected), +{ 4523}(MessageNumber : csSubEntryDisconnected; MessageString : scsSubEntryDisconnected), +{ 4550}(MessageNumber : csRasInteractive; MessageString : scsRasInteractive), +{ 4551}(MessageNumber : csRasRetryAuthentication; MessageString : scsRasRetryAuthentication), +{ 4552}(MessageNumber : csRasCallbackSetByCaller; MessageString : scsRasCallbackSetByCaller), +{ 4553}(MessageNumber : csRasPasswordExpired; MessageString : scsRasPasswordExpired), +{ 4599}(MessageNumber : csRasDeviceConnected; MessageString : scsRasDeviceConnected), +{ 4600}(MessageNumber : 4600; MessageString : sPDS_NONE), +{ 4601}(MessageNumber : 4601; MessageString : sPDS_OFFHOOK), +{ 4602}(MessageNumber : 4602; MessageString : sPDS_DIALING), +{ 4603}(MessageNumber : 4603; MessageString : sPDS_RINGING), +{ 4604}(MessageNumber : 4604; MessageString : sPDS_WAITFORCONNECT), +{ 4605}(MessageNumber : 4605; MessageString : sPDS_CONNECTED), +{ 4606}(MessageNumber : 4606; MessageString : sPDS_WAITINGTOREDIAL), +{ 4607}(MessageNumber : 4607; MessageString : sPDS_REDIALING), +{ 4608}(MessageNumber : 4608; MessageString : sPDS_MSGNOTSENT), +{ 4609}(MessageNumber : 4609; MessageString : sPDS_CANCELLING), +{ 4610}(MessageNumber : 4610; MessageString : sPDS_DISCONNECT), +{ 4611}(MessageNumber : 4611; MessageString : sPDS_CLEANUP), +{ 4630}(MessageNumber : 4630; MessageString : sPDE_NONE), +{ 4631}(MessageNumber : 4631; MessageString : sPDE_NODIALTONE), +{ 4632}(MessageNumber : 4632; MessageString : sPDE_LINEBUSY), +{ 4633}(MessageNumber : 4633; MessageString : sPDE_NOCONNECTION), +{ 4660}(MessageNumber : 4660; MessageString : sTAPS_NONE), +{ 4661}(MessageNumber : 4661; MessageString : sTAPS_LOGINPROMPT), +{ 4662}(MessageNumber : 4662; MessageString : sTAPS_LOGGEDIN), +{ 4663}(MessageNumber : 4663; MessageString : sTAPS_LOGINERR), +{ 4664}(MessageNumber : 4664; MessageString : sTAPS_LOGINFAIL), +{ 4665}(MessageNumber : 4665; MessageString : sTAPS_MSGOKTOSEND), +{ 4666}(MessageNumber : 4666; MessageString : sTAPS_SENDINGMSG), +{ 4667}(MessageNumber : 4667; MessageString : sTAPS_MSGACK), +{ 4668}(MessageNumber : 4668; MessageString : sTAPS_MSGNAK), +{ 4669}(MessageNumber : 4669; MessageString : sTAPS_MSGRS), +{ 4670}(MessageNumber : 4670; MessageString : sTAPS_MSGCOMPLETED), +{ 4671}(MessageNumber : 4671; MessageString : sTAPS_DONE), +{ 4700}(MessageNumber : psOK; MessageString : spsOK), +{ 4701}(MessageNumber : psProtocolHandshake; MessageString : spsProtocolHandshake), +{ 4702}(MessageNumber : psInvalidDate; MessageString : spsInvalidDate), +{ 4703}(MessageNumber : psFileRejected; MessageString : spsFileRejected), +{ 4704}(MessageNumber : psFileRenamed; MessageString : spsFileRenamed), +{ 4705}(MessageNumber : psSkipFile; MessageString : spsSkipFile), +{ 4706}(MessageNumber : psFileDoesntExist; MessageString : spsFileDoesntExist), +{ 4707}(MessageNumber : psCantWriteFile; MessageString : spsCantWriteFile), +{ 4708}(MessageNumber : psTimeout; MessageString : spsTimeout), +{ 4709}(MessageNumber : psBlockCheckError; MessageString : spsBlockCheckError), +{ 4710}(MessageNumber : psLongPacket; MessageString : spsLongPacket), +{ 4711}(MessageNumber : psDuplicateBlock; MessageString : spsDuplicateBlock), +{ 4712}(MessageNumber : psProtocolError; MessageString : spsProtocolError), +{ 4713}(MessageNumber : psCancelRequested; MessageString : spsCancelRequested), +{ 4714}(MessageNumber : psEndFile; MessageString : spsEndFile), +{ 4715}(MessageNumber : psResumeBad; MessageString : spsResumeBad), +{ 4716}(MessageNumber : psSequenceError; MessageString : spsSequenceError), +{ 4717}(MessageNumber : psAbortNoCarrier; MessageString : spsAbortNoCarrier), +{ 4718}(MessageNumber : psGotCrcE; MessageString : spsGotCrcE), +{ 4719}(MessageNumber : psGotCrcG; MessageString : spsGotCrcG), +{ 4720}(MessageNumber : psGotCrcW; MessageString : spsGotCrcW), +{ 4721}(MessageNumber : psGotCrcQ; MessageString : spsGotCrcQ), +{ 4722}(MessageNumber : psTryResume; MessageString : spsTryResume), +{ 4723}(MessageNumber : psHostResume; MessageString : spsHostResume), +{ 4724}(MessageNumber : psWaitAck; MessageString : spsWaitAck), +{ 4725}(MessageNumber : psNoHeader; MessageString : spsNoHeader), +{ 4726}(MessageNumber : psGotHeader; MessageString : spsGotHeader), +{ 4727}(MessageNumber : psGotData; MessageString : spsGotData), +{ 4728}(MessageNumber : psNoData; MessageString : spsNoData), +{ 4730}(MessageNumber : psAbort; MessageString : spsAbort), +{ 4801}(MessageNumber : fpInitModem; MessageString : sfpInitModem), +{ 4802}(MessageNumber : fpDialing; MessageString : sfpDialing), +{ 4803}(MessageNumber : fpBusyWait; MessageString : sfpBusyWait), +{ 4804}(MessageNumber : fpSendPage; MessageString : sfpSendPage), +{ 4805}(MessageNumber : fpSendPageStatus; MessageString : sfpSendPageStatus), +{ 4806}(MessageNumber : fpPageError; MessageString : sfpPageError), +{ 4807}(MessageNumber : fpPageOK; MessageString : sfpPageOK), +{ 4808}(MessageNumber : fpConnecting; MessageString : sfpConnecting), +{ 4820}(MessageNumber : fpWaiting; MessageString : sfpWaiting), +{ 4821}(MessageNumber : fpNoConnect; MessageString : sfpNoConnect), +{ 4822}(MessageNumber : fpAnswer; MessageString : sfpAnswer), +{ 4823}(MessageNumber : fpIncoming; MessageString : sfpIncoming), +{ 4824}(MessageNumber : fpGetPage; MessageString : sfpGetPage), +{ 4825}(MessageNumber : fpGetPageResult; MessageString : sfpGetPageResult), +{ 4826}(MessageNumber : fpCheckMorePages; MessageString : sfpCheckMorePages), +{ 4827}(MessageNumber : fpGetHangup; MessageString : sfpGetHangup), +{ 4828}(MessageNumber : fpGotHangup; MessageString : sfpGotHangup), +{ 4830}(MessageNumber : fpSwitchModes; MessageString : sfpSwitchModes), +{ 4831}(MessageNumber : fpMonitorEnabled; MessageString : sfpMonitorEnabled), +{ 4832}(MessageNumber : fpMonitorDisabled; MessageString : sfpMonitorDisabled), +{ 4840}(MessageNumber : fpSessionParams; MessageString : sfpSessionParams), +{ 4841}(MessageNumber : fpGotRemoteID; MessageString : sfpGotRemoteID), +{ 4842}(MessageNumber : fpCancel; MessageString : sfpCancel), +{ 4843}(MessageNumber : fpFinished; MessageString : sfpFinished), +{ 5001}(MessageNumber : ecNoMoreTriggers; MessageString : secNoMoreTriggers), +{ 5002}(MessageNumber : ecTriggerTooLong; MessageString : secTriggerTooLong), +{ 5003}(MessageNumber : ecBadTriggerHandle; MessageString : secBadTriggerHandle), +{ 5501}(MessageNumber : ecStartStringEmpty; MessageString : secStartStringEmpty), +{ 5502}(MessageNumber : ecPacketTooSmall; MessageString : secPacketTooSmall), +{ 5503}(MessageNumber : ecNoEndCharCount; MessageString : secNoEndCharCount), +{ 5504}(MessageNumber : ecEmptyEndString; MessageString : secEmptyEndString), +{ 5505}(MessageNumber : ecZeroSizePacket; MessageString : secZeroSizePacket), +{ 5506}(MessageNumber : ecPacketTooLong; MessageString : secPacketTooLong), +{ 6001}(MessageNumber : ecBadFileList; MessageString : secBadFileList), +{ 6002}(MessageNumber : ecNoSearchMask; MessageString : secNoSearchMask), +{ 6003}(MessageNumber : ecNoMatchingFiles; MessageString : secNoMatchingFiles), +{ 6004}(MessageNumber : ecDirNotFound; MessageString : secDirNotFound), +{ 6005}(MessageNumber : ecCancelRequested; MessageString : secCancelRequested), +{ 6006}(MessageNumber : ecTimeout; MessageString : secTimeout), +{ 6007}(MessageNumber : ecProtocolError; MessageString : secProtocolError), +{ 6008}(MessageNumber : ecTooManyErrors; MessageString : secTooManyErrors), +{ 6009}(MessageNumber : ecSequenceError; MessageString : secSequenceError), +{ 6010}(MessageNumber : ecNoFilename; MessageString : secNoFilename), +{ 6011}(MessageNumber : ecFileRejected; MessageString : secFileRejected), +{ 6012}(MessageNumber : ecCantWriteFile; MessageString : secCantWriteFile), +{ 6013}(MessageNumber : ecTableFull; MessageString : secTableFull), +{ 6014}(MessageNumber : ecAbortNoCarrier; MessageString : secAbortNoCarrier), +{ 6015}(MessageNumber : ecBadProtocolFunction; MessageString : secBadProtocolFunction), +{ 6016}(MessageNumber : ecProtocolAbort; MessageString : secProtocolAbort), +{ 7001}(MessageNumber : ecKeyTooLong; MessageString : secKeyTooLong), +{ 7002}(MessageNumber : ecDataTooLarge; MessageString : secDataTooLarge), +{ 7003}(MessageNumber : ecNoFieldsDefined; MessageString : secNoFieldsDefined), +{ 7004}(MessageNumber : ecIniWrite; MessageString : secIniWrite), +{ 7005}(MessageNumber : ecIniRead; MessageString : secIniRead), +{ 7006}(MessageNumber : ecNoIndexKey; MessageString : secNoIndexKey), +{ 7007}(MessageNumber : ecRecordExists; MessageString : secRecordExists), +{ 7008}(MessageNumber : ecRecordNotFound; MessageString : secRecordNotFound), +{ 7009}(MessageNumber : ecMustHaveIdxVal; MessageString : secMustHaveIdxVal), +{ 7010}(MessageNumber : ecDatabaseFull; MessageString : secDatabaseFull), +{ 7011}(MessageNumber : ecDatabaseEmpty; MessageString : secDatabaseEmpty), +{ 7012}(MessageNumber : ecDatabaseNotPrepared; MessageString : secDatabaseNotPrepared), +{ 7013}(MessageNumber : ecBadFieldList; MessageString : secBadFieldList), +{ 7014}(MessageNumber : ecBadFieldForIndex; MessageString : secBadFieldForIndex), +{ 7500}(MessageNumber : ecNoStateMachine; MessageString : secNoStateMachine), +{ 7501}(MessageNumber : ecNoStartState; MessageString : secNoStartState), +{ 7502}(MessageNumber : ecNoSapiEngine; MessageString : secNoSapiEngine), +{ 8001}(MessageNumber : ecFaxBadFormat; MessageString : secFaxBadFormat), +{ 8002}(MessageNumber : ecBadGraphicsFormat; MessageString : secBadGraphicsFormat), +{ 8003}(MessageNumber : ecConvertAbort; MessageString : secConvertAbort), +{ 8004}(MessageNumber : ecUnpackAbort; MessageString : secUnpackAbort), +{ 8005}(MessageNumber : ecCantMakeBitmap; MessageString : secCantMakeBitmap), +{ 8050}(MessageNumber : ecNoImageLoaded; MessageString : secNoImageLoaded), +{ 8051}(MessageNumber : ecNoImageBlockMarked; MessageString : secNoImageBlockMarked), +{ 8052}(MessageNumber : ecFontFileNotFound; MessageString : secFontFileNotFound), +{ 8053}(MessageNumber : ecInvalidPageNumber; MessageString : secInvalidPageNumber), +{ 8054}(MessageNumber : ecBmpTooBig; MessageString : secBmpTooBig), +{ 8055}(MessageNumber : ecEnhFontTooBig; MessageString : secEnhFontTooBig), +{ 8060}(MessageNumber : ecFaxBadMachine; MessageString : secFaxBadMachine), +{ 8061}(MessageNumber : ecFaxBadModemResult; MessageString : secFaxBadModemResult), +{ 8062}(MessageNumber : ecFaxTrainError; MessageString : secFaxTrainError), +{ 8063}(MessageNumber : ecFaxInitError; MessageString : secFaxInitError), +{ 8064}(MessageNumber : ecFaxBusy; MessageString : secFaxBusy), +{ 8065}(MessageNumber : ecFaxVoiceCall; MessageString : secFaxVoiceCall), +{ 8066}(MessageNumber : ecFaxDataCall; MessageString : secFaxDataCall), +{ 8067}(MessageNumber : ecFaxNoDialTone; MessageString : secFaxNoDialTone), +{ 8068}(MessageNumber : ecFaxNoCarrier; MessageString : secFaxNoCarrier), +{ 8069}(MessageNumber : ecFaxSessionError; MessageString : secFaxSessionError), +{ 8070}(MessageNumber : ecFaxPageError; MessageString : secFaxPageError), +{ 8071}(MessageNumber : ecFaxGDIPrintError; MessageString : secFaxGDIPrintError), +{ 8072}(MessageNumber : ecFaxMixedResolution; MessageString : secFaxMixedResolution), +{ 8073}(MessageNumber : ecFaxConverterInitFail; MessageString : secFaxConverterInitFail), +{ 8074}(MessageNumber : ecNoAnswer; MessageString : secNoAnswer), +{ 8075}(MessageNumber : ecAlreadyMonitored; MessageString : secAlreadyMonitored), +{ 8080}(MessageNumber : ecUniAlreadyInstalled; MessageString : secUniAlreadyInstalled), +{ 8081}(MessageNumber : ecUniCannotGetSysDir; MessageString : secUniCannotGetSysDir), +{ 8082}(MessageNumber : ecUniCannotGetWinDir; MessageString : secUniCannotGetWinDir), +{ 8083}(MessageNumber : ecUniUnknownLayout; MessageString : secUniUnknownLayout), +{ 8085}(MessageNumber : ecUniCannotInstallFile; MessageString : secUniCannotInstallFile), +{ 8087}(MessageNumber : ecDrvCopyError; MessageString : secDrvCopyError), +{ 8088}(MessageNumber : ecCannotAddPrinter; MessageString : secCannotAddPrinter), +{ 8089}(MessageNumber : ecDrvBadResources; MessageString : secDrvBadResources), +{ 8090}(MessageNumber : ecDrvDriverNotFound; MessageString : secDrvDriverNotFound), +{ 8091}(MessageNumber : ecUniCannotGetPrinterDriverDir;MessageString : secUniCannotGetPrinterDriverDir), +{ 8092}(MessageNumber : ecInstallDriverFailed; MessageString : secInstallDriverFailed), +{ 8100}(MessageNumber : ecSMSBusy; MessageString : secSMSBusy), +{ 8101}(MessageNumber : ecSMSTimedOut; MessageString : secSMSTimedOut), +{ 8102}(MessageNumber : ecSMSTooLong; MessageString : secSMSTooLong), +{ 8103}(MessageNumber : ecSMSUnknownStatus; MessageString : secSMSUnknownStatus), +{ 8300}(MessageNumber : ecMEFailure; MessageString : secMEFailure), +{ 8301}(MessageNumber : ecServiceRes; MessageString : secServiceRes), +{ 8302}(MessageNumber : ecBadOperation; MessageString : secBadOperation), +{ 8303}(MessageNumber : ecUnsupported; MessageString : secUnsupported), +{ 8304}(MessageNumber : ecInvalidPDU; MessageString : secInvalidPDU), +{ 8305}(MessageNumber : ecInvalidText; MessageString : secInvalidText), +{ 8310}(MessageNumber : ecSIMInsert; MessageString : secSIMInsert), +{ 8311}(MessageNumber : ecSIMPin; MessageString : secSIMPin), +{ 8312}(MessageNumber : ecSIMPH; MessageString : secSIMPH), +{ 8313}(MessageNumber : ecSIMFailure; MessageString : secSIMFailure), +{ 8314}(MessageNumber : ecSIMBusy; MessageString : secSIMBusy), +{ 8315}(MessageNumber : ecSIMWrong; MessageString : secSIMWrong), +{ 8316}(MessageNumber : ecSIMPUK; MessageString : secSIMPUK), +{ 8317}(MessageNumber : ecSIMPIN2; MessageString : secSIMPIN2), +{ 8318}(MessageNumber : ecSIMPUK2; MessageString : secSIMPUK2), +{ 8320}(MessageNumber : ecMemFail; MessageString : secMemFail), +{ 8321}(MessageNumber : ecInvalidMemIndex; MessageString : secInvalidMemIndex), +{ 8322}(MessageNumber : ecMemFull; MessageString : secMemFull), +{ 8330}(MessageNumber : ecSMSCAddUnknown; MessageString : secSMSCAddUnknown), +{ 8331}(MessageNumber : ecNoNetwork; MessageString : secNoNetwork), +{ 8332}(MessageNumber : ecNetworkTimeout; MessageString : secNetworkTimeout), +{ 8340}(MessageNumber : ecCNMAAck; MessageString : secCNMAAck), +{ 8500}(MessageNumber : ecUnknown; MessageString : secUnknown), +{ 9001}(MessageNumber : ecADWSERROR; MessageString : secADWSERROR), +{ 9002}(MessageNumber : ecADWSLOADERROR; MessageString : secADWSLOADERROR), +{ 9003}(MessageNumber : ecADWSVERSIONERROR; MessageString : secADWSVERSIONERROR), +{ 9004}(MessageNumber : ecADWSNOTINIT; MessageString : secADWSNOTINIT), +{ 9005}(MessageNumber : ecADWSINVPORT; MessageString : secADWSINVPORT), +{ 9006}(MessageNumber : ecADWSCANTCHANGE; MessageString : secADWSCANTCHANGE), +{ 9007}(MessageNumber : ecADWSCANTRESOLVE; MessageString : secADWSCANTRESOLVE), +{10000}(MessageNumber : wsaBaseErr; MessageString : swsaBaseErr), +{10004}(MessageNumber : wsaEIntr; MessageString : swsaEIntr), +{10009}(MessageNumber : wsaEBadF; MessageString : swsaEBadF), +{10013}(MessageNumber : wsaEAcces; MessageString : swsaEAcces), +{10014}(MessageNumber : wsaEFault; MessageString : swsaEFault), +{10022}(MessageNumber : wsaEInVal; MessageString : swsaEInVal), +{10024}(MessageNumber : wsaEMFile; MessageString : swsaEMFile), +{10035}(MessageNumber : wsaEWouldBlock; MessageString : swsaEWouldBlock), +{10036}(MessageNumber : wsaEInProgress; MessageString : swsaEInProgress), +{10037}(MessageNumber : wsaEAlReady; MessageString : swsaEAlReady), +{10038}(MessageNumber : wsaENotSock; MessageString : swsaENotSock), +{10039}(MessageNumber : wsaEDestAddrReq; MessageString : swsaEDestAddrReq), +{10040}(MessageNumber : wsaEMsgSize; MessageString : swsaEMsgSize), +{10041}(MessageNumber : wsaEPrototype; MessageString : swsaEPrototype), +{10042}(MessageNumber : wsaENoProtoOpt; MessageString : swsaENoProtoOpt), +{10043}(MessageNumber : wsaEProtoNoSupport; MessageString : swsaEProtoNoSupport), +{10044}(MessageNumber : wsaESocktNoSupport; MessageString : swsaESocktNoSupport), +{10045}(MessageNumber : wsaEOpNotSupp; MessageString : swsaEOpNotSupp), +{10046}(MessageNumber : wsaEPfNoSupport; MessageString : swsaEPfNoSupport), +{10047}(MessageNumber : wsaEAfNoSupport; MessageString : swsaEAfNoSupport), +{10048}(MessageNumber : wsaEAddrInUse; MessageString : swsaEAddrInUse), +{10049}(MessageNumber : wsaEAddrNotAvail; MessageString : swsaEAddrNotAvail), +{10050}(MessageNumber : wsaENetDown; MessageString : swsaENetDown), +{10051}(MessageNumber : wsaENetUnreach; MessageString : swsaENetUnreach), +{10052}(MessageNumber : wsaENetReset; MessageString : swsaENetReset), +{10053}(MessageNumber : wsaEConnAborted; MessageString : swsaEConnAborted), +{10054}(MessageNumber : wsaEConnReset; MessageString : swsaEConnReset), +{10055}(MessageNumber : wsaENoBufs; MessageString : swsaENoBufs), +{10056}(MessageNumber : wsaEIsConn; MessageString : swsaEIsConn), +{10057}(MessageNumber : wsaENotConn; MessageString : swsaENotConn), +{10058}(MessageNumber : wsaEShutDown; MessageString : swsaEShutDown), +{10059}(MessageNumber : wsaETooManyRefs; MessageString : swsaETooManyRefs), +{10060}(MessageNumber : wsaETimedOut; MessageString : swsaETimedOut), +{10061}(MessageNumber : wsaEConnRefused; MessageString : swsaEConnRefused), +{10062}(MessageNumber : wsaELoop; MessageString : swsaELoop), +{10063}(MessageNumber : wsaENameTooLong; MessageString : swsaENameTooLong), +{10064}(MessageNumber : wsaEHostDown; MessageString : swsaEHostDown), +{10065}(MessageNumber : wsaEHostUnreach; MessageString : swsaEHostUnreach), +{10066}(MessageNumber : wsaENotEmpty; MessageString : swsaENotEmpty), +{10067}(MessageNumber : wsaEProcLim; MessageString : swsaEProcLim), +{10068}(MessageNumber : wsaEUsers; MessageString : swsaEUsers), +{10069}(MessageNumber : wsaEDQuot; MessageString : swsaEDQuot), +{10070}(MessageNumber : wsaEStale; MessageString : swsaEStale), +{10071}(MessageNumber : wsaERemote; MessageString : swsaERemote), +{10091}(MessageNumber : wsaSysNotReady; MessageString : swsaSysNotReady), +{10092}(MessageNumber : wsaVerNotSupported; MessageString : swsaVerNotSupported), +{10093}(MessageNumber : wsaNotInitialised; MessageString : swsaNotInitialised), +{10101}(MessageNumber : wsaEDiscOn; MessageString : swsaEDiscOn), +{11001}(MessageNumber : wsaHost_Not_Found; MessageString : swsaHost_Not_Found), +{11002}(MessageNumber : wsaTry_Again; MessageString : swsaTry_Again), +{11003}(MessageNumber : wsaNo_Recovery; MessageString : swsaNo_Recovery), +{11004}(MessageNumber : wsaNo_Data; MessageString : swsaNo_Data), +{13501}(MessageNumber : 13501; MessageString : stcs_Idle), +{13502}(MessageNumber : 13502; MessageString : stcs_Offering), +{13503}(MessageNumber : 13503; MessageString : stcs_Accepted), +{13504}(MessageNumber : 13504; MessageString : stcs_Dialtone), +{13505}(MessageNumber : 13505; MessageString : stcs_Dialing), +{13506}(MessageNumber : 13506; MessageString : stcs_Ringback), +{13507}(MessageNumber : 13507; MessageString : stcs_Busy), +{13508}(MessageNumber : 13508; MessageString : stcs_SpecialInfo), +{13509}(MessageNumber : 13509; MessageString : stcs_Connected), +{13510}(MessageNumber : 13510; MessageString : stcs_Proceeding), +{13511}(MessageNumber : 13511; MessageString : stcs_OnHold), +{13512}(MessageNumber : 13512; MessageString : stcs_Conferenced), +{13513}(MessageNumber : 13513; MessageString : stcs_OnHoldPendConf), +{13514}(MessageNumber : 13514; MessageString : stcs_OnHoldPendTransfer), +{13515}(MessageNumber : 13515; MessageString : stcs_Disconnected), +{13516}(MessageNumber : 13516; MessageString : stcs_Unknown), +{13533}(MessageNumber : 13533; MessageString : stds_Other), +{13534}(MessageNumber : 13534; MessageString : stds_Ringing), +{13535}(MessageNumber : 13535; MessageString : stds_Connected), +{13536}(MessageNumber : 13536; MessageString : stds_Disconnected), +{13537}(MessageNumber : 13537; MessageString : stds_MsgWaitOn), +{13538}(MessageNumber : 13538; MessageString : stds_MsgWaitOff), +{13539}(MessageNumber : 13539; MessageString : stds_InService), +{13540}(MessageNumber : 13540; MessageString : stds_OutOfService), +{13541}(MessageNumber : 13541; MessageString : stds_Maintenance), +{13542}(MessageNumber : 13542; MessageString : stds_Open), +{13543}(MessageNumber : 13543; MessageString : stds_Close), +{13544}(MessageNumber : 13544; MessageString : stds_NumCalls), +{13545}(MessageNumber : 13545; MessageString : stds_NumCompletions), +{13546}(MessageNumber : 13546; MessageString : stds_Terminals), +{13547}(MessageNumber : 13547; MessageString : stds_RoamMode), +{13548}(MessageNumber : 13548; MessageString : stds_Battery), +{13549}(MessageNumber : 13549; MessageString : stds_Signal), +{13550}(MessageNumber : 13550; MessageString : stds_DevSpecific), +{13551}(MessageNumber : 13551; MessageString : stds_ReInit), +{13552}(MessageNumber : 13552; MessageString : stds_Lock), +{13553}(MessageNumber : 13553; MessageString : stds_CapsChange), +{13554}(MessageNumber : 13554; MessageString : stds_ConfigChange), +{13555}(MessageNumber : 13555; MessageString : stds_TranslateChange), +{13556}(MessageNumber : 13556; MessageString : stds_ComplCancel), +{13557}(MessageNumber : 13557; MessageString : stds_Removed), +{13565}(MessageNumber : 13565; MessageString : sTAPILineReply), +{13597}(MessageNumber : 13597; MessageString : sTAPIStateChange), +{13598}(MessageNumber : 13598; MessageString : sTAPICalledBusy), +{13599}(MessageNumber : 13599; MessageString : sTAPIDialFail), +{13600}(MessageNumber : 13600; MessageString : sTAPIRetryWait), +{13601}(MessageNumber : 13601; MessageString : sTAPIDeviceInUse), +{13650}(MessageNumber : 13650; MessageString : sTAPIDisconnect_Unspecified), +{13651}(MessageNumber : 13651; MessageString : sTAPIDisconnect_Normal), +{13652}(MessageNumber : 13652; MessageString : sTAPIDisconnect_Unknown), +{13653}(MessageNumber : 13653; MessageString : sTAPIDisconnect_Reject), +{13654}(MessageNumber : 13654; MessageString : sTAPIDisconnect_PickUp), +{13655}(MessageNumber : 13655; MessageString : sTAPIDisconnect_Forwarded), +{13656}(MessageNumber : 13656; MessageString : sTAPIDisconnect_Busy), +{13657}(MessageNumber : 13657; MessageString : sTAPIDisconnect_NoAnswer), +{13658}(MessageNumber : 13658; MessageString : sTAPIDisconnect_BadAddress), +{13659}(MessageNumber : 13659; MessageString : sTAPIDisconnect_Unreachable), +{13660}(MessageNumber : 13660; MessageString : sTAPIDisconnect_Congestion), +{13661}(MessageNumber : 13661; MessageString : sTAPIDisconnect_Incompatible), +{13662}(MessageNumber : 13662; MessageString : sTAPIDisconnect_Unavail), +{13663}(MessageNumber : 13663; MessageString : sTAPIDisconnect_NoDialtone), +{13664}(MessageNumber : 13664; MessageString : sTAPIDisconnect_NumberChanged), +{13665}(MessageNumber : 13665; MessageString : sTAPIDisconnect_OutOfOrder), +{13666}(MessageNumber : 13666; MessageString : sTAPIDisconnect_TempFailure), +{13667}(MessageNumber : 13667; MessageString : sTAPIDisconnect_QOSUnavail), +{13668}(MessageNumber : 13668; MessageString : sTAPIDisconnect_Blocked), +{13669}(MessageNumber : 13669; MessageString : sTAPIDisconnect_DoNotDisturb), +{13670}(MessageNumber : 13670; MessageString : sTAPIDisconnect_Cancelled), +{13801}(MessageNumber : ecAllocated; MessageString : secAllocated), +{13802}(MessageNumber : ecBadDeviceID; MessageString : secBadDeviceID), +{13803}(MessageNumber : ecBearerModeUnavail; MessageString : secBearerModeUnavail), +{13805}(MessageNumber : ecCallUnavail; MessageString : secCallUnavail), +{13806}(MessageNumber : ecCompletionOverrun; MessageString : secCompletionOverrun), +{13807}(MessageNumber : ecConferenceFull; MessageString : secConferenceFull), +{13808}(MessageNumber : ecDialBilling; MessageString : secDialBilling), +{13809}(MessageNumber : ecDialDialtone; MessageString : secDialDialtone), +{13810}(MessageNumber : ecDialPrompt; MessageString : secDialPrompt), +{13811}(MessageNumber : ecDialQuiet; MessageString : secDialQuiet), +{13812}(MessageNumber : ecIncompatibleApiVersion; MessageString : secIncompatibleApiVersion), +{13813}(MessageNumber : ecIncompatibleExtVersion; MessageString : secIncompatibleExtVersion), +{13814}(MessageNumber : ecIniFileCorrupt; MessageString : secIniFileCorrupt), +{13815}(MessageNumber : ecInUse; MessageString : secInUse), +{13816}(MessageNumber : ecInvalAddress; MessageString : secInvalAddress), +{13817}(MessageNumber : ecInvalAddressID; MessageString : secInvalAddressID), +{13818}(MessageNumber : ecInvalAddressMode; MessageString : secInvalAddressMode), +{13819}(MessageNumber : ecInvalAddressState; MessageString : secInvalAddressState), +{13820}(MessageNumber : ecInvalAppHandle; MessageString : secInvalAppHandle), +{13821}(MessageNumber : ecInvalAppName; MessageString : secInvalAppName), +{13822}(MessageNumber : ecInvalBearerMode; MessageString : secInvalBearerMode), +{13823}(MessageNumber : ecInvalCallComplMode; MessageString : secInvalCallComplMode), +{13824}(MessageNumber : ecInvalCallHandle; MessageString : secInvalCallHandle), +{13825}(MessageNumber : ecInvalCallParams; MessageString : secInvalCallParams), +{13826}(MessageNumber : ecInvalCallPrivilege; MessageString : secInvalCallPrivilege), +{13827}(MessageNumber : ecInvalCallSelect; MessageString : secInvalCallSelect), +{13828}(MessageNumber : ecInvalCallState; MessageString : secInvalCallState), +{13829}(MessageNumber : ecInvalCallStatelist; MessageString : secInvalCallStatelist), +{13830}(MessageNumber : ecInvalCard; MessageString : secInvalCard), +{13831}(MessageNumber : ecInvalCompletionID; MessageString : secInvalCompletionID), +{13832}(MessageNumber : ecInvalConfCallHandle; MessageString : secInvalConfCallHandle), +{13833}(MessageNumber : ecInvalConsultCallHandle; MessageString : secInvalConsultCallHandle), +{13834}(MessageNumber : ecInvalCountryCode; MessageString : secInvalCountryCode), +{13835}(MessageNumber : ecInvalDeviceClass; MessageString : secInvalDeviceClass), +{13836}(MessageNumber : ecInvalDeviceHandle; MessageString : secInvalDeviceHandle), +{13837}(MessageNumber : ecInvalDialParams; MessageString : secInvalDialParams), +{13838}(MessageNumber : ecInvalDigitList; MessageString : secInvalDigitList), +{13839}(MessageNumber : ecInvalDigitMode; MessageString : secInvalDigitMode), +{13840}(MessageNumber : ecInvalDigits; MessageString : secInvalDigits), +{13841}(MessageNumber : ecInvalExtVersion; MessageString : secInvalExtVersion), +{13842}(MessageNumber : ecInvalGroupID; MessageString : secInvalGroupID), +{13843}(MessageNumber : ecInvalLineHandle; MessageString : secInvalLineHandle), +{13844}(MessageNumber : ecInvalLineState; MessageString : secInvalLineState), +{13845}(MessageNumber : ecInvalLocation; MessageString : secInvalLocation), +{13846}(MessageNumber : ecInvalMediaList; MessageString : secInvalMediaList), +{13847}(MessageNumber : ecInvalMediaMode; MessageString : secInvalMediaMode), +{13848}(MessageNumber : ecInvalMessageID; MessageString : secInvalMessageID), +{13850}(MessageNumber : ecInvalParam; MessageString : secInvalParam), +{13851}(MessageNumber : ecInvalParkID; MessageString : secInvalParkID), +{13852}(MessageNumber : ecInvalParkMode; MessageString : secInvalParkMode), +{13853}(MessageNumber : ecInvalPointer; MessageString : secInvalPointer), +{13854}(MessageNumber : ecInvalPrivSelect; MessageString : secInvalPrivSelect), +{13855}(MessageNumber : ecInvalRate; MessageString : secInvalRate), +{13856}(MessageNumber : ecInvalRequestMode; MessageString : secInvalRequestMode), +{13857}(MessageNumber : ecInvalTerminalID; MessageString : secInvalTerminalID), +{13858}(MessageNumber : ecInvalTerminalMode; MessageString : secInvalTerminalMode), +{13859}(MessageNumber : ecInvalTimeout; MessageString : secInvalTimeout), +{13860}(MessageNumber : ecInvalTone; MessageString : secInvalTone), +{13861}(MessageNumber : ecInvalToneList; MessageString : secInvalToneList), +{13862}(MessageNumber : ecInvalToneMode; MessageString : secInvalToneMode), +{13863}(MessageNumber : ecInvalTransferMode; MessageString : secInvalTransferMode), +{13864}(MessageNumber : ecLineMapperFailed; MessageString : secLineMapperFailed), +{13865}(MessageNumber : ecNoConference; MessageString : secNoConference), +{13866}(MessageNumber : ecNoDevice; MessageString : secNoDevice), +{13867}(MessageNumber : ecNoDriver; MessageString : secNoDriver), +{13868}(MessageNumber : ecNoMem; MessageString : secNoMem), +{13869}(MessageNumber : ecNoRequest; MessageString : secNoRequest), +{13870}(MessageNumber : ecNotOwner; MessageString : secNotOwner), +{13871}(MessageNumber : ecNotRegistered; MessageString : secNotRegistered), +{13872}(MessageNumber : ecOperationFailed; MessageString : secOperationFailed), +{13873}(MessageNumber : ecOperationUnavail; MessageString : secOperationUnavail), +{13874}(MessageNumber : ecRateUnavail; MessageString : secRateUnavail), +{13875}(MessageNumber : ecResourceUnavail; MessageString : secResourceUnavail), +{13876}(MessageNumber : ecRequestOverrun; MessageString : secRequestOverrun), +{13877}(MessageNumber : ecStructureTooSmall; MessageString : secStructureTooSmall), +{13878}(MessageNumber : ecTargetNotFound; MessageString : secTargetNotFound), +{13879}(MessageNumber : ecTargetSelf; MessageString : secTargetSelf), +{13880}(MessageNumber : ecUninitialized; MessageString : secUninitialized), +{13881}(MessageNumber : ecUserUserInfoTooBig; MessageString : secUserUserInfoTooBig), +{13882}(MessageNumber : ecReinit; MessageString : secReinit), +{13883}(MessageNumber : ecAddressBlocked; MessageString : secAddressBlocked), +{13884}(MessageNumber : ecBillingRejected; MessageString : secBillingRejected), +{13885}(MessageNumber : ecInvalFeature; MessageString : secInvalFeature), +{13886}(MessageNumber : ecNoMultipleInstance; MessageString : secNoMultipleInstance), +{13928}(MessageNumber : ecTapiBusy; MessageString : secTapiBusy), +{13929}(MessageNumber : ecTapiNotSet; MessageString : secTapiNotSet), +{13930}(MessageNumber : ecTapiNoSelect; MessageString : secTapiNoSelect), +{13931}(MessageNumber : ecTapiLoadFail; MessageString : secTapiLoadFail), +{13932}(MessageNumber : ecTapiGetAddrFail; MessageString : secTapiGetAddrFail), +{13933}(MessageNumber : 13933; MessageString : sTAPIdisabled16bit), +{13934}(MessageNumber : ecTapiUnexpected; MessageString : secTapiUnexpected), +{13935}(MessageNumber : ecTapiVoiceNotSupported; MessageString : secTapiVoiceNotSupported), +{13936}(MessageNumber : ecTapiWaveFail; MessageString : secTapiWaveFail), +{13937}(MessageNumber : ecTapiCIDBlocked; MessageString : secTapiCIDBlocked), +{13938}(MessageNumber : ecTapiCIDOutOfArea; MessageString : secTapiCIDOutOfArea), +{13939}(MessageNumber : ecTapiWaveFormatError; MessageString : secTapiWaveFormatError), +{13940}(MessageNumber : ecTapiWaveReadError; MessageString : secTapiWaveReadError), +{13941}(MessageNumber : ecTapiWaveBadFormat; MessageString : secTapiWaveBadFormat), +{13942}(MessageNumber : ecTapiTranslateFail; MessageString : secTapiTranslateFail), +{13943}(MessageNumber : ecTapiWaveDeviceInUse; MessageString : secTapiWaveDeviceInUse), +{13944}(MessageNumber : ecTapiWaveFileExists; MessageString : secTapiWaveFileExists), +{13945}(MessageNumber : ecTapiWaveNoData; MessageString : secTapiWaveNoData), +{13950}(MessageNumber : ecVoIPNotSupported; MessageString : secVoIPNotSupported), +{13951}(MessageNumber : ecVoIPCallBusy; MessageString : secVoIPCallBusy), +{13952}(MessageNumber : ecVoIPBadAddress; MessageString : secVoIPBadAddress), +{13953}(MessageNumber : ecVoIPNoAnswer; MessageString : secVoIPNoAnswer), +{13954}(MessageNumber : ecVoIPCancelled; MessageString : secVoIPCancelled), +{13955}(MessageNumber : ecVoIPRejected; MessageString : secVoIPRejected), +{13956}(MessageNumber : ecVoIPFailed; MessageString : secVoIPFailed), +{13957}(MessageNumber : ecVoIPTapi3NotInstalled; MessageString : secVoIPTapi3NotInstalled), +{13958}(MessageNumber : ecVoIPH323NotFound; MessageString : secVoIPH323NotFound), +{13959}(MessageNumber : ecVoIPTapi3EventFailure; MessageString : secVoIPTapi3EventFailure), +{13980}(MessageNumber : ecRasLoadFail; MessageString : secRasLoadFail), +{15001}(MessageNumber : 15001; MessageString : sdtNone), +{15002}(MessageNumber : 15002; MessageString : sdtDispatch), +{15003}(MessageNumber : 15003; MessageString : sdtTrigger), +{15004}(MessageNumber : 15004; MessageString : sdtError), +{15005}(MessageNumber : 15005; MessageString : sdtThread), +{15006}(MessageNumber : 15006; MessageString : sdtTriggerAlloc), +{15007}(MessageNumber : 15007; MessageString : sdtTriggerDispose), +{15008}(MessageNumber : 15008; MessageString : sdtTriggerHandlerAlloc), +{15009}(MessageNumber : 15009; MessageString : sdtTriggerHandlerDispose), +{15010}(MessageNumber : 15010; MessageString : sdtTriggerDataChange), +{15011}(MessageNumber : 15011; MessageString : sdtTelnet), +{15012}(MessageNumber : 15012; MessageString : sdtFax), +{15013}(MessageNumber : 15013; MessageString : sdtXModem), +{15014}(MessageNumber : 15014; MessageString : sdtYModem), +{15015}(MessageNumber : 15015; MessageString : sdtZModem), +{15016}(MessageNumber : 15016; MessageString : sdtKermit), +{15017}(MessageNumber : 15017; MessageString : sdtAscii), +{15018}(MessageNumber : 15018; MessageString : sdtBPlus), +{15019}(MessageNumber : 15019; MessageString : sdtPacket), +{15020}(MessageNumber : 15020; MessageString : sdtUser), +{15021}(MessageNumber : 15021; MessageString : sdtScript), +{15100}(MessageNumber : 15100; MessageString : sdstNone), +{15101}(MessageNumber : 15101; MessageString : sdstReadCom), +{15102}(MessageNumber : 15102; MessageString : sdstWriteCom), +{15103}(MessageNumber : 15103; MessageString : sdstLineStatus), +{15104}(MessageNumber : 15104; MessageString : sdstModemStatus), +{15105}(MessageNumber : 15105; MessageString : sdstAvail), +{15106}(MessageNumber : 15106; MessageString : sdstTimer), +{15107}(MessageNumber : 15107; MessageString : sdstData), +{15108}(MessageNumber : 15108; MessageString : sdstStatus), +{15109}(MessageNumber : 15109; MessageString : sdstThreadStart), +{15110}(MessageNumber : 15110; MessageString : sdstThreadExit), +{15111}(MessageNumber : 15111; MessageString : sdstThreadSleep), +{15112}(MessageNumber : 15112; MessageString : sdstThreadWake), +{15113}(MessageNumber : 15113; MessageString : sdstDataTrigger), +{15114}(MessageNumber : 15114; MessageString : sdstTimerTrigger), +{15115}(MessageNumber : 15115; MessageString : sdstStatusTrigger), +{15116}(MessageNumber : 15116; MessageString : sdstAvailTrigger), +{15117}(MessageNumber : 15117; MessageString : sdstWndHandler), +{15118}(MessageNumber : 15118; MessageString : sdstProcHandler), +{15119}(MessageNumber : 15119; MessageString : sdstEventHandler), +{15120}(MessageNumber : 15120; MessageString : sdstSWill), +{15121}(MessageNumber : 15121; MessageString : sdstSWont), +{15122}(MessageNumber : 15122; MessageString : sdstSDo), +{15123}(MessageNumber : 15123; MessageString : sdstSDont), +{15124}(MessageNumber : 15124; MessageString : sdstRWill), +{15125}(MessageNumber : 15125; MessageString : sdstRWont), +{15126}(MessageNumber : 15126; MessageString : sdstRDo), +{15127}(MessageNumber : 15127; MessageString : sdstRDont), +{15128}(MessageNumber : 15128; MessageString : sdstCommand), +{15129}(MessageNumber : 15129; MessageString : sdstSTerm), +{15130}(MessageNumber : 15130; MessageString : sdsttfNone), +{15131}(MessageNumber : 15131; MessageString : sdsttfGetEntry), +{15132}(MessageNumber : 15132; MessageString : sdsttfInit), +{15133}(MessageNumber : 15133; MessageString : sdsttf1Init1), +{15134}(MessageNumber : 15134; MessageString : sdsttf2Init1), +{15135}(MessageNumber : 15135; MessageString : sdsttf2Init1A), +{15136}(MessageNumber : 15136; MessageString : sdsttf2Init1B), +{15137}(MessageNumber : 15137; MessageString : sdsttf2Init2), +{15138}(MessageNumber : 15138; MessageString : sdsttf2Init3), +{15139}(MessageNumber : 15139; MessageString : sdsttfDial), +{15140}(MessageNumber : 15140; MessageString : sdsttfRetryWait), +{15141}(MessageNumber : 15141; MessageString : sdsttf1Connect), +{15142}(MessageNumber : 15142; MessageString : sdsttf1SendTSI), +{15143}(MessageNumber : 15143; MessageString : sdsttf1TSIResponse), +{15144}(MessageNumber : 15144; MessageString : sdsttf1DCSResponse), +{15145}(MessageNumber : 15145; MessageString : sdsttf1TrainStart), +{15146}(MessageNumber : 15146; MessageString : sdsttf1TrainFinish), +{15147}(MessageNumber : 15147; MessageString : sdsttf1WaitCFR), +{15148}(MessageNumber : 15148; MessageString : sdsttf1WaitPageConnect), +{15149}(MessageNumber : 15149; MessageString : sdsttf2Connect), +{15150}(MessageNumber : 15150; MessageString : sdsttf2GetParams), +{15151}(MessageNumber : 15151; MessageString : sdsttfWaitXon), +{15152}(MessageNumber : 15152; MessageString : sdsttfWaitFreeHeader), +{15153}(MessageNumber : 15153; MessageString : sdsttfSendPageHeader), +{15154}(MessageNumber : 15154; MessageString : sdsttfOpenCover), +{15155}(MessageNumber : 15155; MessageString : sdsttfSendCover), +{15156}(MessageNumber : 15156; MessageString : sdsttfPrepPage), +{15157}(MessageNumber : 15157; MessageString : sdsttfSendPage), +{15158}(MessageNumber : 15158; MessageString : sdsttfDrainPage), +{15159}(MessageNumber : 15159; MessageString : sdsttf1PageEnd), +{15160}(MessageNumber : 15160; MessageString : sdsttf1PrepareEOP), +{15161}(MessageNumber : 15161; MessageString : sdsttf1SendEOP), +{15162}(MessageNumber : 15162; MessageString : sdsttf1WaitMPS), +{15163}(MessageNumber : 15163; MessageString : sdsttf1WaitEOP), +{15164}(MessageNumber : 15164; MessageString : sdsttf1WaitMCF), +{15165}(MessageNumber : 15165; MessageString : sdsttf1SendDCN), +{15166}(MessageNumber : 15166; MessageString : sdsttf1Hangup), +{15167}(MessageNumber : 15167; MessageString : sdsttf1WaitHangup), +{15168}(MessageNumber : 15168; MessageString : sdsttf2SendEOP), +{15169}(MessageNumber : 15169; MessageString : sdsttf2WaitFPTS), +{15170}(MessageNumber : 15170; MessageString : sdsttf2WaitFET), +{15171}(MessageNumber : 15171; MessageString : sdsttf2WaitPageOK), +{15172}(MessageNumber : 15172; MessageString : sdsttf2SendNewParams), +{15173}(MessageNumber : 15173; MessageString : sdsttf2NextPage), +{15174}(MessageNumber : 15174; MessageString : sdsttf20CheckPage), +{15175}(MessageNumber : 15175; MessageString : sdsttfClose), +{15176}(MessageNumber : 15176; MessageString : sdsttfCompleteOK), +{15177}(MessageNumber : 15177; MessageString : sdsttfAbort), +{15178}(MessageNumber : 15178; MessageString : sdsttfDone), +{15179}(MessageNumber : 15179; MessageString : sdstrfNone), +{15180}(MessageNumber : 15180; MessageString : sdstrfInit), +{15181}(MessageNumber : 15181; MessageString : sdstrf1Init1), +{15182}(MessageNumber : 15182; MessageString : sdstrf2Init1), +{15183}(MessageNumber : 15183; MessageString : sdstrf2Init1A), +{15184}(MessageNumber : 15184; MessageString : sdstrf2Init1B), +{15185}(MessageNumber : 15185; MessageString : sdstrf2Init2), +{15186}(MessageNumber : 15186; MessageString : sdstrf2Init3), +{15187}(MessageNumber : 15187; MessageString : sdstrfWaiting), +{15188}(MessageNumber : 15188; MessageString : sdstrfAnswer), +{15189}(MessageNumber : 15189; MessageString : sdstrf1SendCSI), +{15190}(MessageNumber : 15190; MessageString : sdstrf1SendDIS), +{15191}(MessageNumber : 15191; MessageString : sdstrf1CollectFrames), +{15192}(MessageNumber : 15192; MessageString : sdstrf1CollectRetry1), +{15193}(MessageNumber : 15193; MessageString : sdstrf1CollectRetry2), +{15194}(MessageNumber : 15194; MessageString : sdstrf1StartTrain), +{15195}(MessageNumber : 15195; MessageString : sdstrf1CollectTrain), +{15196}(MessageNumber : 15196; MessageString : sdstrf1Timeout), +{15197}(MessageNumber : 15197; MessageString : sdstrf1Retrain), +{15198}(MessageNumber : 15198; MessageString : sdstrf1FinishTrain), +{15199}(MessageNumber : 15199; MessageString : sdstrf1SendCFR), +{15200}(MessageNumber : 15200; MessageString : sdstrf1WaitPageConnect), +{15201}(MessageNumber : 15201; MessageString : sdstrf2ValidConnect), +{15202}(MessageNumber : 15202; MessageString : sdstrf2GetSenderID), +{15203}(MessageNumber : 15203; MessageString : sdstrf2GetConnect), +{15204}(MessageNumber : 15204; MessageString : sdstrfStartPage), +{15205}(MessageNumber : 15205; MessageString : sdstrfGetPageData), +{15206}(MessageNumber : 15206; MessageString : sdstrf1FinishPage), +{15207}(MessageNumber : 15207; MessageString : sdstrf1WaitEOP), +{15208}(MessageNumber : 15208; MessageString : sdstrf1WritePage), +{15209}(MessageNumber : 15209; MessageString : sdstrf1SendMCF), +{15210}(MessageNumber : 15210; MessageString : sdstrf1WaitDCN), +{15211}(MessageNumber : 15211; MessageString : sdstrf1WaitHangup), +{15212}(MessageNumber : 15212; MessageString : sdstrf2GetPageResult), +{15213}(MessageNumber : 15213; MessageString : sdstrf2GetFHNG), +{15214}(MessageNumber : 15214; MessageString : sdstrfComplete), +{15215}(MessageNumber : 15215; MessageString : sdstrfAbort), +{15216}(MessageNumber : 15216; MessageString : sdstrfDone), +{15217}(MessageNumber : 15217; MessageString : sdsttxInitial), +{15218}(MessageNumber : 15218; MessageString : sdsttxHandshake), +{15219}(MessageNumber : 15219; MessageString : sdsttxGetBlock), +{15220}(MessageNumber : 15220; MessageString : sdsttxWaitFreeSpace), +{15221}(MessageNumber : 15221; MessageString : sdsttxSendBlock), +{15222}(MessageNumber : 15222; MessageString : sdsttxDraining), +{15223}(MessageNumber : 15223; MessageString : sdsttxReplyPending), +{15224}(MessageNumber : 15224; MessageString : sdsttxEndDrain), +{15225}(MessageNumber : 15225; MessageString : sdsttxFirstEndOfTransmit), +{15226}(MessageNumber : 15226; MessageString : sdsttxRestEndOfTransmit), +{15227}(MessageNumber : 15227; MessageString : sdsttxEotReply), +{15228}(MessageNumber : 15228; MessageString : sdsttxFinished), +{15229}(MessageNumber : 15229; MessageString : sdsttxDone), +{15230}(MessageNumber : 15230; MessageString : sdstrxInitial), +{15231}(MessageNumber : 15231; MessageString : sdstrxWaitForHSReply), +{15232}(MessageNumber : 15232; MessageString : sdstrxWaitForBlockStart), +{15233}(MessageNumber : 15233; MessageString : sdstrxCollectBlock), +{15234}(MessageNumber : 15234; MessageString : sdstrxProcessBlock), +{15235}(MessageNumber : 15235; MessageString : sdstrxFinishedSkip), +{15236}(MessageNumber : 15236; MessageString : sdstrxFinished), +{15237}(MessageNumber : 15237; MessageString : sdstrxDone), +{15238}(MessageNumber : 15238; MessageString : sdsttyInitial), +{15239}(MessageNumber : 15239; MessageString : sdsttyHandshake), +{15240}(MessageNumber : 15240; MessageString : sdsttyGetFileName), +{15241}(MessageNumber : 15241; MessageString : sdsttySendFileName), +{15242}(MessageNumber : 15242; MessageString : sdsttyDraining), +{15243}(MessageNumber : 15243; MessageString : sdsttyReplyPending), +{15244}(MessageNumber : 15244; MessageString : sdsttyPrepXmodem), +{15245}(MessageNumber : 15245; MessageString : sdsttySendXmodem), +{15246}(MessageNumber : 15246; MessageString : sdsttyFinished), +{15247}(MessageNumber : 15247; MessageString : sdsttyFinishDrain), +{15248}(MessageNumber : 15248; MessageString : sdsttyDone), +{15249}(MessageNumber : 15249; MessageString : sdstryInitial), +{15250}(MessageNumber : 15250; MessageString : sdstryDelay), +{15251}(MessageNumber : 15251; MessageString : sdstryWaitForHSReply), +{15252}(MessageNumber : 15252; MessageString : sdstryWaitForBlockStart), +{15253}(MessageNumber : 15253; MessageString : sdstryCollectBlock), +{15254}(MessageNumber : 15254; MessageString : sdstryProcessBlock), +{15255}(MessageNumber : 15255; MessageString : sdstryOpenFile), +{15256}(MessageNumber : 15256; MessageString : sdstryPrepXmodem), +{15257}(MessageNumber : 15257; MessageString : sdstryReceiveXmodem), +{15258}(MessageNumber : 15258; MessageString : sdstryFinished), +{15259}(MessageNumber : 15259; MessageString : sdstryDone), +{15260}(MessageNumber : 15260; MessageString : sdsttzInitial), +{15261}(MessageNumber : 15261; MessageString : sdsttzHandshake), +{15262}(MessageNumber : 15262; MessageString : sdsttzGetFile), +{15263}(MessageNumber : 15263; MessageString : sdsttzSendFile), +{15264}(MessageNumber : 15264; MessageString : sdsttzCheckFile), +{15265}(MessageNumber : 15265; MessageString : sdsttzStartData), +{15266}(MessageNumber : 15266; MessageString : sdsttzEscapeData), +{15267}(MessageNumber : 15267; MessageString : sdsttzSendData), +{15268}(MessageNumber : 15268; MessageString : sdsttzWaitAck), +{15269}(MessageNumber : 15269; MessageString : sdsttzSendEof), +{15270}(MessageNumber : 15270; MessageString : sdsttzDrainEof), +{15271}(MessageNumber : 15271; MessageString : sdsttzCheckEof), +{15272}(MessageNumber : 15272; MessageString : sdsttzSendFinish), +{15273}(MessageNumber : 15273; MessageString : sdsttzCheckFinish), +{15274}(MessageNumber : 15274; MessageString : sdsttzError), +{15275}(MessageNumber : 15275; MessageString : sdsttzCleanup), +{15276}(MessageNumber : 15276; MessageString : sdsttzDone), +{15277}(MessageNumber : 15277; MessageString : sdstrzRqstFile), +{15278}(MessageNumber : 15278; MessageString : sdstrzDelay), +{15279}(MessageNumber : 15279; MessageString : sdstrzWaitFile), +{15280}(MessageNumber : 15280; MessageString : sdstrzCollectFile), +{15281}(MessageNumber : 15281; MessageString : sdstrzSendInit), +{15282}(MessageNumber : 15282; MessageString : sdstrzSendBlockPrep), +{15283}(MessageNumber : 15283; MessageString : sdstrzSendBlock), +{15284}(MessageNumber : 15284; MessageString : sdstrzSync), +{15285}(MessageNumber : 15285; MessageString : sdstrzStartFile), +{15286}(MessageNumber : 15286; MessageString : sdstrzStartData), +{15287}(MessageNumber : 15287; MessageString : sdstrzCollectData), +{15288}(MessageNumber : 15288; MessageString : sdstrzGotData), +{15289}(MessageNumber : 15289; MessageString : sdstrzWaitEof), +{15290}(MessageNumber : 15290; MessageString : sdstrzEndOfFile), +{15291}(MessageNumber : 15291; MessageString : sdstrzSendFinish), +{15292}(MessageNumber : 15292; MessageString : sdstrzCollectFinish), +{15293}(MessageNumber : 15293; MessageString : sdstrzError), +{15294}(MessageNumber : 15294; MessageString : sdstrzWaitCancel), +{15295}(MessageNumber : 15295; MessageString : sdstrzCleanup), +{15296}(MessageNumber : 15296; MessageString : sdstrzDone), +{15297}(MessageNumber : 15297; MessageString : sdsttkInit), +{15298}(MessageNumber : 15298; MessageString : sdsttkInitReply), +{15299}(MessageNumber : 15299; MessageString : sdsttkCollectInit), +{15300}(MessageNumber : 15300; MessageString : sdsttkOpenFile), +{15301}(MessageNumber : 15301; MessageString : sdsttkSendFile), +{15302}(MessageNumber : 15302; MessageString : sdsttkFileReply), +{15303}(MessageNumber : 15303; MessageString : sdsttkCollectFile), +{15304}(MessageNumber : 15304; MessageString : sdsttkCheckTable), +{15305}(MessageNumber : 15305; MessageString : sdsttkSendData), +{15306}(MessageNumber : 15306; MessageString : sdsttkBlockReply), +{15307}(MessageNumber : 15307; MessageString : sdsttkCollectBlock), +{15308}(MessageNumber : 15308; MessageString : sdsttkSendEof), +{15309}(MessageNumber : 15309; MessageString : sdsttkEofReply), +{15310}(MessageNumber : 15310; MessageString : sdsttkCollectEof), +{15311}(MessageNumber : 15311; MessageString : sdsttkSendBreak), +{15312}(MessageNumber : 15312; MessageString : sdsttkBreakReply), +{15313}(MessageNumber : 15313; MessageString : sdsttkCollectBreak), +{15314}(MessageNumber : 15314; MessageString : sdsttkComplete), +{15315}(MessageNumber : 15315; MessageString : sdsttkWaitCancel), +{15316}(MessageNumber : 15316; MessageString : sdsttkError), +{15317}(MessageNumber : 15317; MessageString : sdsttkDone), +{15318}(MessageNumber : 15318; MessageString : sdstrkInit), +{15319}(MessageNumber : 15319; MessageString : sdstrkGetInit), +{15320}(MessageNumber : 15320; MessageString : sdstrkCollectInit), +{15321}(MessageNumber : 15321; MessageString : sdstrkGetFile), +{15322}(MessageNumber : 15322; MessageString : sdstrkCollectFile), +{15323}(MessageNumber : 15323; MessageString : sdstrkGetData), +{15324}(MessageNumber : 15324; MessageString : sdstrkCollectData), +{15325}(MessageNumber : 15325; MessageString : sdstrkComplete), +{15326}(MessageNumber : 15326; MessageString : sdstrkWaitCancel), +{15327}(MessageNumber : 15327; MessageString : sdstrkError), +{15328}(MessageNumber : 15328; MessageString : sdstrkDone), +{15329}(MessageNumber : 15329; MessageString : sdsttaInitial), +{15330}(MessageNumber : 15330; MessageString : sdsttaGetBlock), +{15331}(MessageNumber : 15331; MessageString : sdsttaWaitFreeSpace), +{15332}(MessageNumber : 15332; MessageString : sdsttaSendBlock), +{15333}(MessageNumber : 15333; MessageString : sdsttaSendDelay), +{15334}(MessageNumber : 15334; MessageString : sdsttaFinishDrain), +{15335}(MessageNumber : 15335; MessageString : sdsttaFinished), +{15336}(MessageNumber : 15336; MessageString : sdsttaDone), +{15337}(MessageNumber : 15337; MessageString : sdstraInitial), +{15338}(MessageNumber : 15338; MessageString : sdstraCollectBlock), +{15339}(MessageNumber : 15339; MessageString : sdstraProcessBlock), +{15340}(MessageNumber : 15340; MessageString : sdstraFinished), +{15341}(MessageNumber : 15341; MessageString : sdstraDone), +{15342}(MessageNumber : 15342; MessageString : sdstEnable), +{15343}(MessageNumber : 15343; MessageString : sdstDisable), +{15344}(MessageNumber : 15344; MessageString : sdstStringPacket), +{15345}(MessageNumber : 15345; MessageString : sdstSizePacket), +{15346}(MessageNumber : 15346; MessageString : sdstPacketTimeout), +{15347}(MessageNumber : 15347; MessageString : sdstStartStr), +{15348}(MessageNumber : 15348; MessageString : sdstEndStr), +{15349}(MessageNumber : 15349; MessageString : sdstIdle), +{15350}(MessageNumber : 15350; MessageString : sdstWaiting), +{15351}(MessageNumber : 15351; MessageString : sdstCollecting), +{15352}(MessageNumber : 15352; MessageString : sdstThreadStatusQueued), // SWB +{15353}(MessageNumber : 15353; MessageString : sdstThreadDataQueued), // SWB +{15354}(MessageNumber : 15354; MessageString : sdstThreadDataWritten), // SWB +{15355}(MessageNumber : 15355; MessageString : sdsttzSInit), // SWB +{15356}(MessageNumber : 15356; MessageString : sdsttzCheckSInit), // SWB +{15501}(MessageNumber : 15501; MessageString : sdispHeader), +{15502}(MessageNumber : 15502; MessageString : sdispHeaderLine), +{15601}(MessageNumber : 15601; MessageString : sdispmdmtagDCTS), +{15602}(MessageNumber : 15602; MessageString : sdispmdmtagDDSR), +{15603}(MessageNumber : 15603; MessageString : sdispmdmtagTERI), +{15604}(MessageNumber : 15604; MessageString : sdispmdmtagDDCD), +{15605}(MessageNumber : 15605; MessageString : sdispmdmtagCTS), +{15606}(MessageNumber : 15606; MessageString : sdispmdmtagDSR), +{15607}(MessageNumber : 15607; MessageString : sdispmdmtagRI), +{15608}(MessageNumber : 15608; MessageString : sdispmdmtagDCD), +{15700}(MessageNumber : 15700; MessageString : sdispTelnetBinary), +{15701}(MessageNumber : 15701; MessageString : sdispTelnetEcho), +{15702}(MessageNumber : 15702; MessageString : sdispTelnetReconnection), +{15703}(MessageNumber : 15703; MessageString : sdispTelnetSupressGoAhead), +{15704}(MessageNumber : 15704; MessageString : sdispTelnetApproxMsgSize), +{15705}(MessageNumber : 15705; MessageString : sdispTelnetStatus), +{15706}(MessageNumber : 15706; MessageString : sdispTelnetTimingMark), +{15707}(MessageNumber : 15707; MessageString : sdispTelnetRemoteTransEcho), +{15708}(MessageNumber : 15708; MessageString : sdispTelnetOutputLineWidth), +{15709}(MessageNumber : 15709; MessageString : sdispTelnetOutputPageSize), +{15710}(MessageNumber : 15710; MessageString : sdispTelnetOutputCRDisp), +{15711}(MessageNumber : 15711; MessageString : sdispTelnetOutputHorzTabs), +{15712}(MessageNumber : 15712; MessageString : sdispTelnetOutputHorzTabDisp), +{15713}(MessageNumber : 15713; MessageString : sdispTelnetOutputFFDisp), +{15714}(MessageNumber : 15714; MessageString : sdispTelnetOutputVertTabs), +{15715}(MessageNumber : 15715; MessageString : sdispTelnetOutputVertTabDisp), +{15716}(MessageNumber : 15716; MessageString : sdispTelnetOutputLinefeedDisp), +{15717}(MessageNumber : 15717; MessageString : sdispTelnetExtendedASCII), +{15718}(MessageNumber : 15718; MessageString : sdispTelnetLogout), +{15719}(MessageNumber : 15719; MessageString : sdispTelnetByteMacro), +{15720}(MessageNumber : 15720; MessageString : sdispTelnetDataEntryTerminal), +{15721}(MessageNumber : 15721; MessageString : sdispTelnetSUPDUP), +{15722}(MessageNumber : 15722; MessageString : sdispTelnetSUPDUPOutput), +{15723}(MessageNumber : 15723; MessageString : sdispTelnetSendLocation), +{15724}(MessageNumber : 15724; MessageString : sdispTelnetTerminalType), +{15725}(MessageNumber : 15725; MessageString : sdispTelnetEndofRecord), +{15726}(MessageNumber : 15726; MessageString : sdispTelnetTACACSUserID), +{15727}(MessageNumber : 15727; MessageString : sdispTelnetOutputMarking), +{15728}(MessageNumber : 15728; MessageString : sdispTelnetTerminalLocNum), +{15729}(MessageNumber : 15729; MessageString : sdispTelnetTelnet3270Regime), +{15730}(MessageNumber : 15730; MessageString : sdispTelnetX3PAD), +{15731}(MessageNumber : 15731; MessageString : sdispTelnetNegWindowSize), +{15732}(MessageNumber : 15732; MessageString : sdispTelnetTerminalSpeed), +{15733}(MessageNumber : 15733; MessageString : sdispTelnetFlowControl), +{15734}(MessageNumber : 15734; MessageString : sdispTelnetLineMode), +{15735}(MessageNumber : 15735; MessageString : sdispTelnetXDisplayLocation), +{15736}(MessageNumber : 15736; MessageString : sdispTelnetEnvironment), +{15737}(MessageNumber : 15737; MessageString : sdispTelnetAuthentication), +{15738}(MessageNumber : 15738; MessageString : sdispTelnetTelnetcode38), +{15739}(MessageNumber : 15739; MessageString : sdispTelnetNewEnvironment), +{15740}(MessageNumber : 15740; MessageString : sdispTelnetTelnetcode40), +{15741}(MessageNumber : 15741; MessageString : sdispTelnetTelnetcode41), +{15742}(MessageNumber : 15742; MessageString : sdispTelnetCharacterSet) + ); + +implementation +end. diff --git a/AwDefine.inc b/AwDefine.inc new file mode 100644 index 0000000..f88d3c1 --- /dev/null +++ b/AwDefine.inc @@ -0,0 +1,54 @@ +(***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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 TurboPower Async Professional + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1991-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* AWDEFINE.INC 4.06 *} +{*********************************************************} +{* Compiler defines affecting all APRO units *} +{*********************************************************} + +{Because AWDEFINE.INC is included in all APRO units, you can specify global +compiler options here. AWDEFINE is included *before* each units' required +compiler options, so options specified here might be overridden by hardcode +options in the source file.} + +{$S- No stack overflow checking} +{$R- No range checking} +{$B- Incomplete boolean evaluation} +{$P- No open string parameters} +{$Q- No arithmetic overflow checking} +{$T- No type-checked pointers} +{$V- No var string checking} +{$X+ Extended syntax} +{$Z- Enumeration size is 256} + + {$H+ Long string support} + {$J+ Writeable typed constants} + +{.$DEFINE TapiDebug} { creates detailed TAPI debug log } +{.$DEFINE AdModemDebug} { adds debug info to dispatcher log } + +{$WARN SYMBOL_PLATFORM OFF} {APRO only works under Windows} +{$WARN UNIT_PLATFORM OFF} {APRO only works under Windows} diff --git a/AwUser.pas b/AwUser.pas new file mode 100644 index 0000000..1093bea --- /dev/null +++ b/AwUser.pas @@ -0,0 +1,4886 @@ +(***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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 TurboPower Async Professional + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1991-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Stephen W. Boyd - Rewrote the Win32 dispatcher to reduce vulnerability + * August 2005 to badly behaved event handlers. Rather than having + * the read thread block until all events have been processed + * the read thread now places input onto an 'endless' + * queue. The dispatch thread reads this queue and + * calls the event handlers. This allows input the be + * continuously read from the input device while the + * event handlers are executing. Should cut down on + * input overruns. To use the old Win32 dispatcher rather + * then mine define the conditional UseAwWin32 and rebuild + * the library. + * Kevin G. McCoy + * 1 Feb 2008 - Found and fixed the status buffer memory leak. Buffers + * were being popped off the queue but not freed; Added + * D2006 / D2007 compiler strings + * + * Sulaiman Mah + * Sean B. Durkin + * Sebastian Zierer + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* AWUSER.PAS 5.00 *} +{*********************************************************} +{* Low-level dispatcher *} +{*********************************************************} +{* Thanks to David Hudder for his substantial *} +{* contributions to improve efficiency and reliability *} +{*********************************************************} + +{ + This unit defines the dispatcher, com and output threads. When + a serial port is opened (Winsock does not use a multi-threaded + architecture), these three threads are created. The dispatcher + thread is the interface between your application and the port. + The dispatcher thread synchronizes with the thread that opened + the port via SendMessageTimeout, in case of timeout (usually 3 + seconds), we will discard whatever we were trying to notify you + about and resume the thread. For this reason, the thread that + opened the port should not be blocked for more than a few ticks, + and the event handler should get the data and return as quickly + as possible. Do not do any DB or file access inside an OnTriggerXxx + event, those actions can take too long. Instead, collect the data + and process it later. A good approach is to collect the data, + post a message to yourself, and process the data from the message + handler. + The dispatcher thread is the interface between the application + layer and the port. The dispatcher thread runs in the context of + the thread that opened the port. The com thread is tied to the + serial port drivers to receive notification when things change. + The com thread wakes the dispatcher thread, the dispatcher thread + then generates the events. The output thread is there to process + the internal output buffer. + Be extrememly cautious when making changes here. The multi-threaded + nature, and very strict timing requirements, can lead to very + unpredictable results. Things as simple as doing a writeln to a + console window can dramatically change the results. +} +{Global defines potentially affecting this unit} +{$I AWDEFINE.INC} + +{Options required for this unit} +{$X+,B-,I-,T-,J+} + +{.$DEFINE DebugThreads} + +{$IFDEF CONSOLE} +{.$DEFINE DebugThreadConsole} +{$ENDIF} + +{!!.02} { removed Win16 references } +unit AwUser; + {-Basic API provided by APRO} + +interface + +uses + Windows, + Messages, + SysUtils, + Classes, + MMSystem, + OoMisc, + AdExcept, + LNSQueue; // SWB + +const + FirstTriggerCounter = 1; + MaxTriggerHandle = 65536 shr 4;{Highest trigger handle number (4096)} + StatusTypeMask = $0007; + ThreadStartWait = 3000; {Milliseconds to wait for sub-threads to start} + ModemEvent = EV_CTS or EV_DSR or EV_RLSD or EV_RING or EV_RINGTE; // SWB + LineEvent = EV_ERR or EV_BREAK; // SWB + {Use these event bits for fast checking of serial events} // SWB + DefEventMask = ev_CTS + ev_DSR + ev_RLSD + ev_Ring + ev_RingTe + // SWB + ev_RxChar + ev_Err + ev_Break; // SWB + + +type + TApHandlerFlagUpdate = (fuKeepPort, fuEnablePort, fuDisablePort); + + TApdBaseDispatcher = class; + TApdDispatcherThread = class(TThread) + private + pMsg, pTrigger : Cardinal; + plParam : Integer; + pTriggerEvent : TApdNotifyEvent; + procedure SyncEvent; + protected + H : TApdBaseDispatcher; // SWB + public + constructor Create(Disp : TApdBaseDispatcher); + procedure SyncNotify(Msg, Trigger : Cardinal; lParam : Integer; Event : TApdNotifyEvent); + procedure Sync(Method: TThreadMethod); + property ReturnValue; // SWB + end; + + TOutThread = class(TApdDispatcherThread) + procedure Execute; override; + end; + + TComThread = class(TApdDispatcherThread) + procedure Execute; override; + end; + + TDispThread = class(TApdDispatcherThread) + procedure Execute; override; + end; + + {Standard comm port record} + TApdDispatcherClass = class of TApdBaseDispatcher; + TApdBaseDispatcher = class + protected + fOwner : TObject; + fHandle : Integer; {Handle for this comm port} + OpenHandle : Boolean; + CidEx : Integer; {Comm or other device ID} + LastError : Integer; {Last error from COM API} + InQue : Cardinal; {Size of device input buffer} + OutQue : Cardinal; {Size of device output buffer} + ModemStatus : Cardinal; {Modem status register} + ComStatus : TComStat; {Results of last call for com status} + DCB : TDCB; {Results of last call for DCB} + LastBaud : Integer; {Last baud set} + Flags : Cardinal; {Option flags} + DTRState : Boolean; {Last set DTR state} + DTRAuto : Boolean; {True if in handshake mode} + RTSState : Boolean; {Last set RTS state} + RTSAuto : Boolean; {True if in handshake mode} + fDispatcherWindow : Cardinal; {Handle to dispatcher window} + LastModemStatus : Cardinal; {Last modem status read} + LastLineErr : Cardinal; {Last line error read} + RS485Mode : Boolean; {True if in RS485 mode} + BaseAddress : Word; {Base address of port} + + {Trigger stuff} + PortHandlerInstalled : Boolean; {True if any of the comport's trigger handlers <> nil} + HandlerServiceNeeded : Boolean; {True if handlers need to be serviced} + WndTriggerHandlers : TList; + ProcTriggerHandlers : TList; + EventTriggerHandlers : TList; + TimerTriggers : TList; {Timer triggers} + DataTriggers : TList; {Data triggers} + StatusTriggers : TList; {Status triggers} + LastTailData : Cardinal; {Tail of last data checked for data} + LastTailLen : Cardinal; {Tail of last data sent in len msg} + LenTrigger : Cardinal; {Number of bytes before length trigger} + GlobalStatHit : Boolean; {True if at least one status trigger hit} + InAvailMessage : Boolean; {True when within Avail msg} + GetCount : Cardinal; {Chars looked at in Avail msg} + MaxGetCount : Cardinal; {Max chars looked at in Avail} + DispatchFull : Boolean; {True when dispatch buffer full} + NotifyTail : Cardinal; {Position of last character notified} + + {Thread stuff} + KillThreads : Boolean; {True to kill threads} + ComThread : TApdDispatcherThread; // SWB + fDispThread : TDispThread; + OutThread : TApdDispatcherThread; // SWB + StatusThread : TapdDispatcherThread; // SWB + ThreadBoost : Byte; + DataSection : TRTLCriticalSection; {For all routines} + OutputSection : TRTLCriticalSection; {For output buffer and related data} + DispSection : TRTLCriticalSection; {For dispatcher buffer and related data} + ComEvent : THandle; {Signals com thread is ready} + ReadyEvent : THandle; {Signals completion of com thread} + GeneralEvent : THandle; {For general misc signalling} + OutputEvent : THandle; {Signals output buf has data to send} + SentEvent : THandle; {Signals completion of overlapped write} + OutFlushEvent : THandle; {Signals request to flush output buffer} + OutWaitObjects1: array[0..1] of THandle; {Output thread wait objects} + OutWaitObjects2: array[0..1] of THandle; {More output thread wait objects} + CurrentEvent : DWORD; {Current communications event} + RingFlag : Boolean; {True when ringte event received} + FQueue : TIOQueue; {Input queue} // SWB + + { Output buffer -- protected by OutputSection } + OBuffer : POBuffer; {Output buffer} + OBufHead : Cardinal; {Head offset in OBuffer} + OBufTail : Cardinal; {Tail offset in OBuffer} + OBufFull : Boolean; {True when output buffer full} + + { Dispatcher stuff -- protected by DispSection } + DBuffer : PDBuffer; {Dispatcher buffer} + DBufHead : Cardinal; {Head offset in DBuffer} + DBufTail : Cardinal; {Tail offset in DBuffer} + fEventBusy : Boolean; {True if we're processing a COM event} + DeletePending : Boolean; {True if an event handler was deleted during a busy state} + ClosePending : Boolean; {True if close pending} + OutSentPending: Boolean; {True if stOutSent trigger pending} + + {Tracing stuff} + TracingOn : Boolean; {True if tracing is on} + TraceQueue : PTraceQueue; {Circular trace buffer} + TraceIndex : Cardinal; {Head of trace queue} + TraceMax : Cardinal; {Number of trace entries} + TraceWrapped : Boolean; {True if trace wrapped} + + {DispatchLogging stuff} + DLoggingOn : Boolean; {True if dispatch logging is on} + DLoggingQueue : TIOQueue; { 'endless' dispatching buffer } // SWB + DLoggingMax : Cardinal; {Number of bytes in logging buffer} + TimeBase : DWORD; {Time dispatching was turned on} + + {DispatcherMode : Cardinal;} + TimerID : Cardinal; + TriggerCounter : Cardinal; {Last allocated trigger handle} + DispActive : Boolean; + {Protected virtual dispatcher functions:} + + DoDonePortPrim : Boolean; + ActiveThreads : Integer; + CloseComActive : Boolean; // SWB + + function EscapeComFunction(Func : Integer) : Integer; virtual; abstract; + function FlushCom(Queue : Integer) : Integer; virtual; abstract; + function GetComError(var Stat : TComStat) : Integer; virtual; abstract; + function GetComEventMask(EvtMask : Integer) : Cardinal; virtual; abstract; + function GetComState(var DCB: TDCB): Integer; virtual; abstract; + function ReadCom(Buf : PAnsiChar; Size: Integer) : Integer; virtual; abstract; + function SetComState(var DCB : TDCB) : Integer; virtual; abstract; + function WriteCom(Buf : PAnsiChar; Size: Integer) : Integer; virtual; abstract; + function WriteComSafe(ABuf: PAnsiChar; ASize: Integer): Integer; + function WaitComEvent(var EvtMask : DWORD; + lpOverlapped : POverlapped) : Boolean; virtual; abstract; + function SetupCom(InSize, OutSize : Integer) : Boolean; virtual; abstract; + + function CheckReceiveTriggers : Boolean; + function CheckStatusTriggers : Boolean; + function CheckTimerTriggers : Boolean; + function CheckTriggers : Boolean; + procedure CreateDispatcherWindow; + procedure DonePortPrim; virtual; + function DumpDispatchLogPrim( + FName : string; + AppendFile, InHex, AllHex : Boolean) : Integer; + function DumpTracePrim(FName : string; + AppendFile, InHex, AllHex : Boolean) : Integer; + function ExtractData : Boolean; + function FindTriggerFromHandle(TriggerHandle : Cardinal; Delete : Boolean; + var T : TTriggerType; var Trigger : Pointer) : Integer; + function GetDispatchTime : DWORD; + function GetModemStatusPrim(ClearMask : Byte) : Byte; + function GetTriggerHandle : Cardinal; + + procedure MapEventsToMS(Events : Integer); + function PeekBlockPrim( + Block : PAnsiChar; + Offset : Cardinal; + Len : Cardinal; + var NewTail : Cardinal) : Integer; + function PeekCharPrim(var C : AnsiChar; Count : Cardinal) : Integer; + procedure RefreshStatus; + procedure ResetStatusHits; + procedure ResetDataTriggers; + function SendNotify(Msg, Trigger, Data: Cardinal) : Boolean; + function SetCommStateFix(var DCB : TDCB) : Integer; + procedure StartDispatcher; virtual; abstract; + procedure StopDispatcher; virtual; abstract; + procedure ThreadGone(Sender: TObject); // SWB + procedure ThreadStart(Sender : TObject); // SWB + procedure WaitTxSent; + function OutBufUsed: Cardinal; virtual; abstract; // SWB + function InQueueUsed : Cardinal; virtual; // SWB + public + DataPointers : TDataPointerArray; {Array of data pointers} + DeviceName : string; {Name of device being used, for log } + LastWinError : Integer; // SWB + + property Active : Boolean read DispActive; + property Logging : Boolean read DLoggingOn; + procedure AddDispatchEntry( + DT : TDispatchType; + DST : TDispatchSubType; + Data : Cardinal; + Buffer : Pointer; + BufferLen : Cardinal); + procedure AddStringToLog(S : Ansistring); + property ComHandle : Integer read CidEx; + {Public virtual dispatcher functions:} + function OpenCom(ComName: PChar; InQueue, + OutQueue : Cardinal) : Integer; virtual; abstract; + function CloseCom : Integer; virtual; abstract; + function CheckPort(ComName: PChar): Boolean; virtual; abstract; //SZ + + property DispatcherWindow : Cardinal read fDispatcherWindow; + property DispThread : TDispThread read fDispThread; + property EventBusy : boolean read fEventBusy write fEventBusy; + property Handle : Integer read fHandle; + property Owner : TObject read fOwner; + + constructor Create(Owner : TObject); + destructor Destroy; override; + + procedure AbortDispatchLogging; + procedure AbortTracing; + function AddDataTrigger(Data : PAnsiChar; // --sm PansiChar + IgnoreCase : Boolean) : Integer; + function AddDataTriggerLen(Data : PAnsiChar; // --sm Pansichar + IgnoreCase : Boolean; + Len : Cardinal) : Integer; + function AddStatusTrigger(SType : Cardinal) : Integer; + function AddTimerTrigger : Integer; + procedure AddTraceEntry(CurEntry : AnsiChar; CurCh : AnsiChar); + function AppendDispatchLog(FName : string; + InHex, AllHex : Boolean) : Integer; + function AppendTrace(FName : string; + InHex, AllHEx : Boolean) : Integer; + procedure BufferSizes(var InSize, OutSize : Cardinal); + function ChangeBaud(NewBaud : Integer) : Integer; + procedure ChangeLengthTrigger(Length : Cardinal); + function CheckCTS : Boolean; + function CheckDCD : Boolean; + function CheckDeltaCTS : Boolean; + function CheckDeltaDSR : Boolean; + function CheckDeltaRI : Boolean; + function CheckDeltaDCD : Boolean; + function CheckDSR : Boolean; + function CheckLineBreak : Boolean; + function CheckRI : Boolean; + function ClassifyStatusTrigger(TriggerHandle : Cardinal) : Cardinal; + procedure ClearDispatchLogging; + class procedure ClearSaveBuffers(var Save : TTriggerSave); + function ClearTracing : Integer; + procedure DeregisterWndTriggerHandler(HW : TApdHwnd); + procedure DeregisterProcTriggerHandler(NP : TApdNotifyProc); + procedure DeregisterEventTriggerHandler(NP : TApdNotifyEvent); + procedure DonePort; + function DumpDispatchLog(FName : string; InHex, AllHex : Boolean) : Integer; + function DumpTrace(FName : string; InHex, AllHex : Boolean) : Integer; + function ExtendTimer(TriggerHandle : Cardinal; + Ticks : Integer) : Integer; + function FlushInBuffer : Integer; + function FlushOutBuffer : Integer; + function CharReady : Boolean; + function GetBaseAddress : Word; + function GetBlock(Block : PAnsiChar; Len : Cardinal) : Integer; + function GetChar(var C : AnsiChar) : Integer; + function GetDataPointer(var P : Pointer; Index : Cardinal) : Integer; + function GetFlowOptions(var HWOpts, SWOpts, BufferFull, + BufferResume : Cardinal; var OnChar, OffChar : AnsiChar): Integer; + procedure GetLine(var Baud : Integer; var Parity : Word; + var DataBits : TDatabits; var StopBits : TStopbits); + function GetLineError : Integer; + function GetModemStatus : Byte; + function HWFlowOptions(BufferFull, BufferResume : Cardinal; + Options : Cardinal) : Integer; + function HWFlowState : Integer; + function InBuffUsed : Cardinal; + function InBuffFree : Cardinal; + procedure InitDispatchLogging(QueueSize : Cardinal); + function InitPort(AComName : PChar; Baud : Integer; + Parity : Cardinal; DataBits : TDatabits; StopBits : TStopbits; + InSize, OutSize : Cardinal; FlowOpts : DWORD) : Integer; + function InitSocket(InSize, OutSize : Cardinal) : Integer; + function InitTracing(NumEntries : Cardinal) : Integer; + function OptionsAreOn(Options : Cardinal) : Boolean; + procedure OptionsOn(Options : Cardinal); + procedure OptionsOff(Options : Cardinal); + function OutBuffUsed : Cardinal; + function OutBuffFree : Cardinal; + function PeekBlock(Block : PAnsiChar; Len : Cardinal) : Integer; + function PeekChar(var C : AnsiChar; Count : Cardinal) : Integer; + function ProcessCommunications : Integer; virtual; abstract; + function PutBlock(const Block; Len : Cardinal) : Integer; + function PutChar(C : AnsiChar) : Integer; // --sm ansi + function PutString(S : AnsiString) : Integer; + procedure RegisterWndTriggerHandler(HW : TApdHwnd); + procedure RegisterProcTriggerHandler(NP : TApdNotifyProc); + procedure RegisterSyncEventTriggerHandler(NP : TApdNotifyEvent); + procedure RegisterEventTriggerHandler(NP : TApdNotifyEvent); + procedure RemoveAllTriggers; + function RemoveTrigger(TriggerHandle : Cardinal) : Integer; + procedure RestoreTriggers( var Save : TTriggerSave); + procedure SaveTriggers( var Save : TTriggerSave); + procedure SetBaseAddress(NewBaseAddress : Word); + procedure SendBreak(Ticks : Cardinal; Yield : Boolean); + procedure SetBreak(BreakOn : Boolean); + procedure SetThreadBoost(Boost : Byte); virtual; + function SetDataPointer( P : Pointer; Index : Cardinal) : Integer; + function SetDtr(OnOff : Boolean) : Integer; + procedure SetEventBusy(var WasOn : Boolean; SetOn : Boolean); + procedure SetRS485Mode(OnOff : Boolean); + function SetRts(OnOff : Boolean) : Integer; + function SetLine(Baud : Integer; Parity : Cardinal; + DataBits : TDatabits; StopBits : TStopbits) : Integer; + function SetModem(DTR, RTS : Boolean) : Integer; + function SetStatusTrigger(TriggerHandle : Cardinal; + Value : Cardinal; Activate : Boolean) : Integer; + function SetTimerTrigger(TriggerHandle : Cardinal; + Ticks : Integer; Activate : Boolean) : Integer; + function SetCommBuffers(InSize, OutSize : Integer) : Integer; + procedure StartDispatchLogging; + procedure StartTracing; + procedure StopDispatchLogging; + procedure StopTracing; + function SWFlowChars( OnChar, OffChar : AnsiChar) : Integer; + function SWFlowDisable : Integer; + function SWFlowEnable(BufferFull, BufferResume : Cardinal; + Options : Cardinal) : Integer; + function SWFlowState : Integer; + function TimerTicksRemaining(TriggerHandle : Cardinal; + var TicksRemaining : Integer) : Integer; + procedure UpdateHandlerFlags(FlagUpdate : TApHandlerFlagUpdate); virtual; + end; + +function GetTComRecPtr(Cid : Integer; DeviceLayerClass : TApdDispatcherClass) : Pointer; + +var + PortList : TList; + +procedure LockPortList; +procedure UnlockPortList; +function PortIn(Address: Word): Byte; // SWB + +var + GShowExceptionHandler: procedure(ExceptObject: TObject; ExceptAddr: Pointer) = nil; + +implementation + +uses + AnsiStrings; + +var + PortListSection : TRTLCriticalSection; + +const + { This should be the same in ADSOCKET.PAS } + CM_APDSOCKETMESSAGE = WM_USER + $0711; + + {For setting stop bits} + StopBitArray : array[TStopbits] of Byte = (OneStopbit, TwoStopbits, 0); + + {For quick checking and disabling of all flow control options} + InHdwFlow = dcb_DTRBit2 + dcb_RTSBit2; + OutHdwFlow = dcb_OutxDSRFlow + dcb_OutxCTSFlow; + AllHdwFlow = InHdwFlow + OutHdwFlow; + AllSfwFlow = dcb_InX + dcb_OutX; + + {Mask of errors we care about} + ValidErrorMask = + ce_RXOver + {receive queue overflow} + ce_Overrun + {receive overrun error} + ce_RXParity + {receive parity error} + ce_Frame + {receive framing error} + ce_Break; {break detected} + + {For clearing modem status} + ClearDelta = $F0; + ClearNone = $FF; + ClearDeltaCTS = Byte(not DeltaCTSMask); + ClearDeltaDSR = Byte(not DeltaDSRMask); + ClearDeltaRI = Byte(not DeltaRIMask); + ClearDeltaDCD = Byte(not DeltaDCDMask); + +{General purpose routines} + +const + LastCID : Integer = -1; + LastDispatcher : TApdBaseDispatcher = nil; + +//SZ: this was removed, but it is needed by AWWNSOCK.pas +function GetTComRecPtr(Cid : Integer; DeviceLayerClass : TApdDispatcherClass) : Pointer; + {-Find the entry into the port array which has the specified Cid} +var + i : Integer; +begin + LockPortList; + try + {find the correct com port record} + if (LastCID = Cid) and (LastDispatcher <> nil) then + Result := LastDispatcher + else begin + for i := 0 to pred(PortList.Count) do + if PortList[i] <> nil then + with TApdBaseDispatcher(PortList[i]) do + if (CidEx = Cid) and (TObject(PortList[i]) is DeviceLayerClass) then begin + Result := TApdBaseDispatcher(PortList[i]); + LastCID := Cid; + LastDispatcher := Result; + exit; + end; + Result := nil; + end; + finally + UnlockPortList; + end; +end; + +{$IFDEF DebugThreadConsole} + type + TThreadStatus = (ComStart, ComWake, ComSleep, ComKill, + DispStart, DispWake, DispSleep, DispKill, + OutStart, OutWake, OutSleep, OutKill); + var + C, D, O : Char; {!!.02} + function ThreadStatus(Stat : TThreadStatus) : string; + begin + C := '.'; {!!.02} + D := '.'; {!!.02} + O := '.'; {!!.02} + case Stat of + ComStart, + ComWake : C := 'C'; + ComSleep : C := 'c'; + ComKill : C := 'x'; + DispStart, + DispWake : D := 'D'; + DispSleep : D := 'd'; + DispKill : D := 'x'; + OutStart, + OutWake : O := 'O'; + OutSleep : O := 'o'; + OutKill : O := 'x'; + end; + Result := C + D + O + ' ' + IntToStr(AdTimeGetTime); + end; +{$ENDIF} + + function BuffCount(Head, Tail: Cardinal; Full : Boolean) : Cardinal; + {-Return number of chars between Tail and Head} + begin + if Head = Tail then + if Full then + BuffCount := DispatchBufferSize + else + BuffCount := 0 + else if Head > Tail then + BuffCount := Head-Tail + else + BuffCount := (Head+DispatchBufferSize)-Tail; + end; + + function TApdBaseDispatcher.InQueueUsed : Cardinal; // SWB + begin // SWB + Result := 0; // SWB + end; // SWB + + procedure TApdBaseDispatcher.ThreadGone(Sender: TObject); + begin + try // SWB + CheckException(TComponent(Owner), // SWB + TApdDispatcherThread(Sender).ReturnValue); // SWB + except // SWB + on E: Exception do // SWB + begin // SWB + if Assigned(GShowExceptionHandler) then + GShowExceptionHandler(E, ExceptAddr) + else + ShowException(E, ExceptAddr); + end; // SWB + end; // SWB + + if Sender = ComThread then + ComThread := nil; + + if Sender = OutThread then + OutThread := nil; + + if Sender = fDispThread then begin + fDispThread := nil; + if DoDonePortPrim then begin + DonePortPrim; + DoDonePortPrim := False; + end; + end; + + if Sender = StatusThread then // SWB + StatusThread := nil; // SWB + + if (InterLockedDecrement(ActiveThreads) = 0) then begin + DispActive := False; + end; + end; + + procedure TApdBaseDispatcher.ThreadStart(Sender : TObject); // SWB + begin // SWB + InterLockedIncrement(ActiveThreads); // SWB + SetEvent(GeneralEvent); // SWB + end; // SWB + + procedure TApdBaseDispatcher.SetThreadBoost(Boost : Byte); + begin + if Boost <> ThreadBoost then begin + ThreadBoost := Boost; + + if Assigned(ComThread) then + ComThread.Priority := TThreadPriority(Ord(tpNormal) + Boost); + + if Assigned(fDispThread) then + fDispThread.Priority := TThreadPriority(Ord(tpNormal) + Boost); + + if Assigned(fDispThread) then + if RS485Mode then + OutThread.Priority := TThreadPriority(Ord(tpHigher) + Boost) + else + OutThread.Priority := TThreadPriority(Ord(tpNormal) + Boost); + + if Assigned(StatusThread) then // SWB + StatusThread.Priority := TThreadPriority(Ord(tpNormal) + Boost); // SWB + end; + end; + + constructor TApdBaseDispatcher.Create(Owner : TObject); + var + i : Integer; + begin + inherited Create; + fOwner := Owner; + ComEvent := INVALID_HANDLE_VALUE; + ReadyEvent := INVALID_HANDLE_VALUE; + GeneralEvent := INVALID_HANDLE_VALUE; + OutputEvent := INVALID_HANDLE_VALUE; + SentEvent := INVALID_HANDLE_VALUE; + OutFlushEvent := INVALID_HANDLE_VALUE; + + LockPortList; + try + {Find a free slot in PortListX or append if none found (see Destroy) } + fHandle := -1; + for i := 0 to pred(PortList.Count) do + if PortList[i] = nil then begin + PortList[i] := Self; + fHandle := i; + break; + end; + if fHandle = -1 then + fHandle := PortList.Add(Self); + finally + UnlockPortList; + end; + {Allocate critical section objects} + FillChar(DataSection, SizeOf(DataSection), 0); + InitializeCriticalSection(DataSection); + + FillChar(OutputSection, SizeOf(OutputSection), 0); + InitializeCriticalSection(OutputSection); + + FillChar(DispSection, SizeOf(DispSection), 0); + InitializeCriticalSection(DispSection); + WndTriggerHandlers := TList.Create; + ProcTriggerHandlers := TList.Create; + EventTriggerHandlers := TList.Create; + TimerTriggers := TList.Create; + DataTriggers := TList.Create; + StatusTriggers:= TList.Create; + TriggerCounter := FirstTriggerCounter; + FQueue := TIOQueue.Create; // SWB + DLoggingQueue := TIOQueue.Create; // SWB + end; + + destructor TApdBaseDispatcher.Destroy; + var + i : Integer; + begin + if ClosePending then begin + DonePortPrim + end else + DonePort; + + { it's possible for the main VCL thread (or whichever thread opened } + { the port) to destroy the dispatcher while we're still waiting for } + { our Com, Output and Dispatcher threads to terminate, we'll spin } + { here waiting for the threads to terminate. } + while ActiveThreads > 0 do {!!.02} + SafeYield; {!!.02} + + LockPortList; + try + { We can't just call Remove since there may be other ports open where } + { we use the index into the PortListX array as a handle } + PortList[PortList.IndexOf(Self)] := nil; + for i := PortList.Count - 1 downto 0 do + if PortList[i] = nil then + PortList.Delete(i) + else + break; + if LastDispatcher = Self then begin + LastDispatcher := nil; + LastCID := -1; + end; + finally + UnlockPortList; + end; + + while TimerTriggers.Count > 0 do begin + Dispose(PTimerTrigger(TimerTriggers[0])); + TimerTriggers.Delete(0); + end; + TimerTriggers.Free; + + while DataTriggers.Count > 0 do begin + Dispose(PDataTrigger(DataTriggers[0])); + DataTriggers.Delete(0); + end; + DataTriggers.Free; + + while StatusTriggers.Count > 0 do begin + Dispose(PStatusTrigger(StatusTriggers[0])); + StatusTriggers.Delete(0); + end; + StatusTriggers.Free; + + while WndTriggerHandlers.Count > 0 do begin + Dispose(PWndTriggerHandler(WndTriggerHandlers[0])); + WndTriggerHandlers.Delete(0); + end; + WndTriggerHandlers.Free; + + while ProcTriggerHandlers.Count > 0 do begin + Dispose(PProcTriggerHandler(ProcTriggerHandlers[0])); + ProcTriggerHandlers.Delete(0); + end; + ProcTriggerHandlers.Free; + + while EventTriggerHandlers.Count > 0 do begin + Dispose(PEventTriggerHandler(EventTriggerHandlers[0])); + EventTriggerHandlers.Delete(0); + end; + EventTriggerHandlers.Free; + + {Free the critical sections} + DeleteCriticalSection(DataSection); + DeleteCriticalSection(OutputSection); + DeleteCriticalSection(DispSection); + + if (Assigned(FQueue)) then // SWB + FQueue.Free; // SWB + if (Assigned(DLoggingQueue)) then // SWB + DLoggingQueue.Free; // SWB + + inherited Destroy; + end; + + procedure TApdBaseDispatcher.RefreshStatus; + {-Get current ComStatus} + var + NewError : Integer; + begin + {Get latest ComStatus and LastError} + NewError := GetComError(ComStatus); + + {Mask off those bits we don't care about} + LastError := LastError or (NewError and ValidErrorMask); + end; + + procedure TApdBaseDispatcher.MapEventsToMS(Events : Integer); + {-Set bits in ModemStatus according to flags in Events} + var + OldMS : Byte; + Delta : Byte; + begin + {Note old, get new} + OldMS := ModemStatus; + GetModemStatusPrim($FF); + + {Set delta bits} + Delta := (OldMS xor ModemStatus) and $F0; + ModemStatus := ModemStatus or (Delta shr 4); + end; + +{Routines used by constructor} + + procedure TApdBaseDispatcher.RemoveAllTriggers; + {-Remove all triggers} + begin + EnterCriticalSection(DataSection); + try + LenTrigger := 0; + while TimerTriggers.Count > 0 do begin + Dispose(PTimerTrigger(TimerTriggers[0])); + TimerTriggers.Delete(0); + end; + while DataTriggers.Count > 0 do begin + Dispose(PDataTrigger(DataTriggers[0])); + DataTriggers.Delete(0); + end; + while StatusTriggers.Count > 0 do begin + Dispose(PStatusTrigger(StatusTriggers[0])); + StatusTriggers.Delete(0); + end; + + TriggerCounter := FirstTriggerCounter; + finally + LeaveCriticalSection(DataSection); + end; + end; + + function TApdBaseDispatcher.SetCommStateFix(var DCB : TDCB) : Integer; + {-Preserve DTR and RTS states} + begin + if not DTRAuto then begin + DCB.Flags := DCB.Flags and not (dcb_DTRBit1 or dcb_DTRBit2); + if DTRState then begin + { Assert DTR } + DCB.Flags := DCB.Flags or dcb_DTR_CONTROL_ENABLE; + end; + end; + if not RTSAuto then begin + DCB.Flags := DCB.Flags and not (dcb_RTSBit1 or dcb_RTSBit2); + if RTSState then begin + { Assert RTS } + DCB.Flags := DCB.Flags or dcb_RTS_CONTROL_ENABLE; + end; + end; + Result := SetComState(DCB); + LastBaud := DCB.BaudRate; + SetDtr(DtrState); + if not RS485Mode then + SetRts(RtsState); + end; + + procedure TApdBaseDispatcher.ResetStatusHits; + var + i : Integer; + begin + for i := pred(StatusTriggers.Count) downto 0 do + PStatusTrigger(StatusTriggers[i])^.StatusHit := False; + GlobalStatHit := False; + end; + + procedure TApdBaseDispatcher.ResetDataTriggers; + var + i : Integer; + begin + for i := pred(DataTriggers.Count) downto 0 do + with PDataTrigger(DataTriggers[i])^ do + FillChar(tChkIndex, SizeOf(TCheckIndex), 0); + end; + + function TApdBaseDispatcher.InitPort( + AComName : PChar; + Baud : Integer; + Parity : Cardinal; + DataBits : TDatabits; + StopBits : TStopbits; + InSize, OutSize : Cardinal; + FlowOpts : DWORD) : Integer; + type + OS = record + O : Cardinal; + S : Cardinal; + end; + var + Error : Integer; + begin + RingFlag := False; + + {Required inits in case DonePort is called} + DBuffer := nil; + OBuffer := nil; + fEventBusy := False; + DeletePending := False; + + {Create event objects} + ComEvent := CreateEvent(nil, False, False, nil); + ReadyEvent := CreateEvent(nil, False, False, nil); + GeneralEvent := CreateEvent(nil, False, False, nil); + OutputEvent := CreateEvent(nil, False, False, nil); + SentEvent := CreateEvent(nil, True, False, nil); + OutFlushEvent := CreateEvent(nil, False, False, nil); + {wake up xmit thread when it's waiting for data} + OutWaitObjects1[0] := OutputEvent; + OutWaitObjects1[1] := OutFlushEvent; + {wake up xmit thread when it's waiting for i/o completion} + OutWaitObjects2[0] := SentEvent; + OutWaitObjects2[1] := OutFlushEvent; + + {Ask Windows to open the comm port} + CidEx := OpenCom(AComName, InSize, OutSize); + if CidEx < 0 then + begin + if CidEx = ecOutOfMemory then + Result := ecOutOfMemory + else + Result := -Integer(GetLastError); + CloseHandle(ComEvent); + CloseHandle(ReadyEvent); + CloseHandle(GeneralEvent); + CloseHandle(OutputEvent); + CloseHandle(SentEvent); + CloseHandle(OutFlushEvent); + DonePort; + Exit; + end; + + {set the buffer sizes} + Result := SetCommBuffers(InSize, OutSize); + if Result <> 0 then begin + DonePort; + Exit; + end; + + {Allocate dispatch buffer} + DBuffer := AllocMem(DispatchBufferSize); + + {Allocate output buffer} + OBuffer := AllocMem(OutSize); + OBufHead := 0; + OBufTail := 0; + OBufFull := False; + + {Initialize fields} + InQue := InSize; + OutQue := OutSize; + LastError := 0; + OutSentPending := False; + ClosePending := False; + fDispatcherWindow := 0; + DispatchFull := False; + GetCount := 0; + LastLineErr := 0; + LastModemStatus := 0; + RS485Mode := False; + BaseAddress := 0; + + {Assure DCB is up to date in all cases} + GetComState(DCB); + + { Set initial flow control options } + if (FlowOpts and ipAutoDTR) <> 0 then begin + DTRAuto := True; + end else begin + DTRAuto := False; + SetDTR((FlowOpts and ipAssertDTR) <> 0); + end; + + if (FlowOpts and ipAutoRTS) <> 0 then begin + RTSAuto := True; + end else begin + RTSAuto := False; + SetRTS((FlowOpts and ipAssertRTS) <> 0); + end; + + {Trigger inits} + LastTailData := 0; + LastTailLen := 1; + RemoveAllTriggers; + DBufHead := 0; + DBufTail := 0; + NotifyTail := 0; + ResetStatusHits; + + InAvailMessage := False; + + ModemStatus := 0; + GetModemStatusPrim($F0); + + {Set the requested line parameters} + LastBaud := 115200; + + Error := SetLine(Baud, Parity, DataBits, StopBits); + if Error <> ecOk then begin + Result := Error; + DonePort; + Exit; + end; + + {Get initial status} + RefreshStatus; + + TracingOn := False; + TraceQueue := nil; + TraceIndex := 0; + TraceMax := 0; + TraceWrapped := False; + + TimeBase := AdTimeGetTime; + DLoggingOn := False; + DLoggingMax := 0; + + {Start the dispatcher} + StartDispatcher; + end; + + function TApdBaseDispatcher.InitSocket(Insize, OutSize : Cardinal) : Integer; + begin + Result := ecOK; + + {Create a socket} + CidEx := OpenCom(nil, InSize, OutSize); + if CidEx < 0 then begin + Result := -CidEx; + DonePort; + Exit; + end; + + {Connect or bind socket} + if not SetupCom(0, 0) then begin + Result := -GetComError(ComStatus); + DonePort; + Exit; + end; + + {Allocate dispatch buffer} + DBuffer := AllocMem(DispatchBufferSize); + + {Initialize fields} + InQue := InSize; + OutQue := OutSize; + + {Trigger inits} + LastTailLen := 1; + + {Set default options} + ModemStatus := 0; + + {Get initial status} + RefreshStatus; + + TimeBase := AdTimeGetTime; + + {Start the dispatcher} + StartDispatcher; + end; + + function TApdBaseDispatcher.SetCommBuffers(InSize, OutSize : Integer) : Integer; + {-Set the new buffer sizes, win32 only} + begin + if SetupCom(InSize, OutSize) then + Result := ecOK + else + Result := -Integer(GetLastError); + end; + + procedure TApdBaseDispatcher.DonePortPrim; + {-Close the port and free the handle} + begin + {Stop dispatcher} + DoDonePortPrim := False; {!!.02} + if DispActive then + StopDispatcher; + { Free memory for the output buffer } + EnterCriticalSection(DataSection); + try + if OBuffer <> nil then begin + FreeMem(OBuffer); + OBuffer := nil; + end; + + { Free memory for the dispatcher buffer } + if DBuffer <> nil then begin + FreeMem(DBuffer, DispatchBufferSize); + DBuffer := nil; + end; + finally + LeaveCriticalSection(DataSection); + end; + end; + + procedure TApdBaseDispatcher.DonePort; + {-Close the port and free the handle} + begin + {Always close the physical port...} + if CidEx >= 0 then begin + {Flush the output queue} + FlushOutBuffer; + FlushInBuffer; + + CloseCom; + end; + + {...but destroy our object only if not within a notify} + if fEventBusy then begin + ClosePending := True; + end else + DonePortPrim; + end; + + function ActualBaud(BaudCode : Integer) : Integer; + const + BaudTable : array[0..23] of Integer = + (110, 300, 600, 1200, 2400, 4800, 9600, 14400, + 19200, 0, 0, 38400, 0, 0, 0, 56000, + 0, 0, 0, 128000, 0, 0, 0, 256000); + var + Index : Cardinal; + Baud : Integer; + begin + if BaudCode = $FEFF then + {COMM.DRV's 115200 hack} + Result := 115200 + else if BaudCode < $FF10 then + {Must be a baud rate, return it} + Result := BaudCode + else begin + {It's a code, look it up} + Index := BaudCode - $FF10; + if Index > 23 then + {Unknown code, just return it} + Result := BaudCode + else begin + Baud := BaudTable[Index]; + if Baud = 0 then + {Unknown code, just return it} + Result := BaudCode + else + Result := Baud; + end; + end; + end; + + { Wait till pending Tx Data is sent for H -- used for line parameter } + { changes -- so the data in the buffer at the time the change is made } + { goes out under the "old" line parameters. } + procedure TApdBaseDispatcher.WaitTxSent; + var + BitsPerChar : DWORD; + BPS : Integer; + MicroSecsPerBit : DWORD; + MicroSecs : DWORD; + MilliSecs : DWORD; + TxWaitCount : Integer; + begin + { Wait till our Output Buffer becomes free. } + { If output hasn't drained in 10 seconds, punt. } + TxWaitCount := 0; + while((OutBuffUsed > 0) and (TxWaitCount < 5000)) do begin + Sleep(2); + Inc(TxWaitCount); + end; + + { Delay based upon a 16-character TX FIFO + 1 character for TX output } + { register + 1 extra character for slop (= 18). Delay is based upon } + { 1/bps * (start bit + data bits + parity bit + stop bits). } + + GetComState(DCB); + BitsPerChar := DCB.ByteSize + 2; { Bits per Char + 1 start + 1 stop } + if (DCB.Parity <> 0) then + Inc(BitsPerChar); + if (DCB.StopBits <> 0) then + Inc(BitsPerChar); + BPS := ActualBaud(LastBaud); + MicroSecsPerBit := 10000000 div BPS; + MicroSecs := MicroSecsPerBit * BitsPerChar * 18; + if (MicroSecs < 10000) then + MicroSecs := MicroSecs + MicroSecs; + MilliSecs := Microsecs div 10000; + if ((Microsecs mod 10000) <> 0) then + Inc(MilliSecs); + Sleep(MilliSecs); + end; + +function TApdBaseDispatcher.WriteComSafe(ABuf: PAnsiChar; ASize: Integer): Integer; +begin + try + Result := WriteCom(ABuf, ASize); + except + on E: EAccessViolation do + Result := 0; + end; +end; + + function TApdBaseDispatcher.SetLine( + Baud : Integer; + Parity : Cardinal; + DataBits : TDatabits; + StopBits : TStopbits) : Integer; + var + NewBaudRate : DWORD; + NewParity : Cardinal; + NewByteSize : TDatabits; + NewStopBits : Byte; + NewFlags : Integer; // SWB + {-Set or change the line parameters} + begin + Result := ecOK; + EnterCriticalSection(DataSection); + try + {Get current DCB parameters} + GetComState(DCB); + + {Set critical default DCB options} + NewFlags := DCB.Flags; // SWB + NewFlags := NewFlags or dcb_Binary; // SWB + NewFlags := NewFlags and not dcb_Parity; // SWB + NewFlags := NewFlags and not dcb_DsrSensitivity; // SWB + NewFlags := NewFlags or dcb_TxContinueOnXoff; // SWB + NewFlags := NewFlags and not dcb_Null; // SWB + NewFlags := NewFlags and not dcb_Null; // SWB + + {Validate stopbit range} + if StopBits <> DontChangeStopBits then + if StopBits < 1 then + StopBits := 1 + else if StopBits > 2 then + StopBits := 2; + + {Determine new line parameters} + if Baud <> DontChangeBaud then begin + NewBaudRate := Baud; + end else + NewBaudRate := DCB.BaudRate; + + if Parity <> DontChangeParity then + NewParity := Parity + else + NewParity := DCB.Parity; + + NewStopBits := DCB.StopBits; + + if DataBits <> DontChangeDataBits then + begin + NewByteSize := DataBits; + if (DataBits = 5) then + NewStopBits := One5StopBits; + end else + NewByteSize := DCB.ByteSize; + + if StopBits <> DontChangeStopBits then begin + NewStopBits := StopBitArray[StopBits]; + if (NewByteSize = 5) then + NewStopBits := One5StopBits; + end; + finally + LeaveCriticalSection(DataSection); + end; + + if ((DCB.BaudRate = NewBaudRate) and + (DCB.Parity = NewParity) and + (DCB.ByteSize = NewByteSize) and + (DCB.StopBits = NewStopBits) and // SWB + (DCB.Flags = NewFlags)) then // SWB + Exit; + + { wait for the chars to be transmitted, don't want to change line } + { settings while chars are pending } + WaitTxSent; + + EnterCriticalSection(DataSection); + try + {Get current DCB parameters} + GetComState(DCB); + + {Change the parameters} + DCB.BaudRate := NewBaudRate; + DCB.Parity := NewParity; + DCB.ByteSize := NewByteSize; + DCB.StopBits := NewStopBits; + DCB.Flags := NewFlags; // SWB + + {Set line parameters} + Result := SetCommStateFix(DCB); + finally + LeaveCriticalSection(DataSection); + end; + end; + + procedure TApdBaseDispatcher.GetLine( + var Baud : Integer; + var Parity : Word; + var DataBits : TDatabits; + var StopBits : TStopbits); + {-Return line parameters} + begin + EnterCriticalSection(DataSection); + try + {Get current DCB parameters} + GetComState(DCB); + + {Return the line parameters} + Baud := ActualBaud(DCB.Baudrate); + + Parity := DCB.Parity; + DataBits := DCB.ByteSize; + if DCB.StopBits = OneStopBit then + StopBits := 1 + else + StopBits := 2; + finally + LeaveCriticalSection(DataSection); + end; + end; + + function TApdBaseDispatcher.SetModem(Dtr, Rts : Boolean) : Integer; + {-Set modem control lines, Dtr and Rts} + begin + Result := SetDtr(Dtr); + if Result = ecOK then + Result := SetRts(Rts); {!!.02} + end; + + function TApdBaseDispatcher.SetDtr(OnOff : Boolean) : Integer; + {-Set DTR modem control line} + begin + if DtrAuto then begin + { We can't change DTR if we're controlling it automatically } + Result := 1; + Exit; + end; + + if (OnOff = True) then + Result := EscapeComFunction(Windows.SETDTR) + else + Result := EscapeComFunction(Windows.CLRDTR); + + if (Result < ecOK) then + Result := ecBadArgument; + DTRState := OnOff; + end; + + function TApdBaseDispatcher.SetRts(OnOff : Boolean) : Integer; + {-Set RTS modem control line} + begin + if RtsAuto then begin + { We can't change RTS if we're controlling it automatically } + Result := 1; + Exit; + end; + + if (OnOff = True) then + Result := EscapeComFunction(Windows.SETRTS) + else + Result := EscapeComFunction(Windows.CLRRTS); + + if (Result < ecOK) then + Result := ecBadArgument; + RTSState := OnOff; + end; + + function TApdBaseDispatcher.GetModemStatusPrim(ClearMask : Byte) : Byte; + {-Primitive to return the modem status and clear mask} + var + Data : DWORD; + begin + {Get the new absolute values} + // There is no reason for this to be inside the critical section // SWB + // and since this can be a very slow function when using mapped // SWB + // comm ports under Citrix or W2K3 I moved it out here. // SWB + GetCommModemStatus(CidEx, Data); // SWB + EnterCriticalSection(DataSection); + try + ModemStatus := (ModemStatus and $0F) or Byte(Data); + + {Special case, transfer RI bit to TERI bit} + if RingFlag then begin + RingFlag := False; + ModemStatus := ModemStatus or $04; + end; + + {Return the current ModemStatus value} + Result := Lo(ModemStatus); + + {Clear specified delta bits} + ModemStatus := ModemStatus and Clearmask; + + finally + LeaveCriticalSection(DataSection); + end; + end; + + function TApdBaseDispatcher.GetModemStatus : Byte; + {-Return the modem status byte and clear the delta bits} + begin + Result := GetModemStatusPrim(ClearDelta); + end; + + function TApdBaseDispatcher.CheckCTS : Boolean; + {-Returns True if CTS is high} + begin + Result := GetModemStatusPrim(ClearDeltaCTS) and CTSMask = CTSMask; + end; + + function TApdBaseDispatcher.CheckDSR : Boolean; + {-Returns True if DSR is high} + begin + Result := GetModemStatusPrim(ClearDeltaDSR) and DSRMask = DSRMask; + end; + + function TApdBaseDispatcher.CheckRI : Boolean; + {-Returns True if RI is high} + begin + Result := GetModemStatusPrim(ClearDeltaRI) and RIMask = RIMask; + end; + + function TApdBaseDispatcher.CheckDCD : Boolean; + {-Returns True if DCD is high} + begin + Result := GetModemStatusPrim(ClearDeltaDCD) and DCDMask = DCDMask; + end; + + function TApdBaseDispatcher.CheckDeltaCTS : Boolean; + {-Returns True if DeltaCTS is high} + begin + Result := GetModemStatusPrim(ClearDeltaCTS) and DeltaCTSMask = DeltaCTSMask; + end; + + function TApdBaseDispatcher.CheckDeltaDSR : Boolean; + {-Returns True if DeltaDSR is high} + begin + Result := GetModemStatusPrim(ClearDeltaDSR) and DeltaDSRMask = DeltaDSRMask; + end; + + function TApdBaseDispatcher.CheckDeltaRI : Boolean; + {-Returns True if DeltaRI is high} + begin + Result := GetModemStatusPrim(ClearDeltaRI) and DeltaRIMask = DeltaRIMask; + end; + + function TApdBaseDispatcher.CheckDeltaDCD : Boolean; + {-Returns True if DeltaDCD is high} + begin + Result := GetModemStatusPrim(ClearDeltaDCD) and DeltaDCDMask = DeltaDCDMask; + end; + + function TApdBaseDispatcher.GetLineError : Integer; + {-Return current line errors} + const + AllErrorMask = ce_RxOver + + ce_Overrun + ce_RxParity + ce_Frame; + var + GotError : Boolean; + begin + EnterCriticalSection(DataSection); + try + GotError := True; + if FlagIsSet(LastError, ce_RxOver) then + Result := leBuffer + else if FlagIsSet(LastError, ce_Overrun) then + Result := leOverrun + else if FlagIsSet(LastError, ce_RxParity) then + Result := leParity + else if FlagIsSet(LastError, ce_Frame) then + Result := leFraming + else if FlagIsSet(LastError, ce_Break) then + Result := leBreak + else begin + GotError := False; + Result := leNoError; + end; + + {Clear all error flags} + if GotError then + LastError := LastError and not AllErrorMask; + finally + LeaveCriticalSection(DataSection); + end; + end; + + function TApdBaseDispatcher.CheckLineBreak : Boolean; + begin + EnterCriticalSection(DataSection); + try + Result := FlagIsSet(LastError, ce_Break); + LastError := LastError and not ce_Break; + finally + LeaveCriticalSection(DataSection); + end; + end; + + procedure TApdBaseDispatcher.SendBreak(Ticks : Cardinal; Yield : Boolean); + {Send a line break of Ticks ticks, with yields} + begin + { raise RTS for RS485 mode } + if RS485Mode then {!!.01} + SetRTS(True); {!!.01} + SetCommBreak(CidEx); + DelayTicks(Ticks, Yield); + ClearCommBreak(CidEx); + { lower RTS only if the output buffer is empty } + if RS485Mode and (OutBuffUsed = 0) then {!!.01} + SetRTS(False); {!!.01} + end; + + procedure TApdBaseDispatcher.SetBreak(BreakOn: Boolean); + {Sets or clears line break condition} + begin + if BreakOn then begin {!!.01} + if RS485Mode then {!!.01} + SetRTS(True); {!!.01} + SetCommBreak(CidEx) + end else begin {!!.01} + ClearCommBreak(CidEx); + if RS485Mode and (OutBuffUsed = 0) then {!!.01} + SetRTS(False); {!!.01} + end; {!!.01} + end; + + function TApdBaseDispatcher.CharReady : Boolean; + {-Return True if at least one character is ready at the device driver} + var + NewTail : Cardinal; + begin + EnterCriticalSection(DispSection); + try + if InAvailMessage then begin + NewTail := DBufTail + GetCount; + if NewTail >= DispatchBufferSize then + Dec(NewTail, DispatchBufferSize); + Result := (DBufHead <> NewTail) + or (DispatchFull and (GetCount < DispatchBufferSize)); + end else + Result := (DBufHead <> DBufTail) or DispatchFull; + finally + LeaveCriticalSection(DispSection); + end; + end; + + function TApdBaseDispatcher.PeekCharPrim(var C : AnsiChar; Count : Cardinal) : Integer; + {-Return the Count'th character but don't remove it from the buffer} + var + NewTail : Cardinal; + InCount : Cardinal; + begin + Result := ecOK; + EnterCriticalSection(DispSection); + try + if DBufHead > DBufTail then + InCount := DBufHead-DBufTail + else if DBufHead <> DBufTail then + InCount := ((DBufHead+DispatchBufferSize)-DBufTail) + else if DispatchFull then + InCount := DispatchBufferSize + else + InCount := 0; + + if InCount >= Count then begin + {Calculate index of requested character} + NewTail := DBufTail + (Count - 1); + if NewTail >= DispatchBufferSize then + NewTail := (NewTail - DispatchBufferSize); + C := DBuffer^[NewTail]; + end else + Result := ecBufferIsEmpty; + finally + LeaveCriticalSection(DispSection); + end; + end; + + function TApdBaseDispatcher.PeekChar(var C : AnsiChar; Count : Cardinal) : Integer; + {-Return the Count'th character but don't remove it from the buffer} + {-Account for GetCount} + begin + EnterCriticalSection(DispSection); + try + if InAvailMessage then + Inc(Count, GetCount); + Result := PeekCharPrim(C, Count); + finally + LeaveCriticalSection(DispSection); + end; + end; + + function TApdBaseDispatcher.GetChar(var C : AnsiChar) : Integer; + {-Return next char and remove it from buffer} + begin + EnterCriticalSection(DispSection); + try + {If within an apw_TriggerAvail message then do not physically } + {extract the character. It will be removed by the dispatcher after } + {all trigger handlers have seen it. If not within an } + {apw_TriggerAvail message then physically extract the character } + + if InAvailMessage then begin + Inc(GetCount); + Result := PeekCharPrim(C, GetCount); + if Result < ecOK then begin + Dec(GetCount); + Exit; + end; + end else begin + Result := PeekCharPrim(C, 1); + if Result >= ecOK then begin + {Increment the tail index} + Inc(DBufTail); + if DBufTail = DispatchBufferSize then + DBufTail := 0; + DispatchFull := False; + end; + end; + + if TracingOn + and (Result >= ecOK) then + AddTraceEntry('R', C); + finally + LeaveCriticalSection(DispSection); + end; + end; + + function TApdBaseDispatcher.PeekBlockPrim(Block : PAnsiChar; + Offset : Cardinal; Len : Cardinal; var NewTail : Cardinal) : Integer; + {-Return Block from ComPort, return new tail value} + var + Count : Cardinal; + EndCount : Cardinal; + BeginCount : Cardinal; + begin + EnterCriticalSection(DispSection); + try + {Get count} + Count := BuffCount(DBufHead, DBufTail, DispatchFull); + + {Set new tail value} + NewTail := DBufTail + Offset; + if NewTail >= DispatchBufferSize then + Dec(NewTail, DispatchBufferSize); + + if Count >= Len then begin + {Set begin/end buffer counts} + if NewTail+Len < DispatchBufferSize then begin + EndCount := Len; + BeginCount := 0; + end else begin + EndCount := (DispatchBufferSize-NewTail); + BeginCount := Len-EndCount; + end; + + if EndCount <> 0 then begin + {Move data from end of dispatch buffer} + Move(DBuffer^[NewTail], Pointer(Block)^, EndCount); + Inc(NewTail, EndCount); + end; + + if BeginCount <> 0 then begin + {Move data from beginning of dispatch buffer} + Move(DBuffer^[0], + PByteBuffer(Block)^[EndCount+1], + BeginCount); + NewTail := BeginCount; + end; + + {Wrap newtail} + if NewTail = DispatchBufferSize then + NewTail := 0; + + Result := Len; + end else + Result := ecBufferIsEmpty; + finally + LeaveCriticalSection(DispSection); + end; + end; + + function TApdBaseDispatcher.PeekBlock(Block : PAnsiChar; Len : Cardinal) : Integer; + {-Return Block from ComPort but don't set new tail value} + var + Tail : Cardinal; + Offset : Cardinal; + begin + EnterCriticalSection(DispSection); + try + {Get block} + if InAvailMessage then + Offset := GetCount + else + Offset := 0; + Result := PeekBlockPrim(Block, Offset, Len, Tail); + finally + LeaveCriticalSection(DispSection); + end; + end; + + function TApdBaseDispatcher.GetBlock(Block : PAnsiChar; Len : Cardinal) : Integer; + {-Get Block from ComPort and set new tail} + var + Tail : Cardinal; + I : Cardinal; + begin + EnterCriticalSection(DispSection); + try + { If within an apw_TriggerAvail message then do not physically } + { extract the data. It will be removed by the dispatcher after } + { all trigger handlers have seen it. If not within an } + { apw_TriggerAvail message, then physically extract the data } + + if InAvailMessage then begin + Result := PeekBlockPrim(Block, GetCount, Len, Tail); + if Result > 0 then + Inc(GetCount, Result); + end else begin + Result := PeekBlockPrim(Block, 0, Len, Tail); + if Result > 0 then begin + DBufTail := Tail; + DispatchFull := False; + end; + end; + finally + LeaveCriticalSection(DispSection); + end; + + EnterCriticalSection(DataSection); + try + if TracingOn and (Result > 0) then + for I := 0 to Result-1 do + AddTraceEntry('R', Block[I]); + finally + LeaveCriticalSection(DataSection); + end; + end; + + function TApdBaseDispatcher.PutChar(C : AnsiChar) : Integer; + {-Route through PutBlock to transmit a single character} + begin + Result := PutBlock(C, 1); + end; + + function TApdBaseDispatcher.PutString(S : AnsiString) : Integer; + {-Send as a block} + begin + Result := PutBlock(S[1], Length(S)); + end; + + procedure TApdBaseDispatcher.AddStringToLog(S : Ansistring); + begin + if DLoggingOn then + AddDispatchEntry(dtUser, dstNone, 0, @S[1], length(S) * SizeOf(AnsiChar)) + end; + + function TApdBaseDispatcher.PutBlock(const Block; Len : Cardinal) : Integer; + {-Send Block to CommPort} + var + Avail : Cardinal; + I : Cardinal; + CharsOut : Integer; {Chars transmitted from last block} + begin + {Exit immediately if nothing to do} + Result := ecOK; + if Len = 0 then + Exit; + + EnterCriticalSection(OutputSection); + try + { Is there enough free space in the outbuffer? } + {LastError := GetComError(ComStatus); // SWB + Avail := OutQue - ComStatus.cbOutQue;} // SWB + // The old method of determining available space in the output buffer // SWB + // was agonizingly slow when using mapped com ports under Citrix or // SWB + // Windows 2003. Replaced call to GetComError with a call that // SWB + // returns only the used buffer space. // SWB + Avail := OutQue - OutBufUsed; // SWB + if Avail < Len then begin + Result := ecOutputBufferTooSmall; + Exit; + end; + if Avail = Len then + OBufFull := True; + + { Raise RTS if in RS485 mode. In 32bit mode it will be lowered } + { by the output thread. } + if Win32Platform <> VER_PLATFORM_WIN32_NT then + if RS485Mode then begin + if BaseAddress = 0 then begin + Result := ecBaseAddressNotSet; + Exit; + end; + SetRTS(True); + end; + + {Send the data} + CharsOut := WriteCom(PAnsiChar(@Block), Len); + if CharsOut <= 0 then begin + CharsOut := Abs(CharsOut); + Result := ecPutBlockFail; + LastError := GetComError(ComStatus); + end; + + {Flag output trigger} + OutSentPending := True; + finally + LeaveCriticalSection(OutputSection); + end; + + EnterCriticalSection(DataSection); + try + if DLoggingOn then + if CharsOut = 0 then + AddDispatchEntry(dtDispatch, dstWriteCom, 0, nil, 0) + else + AddDispatchEntry(dtDispatch, dstWriteCom, CharsOut, + PAnsiChar(@Block), CharsOut); + + if TracingOn and (CharsOut <> 0) then + for I := 0 to CharsOut-1 do + AddTraceEntry('T', PAnsiChar(@Block)[I]); + finally + LeaveCriticalSection(DataSection); + end; + end; + + function TApdBaseDispatcher.InBuffUsed : Cardinal; + {-Return number of bytes currently in input buffer} + begin + EnterCriticalSection(DispSection); + try + if DBufHead = DBufTail then + if DispatchFull then + Result := DispatchBufferSize + else + Result := 0 + else if DBufHead > DBufTail then + Result := DBufHead-DBufTail + else + Result := (DBufHead+DispatchBufferSize)-DBufTail; + + if InAvailMessage then + {In apw_TriggerAvail message so reduce by retrieved chars} + Dec(Result, GetCount); + finally + LeaveCriticalSection(DispSection); + end; + end; + + function TApdBaseDispatcher.InBuffFree : Cardinal; + {-Return number of bytes free in input buffer} + begin + EnterCriticalSection(DispSection); + try + if DBufHead = DBufTail then + if DispatchFull then + Result := 0 + else + Result := DispatchBufferSize + else if DBufHead > DBufTail then + Result := (DBufTail+DispatchBufferSize)-DBufHead + else + Result := DBufTail-DBufHead; + + if InAvailMessage then + {In apw_TriggerAvail message so reduce by retrieved chars} + Inc(Result, GetCount); + finally + LeaveCriticalSection(DispSection); + end; + end; + + function TApdBaseDispatcher.OutBuffUsed : Cardinal; + {-Return number of bytes currently in output buffer} + begin + EnterCriticalSection(OutputSection); + try + RefreshStatus; + Result := ComStatus.cbOutQue; + finally + LeaveCriticalSection(OutputSection); + end; + end; + + function TApdBaseDispatcher.OutBuffFree : Cardinal; + {-Return number of bytes free in output buffer} + begin + EnterCriticalSection(OutputSection); + try + RefreshStatus; + Result := OutQue - ComStatus.cbOutQue; + finally + LeaveCriticalSection(OutputSection); + end; + end; + + function TApdBaseDispatcher.FlushOutBuffer : Integer; + {-Flush the output buffer} + begin + Result := FlushCom(0); + end; + + function TApdBaseDispatcher.FlushInBuffer : Integer; + begin + EnterCriticalSection(DispSection); + try + {Flush COMM buffer} + Result := FlushCom(1); + + {Flush the dispatcher's buffer} + if InAvailMessage then + MaxGetCount := BuffCount(DBufHead, DBufTail, DispatchFull) + else begin + DBufTail := DBufHead; + GetCount := 0; + end; + DispatchFull := False; + + {Reset data triggers} + ResetDataTriggers; + finally + LeaveCriticalSection(DispSection); + end; + end; + + procedure TApdBaseDispatcher.BufferSizes(var InSize, OutSize : Cardinal); + {-Return buffer sizes} + begin + InSize := InQue; + OutSize := OutQue; + end; + + function TApdBaseDispatcher.HWFlowOptions( + BufferFull, BufferResume : Cardinal; + Options : Cardinal) : Integer; + {-Turn on hardware flow control} + begin + {Validate the buffer points} + if (BufferResume > BufferFull) or + (BufferFull > InQue) then begin + Result := ecBadArgument; + Exit; + end; + + EnterCriticalSection(DataSection); + try + GetComState(DCB); + with DCB do begin + Flags := Flags and not (AllHdwFlow); + Flags := Flags and not (dcb_DTRBit1 or dcb_RTSBit1); + DtrAuto := False; + RtsAuto := False; + + {Receive flow control, set requested signal(s)} + if FlagIsSet(Options, hfUseDtr) then begin + Flags := Flags or dcb_DTR_CONTROL_HANDSHAKE; + DtrAuto := True; + end else begin + { If static DTR wanted } + if DTRState then + { then assert DTR } + Flags := Flags or dcb_DTR_CONTROL_ENABLE; + end; + + if FlagIsSet(Options, hfUseRts) then begin + Flags := Flags or dcb_RTS_CONTROL_HANDSHAKE; + RtsAuto := True; + end else begin + { If static RTS wanted } + if RTSState then + { then assert RTS } + Flags := Flags or dcb_RTS_CONTROL_ENABLE; + end; + + if RS485Mode and (Win32Platform = VER_PLATFORM_WIN32_NT) then begin + Flags := Flags or dcb_RTS_CONTROL_TOGGLE; + RtsAuto := True; + end; + + {Set receive flow buffer limits} + XoffLim := InQue - BufferFull; + XonLim := BufferResume; + + {Transmit flow control, set requested signal(s)} + if FlagIsSet(Options, hfRequireDsr) then + Flags := Flags or dcb_OutxDsrFlow; + + if FlagIsSet(Options, hfRequireCts) then + Flags := Flags or dcb_OutxCtsFlow; + + {Set new DCB} + Result := SetCommStateFix(DCB); + end; + finally + LeaveCriticalSection(DataSection); + end; + end; + + function TApdBaseDispatcher.HWFlowState : Integer; + {-Returns state of flow control} + begin + with DCB do begin + EnterCriticalSection(DataSection); + try + if not FlagIsSet(Flags, AllHdwFlow) then begin + Result := fsOff; + Exit; + end else + Result := fsOn; + + if Flags and InHdwFlow <> 0 then begin + {Get latest flow status} + RefreshStatus; + + {Set appropriate flow state} + if (Flags and dcb_OutxDsrFlow <> 0) and + (fDsrHold in ComStatus.Flags) then + Result := fsDsrHold; + + if (Flags and dcb_OutxCtsFlow <> 0) and + (fCtlHold in ComStatus.Flags) then + Result := fsCtsHold; + end; + finally + LeaveCriticalSection(DataSection); + end; + end; + end; + + function TApdBaseDispatcher.SWFlowEnable( + BufferFull, BufferResume : Cardinal; + Options : Cardinal) : Integer; + {-Turn on software flow control} + begin + {Validate the buffer points} + if (BufferResume > BufferFull) or + (BufferFull > InQue) then begin + Result := ecBadArgument; + Exit; + end; + + EnterCriticalSection(DataSection); + try + { Make sure we have an up-to-date DCB } + GetComState(DCB); + with DCB do begin + if FlagIsSet(Options, sfReceiveFlow) then begin + {Receive flow control} + Flags := Flags or dcb_InX; + + {Set receive flow buffer limits} + XoffLim := InQue - BufferFull; + XonLim := BufferResume; + + {Set flow control characters} + XOnChar := cXon; + XOffChar := cXoff; + end; + + if FlagIsSet(Options, sfTransmitFlow) then begin + {Transmit flow control} + Flags := Flags or dcb_OutX; + + {Set flow control characters} + XOnChar := cXon; + XOffChar := cXoff; + end; + + {Set new DCB} + Result := SetCommStateFix(DCB); + end; + finally + LeaveCriticalSection(DataSection); + end; + end; + + function TApdBaseDispatcher.SWFlowDisable : Integer; + {-Turn off all software flow control} + begin + with DCB do begin + EnterCriticalSection(DataSection); + try + { Make sure we have an up-to-date DCB } + GetComState(DCB); + Flags := Flags and not AllSfwFlow; + Result := SetCommStateFix(DCB); + finally + LeaveCriticalSection(DataSection); + end; + end; + end; + + function TApdBaseDispatcher.SWFlowState : Integer; + {-Returns state of flow control} + begin + with DCB do begin + EnterCriticalSection(DataSection); + try + if FlagIsSet(Flags, dcb_InX) or FlagIsSet(Flags, dcb_OutX) then + Result := fsOn + else begin + Result := fsOff; + Exit; + end; + + {Get latest flow status} + RefreshStatus; + + {Set appropriate flow state} + if (fXoffHold in ComStatus.Flags) then + if (fXoffSent in ComStatus.Flags) then + Result := fsXBothHold + else + Result := fsXOutHold + else if (fXoffSent in ComStatus.Flags) then + Result := fsXInHold; + finally + LeaveCriticalSection(DataSection); + end; + end; + end; + + function TApdBaseDispatcher.SWFlowChars(OnChar, OffChar : AnsiChar) : Integer; + {-Set on/off chars for software flow control} + begin + with DCB do begin + EnterCriticalSection(DataSection); + try + { Make sure we have an up-to-date DCB } + GetComState(DCB); + + {Set flow control characters} + XOnChar := OnChar; + XOffChar := OffChar; + Result := SetCommStateFix(DCB); + finally + LeaveCriticalSection(DataSection); + end; + end; + end; + + function TApdBaseDispatcher.SendNotify(Msg, Trigger, Data: Cardinal) : Boolean; + {-Send trigger messages, return False to stop checking triggers} + var + lParam : DWORD; + Res : DWORD; + i : Integer; + begin + Result := True; + + if not HandlerServiceNeeded then Exit; + + {Don't let dispatcher change anything while sending messages} + EnterCriticalSection(DataSection); + try + fEventBusy := True; + finally + LeaveCriticalSection(DataSection); + end; + + try + MaxGetCount := 0; + + {Flag apw_TriggerAvail messages} + InAvailMessage := (Msg = apw_TriggerAvail) or (Msg = apw_TriggerData); + + {Clear trigger handle modification flags} + lParam := (DWORD(fHandle) shl 16) + Data; + + for i := 0 to pred(EventTriggerHandlers.Count) do + with PEventTriggerHandler(EventTriggerHandlers[i])^ do begin + GetCount := 0; + + if not thDeleted then + if thSync then + DispThread.SyncNotify(Msg,Trigger,lParam,thNotify) + else + thNotify(Msg, Trigger, lParam); + + if ClosePending then begin + {Port was closed by event handler, bail out} + Result := False; + Exit; + end; + + {Note deepest look at input buffer} + if GetCount > MaxGetCount then + MaxGetCount := GetCount; + end; + + for i := 0 to pred(ProcTriggerHandlers.Count) do + with PProcTriggerHandler(ProcTriggerHandlers[i])^ do begin + GetCount := 0; + + if not thDeleted and (@thNotify <> nil) then + thNotify(Msg, Trigger, lParam); + + if ClosePending then begin + {Port was closed by event handler, bail out} + Result := False; + Exit; + end; + + {Note deepest look at input buffer} + if GetCount > MaxGetCount then + MaxGetCount := GetCount; + end; + + if (WndTriggerHandlers.Count > 1) or PortHandlerInstalled then + for i := 0 to pred(WndTriggerHandlers.Count) do + with PWndTriggerHandler(WndTriggerHandlers[i])^ do begin + GetCount := 0; + + if not thDeleted then + SendMessageTimeout(thWnd, Msg, Trigger, lParam, + SMTO_BLOCK, 3000, @Res); + + if ClosePending then begin + {Port was closed by event handler, bail out} + Result := False; + Exit; + end; + + {Note deepest look at input buffer} + if GetCount > MaxGetCount then + MaxGetCount := GetCount; + end; + + { If in apw_TriggerAvail message remove the data now } + if InAvailMessage then begin + EnterCriticalSection(DispSection); + try + InAvailMessage := False; + Inc(DBufTail, MaxGetCount); + if DBufTail >= DispatchBufferSize then + Dec(DBufTail, DispatchBufferSize); + if MaxGetCount <> 0 then + DispatchFull := False; + + {Force CheckTriggers to exit if another avail msg is pending} + {Note: for avail msgs, trigger is really the byte count} + if (Msg = apw_TriggerAvail) and (MaxGetCount <> Trigger) then + Result := False; + finally + LeaveCriticalSection(DispSection); + end; + end; + finally + EnterCriticalSection(DataSection); + try + fEventBusy := False; + + if DeletePending then begin + + for i := pred(WndTriggerHandlers.Count) downto 0 do + if PWndTriggerHandler(WndTriggerHandlers[i])^.thDeleted then begin + Dispose(PWndTriggerHandler(WndTriggerHandlers[i])); + WndTriggerHandlers.Delete(i); + end; + + for i := pred(ProcTriggerHandlers.Count) downto 0 do + if PProcTriggerHandler(ProcTriggerHandlers[i])^.thDeleted then begin + Dispose(PProcTriggerHandler(ProcTriggerHandlers[i])); + ProcTriggerHandlers.Delete(i); + end; + + for i := pred(EventTriggerHandlers.Count) downto 0 do + if PEventTriggerHandler(EventTriggerHandlers[i])^.thDeleted then begin + Dispose(PEventTriggerHandler(EventTriggerHandlers[i])); + EventTriggerHandlers.Delete(i); + end; + + DeletePending := False; + UpdateHandlerFlags(fuKeepPort); + end; + finally + LeaveCriticalSection(DataSection); + end; + end; + GetCount := 0; + end; + + function MatchString(var Indexes : TCheckIndex; const C : AnsiChar; Len : Cardinal; + P : PAnsiChar; IgnoreCase : Boolean) : Boolean; + {-Checks for string P on consecutive calls, returns True when found} + var + I : Cardinal; + Check : Boolean; + GotFirst : Boolean; + begin + Result := False; + + if IgnoreCase then + AnsiUpperBuff(@C, 1); + + GotFirst := False; + Check := True; + for I := 0 to Len-1 do begin + {Check another index?} + if Check then begin + {Compare this index...} + if C = P[Indexes[I]] then + {Got match, was it complete?} + if Indexes[I] = Len-1 then begin + Indexes[I] := 0; + Result := True; + + {Clear all inprogress matches} + FillChar(Indexes, SizeOf(Indexes), 0); + end else + Inc(Indexes[I]) + else + {No match, reset index} + if C = P[0] then begin + GotFirst := True; + Indexes[I] := 1 + end else + Indexes[I] := 0; + end; + + {See if last match was on first char} + if Indexes[I] = 1 then + GotFirst := True; + + {See if we should check the next index} + if I <> Len-1 then + if GotFirst then + {Got a previous restart, don't allow more restarts} + Check := Indexes[I+1] <> 0 + else + {Not a restart, check next index if in progress or on first char} + Check := (Indexes[I+1] <> 0) or (C = P[0]) + else + Check := False; + end; + end; + + function TApdBaseDispatcher.CheckStatusTriggers : Boolean; + {-Check status triggers for H, send notification messages as required} + {-Return True if more checks remain} + var + J : Integer; + Hit : Cardinal; + StatusLen : Cardinal; + Res : Byte; + BufCnt : Cardinal; + begin + {Check status triggers} + for J := 0 to pred(StatusTriggers.Count) do begin + with PStatusTrigger(StatusTriggers[J])^ do begin + if tSActive and not StatusHit then begin + Hit := stNotActive; + StatusLen := 0; + case tSType of + stLine : + if LastError and tValue <> 0 then begin + Hit := stLine; + tValue := LastError; + end; + stModem : + begin + {Check for changed bits} + Res := Lo(tValue) xor ModemStatus; + + {Skip bits not in our mask} + Res := Res and Hi(tValue); + + {If anything is still set, it's a hit} + if Res <> 0 then begin + Hit := stModem; + end; + end; + stOutBuffFree : + begin + BufCnt := OutBuffFree; + if BufCnt >= tValue then begin + StatusLen := BufCnt; + Hit := stOutBuffFree; + end; + end; + stOutBuffUsed : + begin + BufCnt := OutBuffUsed; + if BufCnt <= tValue then begin + StatusLen := BufCnt; + Hit := stOutBuffUsed; + end; + end; + stOutSent : + if OutSentPending then begin + OutSentPending := False; + StatusLen := 0; + Hit := stOutSent; + end; + end; + if Hit <> stNotActive then begin + {Clear the trigger and send the notification message} + tSActive := False; + + {Prevent status trigger re-entrancy issues} + GlobalStatHit := True; + StatusHit := True; + + if DLoggingOn then + AddDispatchEntry(dtTrigger, dstStatus, tHandle, nil, 0); + + Result := + SendNotify(apw_TriggerStatus, tHandle, StatusLen); + Exit; + end; + end; + end; + if J >= StatusTriggers.Count then break; + end; + {No more checks required} + Result := False; + end; + + function TApdBaseDispatcher.CheckReceiveTriggers : Boolean; + {-Check all receive triggers for H, send notification messages as required} + {-Return True if more checks remain} + type + LH = record L,H : Byte; end; + var + I : Cardinal; + J : Integer; + BufCnt : Cardinal; + MatchSize : Cardinal; + CC : Cardinal; + AnyMatch : Boolean; + C : AnsiChar; + + function CharCount(CurTail, Adjust : Cardinal) : Cardinal; + {-Return the number of characters available between CurTail } + { and DBufTail that haven't already been extracted. CurTail } + { is first adjusted downward by Adjust, the size of the } + { current match string } + begin + if Adjust <= CurTail then + Dec(CurTail, Adjust) + else + CurTail := (CurTail + DispatchBufferSize) - Adjust; + Result := BuffCount(CurTail, DBufTail, DispatchFull) + 1; + if InAvailMessage then + Dec(Result, GetCount); + end; + + begin + {Assume triggers need to be re-checked} + Result := True; + + I := LastTailData; + {Check data triggers} + if LastTailData <> DBufHead then begin + {Prepare} + + {Loop through new data in dispatch buffer} + while I <> DBufHead do begin + C := DBuffer^[I]; + + {Check each trigger for a match on this character} + AnyMatch := False; + MatchSize := 0; + for J := 0 to pred(DataTriggers.Count) do + with PDataTrigger(DataTriggers[J])^ do + if tLen <> 0 then begin + tMatched := tMatched or + MatchString(tChkIndex, C, tLen, tData, tIgnoreCase); + if tMatched and (tLen > MatchSize) then + MatchSize := tLen; + if not AnyMatch then + AnyMatch := tMatched; + end; + + {Send len message if we have any matches} + if AnyMatch then begin + {Send len message up to first matching char} + if (LenTrigger <> 0) and + (NotifyTail <> I) and + (Integer(CharCount(I, 0))- + Integer(MatchSize) >= Integer(LenTrigger)) + then begin + + {Generate len message for preceding data} + CC := CharCount(I, MatchSize); + if DLoggingOn then + AddDispatchEntry(dtTrigger, dstAvail, CC, nil, 0); + Result := SendNotify(apw_TriggerAvail, CC, 0); + LastTailData := I; + NotifyTail := I; + end; + + {Process the matches} + for J := pred(DataTriggers.Count) downto 0 do begin + with PDataTrigger(DataTriggers[J])^ do + if tMatched then begin + {No preceding data or msg pending, send data msg} + if DLoggingOn then + AddDispatchEntry(dtTrigger, dstData, tHandle, nil, 0); + + tMatched := False; + Result := + SendNotify(apw_TriggerData, tHandle, tLen); + end; + if J >= DataTriggers.Count then break; + end; + + {Exit after all data triggers that matched on this char} + if I = DispatchBufferSize-1 then + LastTailData := 0 + else + LastTailData := I+1; + Exit; + end; + + {Next index for buffer} + if I = DispatchBufferSize-1 then + I := 0 + else + inc(I); + end; + + {Update last tail for data triggers} + LastTailData := I; + end; + + {Check for length trigger} + + BufCnt := InBuffUsed; + + if (LenTrigger <> 0) and + (NotifyTail <> I) and + (BufCnt >= LenTrigger) then begin + if DLoggingOn then + AddDispatchEntry(dtTrigger, dstAvail, BufCnt, nil, 0); + + Result := + SendNotify(apw_TriggerAvail, BufCnt, 0); + NotifyTail := I; + Exit; + end; + + {No more checks required} + Result := False; + end; + + function TApdBaseDispatcher.CheckTimerTriggers : Boolean; + {-Check timer triggers for H, send notification messages as required} + {-Return True if more checks remain} + var + J : Integer; + begin + {Check for timer triggers} + for J := 0 to pred(TimerTriggers.Count) do begin + with PTimerTrigger(TimerTriggers[J])^ do + if tActive and TimerExpired(tET) then begin + tActive := False; + + if DLoggingOn then + AddDispatchEntry(dtTrigger, dstTimer, tHandle, nil, 0); + + Result := SendNotify(apw_TriggerTimer, tHandle, 0); + Exit; + end; + if J >= TimerTriggers.Count then break; + end; + {No more checks required} + Result := False; + end; + + function TApdBaseDispatcher.ExtractData : Boolean; + {-Move data from communications driver to dispatch buffer} + {-Return True if data available, false otherwise} + var + BytesToRead : Cardinal; + FreeSpace : Cardinal; + BeginFree : Cardinal; + EndFree : Cardinal; + Len : Integer; + begin + EnterCriticalSection(DispSection); + try + {Nothing to do if dispatch buffer is already full} + if DispatchFull then begin + if (DLoggingOn) then // SWB + AddDispatchEntry(dtDispatch, // SWB + dstStatus, // SWB + 0, // SWB + PAnsiChar('Dispatch buffer full.'), // SWB + 21); // SWB + Result := True; + Exit; + end; + + ComStatus.cbInQue := InQueueUsed; // SWB + if ComStatus.cbInQue > 0 then begin + Result := True; + + if DBufHead = DBufTail then begin + {Buffer is completely empty} + FreeSpace := DispatchBufferSize; + EndFree := DispatchBufferSize-DBufHead; + end else if DBufHead > DBufTail then begin + {Buffer not wrapped} + FreeSpace := (DBufTail+DispatchBufferSize)-DBufHead; + EndFree := DispatchBufferSize-DBufHead; + end else begin + {Buffer is wrapped} + FreeSpace := DBufTail-DBufHead; + EndFree := DBufTail-DBufHead; + end; + + {Figure out how much data to read} + if ComStatus.cbInQue > FreeSpace then begin + BytesToRead := FreeSpace; + end else begin + BytesToRead := ComStatus.cbInQue; + end; + + {Figure where data fits (end and/or beginning of buffer)} + if BytesToRead > EndFree then + BeginFree := BytesToRead-EndFree + else + BeginFree := 0; + + {Move data to end of dispatch buffer} + if EndFree <> 0 then begin + Len := ReadCom(PAnsiChar(@DBuffer^[DBufHead]), EndFree); + + {Restore data count on errors} + if Len < 0 then begin + Len := 0; + GetComEventMask(-1); + end; + + if DLoggingOn then + if Len = 0 then + AddDispatchEntry(dtDispatch, dstReadCom, Len, nil, 0) + else + AddDispatchEntry(dtDispatch, dstReadCom, Len, + @DBuffer^[DBufHead], Len); + + {Increment buffer head} + Inc(DBufHead, Len); + + if Cardinal(Len) < EndFree then + BeginFree := 0; + + end else + Len := 0; + + {Handle buffer wrap} + if DBufHead = DispatchBufferSize then + DBufHead := 0; + + {Check for a full dispatch buffer} + if Len <> 0 then + DispatchFull := DBufHead = DBufTail; + + {Move data to beginning of dispatch buffer} + if BeginFree <> 0 then begin + Len := ReadCom(PAnsiChar(@DBuffer^[DBufHead]), BeginFree); + + {Restore data count on errors} + if Len < 0 then begin + Len := Abs(Len); + GetComEventMask(-1); + end; + + if DLoggingOn then + if Len = 0 then + AddDispatchEntry(dtDispatch, dstReadCom, Len, nil, 0) + else + AddDispatchEntry(dtDispatch, dstReadCom, Len, + @DBuffer^[DBufHead], Len); + + {Increment buffer head} + Inc(DBufHead, Len); + + {Check for a full dispatch buffer} + DispatchFull := DBufHead = DBufTail; + + end; + end else + Result := False; + finally + LeaveCriticalSection(DispSection); + end; + end; + + function TApdBaseDispatcher.CheckTriggers : Boolean; + {-Check all triggers for H, send notification messages as required} + {-Return True if more checks remain} + {-Only used by the Winsock dispatcher} + begin + Result := True; + + {Check timers, exit true if any hit} + if CheckTimerTriggers then + Exit; + + {Check status triggers, exit true if any hit} + if CheckStatusTriggers then + Exit; + + {Check receive data triggers, exit true if any hit} + if CheckReceiveTriggers then + Exit; + + {No trigger hits, exit false} + Result := False; + end; + + procedure TApdBaseDispatcher.CreateDispatcherWindow; + {-Create dispatcher window element} + {-Only used by the Winsock dispatcher} + begin + fDispatcherWindow := + CreateWindow(DispatcherClassName, {window class name} + '', {caption} + ws_Overlapped, {window style} + 0, {X} + 0, {Y} + 10, {width} + 10, {height} + 0, {parent} + 0, {menu} + HInstance, {instance} + nil); {parameter} + + ShowWindow(fDispatcherWindow, sw_Hide); + end; + +{Trigger functions} + + procedure TApdBaseDispatcher.RegisterWndTriggerHandler(HW : TApdHwnd); + var + TH : PWndTriggerHandler; + begin + EnterCriticalSection(DataSection); + try + {Allocate memory for TriggerHandler node} + New(TH); + + {Fill in data} + with TH^ do begin + thWnd := HW; + thDeleted := False; + end; + + WndTriggerHandlers.Add(TH); + HandlerServiceNeeded := True; + + if DLoggingOn then + AddDispatchEntry(dtTriggerHandlerAlloc,dstWndHandler,HW,nil,0); + finally + LeaveCriticalSection(DataSection); + end; + end; + + procedure TApdBaseDispatcher.RegisterProcTriggerHandler(NP : TApdNotifyProc); + var + TH : PProcTriggerHandler; + begin + EnterCriticalSection(DataSection); + try + {Allocate memory for TriggerHandler node} + New(TH); + + {Fill in data} + with TH^ do begin + thnotify := NP; + thDeleted := False; + end; + + ProcTriggerHandlers.Add(TH); + HandlerServiceNeeded := True; + + if DLoggingOn then + AddDispatchEntry(dtTriggerHandlerAlloc,dstProcHandler,0,nil,0); + finally + LeaveCriticalSection(DataSection); + end; + end; + + procedure TApdBaseDispatcher.RegisterSyncEventTriggerHandler(NP : TApdNotifyEvent); + var + TH : PEventTriggerHandler; + begin + EnterCriticalSection(DataSection); + try + {Allocate memory for TriggerHandler node} + New(TH); + + {Fill in data} + with TH^ do begin + thNotify := NP; + thSync := True; + thDeleted := False; + end; + + EventTriggerHandlers.Add(TH); + HandlerServiceNeeded := True; + + if DLoggingOn then + AddDispatchEntry(dtTriggerHandlerAlloc,dstEventHandler,1,nil,0); + finally + LeaveCriticalSection(DataSection); + end; + end; + + procedure TApdBaseDispatcher.RegisterEventTriggerHandler(NP : TApdNotifyEvent); + var + TH : PEventTriggerHandler; + begin + EnterCriticalSection(DataSection); + try + {Allocate memory for TriggerHandler node} + New(TH); + + {Fill in data} + with TH^ do begin + thNotify := NP; + thSync := False; + thDeleted := False; + end; + + EventTriggerHandlers.Add(TH); + HandlerServiceNeeded := True; + + if DLoggingOn then + AddDispatchEntry(dtTriggerHandlerAlloc,dstEventHandler,0,nil,0); + finally + LeaveCriticalSection(DataSection); + end; + end; + + procedure TApdBaseDispatcher.DeregisterWndTriggerHandler(HW : TApdHwnd); + var + i : Integer; + begin + EnterCriticalSection(DataSection); + try + for i := 0 to pred(WndTriggerHandlers.Count) do + with PWndTriggerHandler(WndTriggerHandlers[i])^ do + if thWnd = HW then begin + if DLoggingOn then + AddDispatchEntry(dtTriggerHandlerDispose,dstWndHandler,HW,nil,0); + if fEventBusy then begin + thDeleted := True; + DeletePending := True; + end else begin + Dispose(PWndTriggerHandler(WndTriggerHandlers[i])); + WndTriggerHandlers.Delete(i); + end; + exit; + end; + + UpdateHandlerFlags(fuKeepPort); + finally + LeaveCriticalSection(DataSection); + end; + end; + + procedure TApdBaseDispatcher.DeregisterProcTriggerHandler(NP : TApdNotifyProc); + var + i : Integer; + begin + EnterCriticalSection(DataSection); + try + for i := 0 to pred(ProcTriggerHandlers.Count) do + with PProcTriggerHandler(ProcTriggerHandlers[i])^ do + if @thNotify = @NP then begin + if DLoggingOn then + AddDispatchEntry(dtTriggerHandlerDispose,dstProcHandler,0,nil,0); + if fEventBusy then begin + thDeleted := True; + DeletePending := True; + end else begin + Dispose(PProcTriggerHandler(ProcTriggerHandlers[i])); + ProcTriggerHandlers.Delete(i); + end; + exit; + end; + + UpdateHandlerFlags(fuKeepPort); + finally + LeaveCriticalSection(DataSection); + end; + end; + + procedure TApdBaseDispatcher.DeregisterEventTriggerHandler(NP : TApdNotifyEvent); + var + i : Integer; + begin + EnterCriticalSection(DataSection); + try + for i := 0 to pred(EventTriggerHandlers.Count) do + with PEventTriggerHandler(EventTriggerHandlers[i])^ do + if @thNotify = @NP then begin + if DLoggingOn then + AddDispatchEntry(dtTriggerHandlerDispose,dstEventHandler,0,nil,0); + if fEventBusy then begin + thDeleted := True; + DeletePending := True; + end else begin + Dispose(PEventTriggerHandler(EventTriggerHandlers[i])); + EventTriggerHandlers.Delete(i); + end; + exit; + end; + + UpdateHandlerFlags(fuKeepPort); + finally + LeaveCriticalSection(DataSection); + end; + end; + + function TApdBaseDispatcher.GetTriggerHandle : Cardinal; + {-Find, allocate and return the first free trigger handle} + var + I : Integer; + Good : Boolean; + begin + { Allocate a trigger handle. If we can, within the size of the handle's } + { datatype, we just increment TriggerCounter to get a new handle. If not, } + { we need to check the existing handles to find a unique one. } + if TriggerCounter < MaxTriggerHandle then begin + Result := TriggerCounter shl 3; {low three bits reserved for trigger specific information} + inc(TriggerCounter); + end else begin + Result := FirstTriggerCounter shl 3; {lowest possible handle value} + repeat + Good := True; {Assume success} + for i := 0 to pred(TimerTriggers.Count) do + with PTimerTrigger(TimerTriggers[i])^ do + if tHandle = Result then begin + Good := False; + break; + end; + if Good then for i := 0 to pred(StatusTriggers.Count) do + with PStatusTrigger(StatusTriggers[i])^ do + if (tHandle and not 7)= Result then begin + Good := False; + break; + end; + if Good then for i := 0 to pred(DataTriggers.Count) do + with PDataTrigger(DataTriggers[i])^ do + if tHandle = Result then begin + Good := False; + break; + end; + if not Good then + inc(Result,(1 shl 3)); + until Good; + if Result > MaxTriggerHandle then + Result := 0; + end; + end; + + function TApdBaseDispatcher.FindTriggerFromHandle(TriggerHandle : Cardinal; Delete : Boolean; + var T : TTriggerType; var Trigger : Pointer) : Integer; + {-Find the trigger index} + var + i : Integer; + b : Byte; + begin + T := ttNone; + Result := ecOk; + if (TriggerHandle > 1) then begin + for i := 0 to pred(TimerTriggers.Count) do begin + Trigger := TimerTriggers[i]; + with PTimerTrigger(Trigger)^ do + if tHandle = TriggerHandle then begin + T := ttTimer; + if Delete then begin + TimerTriggers.Delete(i); + Dispose(PTimerTrigger(Trigger)); + if DLoggingOn then + AddDispatchEntry(dtTriggerDispose,dstTimer,TriggerHandle,nil,0); + Trigger := nil; + end; + exit; + end; + end; + for i := 0 to pred(StatusTriggers.Count) do begin + Trigger := StatusTriggers[i]; + with PStatusTrigger(Trigger)^ do + if tHandle = TriggerHandle then begin + T := ttStatus; + if Delete then begin + StatusTriggers.Delete(i); + Dispose(PStatusTrigger(Trigger)); + if DLoggingOn then begin + b := lo(TriggerHandle and (StatusTypeMask)); + AddDispatchEntry(dtTriggerDispose,dstStatusTrigger,TriggerHandle,@b,1); + end; + Trigger := nil; + end; + exit; + end; + end; + for i := 0 to pred(DataTriggers.Count) do begin + Trigger := DataTriggers[i]; + with PDataTrigger(Trigger)^ do + if Cardinal(tHandle and not 7) = TriggerHandle then begin {!!.01} + T := ttData; + if Delete then begin + DataTriggers.Delete(i); + Dispose(PDataTrigger(Trigger)); + if DLoggingOn then + AddDispatchEntry(dtTriggerDispose,dstData,TriggerHandle,nil,0); + Trigger := nil; + end; + exit; + end; + end; + end else begin + T := ttNone; + Trigger := nil; + end; + if T = ttNone then + Result := ecBadTriggerHandle; + end; + + procedure TApdBaseDispatcher.ChangeLengthTrigger(Length : Cardinal); + {-Change the length trigger to Length} + begin + EnterCriticalSection(DataSection); + try + LenTrigger := Length; + + if DLoggingOn then + AddDispatchEntry(dtTriggerDataChange,dstAvailTrigger,Length,nil,0); + finally + LeaveCriticalSection(DataSection); + end; + end; + + function TApdBaseDispatcher.AddTimerTrigger : Integer; + {-Add a timer trigger} + var + NewTimerTrigger : PTimerTrigger; + begin + EnterCriticalSection(DataSection); + try + NewTimerTrigger := AllocMem(sizeof(TTimerTrigger)); + with NewTimerTrigger^ do begin + tHandle := GetTriggerHandle; + tTicks := 0; + tActive := False; + tValid := True; + Result := tHandle; + end; + if Result > 0 then begin + TimerTriggers.Add(NewTimerTrigger); + if DLoggingOn then + AddDispatchEntry(dtTriggerAlloc,dstTimerTrigger,Result,nil,0); + end else + Result := ecNoMoreTriggers; + finally + LeaveCriticalSection(DataSection); + end; + end; + + function TApdBaseDispatcher.AddDataTriggerLen(Data : PAnsiChar; + IgnoreCase : Boolean; Len : Cardinal) : Integer; + {-Add a data trigger, data is any ASCIIZ string so no embedded zeros} + var + NewDataTrigger : PDataTrigger; + begin + EnterCriticalSection(DataSection); + try + if Len <= MaxTrigData then begin + NewDataTrigger := AllocMem(sizeof(TDataTrigger)); + with NewDataTrigger^ do begin + tHandle := GetTriggerHandle; + tLen := Len; + FillChar(tChkIndex, SizeOf(TCheckIndex), 0); + tMatched := False; + tIgnoreCase := IgnoreCase; + Move(Data^, tData, Len); + if IgnoreCase and (Len <> 0) then + AnsiUpperBuff(@tData, Len); + Result := tHandle; + end; + if Result > 0 then begin + DataTriggers.Add(NewDataTrigger); + if DLoggingOn then + AddDispatchEntry(dtTriggerAlloc,dstDataTrigger,Result,Data,Len); + end else + Result := ecNoMoreTriggers; + + end else + Result := ecTriggerTooLong; + finally + LeaveCriticalSection(DataSection); + end; + end; + + function TApdBaseDispatcher.AddDataTrigger(Data : PAnsiChar; + IgnoreCase : Boolean) : Integer; + {-Add a data trigger, data is any ASCIIZ string so no embedded nulls} + begin + Result := AddDataTriggerLen(Data, IgnoreCase, AnsiStrings.StrLen(Data)); + end; + + function TApdBaseDispatcher.AddStatusTrigger(SType : Cardinal) : Integer; + {-Add a status trigger of type SType} + var + NewStatusTrigger : PStatusTrigger; + begin + if (SType > stOutSent) then begin + Result := ecBadArgument; + Exit; + end; + + EnterCriticalSection(DataSection); + try + NewStatusTrigger := AllocMem(sizeof(TStatusTrigger)); + with NewStatusTrigger^ do begin + tHandle := GetTriggerHandle or SType; + tSType := SType; + tSActive := False; + Result := tHandle; + end; + if (Result and not 7) > 0 then begin + StatusTriggers.Add(NewStatusTrigger); + if DLoggingOn then + AddDispatchEntry(dtTriggerAlloc, dstStatusTrigger, + Result, @SType, 1); + end else + Result := ecNoMoreTriggers; + finally + LeaveCriticalSection(DataSection); + end; + end; + + function TApdBaseDispatcher.RemoveTrigger(TriggerHandle : Cardinal) : Integer; + {-Remove the trigger for Index} + var + Trigger : Pointer; + T : TTriggerType; + begin + EnterCriticalSection(DataSection); + try + if TriggerHandle = 1 then + {Length trigger} + begin + LenTrigger := 0; + Result := ecOk; + end + else + {Other trigger} + Result := FindTriggerFromHandle(TriggerHandle, True, T, Trigger); + finally + LeaveCriticalSection(DataSection); + end; + end; + + function TApdBaseDispatcher.SetTimerTrigger(TriggerHandle : Cardinal; + Ticks : Integer; Activate : Boolean) : Integer; + const + DeactivateStr : Ansistring = 'Deactivated'; + var + Trigger : PTimerTrigger; + T : TTriggerType; + begin + EnterCriticalSection(DataSection); + try + FindTriggerFromHandle(TriggerHandle, False, T, Pointer(Trigger)); + if (Trigger <> nil) and (T = ttTimer) then + with Trigger^ do begin + if Activate then begin + if Ticks <> 0 then + tTicks := Ticks; + NewTimer(tET, tTicks); + end; + if DLoggingOn then + if Activate then + AddDispatchEntry(dtTriggerDataChange, dstTimerTrigger, + TriggerHandle,@Ticks,sizeof(Ticks)) + else + AddDispatchEntry(dtTriggerDataChange, dstTimerTrigger, + TriggerHandle,@DeactivateStr[1],Length(DeactivateStr)); + tActive := Activate; + Result := ecOk; + end + else + Result := ecBadTriggerHandle; + finally + LeaveCriticalSection(DataSection); + end; + end; + + function TApdBaseDispatcher.ExtendTimer(TriggerHandle : Cardinal; + Ticks : Integer) : Integer; + var + Trigger : PTimerTrigger; + T : TTriggerType; + begin + EnterCriticalSection(DataSection); + try + FindTriggerFromHandle(TriggerHandle, False, T, Pointer(Trigger)); + if (Trigger <> nil) and (T = ttTimer) then + with Trigger^ do begin + Inc(tET.ExpireTicks, Ticks); + Result := ecOk; + if DLoggingOn then + AddDispatchEntry(dtTriggerDataChange, dstTimerTrigger, + TriggerHandle, @Ticks,sizeof(Ticks)); + end + else + Result := ecBadTriggerHandle; + finally + LeaveCriticalSection(DataSection); + end; + end; + + function TApdBaseDispatcher.TimerTicksRemaining(TriggerHandle : Cardinal; + var TicksRemaining : Integer) : Integer; + var + Trigger : PTimerTrigger; + T : TTriggerType; + begin + TicksRemaining := 0; + EnterCriticalSection(DataSection); + try + FindTriggerFromHandle(TriggerHandle, False, T, Pointer(Trigger)); + if (Trigger <> nil) and (T = ttTimer) then + with Trigger^ do begin + TicksRemaining := RemainingTime(tET); + Result := ecOk; + end + else + Result := ecBadTriggerHandle; + finally + LeaveCriticalSection(DataSection); + end; + end; + + procedure TApdBaseDispatcher.UpdateHandlerFlags(FlagUpdate : TApHandlerFlagUpdate); + var + HandlersInstalled : Boolean; + begin + EnterCriticalSection(DataSection); + try + HandlersInstalled := (WndTriggerHandlers.Count > 1) or + (ProcTriggerHandlers.Count > 0) or (EventTriggerHandlers.Count > 0); + + case FlagUpdate of + fuKeepPort : + HandlerServiceNeeded := (HandlersInstalled or PortHandlerInstalled); + + fuEnablePort : + begin + PortHandlerInstalled := True; + HandlerServiceNeeded := True; + end; + + fuDisablePort : + begin + PortHandlerInstalled := False; + HandlerServiceNeeded := HandlersInstalled; + end; + end; + finally + LeaveCriticalSection(DataSection); + end; + end; + + function TApdBaseDispatcher.SetStatusTrigger(TriggerHandle : Cardinal; + Value : Cardinal; Activate : Boolean) : Integer; + type + LH = record L,H : Byte; end; + var + Trigger : PStatusTrigger; + T : TTriggerType; + + function SetLineBits(Value : Cardinal) : Cardinal; + {-Return mask that can be checked against LastError later} + begin + Result := 0; + if FlagIsSet(Value, lsOverrun) then + Result := ce_Overrun; + if FlagIsSet(Value, lsParity) then + Result := Result or ce_RxParity; + if FlagIsSet(Value, lsFraming) then + Result := Result or ce_Frame; + if FlagIsSet(Value, lsBreak) then + Result := Result or ce_Break; + end; + + begin + EnterCriticalSection(DataSection); + try + FindTriggerFromHandle(TriggerHandle, False, T, Pointer(Trigger)); + if (Trigger <> nil) and (T = ttStatus) then + with Trigger^ do begin + if Activate then begin + case tSType of + stLine : + tValue := SetLineBits(Value); + stModem : + begin + {Hi tValue is delta mask, Lo is current modem status} + LH(tValue).H := Value; + LH(tValue).L := Value and ModemStatus; + end; + stOutBuffFree, + stOutBuffUsed : + tValue := Value; + end; + if DLoggingOn then + AddDispatchEntry(dtTriggerDataChange, dstStatusTrigger, + TriggerHandle, @tValue, sizeof(Cardinal)); + end; + tSActive := Activate; + Result := ecOK; + end + else + Result := ecBadTriggerHandle; + finally + LeaveCriticalSection(DataSection); + end; + end; + + class procedure TApdBaseDispatcher.ClearSaveBuffers(var Save : TTriggerSave); + begin + with Save do begin + if tsTimerTriggers <> nil then begin + while tsTimerTriggers.Count > 0 do begin + Dispose(PTimerTrigger(tsTimerTriggers[0])); + tsTimerTriggers.Delete(0); + end; + tsTimerTriggers.Free; + tsTimerTriggers := nil; + end; + if tsDataTriggers <> nil then begin + while tsDataTriggers.Count > 0 do begin + Dispose(PDataTrigger(tsDataTriggers[0])); + tsDataTriggers.Delete(0); + end; + tsDataTriggers.Free; + tsDataTriggers := nil; + end; + if tsStatusTriggers <> nil then begin + while tsStatusTriggers.Count > 0 do begin + Dispose(PStatusTrigger(tsStatusTriggers[0])); + tsStatusTriggers.Delete(0); + end; + tsStatusTriggers.Free; + tsStatusTriggers := nil; + end; + end; + end; + + procedure TApdBaseDispatcher.SaveTriggers(var Save : TTriggerSave); + {-Saves all current triggers to Save} + var + i : Integer; + NewTimerTrigger : PTimerTrigger; + NewDataTrigger : PDataTrigger; + NewStatusTrigger : PStatusTrigger; + begin + with Save do begin + EnterCriticalSection(DataSection); + try + ClearSaveBuffers(Save); + + tsLenTrigger := LenTrigger; + tsTimerTriggers := TList.Create; + for i := 0 to pred(TimerTriggers.Count) do begin + NewTimerTrigger := AllocMem(sizeof(TTimerTrigger)); + move(PTimerTrigger(TimerTriggers[i])^, NewTimerTrigger^, + sizeof(TTimerTrigger)); + tsTimerTriggers.Add(NewTimerTrigger); + end; + tsDataTriggers := TList.Create; + for i := 0 to pred(DataTriggers.Count) do begin + NewDataTrigger := AllocMem(sizeof(TDataTrigger)); + move(PDataTrigger(DataTriggers[i])^, NewDataTrigger^, + sizeof(TDataTrigger)); + tsDataTriggers.Add(NewDataTrigger); + end; + tsStatusTriggers := TList.Create; + for i := 0 to pred(StatusTriggers.Count) do begin + NewStatusTrigger := AllocMem(sizeof(TStatusTrigger)); + move(PStatusTrigger(StatusTriggers[i])^, NewStatusTrigger^, + sizeof(TStatusTrigger)); + tsStatusTriggers.Add(NewStatusTrigger); + end; + finally + LeaveCriticalSection(DataSection); + end; + end; + end; + + procedure TApdBaseDispatcher.RestoreTriggers(var Save : TTriggerSave); + {-Restores previously saved triggers} + var + i : Integer; + NewTimerTrigger : PTimerTrigger; + NewDataTrigger : PDataTrigger; + NewStatusTrigger : PStatusTrigger; + begin + with Save do begin + EnterCriticalSection(DataSection); + try + LenTrigger := tsLenTrigger; + while TimerTriggers.Count > 0 do begin + Dispose(PTimerTrigger(TimerTriggers[0])); + TimerTriggers.Delete(0); + end; + while DataTriggers.Count > 0 do begin + Dispose(PDataTrigger(DataTriggers[0])); + DataTriggers.Delete(0); + end; + while StatusTriggers.Count > 0 do begin + Dispose(PStatusTrigger(StatusTriggers[0])); + StatusTriggers.Delete(0); + end; + if tsTimerTriggers <> nil then + for i := 0 to pred(tsTimerTriggers.Count) do begin + NewTimerTrigger := AllocMem(sizeof(TTimerTrigger)); + move(PTimerTrigger(tsTimerTriggers[i])^, NewTimerTrigger^, + sizeof(TTimerTrigger)); + TimerTriggers.Add(NewTimerTrigger); + end; + if tsDataTriggers <> nil then + for i := 0 to pred(tsDataTriggers.Count) do begin + NewDataTrigger := AllocMem(sizeof(TDataTrigger)); + move(PDataTrigger(tsDataTriggers[i])^, NewDataTrigger^, + sizeof(TDataTrigger)); + DataTriggers.Add(NewDataTrigger); + end; + if tsStatusTriggers <> nil then + for i := 0 to pred(tsStatusTriggers.Count) do begin + NewStatusTrigger := AllocMem(sizeof(TStatusTrigger)); + move(PStatusTrigger(tsStatusTriggers[i])^, NewStatusTrigger^, + sizeof(TStatusTrigger)); + StatusTriggers.Add(NewStatusTrigger); + end; + finally + LeaveCriticalSection(DataSection); + end; + end; + end; + + function TApdBaseDispatcher.ChangeBaud(NewBaud : Integer) : Integer; + {-Change the baud rate of port H to NewBaud} + begin + Result := SetLine(NewBaud, DontChangeParity, DontChangeDatabits, + DontChangeStopbits); + end; + + function TApdBaseDispatcher.SetDataPointer(P : Pointer; Index : Cardinal) : Integer; + {-Set a data pointer} + begin + EnterCriticalSection(DataSection); + try + if (Index >= 1) and (Index <= MaxDataPointers) then begin + DataPointers[Index] := P; + Result := ecOK; + end else + Result := ecBadArgument; + finally + LeaveCriticalSection(DataSection); + end; + end; + + function TApdBaseDispatcher.GetDataPointer(var P : Pointer; + Index : Cardinal) : Integer; + {-Return a data pointer} + begin + EnterCriticalSection(DataSection); + try + if (Index >= 1) and (Index <= MaxDataPointers) then begin + P := DataPointers[Index]; + Result := ecOK; + end else + Result := ecBadArgument; + finally + LeaveCriticalSection(DataSection); + end; + end; + + function TApdBaseDispatcher.GetFlowOptions(var HWOpts, SWOpts, BufferFull, + BufferResume : Cardinal; var OnChar, OffChar : AnsiChar) : Integer; + begin + HWOpts := 0; + SWOpts := 0; + + EnterCriticalSection(DataSection); + try + Result := GetComState(DCB); + + if (DCB.Flags and dcb_DTR_CONTROL_HANDSHAKE) <> 0 then + HWOpts := HWOpts or hfUseDtr; + + if (DCB.Flags and dcb_RTS_CONTROL_HANDSHAKE) <> 0 then + HWOpts := HWOpts or hfUseRts; + + if (DCB.Flags and dcb_OutxDsrFlow) <> 0 then + HWOpts := HWOpts or hfRequireDsr; + + if (DCB.Flags and dcb_OutxCtsFlow) <> 0 then + HWOpts := HWOpts or hfRequireCts; + + if (DCB.Flags and dcb_InX) <> 0 then + SWOpts := SWOpts or sfReceiveFlow; + + if (DCB.Flags and dcb_OutX) <> 0 then + SWOpts := SWOpts or sfTransmitFlow; + + OnChar := DCB.XOnChar; + OffChar := DCB.XOffChar; + finally + LeaveCriticalSection(DataSection); + end; + end; + + procedure TApdBaseDispatcher.OptionsOn(Options : Cardinal); + {-Enable the port options in Options} + begin + EnterCriticalSection(DataSection); + try + Flags := Flags or Options; + finally + LeaveCriticalSection(DataSection); + end; + end; + + procedure TApdBaseDispatcher.OptionsOff(Options : Cardinal); + {-Disable the port options in Options} + begin + EnterCriticalSection(DataSection); + try + Flags := Flags and not Options; + finally + LeaveCriticalSection(DataSection); + end; + end; + + function TApdBaseDispatcher.OptionsAreOn(Options : Cardinal) : Boolean; + {-Return True if the specified options are on} + begin + EnterCriticalSection(DataSection); + try + Result := (Flags and Options) = Options; + finally + LeaveCriticalSection(DataSection); + end; + end; + + function TApdBaseDispatcher.ClearTracing : Integer; + {-Clears the trace buffer} + begin + Result := ecOK; + EnterCriticalSection(DataSection); + try + TraceIndex := 0; + TraceWrapped := False; + finally + LeaveCriticalSection(DataSection); + end; + end; + + procedure TApdBaseDispatcher.AbortTracing; + {-Stops tracing and destroys the tracebuffer} + begin + EnterCriticalSection(DataSection); + try + TracingOn := False; + if TraceQueue <> nil then begin + FreeMem(TraceQueue, TraceMax*2); + TraceQueue := nil; + end; + finally + LeaveCriticalSection(DataSection); + end; + end; + + function TApdBaseDispatcher.InitTracing(NumEntries : Cardinal) : Integer; + {-Prepare a circular tracing queue} + begin + EnterCriticalSection(DataSection); + try + if TraceQueue <> nil then + {Just clear buffer if already on} + ClearTracing + else begin + {Limit check size of trace buffer} + if NumEntries > HighestTrace then begin + Result := ecBadArgument; + exit; + end; + + {Allocate trace buffer and start tracing} + TraceMax := NumEntries; + TraceIndex := 0; + TraceWrapped := False; + TraceQueue := AllocMem(NumEntries*2); + end; + TracingOn := True; + Result := ecOK; + finally + LeaveCriticalSection(DataSection); + end; + end; + + procedure TApdBaseDispatcher.AddTraceEntry(CurEntry : AnsiChar; CurCh : AnsiChar); + {-Add a trace event to the global TraceQueue} + begin + EnterCriticalSection(DataSection); + try + if TraceQueue <> nil then begin + TraceQueue^[TraceIndex].EventType := CurEntry; + TraceQueue^[TraceIndex].C := CurCh; + Inc(TraceIndex); + if TraceIndex = TraceMax then begin + TraceIndex := 0; + TraceWrapped := True; + end; + end; + finally + LeaveCriticalSection(DataSection); + end; + end; + + function TApdBaseDispatcher.DumpTracePrim(FName : string; + AppendFile, InHex, AllHex : Boolean) : Integer; + {-Write the TraceQueue to FName} + const + Digits : array[0..$F] of AnsiChar = '0123456789ABCDEF'; + LowChar : array[Boolean] of Byte = (32, 33); + var + Start, Len : Cardinal; + TraceFile : Text; + TraceFileBuffer : array[1..512] of AnsiChar; + LastEventType : AnsiChar; + First : Boolean; + Col : Cardinal; + I : Cardinal; + Res : Cardinal; + + procedure CheckCol(N : Cardinal); + {-Wrap if N bytes would exceed column limit} + begin + Inc(Col, N); + if Col > MaxTraceCol then begin + WriteLn(TraceFile); + Col := N; + end; + end; + + function HexB(B : Byte) : AnsiString; + {-Return hex string for byte} + begin + SetLength(Result, 2); + HexB[1] := Digits[B shr 4]; + HexB[2] := Digits[B and $F]; + end; + + begin + Result := ecOK; + + {Make sure we have something to do} + if TraceQueue = nil then + Exit; + + {Turn tracing off now} +// TracingOn := False; // SWB + + EnterCriticalSection(DataSection); + try + {Set the Start and Len markers} + Len := TraceIndex; + if TraceWrapped then + Start := TraceIndex + else if TraceIndex <> 0 then + Start := 0 + else begin + {No events, just exit} +// AbortTracing; // SWB + Exit; + end; + + Assign(TraceFile, FName); + SetTextBuf(TraceFile, TraceFileBuffer, SizeOf(TraceFileBuffer)); + if AppendFile and ExistFileZ(FName) then begin + {Open an existing file} + Append(TraceFile); + Res := IoResult; + end else begin + {Open new file} + ReWrite(TraceFile); + Res := IoResult; + end; + if Res <> ecOK then begin + Result := -Res; + AbortTracing; + Exit; + end; + + try + {Write the trace queue} + LastEventType := #0; + First := True; + Col := 0; + repeat + {Some formattting} + with TraceQueue^[Start] do begin + if EventType <> LastEventType then begin + if not First then begin + WriteLn(TraceFile,^M^J); + Col := 0; + end; + {First := False;} + case EventType of + 'T' : WriteLn(TraceFile, 'Transmit: '); + 'R' : WriteLn(TraceFile, 'Receive: '); + else WriteLn(TraceFile, 'Special-'+EventType+': '); + end; + LastEventType := EventType; + end; + + {Write the current char} + if AllHex then begin + CheckCol(4); + Write(TraceFile, '[',HexB(Ord(C)),']'); + end else + if (Ord(C) < LowChar[InHex]) or (Ord(C) > 126) then begin + if InHex then begin + CheckCol(4); + Write(TraceFile, '[',HexB(Ord(C)),']') + end else begin + if Ord(C) > 99 then + I := 5 + else if Ord(C) > 9 then + I := 4 + else + I := 3; + CheckCol(I); + Write(TraceFile, '[',Ord(C),']') + end; + end else begin + CheckCol(1); + Write(TraceFile, C); + end; + + {Get the next char} + Inc(Start); + if Start = TraceMax then + Start := 0; + end; + First := False; + until Start = Len; + + finally + Close(TraceFile); + Result := -IoResult; +// AbortTracing; // SWB + InitTracing(TraceMax); // SWB + end; + + finally + LeaveCriticalSection(DataSection); + end; + end; + + function TApdBaseDispatcher.DumpTrace(FName : string; + InHex, AllHex : Boolean) : Integer; + {-Write the TraceQueue to FName} + begin + Result := DumpTracePrim(FName, False, InHex, AllHex); + end; + + function TApdBaseDispatcher.AppendTrace(FName : string; + InHex, AllHex : Boolean) : Integer; + {-Append the TraceQueue to FName} + begin + Result := DumpTracePrim(FName, True, InHex, AllHex); + end; + + procedure TApdBaseDispatcher.StartTracing; + {-Restarts tracing after a StopTracing} + begin + EnterCriticalSection(DataSection); + try + if TraceQueue <> nil then + TracingOn := True; + finally + LeaveCriticalSection(DataSection); + end; + end; + + procedure TApdBaseDispatcher.StopTracing; + {-Stops tracing temporarily} + begin + EnterCriticalSection(DataSection); + try + TracingOn := False; + finally + LeaveCriticalSection(DataSection); + end; + end; + + procedure TApdBaseDispatcher.ClearDispatchLogging; + {-Clear the dispatch log} + begin + DLoggingQueue.Clear; // SWB + end; + + procedure TApdBaseDispatcher.AbortDispatchLogging; + {-Abort dispatch logging} + begin + DLoggingOn := False; + DLoggingQueue.Clear; // SWB + end; + + procedure TApdBaseDispatcher.StartDispatchLogging; + {-Restarts logging after a pause} + begin + DLoggingOn := True; + end; + + procedure TApdBaseDispatcher.StopDispatchLogging; + {-Pause dispatch logging} + begin + DLoggingOn := False; + end; + + procedure TApdBaseDispatcher.InitDispatchLogging(QueueSize : Cardinal); + {-Enable dispatch logging} + begin + ClearDispatchLogging; + DLoggingMax := QueueSize; + DLoggingOn := True; + end; + + {apro.str offsets used for logging strings:} + const + drTypeBase = 15001; + drSubTypeBase = 15100; + Header1 = 15501; + Header2 = 15502; + MaxTelnetTag = 42; + TelnetBase = 15700; + MSTagBase = 15601; + + function GetDTStr(drType : TDispatchType) : string; + begin + Result := AproLoadStr(drTypeBase + ord(drType)); + end; + + function GetDSTStr(drsType : TDispatchSubType) : string; + begin + if drsType = dstNone then + Result := '' + else + Result := AproLoadStr(drSubTypeBase + ord(drsType)); + end; + + function GetTimeStr(drTime : DWORD) : string; + begin + Result := Format('%07.7d', [drTime]); + Insert('.', Result, Length(Result) - 2); {!!.04} + end; + + function TApdBaseDispatcher.DumpDispatchLogPrim(FName : string; + AppendFile, InHex, AllHex : Boolean) : Integer; + + {-Dump the dispatch log} + const + StartColumn = 45; + Digits : array[0..$F] of AnsiChar = '0123456789ABCDEF'; + LowChar : array[Boolean] of Byte = (32, 33); + var + I, J : Cardinal; + Col : Cardinal; + Res : Integer; + DumpFile : Text; + C : AnsiChar; + LogFileBuffer : array[1..512] of AnsiChar; + S : string[80]; + logBfr : TLogBuffer; // SWB + + function GetOSVersion : string; + var + OSVersion : TOSVersionInfo; + SerPack : string; {!!.04} + begin + OSVersion.dwOSVersionInfoSize := SizeOf(OSVersion); + GetVersionEx(OSVersion); + SerPack := ''; {!!.04} + + case OSVersion.dwPlatformID of + VER_PLATFORM_WIN32s : begin {!!.04} + SerPack := StrPas(OSVersion.szCSDVersion); {!!.04} + Result := 'Win32s on Windows '; + end; {!!.04} + VER_PLATFORM_WIN32_WINDOWS : begin {!!.04} + case OsVersion.dwMinorVersion of {!!.04} + 0 : if Trim(OsVersion.szCSDVersion[1]) = 'B' then {!!.04} + Result := 'Win32 on Windows 95 OSR 2 ' {!!.04} + else {!!.04} + Result := 'Win32 on Windows 95 OSR 1 '; {!!.04} + 10 : if Trim(OsVersion.szCSDVersion[1]) = 'A' then {!!.04} + Result := 'Win32 on Windows 98 OSR 2 ' {!!.04} + else {!!.04} + Result := 'Win32 on Windows 98 OSR 1 '; {!!.04} + 90 : if (OsVersion.dwBuildNumber = 73010104) then {!!.04} + Result := 'Win32 on Windows ME '; {!!.04} + else Result := 'Win32 on Windows 9x'; {!!.04} + end; {!!.04} + end; {!!.04} + VER_PLATFORM_WIN32_NT : begin {!!.04} + SerPack := StrPas(OSVersion.szCSDVersion); {!!.04} + case OSVersion.dwMajorVersion of {!!.04} + 2 : if OsVersion.dwMinorVersion = 6 then // --sm + Result := 'Window CE '; // --sm + 3 : Result := 'Windows NT 3.5 '; {!!.04} + 4 : Result := 'Windows NT 4 '; {!!.04} + 5 : case OSVersion.dwMinorVersion of {!!.04} + 0 : Result := 'Windows 2000 '; {!!.04} + 1 : Result := 'Windows XP '; {!!.04} + 2 : Result := 'Windows 2003 '; // --sm + end; + 6 : case OSVersion.dwMinorVersion of // --sm + 0 : Result := 'Windows Vista '; // --sm + 1 : Result := 'Windows 7 '; // --sm + end; {!!.04} + else Result := 'WinNT '; {!!.04} + end; {!!.04} + end; {!!.04} + else Result := 'Unknown'; + end; + Result := Result + IntToStr(OSVersion.dwMajorVersion) + '.' + + IntToStr(OSVersion.dwMinorVersion) + ' ' + SerPack; {!!.04} + end; + + procedure CheckCol(N : Cardinal); + {-Wrap if N bytes would exceed column limit} + begin + Inc(Col, N); + if Col > MaxTraceCol then begin + WriteLn(DumpFile); + Write(DumpFile, '':StartColumn-1); + Col := StartColumn+N; + end; + end; + + begin + Result := ecOK; + + {Make sure we have something to do} + if ((DLoggingQueue = nil) or // SWB + (DLoggingQueue.Count = 0)) then begin // SWB +// AbortDispatchLogging; // SWB + Exit; + end; + + EnterCriticalSection(DataSection); + try + Assign(DumpFile, FName); + SetTextBuf(DumpFile, LogFileBuffer, SizeOf(LogFileBuffer)); + if AppendFile and ExistFileZ(FName) then begin + {Append to existing file} + Append(DumpFile); + Res := IoResult; + end else begin + {Create new file} + Rewrite(DumpFile); + Res := IoResult; + end; + if Res <> 0 then begin + Result := -Res; + Close(DumpFile); + if IoResult <> 0 then ; + Exit; + end; + + {Write heading just once} + {$IFDEF APAX} + WriteLn(DumpFile, 'APAX', ApaxVersionStr); + {$ELSE} + WriteLn(DumpFile, 'APRO ', ApVersionStr); + {write compiler version to log} + S := 'RAD Studio XEn'; + + WriteLn(DumpFile, 'Compiler : ', S); + {$ENDIF} + + {write operating system to log} + S := ShortString(GetOSVersion()); + WriteLn(DumpFile, 'Operating System : ', S); + + WriteLn(DumpFile, 'Device: ', DeviceName); + + S := ShortString(FormatDateTime('dd/mm/yy, hh:mm:ss', Now)); {!!.02} + WriteLn(DumpFile, 'Date/time: ', S); {!!.02} + + WriteLn(DumpFile, AproLoadStr(Header1)); + WriteLn(DumpFile, AproLoadStr(Header2)); + + {Loop through all entries} + repeat + {Get the next entry and remove from queue} + logBfr := TLogBuffer(DLoggingQueue.Pop); // SWB + {Write a report line} + if (Assigned(logBfr)) then begin // SWB + with logBfr do begin + Write(DumpFile, format('%8s %-8s %-12s %08.8x ', + [GetTimeStr(drTime),GetDTStr(drType),GetDSTStr(drSubType),drData])); + if drMoreData = 0 then begin + + {Add telnet tags if necessary} + if drType = dtTelnet then begin + S := ' ['; + if drData <= MaxTelnetTag then + S := S + ShortString(AproLoadStr(TelnetBase + ord(drData))); + Write(DumpFile, trim(string(S)),']'); + end; + + WriteLn(DumpFile) + end else begin + if (drSubType = dstStatusTrigger) + and ((drType = dtTriggerAlloc) + or (drType = dtTriggerDispose)) + then begin + case Byte(drBuffer^) of // SWB + 0 : Write(DumpFile, '(Not active)'); + 1 : Write(DumpFile, '(Modem status)'); + 2 : Write(DumpFile, '(Line status)'); + 3 : Write(DumpFile, '(Output buffer free)'); + 4 : Write(DumpFile, '(Output buffer used)'); + 5 : Write(DumpFile, '(Output sent)'); + end; + end else begin + Col := StartColumn; + for I := 0 to (drMoreData - 1) do begin // SWB + C := (drBuffer + I)^; // SWB + if AllHex then begin + if drType = dtUser then begin + CheckCol(1); + Write(DumpFile, C); + end else begin + CheckCol(4); + Write(DumpFile, '[',IntToHex(Ord(C), 2),']'); + end; + end else + if (Ord(C) < LowChar[InHex]) or (Ord(C) > 126) then begin + if InHex then begin + CheckCol(4); + Write(DumpFile, '[',IntToHex(Ord(C),2),']') + end else begin + if Ord(C) > 99 then + J := 5 + else if Ord(C) > 9 then + J := 4 + else + J := 3; + CheckCol(J); + Write(DumpFile, '[',Ord(C),']') + end; + end else begin + CheckCol(1); + Write(DumpFile, C); + end; + end; + end; + + {Add modem status tags} + if drSubType = dstModemStatus then begin + S := ' ('; + for I := 0 to 7 do + if Odd(drData shr I) then + S := S + ShortString(AproLoadStr(MSTagBase + I)); + Write(DumpFile, trim(string(S)),')'); + end; + + WriteLn(DumpFile); + + end; + end; + logBfr.Free; // SWB + end; + until (not Assigned(logBfr)); // SWB + + Close(DumpFile); + Result := -IoResult; +// AbortDispatchLogging; // SWB + finally + LeaveCriticalSection(DataSection); + end; + end; + + function TApdBaseDispatcher.DumpDispatchLog( + FName : string; + InHex, AllHex : Boolean) : Integer; + + {-Dump the dispatch log} + begin + Result := DumpDispatchLogPrim(FName, False, InHex, AllHex); + end; + + function TApdBaseDispatcher.AppendDispatchLog( + FName : string; + InHex, AllHex : Boolean) : Integer; + {-Append the dispatch log} + begin + Result := DumpDispatchLogPrim(FName, True, InHex, AllHex); + end; + + function TApdBaseDispatcher.GetDispatchTime : DWORD; + {-Return elapsed time} + begin + Result := (AdTimeGetTime - TimeBase); + end; + + procedure TApdBaseDispatcher.AddDispatchEntry( + DT : TDispatchType; + DST : TDispatchSubType; + Data : Cardinal; + Buffer : Pointer; + BufferLen : Cardinal); + var + logBuf : TLogBuffer; // SWB + begin + if DLoggingOn then {!!.02} + begin // SWB + // If there is a limit to the log queue size and we have // SWB + // exceeded it, pop the oldest entries from the queue until we // SWB + // are under the limit again. // SWB + while ((DLoggingMax > 0) and // SWB + (Cardinal(DLoggingQueue.BytesQueued) > DLoggingMax)) do // SWB + begin // SWB + logBuf := TLogBuffer(DLoggingQueue.Pop); // SWB + logBuf.Free; // SWB + end; // SWB + // Add the new entry to the queue // SWB + logBuf := TLogBuffer.Create(DT, // SWB + DST, // SWB + GetDispatchTime, // SWB + Data, // SWB + PAnsiChar(Buffer), // SWB + BufferLen); // SWB + DLoggingQueue.Push(logBuf); // SWB + end; // SWB + end; + + function TApdBaseDispatcher.ClassifyStatusTrigger( + TriggerHandle : Cardinal) : Cardinal; + {-Return the type for TriggerHandle} + begin + Result := TriggerHandle and StatusTypeMask; + end; + + procedure TApdBaseDispatcher.SetEventBusy( + var WasOn : Boolean; + SetOn : Boolean); + {-Set/Clear the event busy flag} + begin + EnterCriticalSection(DataSection); + try + WasOn := fEventBusy; + fEventBusy := SetOn; + finally + LeaveCriticalSection(DataSection); + end; + end; + + function PortIn(Address: Word): Byte; + {-Use this instead of Port since it works in both 16 and 32-bit mode} + asm + mov dx,ax + in al,dx + end; + + + procedure TApdBaseDispatcher.SetRS485Mode(OnOff : Boolean); + {-Set/reset the RS485 flag} + var + LocalBaseAddress : Word; + + procedure GetLocalBaseAddress; + {Undocumented function returns the base address in edx} + {$ifndef CPUX64} + asm + mov eax,CidEX + push eax + push 10 + call EscapeCommFunction // (CidEx, 10); + mov LocalBaseAddress, dx + end; + {$else} + asm + mov ecx, CidEX + mov rdx,10 + call EscapeCommFunction // (CidEx, 10); + mov LocalBaseAddress, dx + end; + {$endif} + + begin + EnterCriticalSection(DataSection); + try + RS485Mode := OnOff; + + if RS485Mode then begin + {Handle entering RS485 mode} + if Assigned(OutThread) then + OutThread.Priority := + TThreadPriority(Ord(tpHigher) + ThreadBoost); + if Win32Platform <> VER_PLATFORM_WIN32_NT then begin + GetLocalBaseAddress; + BaseAddress := LocalBaseAddress; + end; + end else begin + if Assigned(OutThread) then + OutThread.Priority := + TThreadPriority(Ord(tpNormal) + ThreadBoost); + end; + finally + LeaveCriticalSection(DataSection); + end; + end; + + procedure TApdBaseDispatcher.SetBaseAddress(NewBaseAddress : Word); + {-Set the base address} + begin + EnterCriticalSection(DataSection); + try + BaseAddress := NewBaseAddress; + finally + LeaveCriticalSection(DataSection); + end; + end; + + function TApdBaseDispatcher.GetBaseAddress : Word; + {-Get the base address} + begin + Result := BaseAddress; + end; + + constructor TApdDispatcherThread.Create(Disp : TApdBaseDispatcher); + begin + H := Disp; + inherited Create(False); + FreeOnTerminate := True; + end; + + procedure TApdDispatcherThread.SyncEvent; + begin + pTriggerEvent(pMsg,pTrigger,plParam); + end; + + procedure TApdDispatcherThread.SyncNotify(Msg, Trigger : Cardinal; + lParam : Integer; Event : TApdNotifyEvent); + begin + pMsg := Msg; + pTrigger := Trigger; + plParam := lParam; + pTriggerEvent := Event; + Synchronize(SyncEvent); + end; + + procedure TApdDispatcherThread.Sync(Method: TThreadMethod); + {- public version of Synchronize} + begin + Synchronize(Method); + end; + + {Output event thread} + procedure TOutThread.Execute; + {-Wait for and process output events} + var + Res : Integer; + OutOL : TOverlapped; {For output event waiting} + + function DataInBuffer : Boolean; + {indicate whether the output buffer has data to be sent} + begin + with H do begin + EnterCriticalSection(OutputSection); + try + DataInBuffer := OBufFull or (OBufHead <> OBufTail); + finally + LeaveCriticalSection(OutputSection); + end; + end; + end; + + procedure ProcessOutputEvent(H : TApdBaseDispatcher); + var + NumToWrite : Integer; + NumWritten : DWORD; + Ok : Boolean; + TempBuff : POBuffer; + begin + while DataInBuffer do begin + with H do begin + EnterCriticalSection(OutputSection); + try + {Check for buffer wrap-around. If wrap around has occurred, + use a temp buffer to shuffle around the buffer contents to make the + data in the buffer reside at contiguous locations. This is done to + prevent scheduling delays in the OS from causing us to emit data with + potentially large gaps in the output stream of bytes when buffer wrap- + around occurs.} + if OBufTail < OBufHead then + NumToWrite := OBufHead - OBufTail + else begin + if (OBufHead = 0) then + NumToWrite := OutQue - OBufTail + else begin + GetMem(TempBuff, OBufHead); + Move(OBuffer^, TempBuff^, OBufHead); + Move(OBuffer^[OBufTail], OBuffer^, OutQue - OBufTail); + Move(TempBuff^, OBuffer^[OutQue - OBufTail], OBufHead); + FreeMem(TempBuff); + Inc(OBufHead, OutQue - OBufTail); + NumToWrite := OBufHead; + OBufTail := 0; + end; + end; + finally + LeaveCriticalSection(OutputSection); + end; + Ok := WriteFile(CidEx, + OBuffer^[OBufTail], + NumToWrite, + NumWritten, + @OutOL); + if not Ok then begin + if GetLastError = ERROR_IO_PENDING then begin + {expected -- write is pending} + {$IFDEF DebugThreadConsole} + Writeln(ThreadStatus(OutSleep)); + {$ENDIF} + Res := WaitForMultipleObjects(2, + @OutWaitObjects2, + False, + INFINITE); + {$IFDEF DebugThreadConsole} + Writeln(ThreadStatus(OutWake)); + {$ENDIF} + case Res of + WAIT_OBJECT_0 : + begin + {overlapped i/o completed} + if GetOverLappedResult(CidEx, OutOL, NumWritten, False) then begin + EnterCriticalSection(OutputSection); + try + Inc(OBufTail, NumWritten); + if(OBufTail = OutQue) then + OBufTail := 0; + { If nothing left in the buffer, reset the } + { queue to avoid buffer wrap-arounds. } + if(OBufTail = OBufHead) then begin + OBufTail := 0; + OBufHead := 0; + end; + OBufFull := False; + ResetEvent(OutOL.hEvent); + finally + LeaveCriticalSection(OutputSection); + end; + end else begin + {GetOverLappedResult failed.} + end; + end; + WAIT_OBJECT_0 + 1 : + begin + {flush buffer requested, acknowledge and exit} + SetEvent(GeneralEvent); + Exit; + end; + WAIT_TIMEOUT : + {couldn't send all data} + else + {an unexpected error occurred with WaitForMultipleObjects} + end; + end else begin + {WriteFile failed, but not because of delayed write} + { Give up on sending this block, update the queue + pointers, and continue. We get here if we lose + carrier during a transmit, and if we continue to + try to resend the data, we'll loop forever.} + EnterCriticalSection(OutputSection); + try + inc(OBufTail, NumToWrite); + if (OBufTail = OutQue) then + OBufTail := 0; + { If nothing left in the buffer, reset the queue } + { to avoid buffer wrap-arounds } + if (OBufTail = OBufHead) then begin + OBufTail := 0; + OBufHead := 0; + end; + OBufFull := False; + finally + LeaveCriticalSection(OutputSection); + end; + end; + end else begin + { WriteFile completed immediately -- update buffer pointer } + EnterCriticalSection(OutputSection); + try + Inc(OBufTail, NumWritten); + if (OBufTail = OutQue) then + OBufTail := 0; + { If nothing left in the buffer, reset the queue to } + { avoid buffer wrap-arounds } + if (OBufTail = OBufHead) then begin + OBufTail := 0; + OBufHead := 0; + end; + OBufFull := False; + finally + LeaveCriticalSection(OutputSection); + end; + end; + {No more data in buffer, if in RS485 mode wait for TE} + if Win32Platform <> VER_PLATFORM_WIN32_NT then + if RS485Mode then begin + repeat + until (PortIn(BaseAddress+5) and $40) <> 0; + SetRTS(False); + end; + end; + end; + end; + + begin + InterLockedIncrement(H.ActiveThreads); + try + FillChar(OutOL, SizeOf(OutOL), #0); + with H do begin + {$IFDEF DebugThreads} + if DLoggingOn then + AddDispatchEntry(dtThread, dstThreadStart, 3, nil, 0); + {$ENDIF} + + {set the event used for overlapped i/o to signal completion} + OutOL.hEvent := SentEvent; + + {Ready to go, set the general event} + SetEvent(GeneralEvent); + + {Repeat until port is closed} + repeat + {$IFDEF DebugThreads} + if DLoggingOn then + AddDispatchEntry(dtThread, dstThreadSleep, 3, nil, 0); + {$ENDIF} + + {Wait for either an output event or a flush event} + {$IFDEF DebugThreadConsole} + Writeln(ThreadStatus(OutSleep)); + {$ENDIF} + Res := WaitForMultipleObjects(2, + @OutWaitObjects1, + False, + INFINITE); + {$IFDEF DebugThreadConsole} + Writeln(ThreadStatus(OutWake)); + {$ENDIF} + {$IFDEF DebugThreads} + if DLoggingOn then + AddDispatchEntry(dtThread, dstThreadWake, 3, nil, 0); + {$ENDIF} + + case Res of + WAIT_OBJECT_0 : + begin + {output event} + {Exit immediately if thread was killed while waiting} + if KillThreads then begin + {$IFDEF DebugThreads} + if DLoggingOn then + AddDispatchEntry(dtThread, dstThreadExit, 3, nil, 0); + {$ENDIF} + {Finished here, okay to close the port} + H.ThreadGone(Self); + Exit; + end; + + {We have data to send, so process it...} + ProcessOutputEvent(H); + end; + WAIT_OBJECT_0 + 1 : + begin + {flush buffer requested, acknowledge and continue} + SetEvent(GeneralEvent); + end; + else + {unexpected problem with WaitFor} + end; + until KillThreads or ClosePending; + {$IFDEF DebugThreads} + if DLoggingOn then + AddDispatchEntry(dtThread, dstThreadExit, 3, nil, 0); + {$ENDIF} + end; + H.ThreadGone(Self); + except + if Assigned(GShowExceptionHandler) then + GShowExceptionHandler(ExceptObject, ExceptAddr) + else + ShowException(ExceptObject, ExceptAddr); + end; + end; + + {Communications event thread} + procedure TComThread.Execute; + {-Wait for and process communications events} + var + Junk : DWORD; + LastMask : Integer; + Timeouts : TCommTimeouts; + ComOL : TOverlapped; {For com event waiting} + begin + InterLockedIncrement(H.ActiveThreads); + try + FillChar(ComOL, SizeOf(ComOL), #0); + with H do begin + {$IFDEF DebugThreads} + if DLoggingOn then + AddDispatchEntry(dtThread, dstThreadStart, 1, nil, 0); + {$ENDIF} + + ComOL.hEvent := CreateEvent(nil, True, False, nil); + + {Set our standard win32 events} + + { Note, NuMega's BoundsChecker will flag a bogus error on the } + { following statement because we use the undocumented ring_te flag } + + if Win32Platform = VER_PLATFORM_WIN32_NT then + LastMask := DefEventMask and not ev_RingTe + else + LastMask := DefEventMask; + SetCommMask(CidEx, LastMask); + + FillChar(Timeouts, SizeOf(TCommTimeouts), 0); + Timeouts.ReadIntervalTimeout := MaxDWord; + SetCommTimeouts(CidEx, Timeouts); + + {Ready to go, set the general event} + SetEvent(GeneralEvent); + + {Repeat until port is closed} + repeat + {$IFDEF DebugThreads} + if DLoggingOn then + AddDispatchEntry(dtThread, dstThreadSleep, 1, nil, 0); + {$ENDIF} + + {$IFDEF DebugThreadConsole} + Writeln(ThreadStatus(ComSleep)); + {$ENDIF} + + {Release time slice until we get a communications event} + if not WaitComEvent(CurrentEvent, @ComOL) then begin + if GetLastError = ERROR_IO_PENDING then begin + if GetOverLappedResult(CidEx, + ComOL, + Junk, + True) then begin + + {WIN32 bug workaround: Apro gets the modem status bits + with a call (later) to GetCommModemStatus. Unfortunately, + that routine never seems to return either RI or TERI. + So, we note either EV_RING or EV_RINGTE here and later + manually merge the TERI bit into ModemStatus.} + if ((CurrentEvent and EV_RINGTE) <> 0) or + ((CurrentEvent and EV_RING) <> 0) then + RingFlag := True; + + {Read complete, reset event} + ResetEvent(ComOL.hEvent); + end else begin + {Port closed or other fatal condition, just exit the thread} + SetEvent(GeneralEvent); + CloseHandle(ComOL.hEvent); + H.ThreadGone(Self); + Exit; + end; + end else begin + { If we get an ERROR_INVALID_PARAMETER, we assume it's our } + { use of ev_RingTe -- clear the flag and try again } + if (GetLastError = ERROR_INVALID_PARAMETER) and + (LastMask and EV_RINGTE <> 0) then begin + LastMask := DefEventMask and not EV_RINGTE; + SetCommMask(CidEx, LastMask); + end; + end; + end; + + {Exit immediately if thread was killed while waiting} + if KillThreads then begin + SetEvent(GeneralEvent); + {$IFDEF DebugThreads} + if DLoggingOn then + AddDispatchEntry(dtThread, dstThreadExit, 1, nil, 0); + {$ENDIF} + CloseHandle(ComOL.hEvent); + H.ThreadGone(Self); + Exit; + end; + + {$IFDEF DebugThreadConsole} + Writeln(ThreadStatus(ComWake)); + {$ENDIF} + {$IFDEF DebugThreads} + if DLoggingOn then + AddDispatchEntry(dtThread, dstThreadWake, 1, @CurrentEvent, 2); + {$ENDIF} + + {Signal com event} + SetEvent(ComEvent); + + {$IFDEF DebugThreadConsole} + Writeln(ThreadStatus(ComSleep)); + {$ENDIF} + + {Wait for the dispatcher thread to complete} + WaitForSingleObject(ReadyEvent, INFINITE); + + {$IFDEF DebugThreadConsole} + Writeln(ThreadStatus(ComWake)); + {$ENDIF} + + until KillThreads; + + {$IFDEF DebugThreads} + if DLoggingOn then + AddDispatchEntry(dtThread, dstThreadExit, 1, nil, 0); + {$ENDIF} + + {Finished here, okay to close the port} + SetEvent(GeneralEvent); + end; + CloseHandle(ComOL.hEvent); + H.ThreadGone(Self); + except + if Assigned(GShowExceptionHandler) then + GShowExceptionHandler(ExceptObject, ExceptAddr) + else + ShowException(ExceptObject, ExceptAddr); + end; + end; + + procedure TDispThread.Execute; + {-Wait for and process communications events} + procedure ProcessComEvent(H : TApdBaseDispatcher); + {$IFNDEF UseAwWin32} // SWB + var // SWB + bfr : TIOBuffer; // SWB + {$ENDIF} // SWB + begin + with H do begin + {$IFNDEF UseAwWin32} // SWB + // Read the first status packet from the queue & copy its contents // SWB + // to CurrentEvent so that the status event handlers can process it.// SWB + bfr := FQueue.Peek; // SWB + if (Assigned(bfr)) then // SWB + begin // SWB + if (bfr is TStatusBuffer) then // SWB + begin // SWB + CurrentEvent := TStatusBuffer(bfr).Status; // SWB + FQueue.Pop; // SWB + TStatusBuffer(bfr).Free; // KGM + end else // SWB + begin // SWB + bfr.InUse := False; // SWB + CurrentEvent := 0; // SWB + end; // SWB + end else // SWB + CurrentEvent := 0; // SWB + {WIN32 bug workaround: Apro gets the modem status bits // SWB + with a call (later) to GetCommModemStatus. Unfortunately, // SWB + that routine never seems to return either RI or TERI. // SWB + So, we note either EV_RING or EV_RINGTE here and later // SWB + manually merge the TERI bit into ModemStatus.} // SWB + if ((CurrentEvent and (EV_RINGTE or EV_RING)) <> 0) then // SWB + RingFlag := True; // SWB + {$ENDIF} // SWB + {Check for modem events} + if CurrentEvent and ModemEvent <> 0 then begin + + {A modem status event...} + MapEventsToMS(CurrentEvent); + + {$IFDEF DebugThreads} + if DLoggingOn then + AddDispatchEntry(dtDispatch, dstModemStatus, + ModemStatus, @CurrentEvent, 2); + {$ENDIF} + + {Check for status triggers} + if not fEventBusy then begin + while CheckStatusTriggers do + if ClosePending then + Exit; + + {Allow status triggers to hit again} + if GlobalStatHit then + ResetStatusHits; + end; + end; + + {Check for line events} + if CurrentEvent and LineEvent <> 0 then begin + {A line status/error event} + RefreshStatus; + + {$IFDEF DebugThreads} + if DLoggingOn then + AddDispatchEntry(dtDispatch, dstLineStatus, + 0, @CurrentEvent, 2); + {$ENDIF} + + {Check for status triggers} + if not fEventBusy then begin + while CheckStatusTriggers do + if ClosePending then + Exit; + + {Allow status triggers to hit again} + if GlobalStatHit then + ResetStatusHits; + end; + end; + + { Get any available data } + ExtractData; + + {Check for received status & data triggers} + if not fEventBusy then begin + ModemStatus := GetModemStatus; {!!.06} + while CheckStatusTriggers do + if ClosePending then + Exit; + while CheckReceiveTriggers do + if ClosePending then + Exit; + end; + if GlobalStatHit then + ResetStatusHits; + + {Let the com thread continue...} + SetEvent(ReadyEvent); + end; + end; + + procedure ProcessTimer(H : TApdBaseDispatcher); + begin + with H do begin + if ClosePending then + Exit; + + if not fEventBusy then begin + GlobalStatHit := False; + + {Issue all status and timer triggers} + + while (CheckStatusTriggers or CheckTimerTriggers) and not ClosePending do + ; + {Allow status triggers to hit again} + if GlobalStatHit then + ResetStatusHits; + end else begin + {$IFDEF DebugThreads} + if DLoggingOn then + AddDispatchEntry(dtError, dstNone, 0, nil, 0); + {$ENDIF} + end; + end; + end; + + begin + InterLockedIncrement(H.ActiveThreads); + try + with H do begin + {$IFDEF DebugThreads} + if DLoggingOn then + AddDispatchEntry(dtThread, dstThreadStart, 2, nil, 0); + {$ENDIF} + + try + {Ready to go, set the general event} + SetEvent(GeneralEvent); + + {Repeat until port is closed} + repeat + {$IFDEF DebugThreads} + if DLoggingOn then + AddDispatchEntry(dtThread, dstThreadSleep, 2, nil, 0); + {$ENDIF} + + {$IFDEF DebugThreadConsole} + Writeln(ThreadStatus(DispSleep)); + {$ENDIF} + + {Wait for either a com event or a timeout} + FQueue.WaitForBuffer(50); // SWB + {$IFDEF DebugThreadConsole} + Writeln(ThreadStatus(DispWake)); + {$ENDIF} + + {Exit immediately if thread was killed while waiting} + if KillThreads then begin + {$IFDEF DebugThreads} + if DLoggingOn then + AddDispatchEntry(dtThread, dstThreadExit, 2, nil, 0); + {$ENDIF} + {Finished here, okay to close the port} + Exit; + end; + + {$IFDEF DebugThreads} + if DLoggingOn then + AddDispatchEntry(dtThread, dstThreadWake, 2, nil, 0); + {$ENDIF} + + {Process it...} + ProcessComEvent(H); + ProcessTimer(H); + + until KillThreads or ClosePending; + + {$IFDEF DebugThreads} + if DLoggingOn then + AddDispatchEntry(dtThread, dstThreadExit, 2, nil, 0); + {$ENDIF} + + {Finished here, okay to close the port} + SetEvent(GeneralEvent); + + finally + { Make sure DonePortPrim gets called } + DoDonePortPrim := (ClosePending or KillThreads); + {$IFDEF DebugThreadConsole} + Writeln(ThreadStatus(DispKill)); + {$ENDIF} + H.ThreadGone(Self); + end; + end; + except + if Assigned(GShowExceptionHandler) then + GShowExceptionHandler(ExceptObject, ExceptAddr) + else + ShowException(ExceptObject, ExceptAddr); + end; + end; + +procedure LockPortList; +begin + EnterCriticalSection(PortListSection); +end; + +procedure UnlockPortList; +begin + LeaveCriticalSection(PortListSection); +end; + +procedure FinalizeUnit; far; +begin + PortList.Free; + PortList := nil; +end; + +procedure InitializeUnit; +begin + PortList := TList.Create; + + FillChar(PortListSection, SizeOf(PortListSection), 0); + InitializeCriticalSection(PortListSection); +end; + +initialization // SZ FIXME loader lock + InitializeUnit; + +finalization + FinalizeUnit; + DeleteCriticalSection(PortListSection); + +end. diff --git a/AwWin32.pas b/AwWin32.pas new file mode 100644 index 0000000..25b74ea --- /dev/null +++ b/AwWin32.pas @@ -0,0 +1,563 @@ +(***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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 TurboPower Async Professional + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1991-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Sulaiman Mah + * Sean B. Durkin + * Sebastian Zierer + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* AWWIN32.PAS 5.00 *} +{*********************************************************} +{* Win32 serial device layer and dispatcher *} +{*********************************************************} + +{ + Along with AwUser.pas, this unit defines/implements the dreaded Windows + serial port dispatcher. This unit provides the interface to the Win32 + serial port drivers, the threading code is in AwUser.pas. + Be extrememly cautious when making changes here or in AwUser. The multi- + threaded nature, and very strict timing requirements, can lead to very + unpredictable results. Things as simple as adding doing a writeln to a + console window can dramatically change the results. +} + +{Global defines potentially affecting this unit} +{$I AWDEFINE.INC} + +{Options required for this unit} +{$X+,F+,K+,B-} + +unit AwWin32; + {-Device layer for standard Win32 communications API} + +interface + +uses + Windows, + Classes, + SysUtils, + AdWUtil, + AdSocket, + OoMisc, + awUser; + +type + + TApdWin32Dispatcher = class(TApdBaseDispatcher) + protected + ReadOL : TOverLapped; + WriteOL : TOverLapped; + function EscapeComFunction(Func : Integer) : Integer; override; + function FlushCom(Queue : Integer) : Integer; override; + function GetComError(var Stat : TComStat) : Integer; override; + function GetComEventMask(EvtMask : Integer) : Cardinal; override; + function GetComState(var DCB: TDCB): Integer; override; + function SetComState(var DCB : TDCB) : Integer; override; + function ReadCom(Buf : PAnsiChar; Size: Integer) : Integer; override; + function WriteCom(Buf : PAnsiChar; Size: Integer) : Integer; override; + function SetupCom(InSize, OutSize : Integer) : Boolean; override; + procedure StartDispatcher; override; + procedure StopDispatcher; override; + function WaitComEvent(var EvtMask : DWORD; + lpOverlapped : POverlapped) : Boolean; override; + function OutBufUsed: Cardinal; override; // SWB + public + function CloseCom : Integer; override; + function OpenCom(ComName: PChar; InQueue, + OutQueue : Cardinal) : Integer; override; + function ProcessCommunications : Integer; override; + function CheckPort(ComName: PChar): Boolean; override; + end; + + TApdTAPI32Dispatcher = class(TApdWin32Dispatcher) + public + constructor Create(Owner : TObject; InCid : Integer); + function OpenCom(ComName: PChar; InQueue, + OutQueue : Cardinal) : Integer; override; + end; + +implementation + +uses + StrUtils; + +function TApdWin32Dispatcher.CheckPort(ComName: PChar): Boolean; //SZ +// Returns true if a port exists +var + Tmp: string; + CC: PCommConfig; + Len: Cardinal; +begin + Tmp := ComName; + if AnsiStartsText('\\.\', Tmp) then + Delete(Tmp, 1, 4); + + New(CC); + try + FillChar(CC^, SizeOf(CC^), 0); + CC^.dwSize := SizeOf(CC^); + Len := SizeOf(CC^); + Result := GetDefaultCommConfig(PChar(Tmp), CC^, Len); + finally + Dispose(CC); + end; + if (not Result) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) then + begin + GetMem(CC, Len); + try + FillChar(CC^, SizeOf(CC^), 0); + CC^.dwSize := SizeOf(CC^); + Result := GetDefaultCommConfig(PChar(Tmp), CC^, Len); + finally + FreeMem(CC); + end; + end; +end; + + function TApdWin32Dispatcher.CloseCom : Integer; + {-Close the comport and cleanup} + begin + // Under certain circumstances, it is possible that CloseCom can be called + // recursively. In that event, we don't want to be re-executing this code. + // So, set a flag to show that we are inside this method and check it + // every time we enter. If it is already set, just exit and do nothing. + // This used to be accomplished by acquiring the DataSection critical section + // but this lead to occasional deadlocks. + EnterCriticalSection(DataSection); // SWB + if (CloseComActive) then // SWB + begin // SWB + LeaveCriticalSection(DataSection); // SWB + Result := 0; // SWB + Exit; // SWB + end; // SWB + CloseComActive := True; // SWB + LeaveCriticalSection(DataSection); // SWB + try // SWB + {Release the events} + if ReadOL.hEvent <> 0 then begin + CloseHandle(ReadOL.hEvent); + ReadOL.hEvent := 0; + end; + if WriteOL.hEvent <> 0 then begin + CloseHandle(WriteOL.hEvent); + WriteOL.hEvent := 0; + end; + + if DispActive then begin + KillThreads := True; + + {Force the comm thread to wake...} + SetCommMask(CidEx, 0); + SetEvent(ReadyEvent); + ResetEvent(GeneralEvent); + + {$IFDEF DebugThreadConsole} + Writeln(ThreadStatus(ComKill)); + {$ENDIF} + end; + + {Close the comport} + if CloseHandle(CidEx) then begin + Result := 0; + CidEx := -1; + end else + Result := -1; + finally // SWB + CloseComActive := False; // SWB + end; // SWB + end; + + function TApdWin32Dispatcher.EscapeComFunction(Func: Integer): Integer; + {-Perform the extended comm function Func} + begin + EscapeCommFunction(CidEx, Func); + Result := 0; + end; + + function TApdWin32Dispatcher.FlushCom(Queue: Integer): Integer; + {-Flush the input or output buffer} + begin + if (Queue = 0) and (OutThread <> nil) then begin + {Flush our own output buffer...} + SetEvent(OutFlushEvent); + { this can cause a hang when using an IR port that does not have a } + { connection (the IR receiver is not in range), the port drivers } + { will not flush the buffers, so we'd wait forever } + WaitForSingleObject(GeneralEvent, 5000);{INFINITE);} {!!.02} + {...XMit thread has acknowledged our request, so flush it} + EnterCriticalSection(OutputSection); + try + OBufFull := False; + OBufHead := 0; + OBufTail := 0; + Result := Integer(PurgeComm(CidEx, + PURGE_TXABORT or PURGE_TXCLEAR)); + finally + LeaveCriticalSection(OutputSection); + end; + end else + Result := Integer(PurgeComm(CidEx, PURGE_RXABORT or PURGE_RXCLEAR)); + + if Result = 1 then + Result := 0 + else + Result := -Integer(GetLastError); + end; + + function TApdWin32Dispatcher.GetComError(var Stat: TComStat): Integer; + {-Get the current error and update Stat} + var + Errors : DWORD; + begin + if ClearCommError(CidEx, Errors, @Stat) then + Result := Errors + else + Result := 0; + + {Replace information about Windows output buffer with our own} + Stat.cbOutQue := OutBufUsed; // SWB + end; + + function TApdWin32Dispatcher.GetComEventMask(EvtMask: Integer): Cardinal; + {-Set the communications event mask} + begin + Result := 0; + end; + + function TApdWin32Dispatcher.GetComState(var DCB: TDCB): Integer; + {-Fill in DCB with the current communications state} + begin + if Integer(GetCommState(CidEx, DCB)) = 1 then + Result := 0 + else + Result := -1; + end; + + function TApdWin32Dispatcher.OpenCom(ComName: PChar; InQueue, OutQueue: Cardinal): Integer; + {-Open the comport specified by ComName} + begin + {Open the device} + Result := CreateFile(ComName, {name} + GENERIC_READ or GENERIC_WRITE, {access attributes} + 0, {no sharing} + nil, {no security} + OPEN_EXISTING, {creation action} + FILE_ATTRIBUTE_NORMAL or + FILE_FLAG_OVERLAPPED, {attributes} + 0); {no template} + + if Result <> Integer(INVALID_HANDLE_VALUE) then begin + CidEx := Result; + {Create port data structure} + ReadOL.hEvent := CreateEvent(nil, True, False, nil); + WriteOL.hEvent := CreateEvent(nil, True, False, nil); + if (ReadOL.hEvent = 0) or (WriteOL.hEvent = 0) then begin + {Failed to create events, get rid of everything} + CloseHandle(ReadOL.hEvent); + CloseHandle(WriteOL.hEvent); + CloseHandle(Result); + Result := ecOutOfMemory; + Exit; + end; + end else + {Failed to open port, just return error signal, caller will + call GetLastError to get actual error code} + Result := -1; + end; + + function TApdWin32Dispatcher.ReadCom(Buf: PAnsiChar; Size: Integer): Integer; + {-Read Size bytes from the comport specified by Cid} + var + OK : Bool; + Temp : DWORD; + begin + {Post a read request...} + OK := ReadFile(CidEx, {handle} + Buf^, {buffer} + Size, {bytes to read} + Temp, {bytes read} + @ReadOL); {overlap record} + + {...and see what happened} + if not OK then begin + if GetLastError = ERROR_IO_PENDING then begin + {Waiting for data} + if GetOverLappedResult(CidEx, {handle} + ReadOL, {overlapped structure} + Temp, {bytes written} + True) then begin {wait for completion} + {Read complete, reset event} + ResetEvent(ReadOL.hEvent); + end; + end; + end; + Result := Integer(Temp); + end; + + function TApdWin32Dispatcher.SetComState(var DCB: TDCB): Integer; + {-Set the a new communications device state from DCB} + begin + if SetCommState(CidEx, DCB) then + Result := 0 + else + Result := -Integer(GetLastError); + end; + + function TApdWin32Dispatcher.WriteCom(Buf: PAnsiChar; Size: Integer): Integer; + {-Write data to the comport} + type + PBArray = ^TBArray; + TBArray = array[0..pred(High(Integer))] of Byte; + var + SizeAtEnd : Integer; + LeftOver : Integer; + begin + {Add the data to the output queue} + EnterCriticalSection(OutputSection); + try + {we already know at this point that there is enough room for the block} + SizeAtEnd := OutQue - OBufHead; + if SizeAtEnd >= Size then begin + {can move data to output queue in one block} + Move(Buf^, OBuffer^[OBufHead], Size); + if SizeAtEnd = Size then + OBufHead := 0 + else + Inc(OBufHead, Size); + end else begin + { need to use two moves } + Move(Buf^, OBuffer^[OBufHead], SizeAtEnd); + LeftOver := Size - SizeAtEnd; + Move(PBArray(Buf)^[SizeAtEnd], OBuffer^, LeftOver); + OBufHead := LeftOver; + end; + finally + LeaveCriticalSection(OutputSection); + end; + + {...finally, wake up the output thread to send the data} + SetEvent(OutputEvent); + Result := Size; {report all was sent} + end; + + function TApdWin32Dispatcher.SetupCom(InSize, OutSize : Integer) : Boolean; + {-Set new in/out buffer sizes} + begin + Result := SetupComm(CidEx, InSize, OutSize); + end; + + function TApdWin32Dispatcher.WaitComEvent(var EvtMask : DWORD; + lpOverlapped : POverlapped) : Boolean; + begin + Result := WaitCommEvent(CidEx, EvtMask, lpOverlapped); + end; + + procedure TApdWin32Dispatcher.StartDispatcher; + begin + EnterCriticalSection(DataSection); + try + {See if we're already active} + if DispActive then + raise Exception.Create('Dispatcher already started'); + + DispActive := True; + + {Create the com events thread} + KillThreads := False; + + ComThread := TComThread.Create(Self); + {Wait for it to start...} + WaitForSingleObject(GeneralEvent, ThreadStartWait); + {$IFDEF DebugThreadConsole} + Writeln(ThreadStatus(ComStart)); + {$ENDIF} + + {Create the dispatcher thread} + fDispThread := TDispThread.Create(Self); + {Wait for it to start...} + WaitForSingleObject(GeneralEvent, ThreadStartWait); + {$IFDEF DebugThreadConsole} + Writeln(ThreadStatus(DispStart)); + {$ENDIF} + + {Create the output thread} + OutThread := TOutThread.Create(Self); + {Wait for it to start...} + WaitForSingleObject(GeneralEvent, ThreadStartWait); + {$IFDEF DebugThreadConsole} + Writeln(ThreadStatus(OutStart)); + {$ENDIF} + finally + LeaveCriticalSection(DataSection); + end; + end; + + procedure TApdWin32Dispatcher.StopDispatcher; + var + ET : EventTimer; + begin + if not DispActive then + Exit; + + { Set the flag to kill the threads next time they wake, or after } + { their current processing } + KillThreads := True; + + if Assigned(OutThread) then begin + {Force the output thread to wake...} + SetEvent(OutFlushEvent); + + {...and wait for it to die} + while (OutThread <> nil) do + SafeYield; + + {$IFDEF DebugThreadConsole} + Writeln(ThreadStatus(OutKill)); + {$ENDIF} + end; + + if Assigned(ComThread) then begin + {Force the comm thread to wake...} + SetCommMask(CidEx, 0); + SetEvent(ReadyEvent); + + {... and wait for it to die} + ResetEvent(GeneralEvent); + while (ComThread <> nil) do + SafeYield; + + {$IFDEF DebugThreadConsole} + Writeln(ThreadStatus(ComKill)); + {$ENDIF} + end; + + {Now kill the timer} + KillTimer(0, TimerID); + + if Assigned(DispThread) then begin + KillThreads := True; + {Wait for it to die} + NewTimer(ET, 36); { start a 2-second timer to prevent blocks } + while (DispThread <> nil) and not(TimerExpired(ET)) do + SafeYield; + if DispThread <> nil then begin + {$IFDEF DebugThreadConsole} + WriteLn('DispThread<>nil'); + {$ENDIF} + { thread didn't die, reset the event } + SetEvent(ComEvent); + {Wait for it to die yet again} + NewTimer(ET, 36); { start a 2-second timer to prevent blocks } + while (DispThread <> nil) and not(TimerExpired(ET)) do + SafeYield; + if DispThread <> nil then + { disp thread is not responding, brutally terminate it } + DispThread.Free; + end; + + {$IFDEF DebugThreadConsole} + Writeln(ThreadStatus(DispKill)); + {$ENDIF} + end; + + if ComEvent <> INVALID_HANDLE_VALUE then begin + if CloseHandle(ComEvent) then + ComEvent := INVALID_HANDLE_VALUE; + end; + + if ReadyEvent <> INVALID_HANDLE_VALUE then begin + if CloseHandle(ReadyEvent) then + ReadyEvent := INVALID_HANDLE_VALUE; + end; + + if GeneralEvent <> INVALID_HANDLE_VALUE then begin + if CloseHandle(GeneralEvent) then + GeneralEvent := INVALID_HANDLE_VALUE; + end; + + if OutputEvent <> INVALID_HANDLE_VALUE then begin + if CloseHandle(OutputEvent) then + OutputEvent := INVALID_HANDLE_VALUE; + end; + + if SentEvent <> INVALID_HANDLE_VALUE then begin + if CloseHandle(SentEvent) then + SentEvent := INVALID_HANDLE_VALUE; + end; + + if OutFlushEvent <> INVALID_HANDLE_VALUE then begin + if CloseHandle(OutFlushEvent) then + OutFlushEvent := INVALID_HANDLE_VALUE; + end; + end; + + function TApdWin32Dispatcher.ProcessCommunications : Integer; + {-Communications are running in separate threads -- give them a chance} + begin + Sleep(0); + Result := 0; + end; + + constructor TApdTAPI32Dispatcher.Create(Owner : TObject; InCid : Integer); + begin + CidEx := InCid; + inherited Create(Owner); + end; + + function TApdTAPI32Dispatcher.OpenCom(ComName: PChar; InQueue, OutQueue : Cardinal) : Integer; + begin + ReadOL.hEvent := CreateEvent(nil, True, False, nil); + WriteOL.hEvent := CreateEvent(nil, True, False, nil); + if (ReadOL.hEvent = 0) or (WriteOL.hEvent = 0) then begin + CloseCom; + Result := -1; + Exit; + end; + if CidEx <> 0 then + Result := CidEx + else begin + Result := ecCommNotOpen; + SetLastError(-Result); + end; + end; +// Added by SWB +function TApdWin32Dispatcher.OutBufUsed: Cardinal; +begin + EnterCriticalSection(OutputSection); + try + Result := 0; + if OBufFull then + Result := OutQue + else if OBufHead > OBufTail then + {Buffer is not wrapped} + Result := OBufHead - OBufTail + else if OBufHead < OBufTail then + {Buffer is wrapped} + Result := OBufHead + (OutQue - OBufTail); + finally + LeaveCriticalSection(OutputSection); + end; +end; + +end. diff --git a/Installeur.exe b/Installeur.exe index 74ce0cc..26b8309 100644 Binary files a/Installeur.exe and b/Installeur.exe differ diff --git a/LNSWin32.pas b/LNSWin32.pas new file mode 100644 index 0000000..d78ec55 --- /dev/null +++ b/LNSWin32.pas @@ -0,0 +1,1278 @@ +(***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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 TurboPower Async Professional + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1991-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Stephen W. Boyd - Created this module to replace serial port + * dispatcher. The old dispatcher was too + * prone to suffering input overruns if the + * event handlers didn't return control to + * the dispatch thread fast enough. + * August 2005. + * Sulaiman Mah + * Sean B. Durkin + * Sebastian Zierer + * ***** END LICENSE BLOCK ***** *) +{*********************************************************} +{* LNSWIN32.PAS 4.06 *} +{*********************************************************} +{* Win32 serial device layer and dispatcher *} +{*********************************************************} + +{Global defines potentially affecting this unit} +{$I AWDEFINE.INC} + +{ A direct replacement for AwWin32.pas. The multithreading aspects have been + redesigned where necessary to make it more efficient and less prone to + data overruns. Anything not directly related to multithreading has been + stolen from AwWin32.pas mostly unchanged. + + TApdTAPIDispatcher stolen in its entirety from AwWin32.pas + + The Win32 Dispatcher now consists of 4 threads. These are: + + 1) TReadThread - Waits for TStatusThread to notify it that an EV_RXCHAR + event has occured and reads as much data as is + available at that time. It also reads any available data + every 50 ms just in case we have a misbehaving driver + that doesn't provide the EV_RXCHAR event reliably. + All data read is placed onto a QueueProp for TDispThread + to process. This allows TDispThread, and hence any + event handlers, to take as much time as they need + without worrying about data overruns. + 2) TWriteThread - Waits for output to appear in the dispatcher's output + buffer. It copies all available output to a temporary + buffer, marks the dispatcher's buffer as empty and + sends the data from the temporary buffer. This provides + a crude double buffering capability and improves + performance for streaming protocols like zmodem. + 3) TStatusThread - Waits for serial port events by calling WaitCommEvent. + When an event occurs it either wakes up TReadThread or + queues a status change notification to TDispThread as + appropriate. + 4) TDispThread - This is the original TDispThread from AwUser. It + continues largely unchanged from the original. The + only real difference is that it now waits for data to + appear in the QueueProp and reads from the QueueProp rather than + issuing its own WaitCommEvent and ReadFile calls. + + The original serial port dispatcher in AwWin32 can still be used by setting + the condition UseAwWin32 and recompiling. +} + +unit LNSWin32; + +interface + +uses Windows, AwUser, SysUtils, OoMisc, LNSQueue, SyncObjs; + +type + TApdWin32Thread = class(TApdDispatcherThread) + private + function GetComHandle : THandle; + function GetDLoggingOn : Boolean; + function GetGeneralEvent : THandle; + function GetKillThreads : Boolean; + function GetQueue : TIOQueue; + function GetSerialEvent : TEvent; + procedure SetKillThreads(value : Boolean); + procedure ThreadGone(Sender : TObject); + procedure ThreadStart(Sender : TObject); + protected + procedure AddDispatchEntry(DT : TDispatchType; + DST : TDispatchSubType; + Data : Cardinal; + Buffer : Pointer; + BufferLen : Cardinal); + function WaitForOverlapped(ovl : POverlapped) : Integer; virtual; + + property ComHandle : THandle read GetComHandle; + property DLoggingOn : Boolean read GetDLoggingOn; + property GeneralEvent : THandle read GetGeneralEvent; + property KillThreads : Boolean read GetKillThreads write SetKillThreads; + property QueueProp : TIOQueue read GetQueue; + property SerialEvent : TEvent read GetSerialEvent; + end; + + TReadThread = class(TApdWin32Thread) + protected + procedure Execute; override; + function ReadSerial(Buf : PAnsiChar; + Size: Integer; + ovl : POverlapped) : Integer; + end; + + TWriteThread = class(TApdWin32Thread) + private + function GetOutFlushEvent : THandle; + function GetOutputEvent : THandle; + protected + function DataInBuffer : Boolean; + procedure Execute; override; + function WaitForOverlapped(ovl : POverlapped) : Integer; override; + function WriteSerial(ovl : POverlapped) : Integer; + + property OutFlushEvent : THandle read GetOutFlushEvent; + property OutputEvent : THandle read GetOutputEvent; + end; + + TStatusThread = class(TApdWin32Thread) + private + LastMask : DWORD; + protected + procedure Execute; override; + function WaitSerialEvent(var EvtMask : DWORD; + ovl : POverlapped) : Integer; + end; + + TApdWin32Dispatcher = class(TApdBaseDispatcher) + private + FSerialEvent : TEvent; + protected + function EscapeComFunction(Func : Integer) : Integer; override; + function FlushCom(QueueProp : Integer) : Integer; override; + function GetComError(var Stat : TComStat) : Integer; override; + function GetComEventMask(EvtMask : Integer) : Cardinal; override; + function GetComState(var DCB: TDCB): Integer; override; + function InQueueUsed : Cardinal; override; + function OutBufUsed: Cardinal; override; + function ReadCom(Buf : PAnsiChar; Size: Integer) : Integer; override; + function SetComState(var DCB : TDCB) : Integer; override; + function SetupCom(InSize, OutSize : Integer) : Boolean; override; + procedure StartDispatcher; override; + procedure StopDispatcher; override; + function WaitComEvent(var EvtMask : DWORD; + lpOverlapped : POverlapped) : Boolean; override; + function WriteCom(Buf : PAnsiChar; Size: Integer) : Integer; override; + public + constructor Create(Owner : TObject); + destructor Destroy; override; + function CloseCom : Integer; override; + function OpenCom(ComName: PChar; InQueue, OutQueue : Cardinal) : Integer; override; + function ProcessCommunications : Integer; override; + function CheckPort(ComName: PChar): Boolean; override; + end; + + TApdTAPI32Dispatcher = class(TApdWin32Dispatcher) + public + constructor Create(Owner : TObject; InCid : Integer); + function OpenCom(ComName: PChar; InQueue, + OutQueue : Cardinal) : Integer; override; + end; + +implementation + +uses Math, StrUtils; + +// TApdWin32Dispatcher methods +// +constructor TApdWin32Dispatcher.Create(Owner : TObject); +begin + inherited Create(Owner); + FSerialEvent := TEvent.Create(nil, False, False, ''); +end; + +destructor TApdWin32Dispatcher.Destroy; +begin + if (Assigned(FSerialEvent)) then + FSerialEvent.Free; + inherited Destroy; +end; + +function TApdWin32Dispatcher.CheckPort(ComName: PChar): Boolean; +// Returns true if a port exists +var + Tmp: string; + CC: PCommConfig; + Len: Cardinal; +begin + Tmp := ComName; + if AnsiStartsText('\\.\', Tmp) then + Delete(Tmp, 1, 4); + + New(CC); + try + FillChar(CC^, SizeOf(CC^), 0); + CC^.dwSize := SizeOf(CC^); + Len := SizeOf(CC^); + Result := GetDefaultCommConfig(PChar(Tmp), CC^, Len); + finally + Dispose(CC); + end; + if (not Result) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) then + begin + GetMem(CC, Len); + try + FillChar(CC^, SizeOf(CC^), 0); + CC^.dwSize := SizeOf(CC^); + Result := GetDefaultCommConfig(PChar(Tmp), CC^, Len); + finally + FreeMem(CC); + end; + end; +end; + +// Close the comport and wait for the I/O threads to terminate +function TApdWin32Dispatcher.CloseCom : Integer; +var + ET : EventTimer; +begin + // Under certain circumstances, it is possible that CloseCom can be called + // recursively. In that event, we don't want to be re-executing this code. + // So, set a flag to show that we are inside this method and check it + // every time we enter. If it is already set, just exit and do nothing. + // This used to be accomplished by acquiring the DataSection critical section + // but this lead to occasional deadlocks. + + EnterCriticalSection(DataSection); + if (CloseComActive) then + begin + LeaveCriticalSection(DataSection); + Result := 0; + Exit; + end; + CloseComActive := True; + LeaveCriticalSection(DataSection); + + try + if DispActive then + begin + { Set the flag to kill the threads next time they wake, or after } + { their current processing } + KillThreads := True; + + if Assigned(StatusThread) then + begin + {Force the comm thread to wake...} + SetCommMask(CidEx, 0); + SetEvent(ReadyEvent); + {...and wait for it to die} + while (StatusThread <> nil) do + SafeYield; + end; + + if Assigned(OutThread) then + begin + {Force the output thread to wake...} + SetEvent(OutFlushEvent); + {...and wait for it to die} + while (OutThread <> nil) do + SafeYield; + end; + + if Assigned(ComThread) then + begin + {Force the comm thread to wake...} + FSerialEvent.SetEvent; + {... and wait for it to die} + ResetEvent(GeneralEvent); + while (ComThread <> nil) do + SafeYield; + end; + + {Now kill the timer} + KillTimer(0, TimerID); + + if Assigned(DispThread) then + begin + {Wait for it to die} + NewTimer(ET, 36); { start a 2-second timer to prevent blocks } + while (DispThread <> nil) and not(TimerExpired(ET)) do + SafeYield; + if DispThread <> nil then + begin + {$IFDEF DebugThreadConsole} + WriteLn('DispThread<>nil'); + {$ENDIF} + { thread didn't die, reset the event } + SetEvent(ComEvent); + {Wait for it to die yet again} + NewTimer(ET, 36); { start a 2-second timer to prevent blocks } + while (DispThread <> nil) and not(TimerExpired(ET)) do + SafeYield; + if DispThread <> nil then + { disp thread is not responding, brutally terminate it } + DispThread.Free; + end; + {$IFDEF DebugThreadConsole} + Writeln(ThreadStatus(DispKill)); + {$ENDIF} + end; + {$IFDEF DebugThreadConsole} + Writeln(ThreadStatus(ComKill)); + {$ENDIF} + end; + {Close the comport} + if (CidEx >= 0) then + begin + if CloseHandle(CidEx) then + begin + Result := 0; + CidEx := -1; + end else + Result := -1; + end else + Result := 0; + finally + CloseComActive := False; + end; +end; + +function TApdWin32Dispatcher.EscapeComFunction(Func: Integer): Integer; +begin + EscapeCommFunction(CidEx, Func); + Result := 0; +end; +// Flush the I/O buffers. QueueProp = 0 - flush output queues. QueueProp = 1 - flush input. +function TApdWin32Dispatcher.FlushCom(QueueProp : Integer) : Integer; +begin + Result := 0; + if ((QueueProp = 0) and Assigned(OutThread)) then + begin + // Flush output buffers + EnterCriticalSection(OutputSection); + try + OBufFull := False; + OBufHead := 0; + OBufTail := 0; + finally + LeaveCriticalSection(OutputSection); + end; + Result := Integer(PurgeComm(CidEx, PURGE_TXABORT or PURGE_TXCLEAR)); + // Wake up the output thread in case it was waiting for I/O completion + // and Windows failed to wake it up after we flushed the buffers. + SetEvent(OutFlushEvent); + WaitForSingleObject(GeneralEvent, 5000); + end; + if (QueueProp = 1) then + begin + // Flush input buffers + Result := Integer(PurgeComm(CidEx, PURGE_RXABORT or PURGE_RXCLEAR)); + FQueue.Clear; + end; +end; +// Get the current error and status +function TApdWin32Dispatcher.GetComError(var Stat: TComStat): Integer; +var + Errors : DWORD; +begin + if (ClearCommError(CidEx, Errors, @Stat)) then + Result := Errors + else + Result := 0; + {Replace information about Windows output buffer with our own} + Stat.cbOutQue := OutBufUsed; +end; +// Set the communications event mask +function TApdWin32Dispatcher.GetComEventMask(EvtMask: Integer): Cardinal; +begin + Result := 0; +end; +// Fill in DCB with the current communications state +function TApdWin32Dispatcher.GetComState(var DCB: TDCB): Integer; +begin +if Integer(GetCommState(CidEx, DCB)) = 1 then + Result := 0 +else + Result := -1; +end; +// Open the COM port specified by ComName +function TApdWin32Dispatcher.OpenCom(ComName: PChar; InQueue, OutQueue: Cardinal): Integer; +begin + {Open the device} + Result := CreateFile(ComName, {name} + GENERIC_READ or GENERIC_WRITE, {access attributes} + 0, {no sharing} + nil, {no security} + OPEN_EXISTING, {creation action} + FILE_ATTRIBUTE_NORMAL or + FILE_FLAG_OVERLAPPED, {attributes} + 0); {no template} + + if Result <> Integer(INVALID_HANDLE_VALUE) then + begin + CidEx := Result; + end else + {Failed to open port, just return error signal, caller will + call GetLastError to get actual error code} + Result := -1; +end; +// Return the number of bytes available to be read from the input QueueProp. Returns +// zero if the first buffer on the QueueProp is not a data buffer, returns the number +// of bytes available in the first buffer otherwise. +function TApdWin32Dispatcher.InQueueUsed : Cardinal; +var + bfr : TIOBuffer; +begin + bfr := FQueue.Peek; + if (Assigned(bfr)) then + begin + if (bfr is TDataBuffer) then + begin + Result := TDataBuffer(bfr).BytesUsed - TDataBuffer(bfr).BytesRead; + bfr.InUse := False; + end else + begin + Result := 0; + bfr.InUse := False; + end; + end else + Result := 0; +end; +// Return the number of bytes currently used in the output buffer +function TApdWin32Dispatcher.OutBufUsed: Cardinal; +begin + EnterCriticalSection(OutputSection); + try + Result := 0; + if OBufFull then + Result := OutQue + else if OBufHead > OBufTail then + {Buffer is not wrapped} + Result := OBufHead - OBufTail + else if OBufHead < OBufTail then + {Buffer is wrapped} + Result := OBufHead + (OutQue - OBufTail); + finally + LeaveCriticalSection(OutputSection); + end; +end; +// Communications are running in separate threads -- give them a chance +function TApdWin32Dispatcher.ProcessCommunications : Integer; +begin + Sleep(0); + Result := 0; +end; +// Rather than reading directly from the serial port, as we used to do, we +// now read from the input QueueProp. +function TApdWin32Dispatcher.ReadCom(Buf : PAnsiChar; Size: Integer) : Integer; +var + bfr : TIOBuffer; + len : Integer; + bytesToRead : Integer; + done : Boolean; +begin + len := Size; + done := False; + while (not done) do + begin + bfr := FQueue.Peek; + // We can only read if the first buffer on the QueueProp is a data buffer. + // If it is a status buffer, it must be processed first. + if (Assigned(bfr)) then + begin + if (bfr is TDataBuffer) then + begin + with TDataBuffer(bfr) do + begin + // Read either all the data in the buffer or as much as the caller + // can accept. + bytesToRead := Min(len, BytesUsed - BytesRead); + Move((Data + BytesRead)^, Buf^, bytesToRead);// --sm check + BytesRead := BytesRead + bytesToRead; + Dec(len, bytesToRead); + Inc(Buf, bytesToRead); + // If all data has been read from the buffer, remove it from the QueueProp + // and free it. Otherwise, leave it on the QueueProp so we can read + // the remainder on the next call to this subroutine. + if (BytesRead >= BytesUsed) then + begin + FQueue.Pop; + Free; + end else + InUse := False; + if (len <= 0) then + done := True; + end; + end else + begin + bfr.InUse := False; + done := True; + end; + end else + done := True; + end; + Result := Size - len; // ttl # bytes read +end; +// Set the a new communications device state from DCB +function TApdWin32Dispatcher.SetComState(var DCB: TDCB): Integer; +begin +if SetCommState(CidEx, DCB) then + Result := 0 +else + Result := -Integer(GetLastError); +end; + +// Set new in/out buffer sizes +function TApdWin32Dispatcher.SetupCom(InSize, OutSize : Integer) : Boolean; +begin + Result := SetupComm(CidEx, InSize, OutSize); +end; + +// Start all threads and generally get the dispatcher ready to go +procedure TApdWin32Dispatcher.StartDispatcher; +begin + EnterCriticalSection(DataSection); + try + if (DispActive) then + raise Exception.Create('Dispatcher already started.'); + DispActive := True; + KillThreads := False; + ComThread := TReadThread.Create(Self); + WaitForSingleObject(GeneralEvent, ThreadStartWait); + fDispThread := TDispThread.Create(Self); + WaitForSingleObject(GeneralEvent, ThreadStartWait); + OutThread := TWriteThread.Create(Self); + WaitForSingleObject(GeneralEvent, ThreadStartWait); + StatusThread := TStatusThread.Create(Self); + WaitForSingleObject(GeneralEvent, ThreadStartWait); + finally + LeaveCriticalSection(DataSection); + end; +end; + +// Shutdown the dispatcher +procedure TApdWin32Dispatcher.StopDispatcher; +begin + if DispActive then + CloseCom; + + if ComEvent <> INVALID_HANDLE_VALUE then + begin + if CloseHandle(ComEvent) then + ComEvent := INVALID_HANDLE_VALUE; + end; + + if ReadyEvent <> INVALID_HANDLE_VALUE then + begin + if CloseHandle(ReadyEvent) then + ReadyEvent := INVALID_HANDLE_VALUE; + end; + + if GeneralEvent <> INVALID_HANDLE_VALUE then + begin + if CloseHandle(GeneralEvent) then + GeneralEvent := INVALID_HANDLE_VALUE; + end; + + if OutputEvent <> INVALID_HANDLE_VALUE then + begin + if CloseHandle(OutputEvent) then + OutputEvent := INVALID_HANDLE_VALUE; + end; + + if SentEvent <> INVALID_HANDLE_VALUE then + begin + if CloseHandle(SentEvent) then + SentEvent := INVALID_HANDLE_VALUE; + end; + + if OutFlushEvent <> INVALID_HANDLE_VALUE then + begin + if CloseHandle(OutFlushEvent) then + OutFlushEvent := INVALID_HANDLE_VALUE; + end; +end; + +// This doesn't apply to WIN32 dispatcher any more +function TApdWin32Dispatcher.WaitComEvent(var EvtMask : DWORD; + lpOverlapped : POverlapped) : Boolean; +begin + EvtMask := 0; + Result := True; +end; + +// Place outbound data into the output buffer & wake up the output thread +function TApdWin32Dispatcher.WriteCom(Buf: PAnsiChar; Size: Integer): Integer; +type + PBArray = ^TBArray; + TBArray = array[0..pred(High(Integer))] of Byte; +var + SizeAtEnd : Integer; + LeftOver : Integer; +begin + {Add the data to the output QueueProp} + EnterCriticalSection(OutputSection); + try + {we already know at this point that there is enough room for the block} + SizeAtEnd := OutQue - OBufHead; + if SizeAtEnd >= Size then + begin + {can move data to output QueueProp in one block} + Move(Buf^, OBuffer^[OBufHead], Size); + if SizeAtEnd = Size then + OBufHead := 0 + else + Inc(OBufHead, Size); + end else + begin + { need to use two moves } + Move(Buf^, OBuffer^[OBufHead], SizeAtEnd); + LeftOver := Size - SizeAtEnd; + Move(PBArray(Buf)^[SizeAtEnd], OBuffer^, LeftOver); + OBufHead := LeftOver; + end; + finally + LeaveCriticalSection(OutputSection); + end; + {...finally, wake up the output thread to send the data} + SetEvent(OutputEvent); + Result := Size; {report all was sent} +end; + +// TApdWin32Threads. Contains some general support routines required by both +// read & write threads. +procedure TApdWin32Thread.AddDispatchEntry(DT : TDispatchType; + DST : TDispatchSubType; + Data : Cardinal; + Buffer : Pointer; + BufferLen : Cardinal); +begin + TApdWin32Dispatcher(H).AddDispatchEntry(DT, DST, Data, Buffer, BufferLen); +end; + +function TApdWin32Thread.GetComHandle : THandle; +begin + Result := TApdWin32Dispatcher(H).ComHandle; +end; + +function TApdWin32Thread.GetDLoggingOn : Boolean; +begin + Result := TApdWin32Dispatcher(H).DLoggingOn; +end; + +function TApdWin32Thread.GetGeneralEvent : THandle; +begin + Result := TApdWin32Dispatcher(H).GeneralEvent; +end; + +function TApdWin32Thread.GetKillThreads : Boolean; +begin + Result := TApdWin32Dispatcher(H).KillThreads; +end; + +function TApdWin32Thread.GetQueue : TIOQueue; +begin + Result := TApdWin32Dispatcher(H).FQueue; +end; + +function TApdWin32Thread.GetSerialEvent : TEvent; +begin + Result := TApdWin32Dispatcher(H).FSerialEvent; +end; + +procedure TApdWin32Thread.SetKillThreads(value : Boolean); +begin + TApdWin32Dispatcher(H).KillThreads := value; +end; + +procedure TApdWin32Thread.ThreadGone(Sender : TObject); +begin + TApdWin32Dispatcher(H).ThreadGone(Sender); +end; + +procedure TApdWin32Thread.ThreadStart(Sender : TObject); +begin + TApdWin32Dispatcher(H).ThreadStart(Sender); +end; + +// Wait for an overlapped I/O to complete. We wake up every 100ms and check to +// see if the dispatcher has been shutdown. +function TApdWin32Thread.WaitForOverlapped(ovl : POverlapped) : Integer; +var + stat : DWORD; + bytesRead : Cardinal; +begin + repeat + stat := WaitForSingleObject(ovl.hEvent, 100); + until ((stat <> WAIT_TIMEOUT) or Terminated or KillThreads); + case stat of + WAIT_OBJECT_0: + if (GetOverlappedResult(ComHandle, + ovl^, + bytesRead, + True)) then + begin + Result := bytesRead; + ResetEvent(ovl.hEvent); + end else + Result := ecDeviceRead; + WAIT_TIMEOUT: + Result := 0; + else + Result := ecDeviceRead; + end; +end; + +// TReadThread methods. This thread does nothing except wait for input +// from the comm port. When input is received it is placed onto the QueueProp +// for the dispatcher thread to process. +procedure TReadThread.Execute; +var + dbfr : TDataBuffer; + bytesRead : Integer; + stat : TWaitResult; + rovl : TOverlapped; + Timeouts : TCommTimeouts; + istat : Integer; +begin + ThreadStart(Self); +{$IFDEF DebugThreads} + if (DLoggingOn) then + AddDispatchEntry(dtThread, dstThreadStart, 1, nil, 0); +{$ENDIF} + FillChar(rovl, SizeOf(rovl), 0); + rovl.hEvent := CreateEvent(nil, True, False, nil); + dbfr := nil; + try + // Set the timeouts so that a read will return immediately. + FillChar(Timeouts, SizeOf(TCommTimeouts), 0); + Timeouts.ReadIntervalTimeout := MaxDWord; + SetCommTimeouts(ComHandle, Timeouts); + + ReturnValue := 0; + while ((not Terminated) and (not KillThreads)) do + begin + // Wait for something to happen on the serial port +{$IFDEF DebugThreads} + if (DLoggingOn) then + AddDispatchEntry(dtThread, dstThreadSleep, 1, nil, 0); +{$ENDIF} + stat := SerialEvent.WaitFor(50); + if ((stat <> wrSignaled) and (stat <> wrTimeout)) then + begin + ReturnValue := ecDeviceRead; + KillThreads := True; + Continue; + end; +{$IFDEF DebugThreads} + if (DLoggingOn) then + AddDispatchEntry(dtThread, dstThreadWake, 1, nil, 0); +{$ENDIF} + // Was it an input arrival notification? If so, read the + // available input & QueueProp it to the dispatcher thread. + try + if (not Assigned(dbfr)) then + dbfr := TDataBuffer.Create(IO_BUFFER_SIZE); + except + dbfr := nil; + ReturnValue := ecNoMem; + KillThreads := True; + Continue; + end; + bytesRead := ReadSerial(dbfr.Data, dbfr.Size, @rovl); + while (bytesRead > 0) do + begin +{$IFDEF DebugThreads} + if (DLoggingOn) then + AddDispatchEntry(dtThread, + dstThreadDataQueued, + ComHandle, + dbfr.Data, + bytesRead); +{$ENDIF} + dbfr.BytesUsed := bytesRead; + QueueProp.Push(dbfr); + try + dbfr := TDataBuffer.Create(IO_BUFFER_SIZE); + except + dbfr := nil; + ReturnValue := ecNoMem; + KillThreads := True; + Break; + end; + bytesRead := ReadSerial(dbfr.Data, dbfr.Size, @rovl); + end; + if (bytesRead < 0) then + begin + istat := GetLastError; +{$IFDEF DebugSerialIO} + MessageBox(0, + PChar(Format('ReadSerial failed! Error = %d.', + [istat])), + '', + MB_OK or MB_APPLMODAL or MB_ICONEXCLAMATION); +{$ENDIF} + // An invalid handle error means that someone else (probably + // TAPI) has closed the port. So just quit without an error. + if (istat <> ERROR_INVALID_HANDLE) then + ReturnValue := ecDeviceRead; + KillThreads := True; + Continue; + end; + end; + finally + CloseHandle(rovl.hEvent); + if (Assigned(dbfr)) then + dbfr.Free; +{$IFDEF DebugThreads} + if (DLoggingOn) then + AddDispatchEntry(dtThread, dstThreadExit, 1, nil, 0); +{$ENDIF} + ThreadGone(Self); + end; +end; +// Read up to Size bytes from the serial port into Buf. Return the number of +// bytes read or a negative error number. An error code of ERROR_OPERATION_ABORTED +// is caused by flushing the com port so we just ignore it. +function TReadThread.ReadSerial(Buf : PAnsiChar; + Size : Integer; + ovl : POverlapped) : Integer; +var + bytesRead : Cardinal; + istat : Integer; +begin + if (not ReadFile(ComHandle, Buf^, Size, bytesRead, ovl)) then + begin + istat := GetLastError; + if (istat = ERROR_IO_PENDING) then + begin + Result := WaitForOverlapped(ovl); + if (Result < 0) then + begin + istat := GetLastError; + if (GetLastError = ERROR_OPERATION_ABORTED) then + Result := 0 + else + TApdBaseDispatcher(H).LastWinError := istat; + end; + end else + begin + TApdBaseDispatcher(H).LastWinError := istat; + Result := ecDeviceRead; + end; + end else + Result := bytesRead; +end; +// TWriteThread methods. This thread does nothing except wait for data to +// be written to the comm port. When output arrives it is written to the +// port. +function TWriteThread.DataInBuffer : Boolean; +begin + with TApdWin32Dispatcher(H) do begin + EnterCriticalSection(OutputSection); + try + DataInBuffer := OBufFull or (OBufHead <> OBufTail); + finally + LeaveCriticalSection(OutputSection); + end; + end; +end; + +procedure TWriteThread.Execute; +var + outEvents : array [0..1] of THandle; + stat : DWORD; + ovl : TOverlapped; + istat : Integer; +begin + ThreadStart(Self); +{$IFDEF DebugThreads} + if (DLoggingOn) then + AddDispatchEntry(dtThread, dstThreadStart, 3, nil, 0); +{$ENDIF} + outEvents[0] := OutputEvent; + outEvents[1] := OutFlushEvent; + FillChar(ovl, SizeOf(ovl), 0); + ovl.hEvent := CreateEvent(nil, True, False, nil); + try + ReturnValue := 0; + while ((not Terminated) and (not KillThreads)) do + begin +{$IFDEF DebugThreads} + if (DLoggingOn) then + AddDispatchEntry(dtThread, dstThreadSleep, 3, nil, 0); +{$ENDIF} + // Wait for output to appear in the QueueProp or for a flush request + stat := WaitForMultipleObjects(Length(outEvents), + @outEvents[0], + False, + 100); +{$IFDEF DebugThreads} + if (DLoggingOn) then + AddDispatchEntry(dtThread, dstThreadWake, 3, nil, 0); +{$ENDIF} + case stat of + WAIT_OBJECT_0: + // Output has arrived in buffer, send it + if (not KillThreads) then + if (WriteSerial(@ovl) <> 0) then + begin + istat := GetLastError; +{$IFDEF DebugSerialIO} + MessageBox(0, + PChar(Format('WriteSerial failed! Error = %d.', + [istat])), + '', + MB_OK or MB_APPLMODAL or MB_ICONEXCLAMATION); +{$ENDIF} + // An invalid handle error means that someone else (probably + // TAPI) has closed the port. So just quit without an error. + if (istat <> ERROR_INVALID_HANDLE) then + begin + TApdBaseDispatcher(H).LastWinError := istat; + ReturnValue := ecDeviceWrite; + end; + KillThreads := True; + end; + WAIT_OBJECT_0 + 1: + // Flush of output buffer requested, acknowledge & continue + SetEvent(GeneralEvent); + WAIT_TIMEOUT: + ; + else + begin + TApdBaseDispatcher(H).LastWinError := GetLastError; + ReturnValue := ecDeviceWrite; + KillThreads := True; + end; + end; + end; + finally + CloseHandle(ovl.hEvent); +{$IFDEF DebugThreads} + if (DLoggingOn) then + AddDispatchEntry(dtThread, dstThreadExit, 3, nil, 0); +{$ENDIF} + ThreadGone(Self); + end; +end; + +function TWriteThread.GetOutFlushEvent : THandle; +begin + Result := TApdWin32Dispatcher(H).OutFlushEvent; +end; + +function TWriteThread.GetOutputEvent : THandle; +begin + Result := TApdWin32Dispatcher(H).OutputEvent; +end; +// Write all data currently in the output buffer to the serial port. The +// output is copied to a temporary buffer first to free the main output buffer +// faster and to make buffer flush requests easier to handle properly. +function TWriteThread.WriteSerial(ovl : POverlapped) : Integer; +var + numToWrite : Integer; + numWritten : Cardinal; + count : Integer; + tempBuff : POBuffer; + stat : Integer; +begin + tempBuff := nil; + try + while (DataInBuffer) do + begin + with TApdWin32Dispatcher(H) do + begin + EnterCriticalSection(OutputSection); + try + // Move everything from the main buffer to a temporary buffer. + // This accomplishes 2 things: 1) It frees the main buffer so that + // that main thread can continue writing sooner. 2) It simplifies + // matters when we receive a flush request while waiting for I/O + // to complete because the flush routine can do its thing without + // having to worry about messing with our buffer management. + if OBufTail < OBufHead then + begin + numToWrite := OBufHead - OBufTail; + GetMem(tempBuff, numToWrite); + Move(OBuffer^[OBufTail], tempBuff^, numToWrite); + end else + begin + numToWrite := (OutQue - OBufTail) + OBufHead; + GetMem(tempBuff, numToWrite); + Move(OBuffer^[OBufTail], tempBuff^, OutQue - OBufTail); + Move(OBuffer^[0], tempBuff^[OutQue - OBufTail], OBufHead); + end; + // Reset the QueueProp head and tail + OBufHead := 0; + OBufTail := 0; + OBufFull := False; + finally + LeaveCriticalSection(OutputSection); + end; + // write the data that we found in tbe buffer & wait for I/O + // completion. Wait for all data in tempBuff to be written + count := 0; + while (count < numToWrite) do + begin +{$IFDEF DebugThreads} + if (DLoggingOn) then + AddDispatchEntry(dtThread, + dstThreadDataWritten, + ComHandle, + tempBuff, + numToWrite - count); +{$ENDIF} + if (not WriteFile(ComHandle, + tempBuff^[count], + numToWrite - count, + numWritten, + ovl)) then + if (GetLastError = ERROR_IO_PENDING) then + begin + stat := WaitForOverlapped(ovl); + case stat of + // Flush request. Set the general event & quit. + -(WAIT_OBJECT_0 + 1): + begin + SetEvent(GeneralEvent); + Result := 0; + Exit; + end; + // I/O error. Propogate the error and quit. + // An error of ERROR_OPERATION_ABORTED is caused + // by flushing the com port so we just ignore it. + ecDeviceWrite: + begin + stat := GetLastError; + if (stat = ERROR_OPERATION_ABORTED) then + Result := 0 + else + begin + LastWinError := stat; + Result := ecDeviceWrite; + end; + Exit; + end; + // I/O complete. Increment count of bytes written & loop + else + Inc(count, stat); + end; + end else + begin + LastWinError := GetLastError; + Result := ecDeviceWrite; + Exit; + end + else + // Increment count of bytes written & loop + Inc(count, numWritten); + end; + // All data written, release the buffer + FreeMem(tempBuff); + tempBuff := nil; + // No more data in buffer, if in RS485 mode wait for TE + if Win32Platform <> VER_PLATFORM_WIN32_NT then + if RS485Mode then + begin + repeat + until (PortIn(BaseAddress+5) and $40) <> 0; + SetRTS(False); + end; + end; + end; + Result := 0; + finally + if (Assigned(tempBuff)) then + FreeMem(tempBuff); + end; +end; +// Wait for either the event signalling I/O completion of the OutputFlushEvent. +// Returns the number of bytes written if I/O complete, -(WAIT_IBJECT_0 + 1) if +// flush requested or ecDeviceWrite if error. +function TWriteThread.WaitForOverlapped(ovl : POverlapped) : Integer; +var + waitEvents : array [0..1] of THandle; + stat : DWORD; + bytesWritten : Cardinal; +begin + waitEvents[0] := ovl.hEvent; + waitEvents[1] := OutFlushEvent; + repeat + stat := WaitForMultipleObjects(Length(waitEvents), + @waitEvents[0], + False, + 100); + until ((stat <> WAIT_TIMEOUT) or Terminated or KillThreads); + case stat of + WAIT_OBJECT_0: + if (GetOverlappedResult(ComHandle, ovl^, bytesWritten, True)) then + begin + Result := BytesWritten; + ResetEvent(ovl.hEvent); + end else + begin + TApdBaseDispatcher(H).LastWinError := GetLastError; + Result := ecDeviceWrite; + end; + WAIT_OBJECT_0 + 1: + Result := -(WAIT_OBJECT_0 + 1); + else + begin + TApdBaseDispatcher(H).LastWinError := GetLastError; + Result := ecDeviceWrite; + end; + end; +end; + +// TStatusThread methods. This thread does nothing except wait for line and / or +// modem events. When an event occurs a status buffer is added to the QueueProp +// for processing by the dispatcher thread. +procedure TStatusThread.Execute; +var + evt : DWORD; + stat : Integer; + wovl : TOverlapped; + sbfr : TStatusBuffer; + istat : Integer; +begin + ThreadStart(Self); +{$IFDEF DebugThreads} + if (DLoggingOn) then + AddDispatchEntry(dtThread, dstThreadStart, 4, nil, 0); +{$ENDIF} + FillChar(wovl, SizeOf(wovl), 0); + wovl.hEvent := CreateEvent(nil, True, False, nil); + sbfr := nil; + try + // Set the mask used to signal WaitCommEvent which events to wait for. + { Note, NuMega's BoundsChecker will flag a bogus error on the } + { following statement because we use the undocumented ring_te flag } + if Win32Platform = VER_PLATFORM_WIN32_NT then + LastMask := DefEventMask and (not ev_RingTe) + else + LastMask := DefEventMask; + SetCommMask(ComHandle, LastMask); + + ReturnValue := 0; + while ((not Terminated) and (not KillThreads)) do + begin +{$IFDEF DebugThreads} + if (DLoggingOn) then + AddDispatchEntry(dtThread, dstThreadSleep, 4, nil, 0); +{$ENDIF} + stat := WaitSerialEvent(evt, @wovl); + if (stat < 0) then + begin + istat := GetLastError; +{$IFDEF DebugSerialIO} + MessageBox(0, + PChar(Format('ReadSerial failed! Error = %d.', + [istat])), + '', + MB_OK or MB_APPLMODAL or MB_ICONEXCLAMATION); +{$ENDIF} + // An invalid handle error means that someone else (probably + // TAPI) has closed the port. So just quit without an error. + if (istat <> ERROR_INVALID_HANDLE) then + ReturnValue := stat; + KillThreads := True; + Continue; + end; +{$IFDEF DebugThreads} + if (DLoggingOn) then + AddDispatchEntry(dtThread, dstThreadWake, 4, nil, 0); +{$ENDIF} + // Was it a data notification event? If so, kick the read thread + // in the butt. + if ((evt and EV_RXCHAR) <> 0) then + SerialEvent.SetEvent; + // Was it a modem or line status change? If so, QueueProp + // a status buffer to the dispatcher thread. + if ((evt and (ModemEvent or LineEvent)) <> 0) then + begin + try + sbfr := TStatusBuffer.Create; + except + sbfr := nil; + ReturnValue := ecNoMem; + KillThreads := True; + end; +{$IFDEF DebugThreads} + if (DLoggingOn) then + AddDispatchEntry(dtThread, + dstThreadStatusQueued, + ComHandle, + @evt, + SizeOf(evt)); +{$ENDIF} + sbfr.Status := evt; + QueueProp.Push(sbfr); + sbfr := nil; + end; + end; + finally + CloseHandle(wovl.hEvent); + if (Assigned(sbfr)) then + sbfr.Free; +{$IFDEF DebugThreads} + if (DLoggingOn) then + AddDispatchEntry(dtThread, dstThreadExit, 4, nil, 0); +{$ENDIF} + ThreadGone(Self); + end; +end; +// Wait for an event on the serial port. Returns 0 if OK, or a negative error +// number otherwise. It is OK to wait indefinitely for the overlapped I/O +// to complete because we do a SetCommMask in StopDispatcher, which causes +// WaitCommEvent to wake up. +function TStatusThread.WaitSerialEvent(var EvtMask : DWORD; + ovl : POverlapped) : Integer; +var + bStat : Boolean; + istat : Integer; +begin + EvtMask := 0; + bStat := WaitCommEvent(ComHandle, EvtMask, ovl); + if (not bStat) then + begin + // If error is ERROR_INVALID_PARAMETER, assume it's our use of + // ev_RingTe. Clear the flag and try again. + if ((GetLastError = ERROR_INVALID_PARAMETER) and + ((LastMask and EV_RINGTE) <> 0)) then + begin + LastMask := LastMask and (not EV_RINGTE); + SetCommMask(ComHandle, LastMask); + bStat := WaitCommEvent(ComHandle, EvtMask, ovl); + end; + end; + if (not bStat) then + begin + istat := GetLastError; + if (istat = ERROR_IO_PENDING) then + Result := WaitForOverlapped(ovl) + else + begin + TApdBaseDispatcher(H).LastWinError := istat; + Result := ecDeviceRead; + end; + end else + Result := 0; +end; + +constructor TApdTAPI32Dispatcher.Create(Owner : TObject; InCid : Integer); +begin + CidEx := InCid; + inherited Create(Owner); +end; + +function TApdTAPI32Dispatcher.OpenCom(ComName: PChar; InQueue, OutQueue : Cardinal) : Integer; +begin + if CidEx <> 0 then + Result := CidEx + else + begin + Result := ecCommNotOpen; + SetLastError(-Result); + end; +end; + +end. diff --git a/LnsQueue.pas b/LnsQueue.pas new file mode 100644 index 0000000..2e93c2a --- /dev/null +++ b/LnsQueue.pas @@ -0,0 +1,283 @@ +(***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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 TurboPower Async Professional + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1991-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Stephen W. Boyd - Created this module to provide input queueing for + * serial port dispatcher. + * August 2005 + * Sebastian Zierer + * + * ***** END LICENSE BLOCK ***** *) +{Global defines potentially affecting this unit} +{$I AWDEFINE.INC} + +unit LnsQueue; + +interface + +uses Windows, SysUtils, SyncObjs, Classes, OoMisc; + +const + IO_BUFFER_SIZE = 256; + +type + // An object to encapsulate an I/O buffer. There a 3 kinds of buffer. Data + // buffers trace (logging) buffers and status buffers. + TIOBuffer = class(TObject) + protected + FInUse : Boolean; // Set to true while processing events + // and triggers for this buffer. + FDataSize : Integer; + public + property InUse : Boolean read FInUse write FInUse; + property Size : Integer read FDataSize; + end; + + TDataBuffer = class(TIOBuffer) + private + FData : PAnsiChar; + FDataUsed : Integer; + FDataRead : Integer; + public + constructor Create(size : Integer); + destructor Destroy; override; + property Data : PAnsiChar read FData write FData; + property BytesUsed : Integer read FDataUsed write FDataUsed; + property BytesRead : Integer read FDataRead write FDataRead; + end; + + TStatusBuffer = class(TIOBuffer) + private + FStatus : DWORD; + public + property Status : DWORD read FStatus write FStatus; + end; + + TLogBuffer = class(TIOBuffer) + private + FType : TDispatchType; + FSubType : TDispatchSubType; + FTime : DWord; + FData : Cardinal; + FBuffer : PAnsiChar; + + function GetMoreData : Cardinal; + public + constructor Create(typ : TDispatchType; + styp : TDispatchSubType; + tim : DWORD; + data : Cardinal; + bfr : PAnsiChar; + bfrLen : Integer); + destructor Destroy; override; + + property drType : TDispatchType read FType; + property drSubType : TDispatchSubType read FSubType; + property drTime : DWORD read FTime; + property drData : Cardinal read FData; + property drMoreData : Cardinal read GetMoreData; + property drBuffer : PAnsiChar read FBuffer; + end; + // A queue to hold serial port I/O buffers for delivery to / from the + // dispatcher thread. Also used to queue items to the dispatcher log. + TIOQueue = class(TList) + private + FLock : TCriticalSection; + FEvent : TEvent; + FBytesQueued: Integer; + public + constructor Create; + destructor Destroy; override; + procedure Clear; override; + function Peek : TIOBuffer; + function Pop : TIOBuffer; + procedure Push(item : TIOBuffer); + function WaitForBuffer(tmo : Integer) : TWaitResult; + + property BytesQueued : Integer read FBytesQueued; + end; + +implementation + +{ TDataBuffer methods } +constructor TDataBuffer.Create(size : Integer); +begin + inherited Create; + FData := AllocMem(size); + if (not Assigned(FData)) then + raise Exception.Create('Insufficient memory to allocate I/O buffer.'); + FDataSize := size; + FDataUsed := 0; + FDataRead := 0; +end; + +destructor TDataBuffer.Destroy; +begin + if (Assigned(FData)) then + FreeMem(FData); + inherited Destroy; +end; +{ TLogBuffer methods } +constructor TLogBuffer.Create(typ : TDispatchType; + styp : TDispatchSubType; + tim : DWORD; + data : Cardinal; + bfr : PAnsiChar; + bfrLen : Integer); +begin + inherited Create; + FType := typ; + FSubType := styp; + FTime := tim; + FData := data; + FDataSize := bfrLen; + if (FDataSize > 0) then + begin + GetMem(FBuffer, FDataSize); + Move(bfr^, FBuffer^, FDataSize); + end; +end; + +destructor TLogBuffer.Destroy; +begin + if (Assigned(FBuffer)) then + FreeMem(FBuffer); + inherited Destroy; +end; + +function TLogBuffer.GetMoreData : Cardinal; +begin + Result := Cardinal(FDataSize); +end; +{ TIOQueue methods } +constructor TIOQueue.Create; +begin + inherited Create; + FLock := TCriticalSection.Create; + FEvent := TEvent.Create(nil, False, False, ''); +end; + +destructor TIOQueue.Destroy; +begin + Clear; + if (Assigned(FLock)) then + begin + FLock.Free; + // We must clear this pointer here so that Clear, which gets called + // by the inherited Destroy method, knows that the lock is no longer + // valid and won't try to acquire it. + FLock := nil; + end; + if (Assigned(FEvent)) then + FEvent.Free; + inherited Destroy; +end; +// Remove all non-InUse buffers from the queue. This used to purge the queue +// when the dispatcher is requested to flush the buffers. +procedure TIOQueue.Clear; +var + i: Integer; +begin + if (Assigned(FLock)) then + FLock.Acquire; + try + i := 0; + while (i < Count) do + with TIOBuffer(Items[i]) do + begin + if (InUse) then + Inc(i) + else + begin + Free; + Delete(i); + end; + end; + finally + if (Assigned(FLock)) then + FLock.Release + else + // If FLock is nil then we are Destroying so we should call the + // inherited clear method to make sure that all memory allocated + // by TList gets released. + inherited Clear; + end; +end; +// Return a pointer to the first buffer without removing it from the queue. +// Sets the FInUse flag to prevent the I/O threads from appending to the +// buffer while the dispatcher thread is reading it. Do not return a buffer +// pointer if the first buffer is being written to by the I/O thread. +function TIOQueue.Peek : TIOBuffer; +begin + FLock.Acquire; + try + if (Count > 0) then + begin + Result := TIOBuffer(Items[0]); + if (Result.InUse) then + Result := nil + else + Result.InUse := True; + end else + Result := nil; + finally + FLock.Release; + end; +end; +// Remove the first buffer from the queue and return a pointer to it. +function TIOQueue.Pop : TIOBuffer; +begin + FLock.Acquire; + try + if (Count > 0) then + begin + Result := TIOBuffer(Items[0]); + Dec(FBytesQueued, Result.Size); + Delete(0); + end else + Result := nil; + finally + FLock.Release; + end; +end; +// Add a new buffer to the end of the queue +procedure TIOQueue.Push(item : TIOBuffer); +begin + FLock.Acquire; + try + Add(item); + Inc(FBytesQueued, item.Size); + FEvent.SetEvent; + finally + FLock.Release; + end; +end; +// Wait for a buffer to appear on the queue. If there is a buffer available, +// we return immediately, otherwise we wait for FEvent to be set. +function TIOQueue.WaitForBuffer(tmo : Integer) : TWaitResult; +begin + if (Count > 0) then + Result := wrSignaled + else + Result := FEvent.WaitFor(tmo); +end; + +end. diff --git a/MSCommLib_TLB.dcu b/MSCommLib_TLB.dcu index 707fabd..4c6ccaa 100644 Binary files a/MSCommLib_TLB.dcu and b/MSCommLib_TLB.dcu differ diff --git a/Notice avancée pour les signaux complexes GL.pdf b/Notice avancée pour les signaux complexes GL.pdf index d8e71e6..3b2af64 100644 Binary files a/Notice avancée pour les signaux complexes GL.pdf and b/Notice avancée pour les signaux complexes GL.pdf differ diff --git a/Notice d'utilisation des signaux_complexes_GL_V9.1.pdf b/Notice d'utilisation des signaux_complexes_GL_V9.2.pdf similarity index 79% rename from Notice d'utilisation des signaux_complexes_GL_V9.1.pdf rename to Notice d'utilisation des signaux_complexes_GL_V9.2.pdf index 9b3bfcb..8c57693 100644 Binary files a/Notice d'utilisation des signaux_complexes_GL_V9.1.pdf and b/Notice d'utilisation des signaux_complexes_GL_V9.2.pdf differ diff --git a/OoMisc.pas b/OoMisc.pas new file mode 100644 index 0000000..5235f66 --- /dev/null +++ b/OoMisc.pas @@ -0,0 +1,3894 @@ +(***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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 TurboPower Async Professional + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1991-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Sulaiman Mah + * Sean B. Durkin + * Sebastian Zierer + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* OOMISC.PAS 5.00 *} +{*********************************************************} +{* Miscellaneous supporting methods and types *} +{*********************************************************} + +{ + OOMisc is our catch-all unit for supporting methods and definitions. + OOMisc is used by almost all APRO units, and is automatically included + in the uses clause when an APRO component is dropped on a form. + The APRO base classes are defined here also. + A bit of APRO trivia: OOMisc stands for "Object Oriented Miscellaneous", + and was introduced in the early DOS days. +} + +{Global defines potentially affecting this unit} +{$I AWDEFINE.INC} + +unit OoMisc; + {-Unit for miscellaneous routines} + +interface + +uses + Windows, + Classes, + Controls, + ShellAPI, + OleCtrls, + Forms, + Graphics, + MMSystem, + SysUtils, + Messages; + +const + ApVersionStr = 'v5.00'; + {$IFDEF Apax} + ApaxVersionStr = 'v1.14'; // SWB + {$ENDIF} + + { Product name} + ApdProductName = 'Async Professional'; + ApdShortProductName = 'APRO'; + + ApdVendor = 'TurboPower Software Company'; + ApdVendorURL = 'http://www.TurboPower.com'; + + { Version numbers } + ApdXSLImplementation = 0.0; + ApdXMLSpecification = '1.0'; + + fsPathName = 255; + fsDirectory = 255; + fsFileName = 255; + fsExtension = 255; + fsName = 255; + + {shareable reading file mode} + ApdShareFileRead = $40; + +const + { Printer driver consts } + ApdDefFileName = 'C:\DEFAULT.APF'; + ApdPipeTimeout = 5000; { ms } + ApdPipeName = '\\.\pipe\ApFaxCnv'; + ApdSemaphoreName = 'ApFaxCnvSem'; + ApdRegKey = '\SOFTWARE\TurboPower\ApFaxCnv\Settings'; + ApdIniFileName = 'APFPDENG.INI'; + ApdIniSection = 'Settings'; + ApdIniKey = 'AutoExec'; + ApdDef32PrinterName = 'APF Fax Printer'; + ApdDef16PrinterName = 'Print To Fax'; + ApdDefPrinterPort = 'PRINTFAX'; + + ApdDefaultTerminalName = ''; + ApdNoTerminalName = ''; + + + {Event codes: (inbound)} + eNull = 0; + eStartDoc = 1; + eEndDoc = 2; + + {Event codes: (outbound)} + eSetFileName = 3; + +type + TPipeEvent = record + Event : Byte; + Data : ShortString; + end; + { XML definitions } + DOMString = WideString; +type + CharSet = set of AnsiChar; + + TPassString = string[255]; + TApdHwnd = HWND; + + + {Standard event timer record structure used by all timing routines} + EventTimer = record + StartTicks : Integer; {Tick count when timer was initialized} + ExpireTicks : Integer; {Tick count when timer will expire} + end; + +{$IFNDEF PRNDRV} {!!.06} +type{ moved from AdTapi.pas } {!!.06} + { TAPI device config record, opaque and undefined by definition } {!!.06} + PTapiConfigRec = ^TTapiConfigRec; {!!.06} + TTapiConfigRec = record {!!.06} + DataSize : Cardinal; {!!.06} + Data : array[0..1023] of Byte; {!!.06} + end; + +{ moved from AdRasUtl.pas } {!!.06} +const {RasMaximum buffer sizes} {!!.06} + RasMaxDomain = 15; {!!.06} + RasMaxPassword = 256; {!!.06} + RasMaxUserName = 256; {!!.06} + RasMaxEntryName = 256; {!!.06} + RasMaxPhoneBook = 256; {!!.06} + RasMaxError = 256; {!!.06} + RasMaxEntries = 64; {!!.06} + RasMaxDeviceName = 128; {!!.06} + RasMaxDeviceType = 16; {!!.06} + RasMaxPhoneNumber = 128; {!!.06} + RasMaxCallBackNum = 128; {!!.06} + RasMaxAreaCode = 10; {!!.06} + RasMaxPadType = 32; {!!.06} + RasMaxX25Address = 200; {!!.06} + RasMaxIPAddress = 15; {!!.06} + RasMaxIPXAddress = 21; {!!.06} + RasMaxFacilities = 200; {!!.06} + RasMaxUserData = 200; {!!.06} + +type { moved from AdRasUtl.pas } {!!.06} + {RAS IP address - "a.b.c.d"} {!!.06} + PRasIPAddr = ^TRasIPAddr; {!!.06} + TRasIPAddr = record {!!.06} + a : byte; {!!.06} + b : byte; {!!.06} + c : byte; {!!.06} + d : byte; {!!.06} + end; {!!.06} + +type { moved from AdRasUtl.pas } {!!.06} + {RAS phonebook entry properties} {!!.06} + {!!.06} {Renamed fields to sync with underlying RASENTRY structure } + { dwOptions -> dwfOptions, dwAlternatesOffset -> dwAlternateOffset, } + { dwNetProtocols -> dwfNetProtocols } + PRasEntry = ^TRasEntry; {!!.06} + TRasEntry = record {!!.06} + dwSize : DWord; {!!.06} + dwfOptions : DWord; {!!.06} + dwCountryID : DWord; {!!.06} + dwCountryCode : DWord; {!!.06} + szAreaCode : array[0..RasMaxAreaCode] of char; {!!.06} // tchar + szLocalPhoneNumber : array[0..RasMaxPhoneNumber] of char; {!!.06} // tchar + dwAlternateOffset : DWord; {!!.06} + IPAddr : TRasIPAddr; {!!.06} + IPAddrDns : TRasIPAddr; {!!.06} + IPAddrDnsAlt : TRasIPAddr; {!!.06} + IPAddrWins : TRasIPAddr; {!!.06} + IPAddrWinsAlt : TRasIPAddr; {!!.06} + dwFrameSize : DWord; {!!.06} + dwfNetProtocols : DWord; {!!.06} + dwFramingProtocol : DWord; {!!.06} + szScript : array[0..Max_PATH-1] of char; {!!.06} // --SZ TCHAR in ras.h, so use char here + szAutodialDll : array[0..Max_PATH-1] of char; {!!.06} + szAutodialFunc : array[0..Max_PATH-1] of char; {!!.06} + szDeviceType : array[0..RasMaxDeviceType] of char; {!!.06} + szDeviceName : array[0..RasMaxDeviceName] of char; {!!.06} + szX25PadType : array[0..RasMaxPadType] of char; {!!.06} + szX25Address : array[0..RasMaxX25Address] of char; {!!.06} + szX25Facilities : array[0..RasMaxFacilities] of char; {!!.06} + szX25UserData : array[0..RasMaxUserData] of char; {!!.06} + dwChannels : DWord; {!!.06} + dwReserved1 : DWord; {!!.06} + dwReserved2 : DWord; {!!.06} + end; {!!.06} + +const {RASENTRY 'dwfOptions' bit flags} {!!.06} + RASEO_UseCountryAndAreaCodes = $00000001; {!!.06} + RASEO_SpecificIpAddr = $00000002; {!!.06} + RASEO_SpecificNameServers = $00000004; {!!.06} + RASEO_IpHeaderCompression = $00000008; {!!.06} + RASEO_RemoteDefaultGateway = $00000010; {!!.06} + RASEO_DisableLcpExtensions = $00000020; {!!.06} + RASEO_TerminalBeforeDial = $00000040; {!!.06} + RASEO_TerminalAfterDial = $00000080; {!!.06} + RASEO_ModemLights = $00000100; {!!.06} + RASEO_SwCompression = $00000200; {!!.06} + RASEO_RequireEncryptedPw = $00000400; {!!.06} + RASEO_RequireMsEncryptedPw = $00000800; {!!.06} + RASEO_RequireDataEncryption = $00001000; {!!.06} + RASEO_NetworkLogon = $00002000; {!!.06} + RASEO_UseLogonCredentials = $00004000; {!!.06} + RASEO_PromoteAlternates = $00008000; {!!.06} + RASEO_SecureLocalFiles = $00010000; {!!.06} + RASEO_RequireEAP = $00020000; {!!.06} + RASEO_RequirePAP = $00040000; {!!.06} + RASEO_RequireSPAP = $00080000; {!!.06} + RASEO_Custom = $00100000; {!!.06} + RASEO_PreviewPhoneNumber = $00200000; {!!.06} + RASEO_SharedPhoneNumbers = $00800000; {!!.06} + RASEO_PreviewUserPw = $01000000; {!!.06} + RASEO_PreviewDomain = $02000000; {!!.06} + RASEO_ShowDialingProgress = $04000000; {!!.06} + RASEO_RequireCHAP = $08000000; {!!.06} + RASEO_RequireMsCHAP = $10000000; {!!.06} + RASEO_RequireMsCHAP2 = $20000000; {!!.06} + RASEO_RequireW95MSCHAP = $40000000; {!!.06} + RASEO_CustomScript = $80000000; {!!.06} + + {RASENTRY 'dwfNetProtocols' bit flags} {!!.06} + RASNP_NetBEUI = $00000001; {!!.06} + RASNP_Ipx = $00000002; {!!.06} + RASNP_Ip = $00000004; {!!.06} + + {RASENTRY 'dwFramingProtocols' bit flags} {!!.06} + RASFP_Ppp = $00000001; {!!.06} + RASFP_Slip = $00000002; {!!.06} + RASFP_Ras = $00000004; {!!.06} + + {RASENTRY 'szDeviceType' default strings} {!!.06} + RASDT_Modem = 'modem'; {!!.06} + RASDT_Isdn = 'isdn'; {!!.06} + RASDT_X25 = 'x25'; {!!.06} + RASDT_Vpn = 'vpn'; {!!.06} + RASDT_Pad = 'pad'; {!!.06} + RASDT_Generic = 'GENERIC'; {!!.06} + RASDT_Serial = 'SERIAL'; {!!.06} + RASDT_FrameRelay = 'FRAMERELAY'; {!!.06} + RASDT_Atm = 'ATM'; {!!.06} + RASDT_Sonet = 'SONET'; {!!.06} + RASDT_SW56 = 'SW56'; {!!.06} + RASDT_Irda = 'IRDA'; {!!.06} + RASDT_Parallel = 'PARALLEL'; {!!.06} + +type + PRasStatistics = ^TRasStatistics; {!!.06} + TRasStatistics = record {!!.06} + dwSize : DWORD; {!!.06} + dwBytesXmited : DWORD; {!!.06} + dwBytesRcved : DWORD; {!!.06} + dwFramesXmited : DWORD; {!!.06} + dwFramesRcved : DWORD; {!!.06} + dwCrcErr : DWORD; {!!.06} + dwTimeoutErr : DWORD; {!!.06} + dwAlignmentErr : DWORD; {!!.06} + dwHardwareOverrunErr : DWORD; {!!.06} + dwFramingErr : DWORD; {!!.06} + dwBufferOverrunErr : DWORD; {!!.06} + dwCompressionRatioIn : DWORD; {!!.06} + dwCompressionRatioOut : DWORD; {!!.06} + dwBps : DWORD; {!!.06} + dwConnectDuration : DWORD; {!!.06} + end; {!!.06} +{$ENDIF} {!!.06} +const + {Compile-time configurations} + MaxComHandles = 50; {Max comm ports open at once} + DispatchBufferSize = 8192; {Size of each port's dispatch buffer} + MaxMessageLen = 80; {All error and status strings less than 80} + + {For skipping line parameter changes} + DontChangeBaud = 0; + DontChangeParity = SpaceParity + 1; + DontChangeDatabits = 9; + DontChangeStopbits = TwoStopbits + 1; + + {Modem status trigger options} + msCTSDelta = $0010; + msDSRDelta = $0020; + msRingDelta = $0004; + msDCDDelta = $0080; + + {Line status trigger options} + lsOverrun = $0001; + lsParity = $0002; + lsFraming = $0004; + lsBreak = $0008; + + {Line and driver errors} + leNoError = 0; {No error, ordinal value matches ecOK} + leBuffer = 1; {Buffer overrun in COMM.DRV} + leOverrun = 2; {UART receiver overrun} + leParity = 3; {UART receiver parity error} + leFraming = 4; {UART receiver framing error} + leCTSTO = 5; {Transmit timeout waiting for CTS} + leDSRTO = 6; {Transmit timeout waiting for DSR} + leDCDTO = 7; {Transmit timeout waiting for RLSD} + leTxFull = 8; {Transmit queue is full} + leBreak = 9; {Break condition received} + leIOError = 10; {Windows error. LastWinError contains the error code.} + + {Status trigger subtypes} + stNotActive = 0; {not active} + stModem = 1; {Trigger on modem status change} + stLine = 2; {Trigger on line status change} + stOutBuffFree = 3; {Trigger on outbuff free level} + stOutBuffUsed = 4; {Trigger on outbuff used level} + stOutSent = 5; {Trigger on any PutXxx call} + + {Next file method} + nfNone = 0; {No next file method specified} + nfMask = 1; {Use built-in next file mask method} + nfList = 2; {Use built-in next file list method} + + {Action to take if incoming file exists} + wfcWriteNone = 0; {No option set yet} + wfcWriteFail = 1; {Fail the open attempt} + wfcWriteRename = 2; {Rename the incoming file} + wfcWriteAnyway = 3; {Overwrite the existing file} + wfcWriteResume = 4; {Resume an interrupted receive} + + {Ascii CR/LF translation options} + atNone = 0; {No CR/LF translations} + atStrip = 1; {Strip CRs or LFs} + atAddCRBefore = 2; {Add CR before each LF} + atAddLFAfter = 3; {Add LF after each CR} + atEOFMarker : Ansichar = ^Z; {Add constant for standard EOF } + + {Protocol status start/end flags} + apFirstCall = $01; {Indicates the first call to status} + apLastCall = $02; {Indicates the last call to status} + + {For specifying log file calls} + lfReceiveStart = 0; {Receive starting} + lfReceiveOk = 1; {File received ok} + lfReceiveFail = 2; {File receive failed} + lfReceiveSkip = 3; {File was rejected by receiver} + lfTransmitStart = 4; {Transmit starting} + lfTransmitOk = 5; {File was transmitted ok} + lfTransmitFail = 6; {File transmit failed} + lfTransmitSkip = 7; {File was skipped, rejected by receiver} + +type + {Convenient types used by protocols} + TNameCharArray = array[0..fsFileName ] of AnsiChar; //SZ used by protocols --> Ansi + TExtCharArray = array[0..fsExtension] of AnsiChar; + TPathCharArray = array[0..fsPathName ] of Char; + TPathCharArrayA = array[0..fsPathName ] of AnsiChar; //SZ FIXME can this be changed to Char?? + TDirCharArray = array[0..fsDirectory] of AnsiChar; + TChar20Array = array[0..20] of AnsiChar; + TCharArray = array[0..255] of AnsiChar; + + {For generic buffer typecasts} + PByteBuffer = ^TByteBuffer; + TByteBuffer = array[1..65535] of Byte; + + {Port characteristic constants} + TDatabits = 5..DontChangeDatabits; + TStopbits = 1..DontChangeStopbits; + + {NotifyProc type, same as a window procedure} + TApdNotifyProc = procedure(Msg, wParam : Cardinal; + lParam : Integer); + TApdNotifyEvent = procedure(Msg, wParam : Cardinal; + lParam : Integer) of object; +const + {Avoid requiring WIN31} + ev_CTSS = $0400; {CTS state} + ev_DSRS = $0800; {DSR state} + ev_RLSDS = $1000; {RLSD state} + ev_RingTe = $2000; {Ring trailing edge indicator} + +const + {MSRShadow register from COMM.DRV} + MsrShadowOfs = 35; {Offset of MSRShadow from EventWord} + +const + {Modem status bit masks} + DeltaCTSMask = $01; {CTS changed since last read} + DeltaDSRMask = $02; {DSR changed since last read} + DeltaRIMask = $04; {RI changed since last read} + DeltaDCDMask = $08; {DCD changed since last read} + CTSMask = $10; {Clear to send} + DSRMask = $20; {Data set ready} + RIMask = $40; {Ring indicator} + DCDMask = $80; {Data carrier detect} + +const + {Message base} + apw_First = $7E00; {Sets base for all APW messages} + +const + {Custom message types} + apw_TriggerAvail = apw_First+1; {Trigger for any data avail} + apw_TriggerData = apw_First+2; {Trigger data} + apw_TriggerTimer = apw_First+3; {Trigger timer} + apw_TriggerStatus = apw_First+4; {Status change (modem, line, buffer)} + apw_FromYmodem = apw_First+5; {Tells Xmodem it was called from Ymodem} + apw_PortOpen = apw_First+8; {Apro, tell users port open} + apw_PortClose = apw_First+9; {Apro, tell users port closed} + apw_ClosePending = apw_First+10; {Apro, tell ourself that the port was closed} + +const + {Protocol message types} + apw_ProtocolCancel = apw_First+20; {To protocol - chk for protcl abort} + apw_ProtocolStatus = apw_First+21; {From protocol - update status display} + apw_ProtocolLog = apw_First+22; {From protocol - LogFile message} + apw_ProtocolNextFile = apw_First+23; {From protocol - return next file} + apw_ProtocolAcceptFile = apw_First+24; {From protocol - accept file} + apw_ProtocolFinish = apw_First+25; {From protocol - protocol is finished} + apw_ProtocolResume = apw_First+26; {From protocol - resume request} + apw_ProtocolError = apw_First+27; {From protocol - error during protocol} + apw_ProtocolAbort = apw_First+28; {To protocol - abort the transfer} + +const + {Modem message types} + apw_AutoAnswer = apw_First+40; {To modem, enter AutoAnswer} + apw_CancelCall = apw_First+41; {To modem, cancel the call} + apw_StartDial = apw_First+42; {To modem, start the process} + + {deprecated modem message types, note that some conflict with new messages} + apw_ModemOk = apw_First+40; {From modem - got OK response} + apw_ModemConnect = apw_First+41; {From modem - got CONNECT response} + apw_ModemBusy = apw_First+42; {From modem - got BUSY response} + apw_ModemVoice = apw_First+43; {From modem - got VOICE response} + apw_ModemNoCarrier = apw_First+44; {From modem - got NO CARRIER response} + apw_ModemNoDialTone = apw_First+45; {From modem - got NO DIALTONE response} + apw_ModemError = apw_First+46; {From modem - got ERROR response} + apw_GotLineSpeed = apw_First+47; {From modem - got connect speed} + apw_GotErrCorrection = apw_First+48; {From modem - got EC response} + apw_GotDataCompression = apw_First+49; {From modem - got compression response} + apw_CmdTimeout = apw_First+50; {From modem - command timed out} + apw_DialTimeout = apw_First+51; {From modem - dial timed out} + apw_AnswerTimeout = apw_First+52; {From modem - answer timed out} + apw_DialCount = apw_First+53; {From modem - dial still in progress} + apw_AnswerCount = apw_First+54; {From modem - answer still in progress} + apw_ModemRing = apw_First+55; {From modem - phone rang} + apw_ModemIsConnected = apw_First+56; {From modem - connection completed} + apw_ConnectFailed = apw_First+57; {From modem - connection failed} + apw_CommandProcessed = apw_First+58; {From modem - finished command} + +const + {Terminal message types} + apw_TermStart = apw_First+60; {To terminal - start} + apw_TermStop = apw_First+61; {To terminal - stop} + apw_TermSetCom = apw_First+62; {To terminal - set com handle} + apw_TermRelCom = apw_First+63; {To terminal - release com handle} + apw_TermSetEmuPtr = apw_First+64; {To terminal - set emulator pointer} + apw_TermSetEmuProc = apw_First+65; {To terminal - set emulator proc} + apw_TermClear = apw_First+66; {To terminal - clear window} + apw_TermBuffer = apw_First+67; {To terminal - alloc new buffers} + apw_TermColors = apw_First+68; {To terminal - set new colors} + apw_TermToggleScroll = apw_First+69; {To terminal - toggle scrollback} + apw_TermCapture = apw_First+70; {To terminal - set capture mode} + apw_TermStuff = apw_First+71; {To terminal - stuff data} + apw_TermPaint = apw_First+72; {To terminal - update screen} + apw_TermSetWndProc = apw_First+73; {To terminal - set window proc} + apw_TermColorsH = apw_First+74; {To terminal - set highlight colors} + apw_TermSave = apw_First+75; {To terminal - save/restore} + apw_TermColorMap = apw_First+76; {To terminal - get/set color map} + apw_TermForceSize = apw_First+77; {To terminal - force new size} + apw_TermFontSize = apw_First+78; {To terminal - get font size} + +const + apw_TermStatus = apw_First+80; {From terminal - show status} + apw_TermBPlusStart = apw_First+81; {From terminal - B+ is starting} + apw_TermError = apw_First+82; {From terminal - error} + apw_CursorPosReport = apw_First+83; {From terminal - Cursor Pos Report} + +const + apw_FaxCvtStatus = apw_First+90; {From fax converter - show status} + apw_FaxUnpStatus = apw_First+91; {From fax unpacker - show status} + apw_FaxOutput = apw_First+92; {From fax unpacker - output line} + +const + apw_ViewSetFile = apw_First+100; {To fax viewer - change file name} + apw_ViewSetFG = apw_First+101; {To fax viewer - set foreground color} + apw_ViewSetBG = apw_First+102; {To fax viewer - set background color} + apw_ViewSetScale = apw_First+103; {To fax viewer - set scale factors} + apw_ViewSetScroll = apw_First+104; {To fax viewer - set scroll increments} + apw_ViewSelectAll = apw_First+105; {To fax viewer - select entire image} + apw_ViewSelect = apw_First+106; {To fax viewer - select image rect} + apw_ViewCopy = apw_First+107; {To fax viewer - copy data to cboard} + apw_ViewSetWndProc = apw_First+108; {To fax viewer - set window procedure} + apw_ViewSetWhitespace = apw_First+109; {To fax viewer - set whitespace comp} + apw_ViewGetBitmap = apw_First+110; {To fax viewer - get memory bmp} + apw_ViewGetNumPages = apw_First+111; {To fax viewer - get num pages} + apw_ViewStartUpdate = apw_First+112; {To fax viewer - start scale update} + apw_ViewEndUpdate = apw_First+113; {To fax viewer - end scale upate} + apw_ViewGotoPage = apw_First+114; {To fax viewer - go to a page} + apw_ViewGetCurPage = apw_First+115; {To fax viewer - get current page #} + apw_ViewSetDesignMode = apw_First+116; {To fax viewer - indicate in design} + apw_ViewSetRotation = apw_First+117; {To fax viewer - set rotation} + apw_ViewSetAutoScale = apw_First+118; {To fax viewer - auto scaling} + apw_ViewNotifyPage = apw_First+119; {To fax viewer - notify of page chg} + apw_ViewGetPageDim = apw_First+120; {To fax viewer - get pg dimensions} + apw_ViewSetLoadWholeFax= apw_First+121; {To fax viewer - set load whole fax} + apw_ViewSetBusyCursor = apw_First+122; {To fax viewer - set cursor for busy} + apw_ViewerError = apw_First+123; {Fax viewer error report} + apw_ViewGetPageFlags = apw_First+124; {To fax viewer - get pg flags} + apw_ViewGetFileName = apw_First+125; {To fax viewer - get file name} + +const + apw_TermBlinkTimeChange = apw_First+130; {set new blink time} + apw_TermPersistentMarkChange = apw_First+131; {set persistent blocks} + apw_TermSetKeyEmuPtr = apw_First+132; {set Key Emulator pointer } + apw_TermSetKeyEmuProc = apw_First+133; {set Key Emulator proc } + apw_TermSetHalfDuplex = apw_First+134; {set Duplex mode} + apw_TermGetBuffPtr = apw_First+135; {get a pointer to term buffer} + apw_TermGetClientLine = apw_First+136; {get the first client line in buffer} + apw_TermWaitForPort = apw_First+137; {wait for the port to open}{!!.03} + apw_TermNeedsUpdate = apw_First+138; {update needed} {!!.05} + +const + apw_PrintDriverJobCreated = apw_First+140; {printer driver created fax job} + apw_BeginDoc = apw_First+141; {printer driver starts printing} + apw_EndDoc = apw_First+142; {printer driver has finished printing} + apw_AddPrim = apw_First+143; {internal FaxSrvx sample message} + apw_EndPage = apw_First+144; {printer driver EndOfPage/idShell} + +const + apw_FaxCancel = apw_First+160; {To fax - cancel the session} + apw_FaxNextfile = apw_First+161; {From fax - return next fax to send} + apw_FaxStatus = apw_First+162; {From fax - show the fax status} + apw_FaxLog = apw_First+163; {From fax - log the fax start/stop} + apw_FaxName = apw_First+164; {From fax - name the incoming fax} + apw_FaxAccept = apw_First+165; {From fax - accept this fax?} + apw_FaxError = apw_First+166; {From fax - session had error} + apw_FaxFinish = apw_First+167; {From fax - session finished} + +const + apw_TapiWaveMessage = apw_First+180; {Tapi wave event message} + apw_TapiEventMessage = apw_First+181; {Tapi general event message} + apw_VoIPEventMessage = apw_First+182; {AdVoIP general event message} + apw_VoIPNotifyMessage = apw_First+183; {AdVoIP internal notification message} + +const + apw_StateDeactivate = apw_First+190; {State deactivation message } + apw_StateChange = apw_First+191; {from State to StateMachine } + +const + apw_SapiTrain = apw_First+192; {Sapi training requested} + apw_SapiPhoneCallBack = apw_First+193; {Sapi AskFor phrase return} + apw_SapiInfoPhrase = apw_First+194; {Sapi TAPI connection status} + +const + apw_PgrStatusEvent = apw_First+200; {Pager status event} + +const + {Window class names} + DispatcherClassName = 'awDispatch'; + ProtocolClassName = 'awProtocol'; + TerminalClassName = 'awTerminal'; + MessageHandlerClassName = 'awMsgHandler'; + FaxViewerClassName = 'awViewer'; + FaxViewerClassNameDesign = 'dcViewer'; + TerminalClassNameDesign = 'dcTerminal'; + FaxHandlerClassName = 'awFaxHandler'; + +const + {Error groups} + egDos = -0; {DOS, DOS critical and file I/O} + egGeneral = -1; {General errors} + egOpenComm = -2; {OpenComm errors} + egSerialIO = -3; {Errors during serial I/O processing} + egModem = -4; {Errors during modem processing} + egTrigger = -5; {Error setting up triggers} + egProtocol = -6; {Errors that apply to one or more protocols} + egINI = -7; {INI database errors} + egFax = -8; {FAX errors} + egAdWinsock = 9; {APro specific Winsock errors} + egWinsock = 10; {Winsock errors} + egWinsockEx = 11; {Additional Winsock errors} + egTapi = -13; {TAPI errors} + +const + { Below are all error codes used by APRO -- resource IDs are Abs(ErrorCode) } + { The corresponding strings can be found in APW.STR and AdExcept.inc. If } + { you are adding strings, it's best to go there first to 'stake a claim' on } + { an appropriate range of IDs -- since constants for some status strings } + { are found in the applicable component's unit instead of here... } + + {No error} + ecOK = 0; {Okay} + +const + {egDOS} + ecFileNotFound = -2; {File not found} + ecPathNotFound = -3; {Path not found} + ecTooManyFiles = -4; {Too many open files} + ecAccessDenied = -5; {File access denied} + ecInvalidHandle = -6; {Invalid file handle} + ecOutOfMemory = -8; {Insufficient memory} + ecInvalidDrive = -15; {Invalid drive} + ecNoMoreFiles = -18; {No more files} + ecDiskRead = -100; {Attempt to read beyond end of file} + ecDiskFull = -101; {Disk is full} + ecNotAssigned = -102; {File not Assign-ed} + ecNotOpen = -103; {File not open} + ecNotOpenInput = -104; {File not open for input} + ecNotOpenOutput = -105; {File not open for output} + ecWriteProtected = -150; {Disk is write-protected} + ecUnknownUnit = -151; {Unknown disk unit} + ecDriveNotReady = -152; {Drive is not ready} + ecUnknownCommand = -153; {Unknown command} + ecCrcError = -154; {Data error} + ecBadStructLen = -155; {Bad request structure length} + ecSeekError = -156; {Seek error} + ecUnknownMedia = -157; {Unknown media type} + ecSectorNotFound = -158; {Disk sector not found} + ecOutOfPaper = -159; {Printer is out of paper} + ecDeviceWrite = -160; {Device write error} + ecDeviceRead = -161; {Device read error} + ecHardwareFailure = -162; {General failure} + +const + {egGeneral} + ecBadHandle = -1001; {Bad handle passed to com function} + ecBadArgument = -1002; {Bad argument passed to function} + ecGotQuitMsg = -1003; {Yielding routine got WM_QUIT message} + ecBufferTooBig = -1004; {Terminal buffer size too big} + ecPortNotAssigned = -1005; {ComPort component not assigned} + ecInternal = -1006; {Internal INIDB errors} + ecModemNotAssigned = -1007; {Modem component not assigned} + ecPhonebookNotAssigned = -1008; {Phonebook component not assgnd} + ecCannotUseWithWinSock = -1009; {Component not compatible with WinSock} + +const + {egOpenComm} + ecBadId = -2001; {ie_BadId - bad or unsupported ID} + ecBaudRate = -2002; {ie_Baudrate - unsupported baud rate} + ecByteSize = -2003; {ie_Bytesize - invalid byte size} + ecDefault = -2004; {ie_Default - error in default parameters} + ecHardware = -2005; {ie_Hardware - hardware not present} + ecMemory = -2006; {ie_Memory - unable to allocate queues} + ecCommNotOpen = -2007; {ie_NOpen - device not open} + ecAlreadyOpen = -2008; {ie_Open - device already open} + ecNoHandles = -2009; {No more handles, can't open port} + ecNoTimers = -2010; {No timers available} + ecNoPortSelected = -2011; {No port selected (attempt to open com0)} + ecNotOpenedByTapi = -2012; {Comport was not opened by Tapi} + +const + {egSerialIO} + ecNullApi = -3001; {No device layer specified} + ecNotSupported = -3002; {Function not supported by driver} + ecRegisterHandlerFailed = -3003; {EnableCommNotification failed} + ecPutBlockFail = -3004; {Failed to put entire block} + ecGetBlockFail = -3005; {Failed to get entire block} + ecOutputBufferTooSmall = -3006; {Output buffer too small for block} + ecBufferIsEmpty = -3007; {Buffer is empty} + ecTracingNotEnabled = -3008; {Tracing not enabled} + ecLoggingNotEnabled = -3009; {Logging not enabled} + ecBaseAddressNotSet = -3010; {Base addr not found, RS485 mode} + +const + {Modem/Pager} + ecModemNotStarted = -4001; {StartModem has not been called} + ecModemBusy = -4002; {Modem is busy elsewhere} + ecModemNotDialing = -4003; {Modem is not currently dialing} + ecNotDialing = -4004; {TModemDialer is not dialing} + ecAlreadyDialing = -4005; {TModemdialer is already dialing} + ecModemNotResponding = -4006; {No response from modem} + ecModemRejectedCommand = -4007; {Bad command sent to modem} + ecModemStatusMismatch = -4008; {Wrong modem status requested} + + ecDeviceNotSelected = -4009; { Um, the modem wan't selected } + ecModemDetectedBusy = -4010; { Modem detected busy signal } + ecModemNoDialtone = -4011; { No dialtone detected } + ecModemNoCarrier = -4012; { No carrier from modem } + ecModemNoAnswer = -4013; { Modem returned No Answer response } + + { Pager } + ecInitFail = -4014; { Modem initialization failure } + ecLoginFail = -4015; { Login Failure } + ecMinorSrvErr = -4016; { SNPP - Minor Server Error } + ecFatalSrvErr = -4017; { SNPP - Fatal Server Error } + +const + {LibModem} + ecModemNotFound = -4020; { Modem not found in modemcap } + ecInvalidFile = -4021; { a modemcap file is invalid } + +const {RAS connection status codes} + csOpenPort = 4500; + csPortOpened = 4501; + csConnectDevice = 4502; + csDeviceConnected = 4503; + csAllDevicesConnected = 4504; + csAuthenticate = 4505; + csAuthNotify = 4506; + csAuthRetry = 4507; + csAuthCallback = 4508; + csAuthChangePassword = 4509; + csAuthProject = 4510; + csAuthLinkSpeed = 4511; + csAuthAck = 4512; + csReAuthenticate = 4513; + csAuthenticated = 4514; + csPrepareForCallback = 4515; + csWaitForModemReset = 4516; + csWaitForCallback = 4517; + csProjected = 4518; + + csStartAuthentication = 4519; + csCallbackComplete = 4520; + csLogonNetwork = 4521; + csSubEntryConnected = 4522; + csSubEntryDisconnected = 4523; + csRasInteractive = 4550; + csRasRetryAuthentication = 4551; + csRasCallbackSetByCaller = 4552; + csRasPasswordExpired = 4553; + csRasDeviceConnected = 4599; + csRasBaseEnd = csSubEntryDisconnected; + csRasPaused = $1000; + csInteractive = csRasPaused; + csRetryAuthentication = csRasPaused + 1; + csCallbackSetByCaller = csRasPaused + 2; + csPasswordExpired = csRasPaused + 3; + csRasPausedEnd = csRasPaused + 3; + + csRasConnected = $2000; + csRasDisconnected = csRasConnected + 1; + + { Protocols } + { If strings are added -- apStatusMsg needs to be changed in AWABSPCL.PAS } + +const + psOK = 4700; {Protocol is ok} + psProtocolHandshake = 4701; {Protocol handshaking in progress} + psInvalidDate = 4702; {Bad date/time stamp received and ignored} + psFileRejected = 4703; {Incoming file was rejected} + psFileRenamed = 4704; {Incoming file was renamed} + psSkipFile = 4705; {Incoming file was skipped} + psFileDoesntExist = 4706; {Incoming file doesn't exist locally, skipped} + psCantWriteFile = 4707; {Incoming file skipped due to Zmodem options} + psTimeout = 4708; {Timed out waiting for something} + psBlockCheckError = 4709; {Bad checksum or CRC} + psLongPacket = 4710; {Block too long} + psDuplicateBlock = 4711; {Duplicate block received and ignored} + psProtocolError = 4712; {Error in protocol} + psCancelRequested = 4713; {Cancel requested} + psEndFile = 4714; {At end of file} + psResumeBad = 4715; {B+ host refused resume request} + psSequenceError = 4716; {Block was out of sequence} + psAbortNoCarrier = 4717; {Aborting on carrier loss} + psAbort = 4730; {Session aborted} + +const + {Specific to certain protocols} + psGotCrcE = 4718; {Got CrcE packet (Zmodem)} + psGotCrcG = 4719; {Got CrcG packet (Zmodem)} + psGotCrcW = 4720; {Got CrcW packet (Zmodem)} + psGotCrcQ = 4721; {Got CrcQ packet (Zmodem)} + psTryResume = 4722; {B+ is trying to resume a download} + psHostResume = 4723; {B+ host is resuming} + psWaitAck = 4724; {Waiting for B+ ack (internal)} + +const + {Internal} + psNoHeader = 4725; {Protocol is waiting for header (internal)} + psGotHeader = 4726; {Protocol has header (internal)} + psGotData = 4727; {Protocol has data packet (internal)} + psNoData = 4728; {Protocol doesn't have data packet yet (internal)} + + { Constants for fax strings } + { If strings are added -- afStatusMsg needs to be changed in AWABSFAX.PAS } +const + {Fax progress codes, sending} + fpInitModem = 4801; {Initializing modem for fax processing} + fpDialing = 4802; {Dialing} + fpBusyWait = 4803; {Busy, FaxTransmit is waiting} + fpSendPage = 4804; {Sending document page data} + fpSendPageStatus = 4805; {Send EOP} + fpPageError = 4806; {Error sending page} + fpPageOK = 4807; {Page accepted by remote} + fpConnecting = 4808; {Send call handoff connecting} + +const + {Fax progress codes, receiving} + fpWaiting = 4820; {Waiting for incoming call} + fpNoConnect = 4821; {No connect on this call} + fpAnswer = 4822; {Answering incoming call} + fpIncoming = 4823; {Incoming call validated as fax} + fpGetPage = 4824; {Getting page data} + fpGetPageResult = 4825; {Getting end-of-page signal} + fpCheckMorePages = 4826; {getting end-of-document status} + fpGetHangup = 4827; {Get hangup command} + fpGotHangup = 4828; {Got Class 2 FHNG code} + +const + {Fax server codes } + fpSwitchModes = 4830; {Switching from send/recv or recv/send} + fpMonitorEnabled = 4831; {Monitoring for incoming faxes} + fpMonitorDisabled = 4832; {Not monitoring for incoming faxes} + +const + {Fax progress codes, common} + fpSessionParams = 4840; {Getting connection params} + fpGotRemoteID = 4841; {got called-station ID} + fpCancel = 4842; {User abort} + fpFinished = 4843; {Finished with this fax} + +const + {Trigger errors} + ecNoMoreTriggers = -5001; {No more trigger slots} + ecTriggerTooLong = -5002; {Data trigger too long} + ecBadTriggerHandle = -5003; {Bad trigger handle} + +const + {Packet errors} + ecStartStringEmpty = -5501; {Start string is empty} + ecPacketTooSmall = -5502; {Packet size cannot be smaller than start string} + ecNoEndCharCount = -5503; {CharCount packets must have an end-condition} + ecEmptyEndString = -5504; {End string is empty} + ecZeroSizePacket = -5505; {Packet size cannot be zero} + ecPacketTooLong = -5506; {Packet too long} + +const + {Protocol errors} + ecBadFileList = -6001; {Bad format in file list} + ecNoSearchMask = -6002; {No search mask specified during transmit} + ecNoMatchingFiles = -6003; {No files matched search mask} + ecDirNotFound = -6004; {Directory in search mask doesn't exist} + ecCancelRequested = -6005; {Cancel requested} + ecTimeout = -6006; {Fatal time out} + ecProtocolError = -6007; {Unrecoverable event during protocol} + ecTooManyErrors = -6008; {Too many errors during protocol} + ecSequenceError = -6009; {Block sequence error in Xmodem} + ecNoFilename = -6010; {No filename specified in protocol receive} + ecFileRejected = -6011; {File was rejected} + ecCantWriteFile = -6012; {Cant write file} + ecTableFull = -6013; {Kermit window table is full, fatal error} + ecAbortNoCarrier = -6014; {Aborting due to carrier loss} + ecBadProtocolFunction = -6015; {Function not support by protocol} + ecProtocolAbort = -6016; {Session aborted} + +const + {INI database} + ecKeyTooLong = -7001; {Key string too long} + ecDataTooLarge = -7002; {Data string too long} + ecNoFieldsDefined = -7003; {No fields defined in database} + ecIniWrite = -7004; {Generic INI file write error} + ecIniRead = -7005; {Generic INI file read error} + ecNoIndexKey = -7006; {No index defined for database} + ecRecordExists = -7007; {Record already exists} + ecRecordNotFound = -7008; {Record not found in database} + ecMustHaveIdxVal = -7009; {Invalid index key name} + ecDatabaseFull = -7010; {Maximum database records (999) reached} + ecDatabaseEmpty = -7011; {No records in database} + ecDatabaseNotPrepared = -7012; {iPrepareIniDatabase not called} + ecBadFieldList = -7013; {Bad field list in INIDB} + ecBadFieldForIndex = -7014; {Bad field for index in INIDB} + +const {!!.04} + {State Machine} {!!.04} + ecNoStateMachine = -7500; {No state machine} {!!.04} + ecNoStartState = -7501; {StartState not set} {!!.04} + ecNoSapiEngine = -7502; {SAPI Engine not set} {!!.04} + +const + ecFaxBadFormat = -8001; {File is not an APF file} + ecBadGraphicsFormat = -8002; {Unsupported graphics file format} + ecConvertAbort = -8003; {User aborted fax conversion} + ecUnpackAbort = -8004; {User aborted fax unpack} + ecCantMakeBitmap = -8005; {CreateBitmapIndirect API failure} + ecNoImageLoaded = -8050; {no image loaded into viewer} + ecNoImageBlockMarked = -8051; {no block of image marked} + ecFontFileNotFound = -8052; {APFAX.FNT not found, or resource bad} + ecInvalidPageNumber = -8053; {Invalid page number specified for fax} + ecBmpTooBig = -8054; {BMP size exceeds Windows' maxheight of 32767} + ecEnhFontTooBig = -8055; {Font selected for enh text converter too large} + +const + ecFaxBadMachine = -8060; {Fax incompatible with remote fax} + ecFaxBadModemResult = -8061; {Bad response from modem} + ecFaxTrainError = -8062; {Modems failed to train} + ecFaxInitError = -8063; {Error while initializing modem} + ecFaxBusy = -8064; {Called fax number was busy} + ecFaxVoiceCall = -8065; {Called fax number answered with voice} + ecFaxDataCall = -8066; {Incoming data call} + ecFaxNoDialTone = -8067; {No dial tone} + ecFaxNoCarrier = -8068; {Failed to connect to remote fax} + ecFaxSessionError = -8069; {Fax failed in mid-session} + ecFaxPageError = -8070; {Fax failed at page end} + ecFaxGDIPrintError = -8071; {NextBand GDI error in fax print driver} + ecFaxMixedResolution = -8072; {Multiple resolutions in one session} + ecFaxConverterInitFail = -8073; {Initialization of fax converter failed} + ecNoAnswer = -8074; {Remote fax did not answer} + ecAlreadyMonitored = -8075; {MonitorDir already being used} + ecFaxMCFNoAnswer = -8076; {Remote disconnected after last page}{!!.06} + +const + ecUniAlreadyInstalled = -8080; {Unidrv support files already installed} + ecUniCannotGetSysDir = -8081; {Cannot determine windows system dir} + ecUniCannotGetWinDir = -8082; {Cannot determine windows dir} + ecUniUnknownLayout = -8083; {Cannot determine setup file layout} + ecUniCannotInstallFile = -8085; {Cannot install Unidrv files to system dir} + ecRasDDNotInstalled = -8086; {Cannot install RASDD files } {!!.05} + ecDrvCopyError = -8087; {Error copying printer driver} + ecCannotAddPrinter = -8088; {32-bit AddPrinter call failed} + ecDrvBadResources = -8089; {Bad/missing resources in driver} + ecDrvDriverNotFound = -8090; {Driver file not found} + ecUniCannotGetPrinterDriverDir + = -8091; {Cannot determine Win NT printer driver dir} + ecInstallDriverFailed = -8092; {AddPrinterDriver API failed} + + { TApdGSMPhone error codes } +const + ecSMSBusy = -8100; {Busy with another command} + ecSMSTimedOut = -8101; {Timed out, no response back} + ecSMSTooLong = -8102; {SMS message too long} + ecSMSUnknownStatus = -8103; {Status unknown} + ecSMSInvalidNumber = -8138; {Invalid Number or Network out of order} {!!.06} + ecMEFailure = -8300; {Mobile Equipment Failure} + ecServiceRes = -8301; {SMS service of ME reserved} + ecBadOperation = -8302; {Operation not allowed} + ecUnsupported = -8303; {Operation not supported} + ecInvalidPDU = -8304; {Invalid PDU mode parameter} + ecInvalidText = -8305; {Invalid Text mode parameter} + ecSIMInsert = -8310; {SIM card not inserted} + ecSIMPin = -8311; {SIM PIN required} + ecSIMPH = -8312; {PH-SIM PIN required} + ecSIMFailure = -8313; {SIM failure} + ecSIMBusy = -8314; {SIM busy} + ecSIMWrong = -8315; {SIM wrong} + ecSIMPUK = -8316; {SIM PUK required} + ecSIMPIN2 = -8317; {SIM PIN2 required} + ecSIMPUK2 = -8318; {SIM PUK2 required} + ecMemFail = -8320; {Memory failure} + ecInvalidMemIndex = -8321; {Invalid memory index} + ecMemFull = -8322; {Memory full} + ecSMSCAddUnknown = -8330; {SMS Center Address unknown} + ecNoNetwork = -8331; {No network service} + ecNetworkTimeout = -8332; {Network timeout} + ecCNMAAck = -8340; {No +CNMA acknowledgement expected} + ecUnknown = -8500; {Unknown error} + + +const + ecADWSERROR = 9001; + ecADWSLOADERROR = 9002; + ecADWSVERSIONERROR = 9003; + ecADWSNOTINIT = 9004; + ecADWSINVPORT = 9005; + ecADWSCANTCHANGE = 9006; + ecADWSCANTRESOLVE = 9007; + + { All Windows Sockets error constants are biased by 10000 from the "normal" } + wsaBaseErr = 10000; + + { Windows Sockets definitions of regular Microsoft C error constants } + wsaEIntr = 10004; + wsaEBadF = 10009; + wsaEAcces = 10013; + wsaEFault = 10014; + wsaEInVal = 10022; + wsaEMFile = 10024; + + { Windows Sockets definitions of regular Berkeley error constants } + wsaEWouldBlock = 10035; + wsaEInProgress = 10036; + wsaEAlReady = 10037; + wsaENotSock = 10038; + wsaEDestAddrReq = 10039; + wsaEMsgSize = 10040; + wsaEPrototype = 10041; + wsaENoProtoOpt = 10042; + wsaEProtoNoSupport = 10043; + wsaESocktNoSupport = 10044; + wsaEOpNotSupp = 10045; + wsaEPfNoSupport = 10046; + wsaEAfNoSupport = 10047; + wsaEAddrInUse = 10048; + wsaEAddrNotAvail = 10049; + wsaENetDown = 10050; + wsaENetUnreach = 10051; + wsaENetReset = 10052; + wsaEConnAborted = 10053; + wsaEConnReset = 10054; + wsaENoBufs = 10055; + wsaEIsConn = 10056; + wsaENotConn = 10057; + wsaEShutDown = 10058; + wsaETooManyRefs = 10059; + wsaETimedOut = 10060; + wsaEConnRefused = 10061; + wsaELoop = 10062; + wsaENameTooLong = 10063; + wsaEHostDown = 10064; + wsaEHostUnreach = 10065; + wsaENotEmpty = 10066; + wsaEProcLim = 10067; + wsaEUsers = 10068; + wsaEDQuot = 10069; + wsaEStale = 10070; + wsaERemote = 10071; + wsaEDiscOn = 10101; + + { Extended Windows Sockets error constant definitions } + + wsaSysNotReady = 10091; + wsaVerNotSupported = 10092; + wsaNotInitialised = 10093; + + { Error return codes from gethostbyname() and gethostbyaddr() (when using the } + { resolver). Note that these errors are retrieved via wsaGetLastError() and } + { must therefore follow the rules for avoiding clashes with error numbers from } + { specific implementations or language run-time systems. For this reason the } + { codes are based at 10000+1001. Note also that [wsa]No_Address is defined } + { only for compatibility purposes. } + { Authoritative Answer: Host not found } + wsaHost_Not_Found = 11001; + Host_Not_Found = wsaHost_Not_Found; + + { Non-Authoritative: Host not found, or ServerFAIL } + wsaTry_Again = 11002; + Try_Again = wsaTry_Again; + + { Non recoverable errors, FORMERR, REFUSED, NotIMP } + wsaNo_Recovery = 11003; + No_Recovery = wsaNo_Recovery; + + { Valid name, no data record of requested type } + wsaNo_Data = 11004; + No_Data = wsaNo_Data; + + { no address, look for MX record } + wsaNo_Address = wsaNo_Data; + No_Address = wsaNo_Address; + + { The string resource range 13500 - 13800 is used for TAPI } + { status messages, which do not require constants here } + +const + {Adjusted TAPI error codes} + ecAllocated = -13801; + ecBadDeviceID = -13802; + ecBearerModeUnavail = -13803; + ecCallUnavail = -13805; + ecCompletionOverrun = -13806; + ecConferenceFull = -13807; + ecDialBilling = -13808; + ecDialDialtone = -13809; + ecDialPrompt = -13810; + ecDialQuiet = -13811; + ecIncompatibleApiVersion = -13812; + ecIncompatibleExtVersion = -13813; + ecIniFileCorrupt = -13814; + ecInUse = -13815; + ecInvalAddress = -13816; + ecInvalAddressID = -13817; + ecInvalAddressMode = -13818; + ecInvalAddressState = -13819; + ecInvalAppHandle = -13820; + ecInvalAppName = -13821; + ecInvalBearerMode = -13822; + ecInvalCallComplMode = -13823; + ecInvalCallHandle = -13824; + ecInvalCallParams = -13825; + ecInvalCallPrivilege = -13826; + ecInvalCallSelect = -13827; + ecInvalCallState = -13828; + ecInvalCallStatelist = -13829; + ecInvalCard = -13830; + ecInvalCompletionID = -13831; + ecInvalConfCallHandle = -13832; + ecInvalConsultCallHandle = -13833; + ecInvalCountryCode = -13834; + ecInvalDeviceClass = -13835; + ecInvalDeviceHandle = -13836; + ecInvalDialParams = -13837; + ecInvalDigitList = -13838; + ecInvalDigitMode = -13839; + ecInvalDigits = -13840; + ecInvalExtVersion = -13841; + ecInvalGroupID = -13842; + ecInvalLineHandle = -13843; + ecInvalLineState = -13844; + ecInvalLocation = -13845; + ecInvalMediaList = -13846; + ecInvalMediaMode = -13847; + ecInvalMessageID = -13848; + ecInvalParam = -13850; + ecInvalParkID = -13851; + ecInvalParkMode = -13852; + ecInvalPointer = -13853; + ecInvalPrivSelect = -13854; + ecInvalRate = -13855; + ecInvalRequestMode = -13856; + ecInvalTerminalID = -13857; + ecInvalTerminalMode = -13858; + ecInvalTimeout = -13859; + ecInvalTone = -13860; + ecInvalToneList = -13861; + ecInvalToneMode = -13862; + ecInvalTransferMode = -13863; + ecLineMapperFailed = -13864; + ecNoConference = -13865; + ecNoDevice = -13866; + ecNoDriver = -13867; + ecNoMem = -13868; + ecNoRequest = -13869; + ecNotOwner = -13870; + ecNotRegistered = -13871; + ecOperationFailed = -13872; + ecOperationUnavail = -13873; + ecRateUnavail = -13874; + ecResourceUnavail = -13875; + ecRequestOverrun = -13876; + ecStructureTooSmall = -13877; + ecTargetNotFound = -13878; + ecTargetSelf = -13879; + ecUninitialized = -13880; + ecUserUserInfoTooBig = -13881; + ecReinit = -13882; + ecAddressBlocked = -13883; + ecBillingRejected = -13884; + ecInvalFeature = -13885; + ecNoMultipleInstance = -13886; + +const + {Apro encounters a few of its own TAPI errors, place these error + codes after the native TAPI error codes, but leave a little bit + of room for expansion of the TAPI error codes.} + ecTapiBusy = -13928; + ecTapiNotSet = -13929; + ecTapiNoSelect = -13930; + ecTapiLoadFail = -13931; + ecTapiGetAddrFail = -13932; + ecTapiUnexpected = -13934; + ecTapiVoiceNotSupported = -13935; + ecTapiWaveFail = -13936; + ecTapiCIDBlocked = -13937; + ecTapiCIDOutOfArea = -13938; + ecTapiWaveFormatError = -13939; + ecTapiWaveReadError = -13940; + ecTapiWaveBadFormat = -13941; + ecTapiTranslateFail = -13942; + ecTapiWaveDeviceInUse = -13943; + ecTapiWaveFileExists = -13944; + ecTapiWaveNoData = -13945; + + ecVoIPNotSupported = -13950; { TAPI3/H.323 not found } + ecVoIPCallBusy = -13951; { remote was busy } + ecVoIPBadAddress = -13952; { destination address bad } + ecVoIPNoAnswer = -13953; { remote did not answer } + ecVoIPCancelled = -13954; { cancelled } + ecVoIPRejected = -13955; { remote rejected the call } + ecVoIPFailed = -13956; { general failure } + ecVoIPTapi3NotInstalled = -13957; { ITTapi interface failure } {!!.01} + ecVoIPH323NotFound = -13958; { H.323 line not found } {!!.01} + ecVoIPTapi3EventFailure = -13959; { event notify failure } {!!.01} + + {RAS error codes} + ecRasLoadFail = -13980; + +const + {Convenient character constants (and aliases)} + cNul = #0; + cSoh = #1; + cStx = #2; + cEtx = #3; + cEot = #4; + cEnq = #5; + cAck = #6; + cBel = #7; + cBS = #8; + cTab = #9; + cLF = #10; + cVT = #11; + cFF = #12; + cCR = #13; + cSO = #14; + cSI = #15; + cDle = #16; + cDC1 = #17; cXon = #17; + cDC2 = #18; + cDC3 = #19; cXoff = #19; + cDC4 = #20; + cNak = #21; + cSyn = #22; + cEtb = #23; + cCan = #24; + cEM = #25; + cSub = #26; + cEsc = #27; + cFS = #28; + cGS = #29; + cRS = #30; + cUS = #31; + +type + {Protocol status information record} + TProtocolInfo = record + piProtocolType : Cardinal; + piBlockErrors : Cardinal; + piTotalErrors : Cardinal; + piBlockSize : Cardinal; + piBlockNum : Cardinal; + piFileSize : Integer; + piBytesTransferred : Integer; + piBytesRemaining : Integer; + piInitFilePos : Integer; + piElapsedTicks : Integer; + piFlags : Integer; + piBlockCheck : Cardinal; + piFileName : TPathCharArrayA; + piError : Integer; + piStatus : Cardinal; + end; + +const + {Port options} + poUseEventWord = $04; {Set to use the event word} + + { APRO-specific flags used in InitPort} + ipAssertDTR = $00000001; + ipAssertRTS = $00000002; + ipAutoDTR = $00000010; + ipAutoRTS = $00000020; + + {Hardware flow control options} + hfUseDTR = $01; {Use DTR for receive flow control} + hfUseRTS = $02; {Use RTS for receive flow control} + hfRequireDSR = $04; {Require DSR before transmitting} + hfRequireCTS = $08; {Require CTS before transmitting} + + {Software flow control options} + sfTransmitFlow = $01; {Honor received Xon/Xoffs} + sfReceiveFlow = $02; {Send Xon/Xoff as required} + + {Define bits for TDCB Flags field} + dcb_Binary = $0001; + dcb_Parity = $0002; + dcb_OutxCTSFlow = $0004; + dcb_OutxDSRFlow = $0008; + dcb_DTRBit1 = $0010; + dcb_DTRBit2 = $0020; + dcb_DsrSensitivity = $0040; + dcb_TxContinueOnXoff = $0080; + dcb_OutX = $0100; + dcb_InX = $0200; + dcb_ErrorChar = $0400; + dcb_Null = $0800; + dcb_RTSBit1 = $1000; + dcb_RTSBit2 = $2000; + dcb_AbortOnError = $4000; + + dcb_DTR_CONTROL_ENABLE = dcb_DTRBit1; + dcb_DTR_CONTROL_HANDSHAKE = dcb_DTRBit2; + dcb_RTS_CONTROL_ENABLE = dcb_RTSBit1; + dcb_RTS_CONTROL_HANDSHAKE = dcb_RTSBit2; + dcb_RTS_CONTROL_TOGGLE = (dcb_RTSBit1 + dcb_RTSBit2); + + {For reporting flow states, note: no receive hardware flow status is provided} + fsOff = 1; {No flow control is in use} + fsOn = 2; {Flow control is but not transmit blocked} + fsDsrHold = 3; {Flow control is on and transmit blocked by low DSR} + fsCtsHold = 4; {Flow control is on and transmit blocked by low CTS} + fsDcdHold = 5; {Flow control is on and transmit blocked by low DCD} + fsXOutHold = 6; {Flow control is on and transmit blocked by Xoff} + fsXInHold = 7; {Flow control is on and receive blocked by Xoff} + fsXBothHold= 8; {Flow control is on and both are blocked by Xoff} + +const + {Emulator commands} + eNone = 0; {No command, ignore this char} + eChar = 1; {No command, process the char} + eGotoXY = 2; {X} {Absolute goto cursor position call} + eUp = 3; {X} {Cursor up} + eDown = 4; {X} {Cursor down} + eRight = 5; {X} {Cursor right} + eLeft = 6; {X} {Cursor left} + eClearBelow = 7; {R} {Clear screen below cursor} + eClearAbove = 8; {R} {Clear screen above cursor} + eClearScreen = 9; {R} {Clear entire screen} + eClearEndofLine = 10;{R} {Clear from cursor to end of line} + eClearStartOfLine= 11;{R} {Clear from cursor to the start of line} + eClearLine = 12;{R} {Clear entire line that cursor is on} + eSetMode = 13;{X} {Set video mode} + eSetBackground = 14; {Set background attribute} + eSetForeground = 15; {Set foreground attribute} + eSetAttribute = 16;{X} {Set video attribute (foreground and background)} + eSaveCursorPos = 17; {Save cursor position} + eRestoreCursorPos= 18; {Restore cursor position} + eDeviceStatusReport = 19;{X}{Report device status or cursor position} + eString = 20; {Pascal style string} + eHT = 21; {Horizontal Tab Character} + eError = 255; {indicates a parser error} + + eAPC { } = 30; {Application programming command} + eCBT {X} = 31; {Cursor backward tabulation} + eCCH { } = 32; {Cancel character} + eCHA {X} = 33; {Cursor horizontal absolute} + eCHT {X} = 34; {Cursor horizontal tabulation} + eCNL {X} = 35; {Cursor next line} + eCPL {X} = 36; {Cursor preceding line} + eCPR {X} = 37; {Cursor position report} + eCRM {.} = 38; {Control representation mode} + eCTC {X} = 39; {Cursor tabulation control} + eCUB {X} = eLeft; {Cursor backward} + eCUD {X} = eDown; {Cursor down} + eCUF {X} = eRight; {Cursor forward} + eCUP {X} = eGotoXY; {Cursor position} + eCUU {X} = eUp; {Cursor up} + eCVT {X} = 40; {Cursor vertical tabulation} + eDA {X} = 41; {Device attributes} + eDAQ { } = 42; {Define area qualification} + eDCH {X} = 43; {Delete character} + eDCS { } = 44; {Device control string} + eDL {X} = 45; {Delete line} + eDMI { } = 46; {Disable manual input} + eDSR {X} = eDeviceStatusReport;{Device status report} + eEA { } = 47; {Erase in area} + eEBM { } = 48; {Editing boundry mode} + eECH {X} = 49; {Erase character} + eED {X} = 50; {Erase in Display} + eEF { } = 51; {Erase in field} + eEL {X} = 52; {Erase in line} + eEMI { } = 53; {Enable manual input} + eEPA { } = 54; {End of protected mode} + eERM { } = 55; {Erasure mode} + eESA { } = 56; {End of selected area} + eFEAM { } = 57; {Format effector action mode} + eFETM { } = 58; {Format effector transfer mode} + eFNT { } = 59; {Font selection} + eGATM { } = 60; {Guarded area transfer mode} + eGSM { } = 61; {Graphics size modification} + eGSS { } = 62; {Graphics size selection} + eHEM { } = 63; {Horizontal editing mode} + eHPA {X} = eCHA; {Horizontal position absolute} + eHPR {X} = eCUF; {Horizontal position relative} + eHTJ {X} = 64; {Horizontal tab with justification} + eHTS {X} = 65; {Horizontal tabulation set} + eHVP {X} = eCUP; {Horizontal and vertical position} + eICH {X} = 66; {Insert character} + eIL {X} = 67; {Insert line} + eIND {X} = eCUD; {Index} + eINT { } = 68; {Interrupt} + eIRM {.} = 69; {Inseration-Replacement mode} + eJFY { } = 70; {Justify} + eKAM {.} = 71; {Keyboard action mode} + eLNM {.} = 72; {Line feed new line mode} + eMATM { } = 73; {Multiple area transfer mode} + eMC {.} = 74; {Media copy} + eMW {.} = 75; {Message waiting} + eNEL {X} = 76; {Next line} + eNP {.} = 77; {Next page} + eOSC { } = 78; {Operating system command} + ePLD { } = 79; {Partial line down} + ePLU { } = 80; {Partial line up} + ePM { } = 81; {Privacy message} + ePP {.} = 82; {Preceding page} + ePU1 { } = 83; {Private use 1} + ePU2 { } = 84; {Private use 2} + ePUM { } = 85; {Positioning unit mode} + eQUAD { } = 86; {Quad} + eREP { } = 87; {Repeat} + eRI {X} = 88; {Reverse index} + eRIS {.} = 89; {Reset to initial state} + eRM {.} = 90; {Reset mode} + eSATM { } = 91; {Selected area transfer mode} + eSD { } = 92; {Scroll down} + eSEM { } = 93; {selected editing extent mode} + eSGR {X} = eSetAttribute;{Select graphics rendition} + eSL { } = 94; {Scroll left} + eSM {.} = eSetMode;{Set Mode} + eSPA { } = 95; {Start of protected area} + eSPI { } = 96; {Spacing increment} + eSR { } = 97; {Scroll right} + eSRM { } = 98; {Send-Receive mode} + eSRTM { } = 99; {Status report transfer mode} + eSS2 { } = 100; {Single shift 2} + eSS3 { } = 101; {Single shift 3} + eSSA { } = 102; {Start of selected area} + eST { } = 103; {String terminator} + eSTS { } = 104; {Set transmit state} + eSU { } = 105; {Scroll up} + eTBC {X} = 106; {Tabulation clear} + eTSM { } = 107; {Tabulation stop mode} + eTSS { } = 108; {Thin space specification} + eTTM { } = 109; {Transfer termination mode} + eVEM { } = 110; {Vertical editing mode} + eVPA {X} = 111; {Vertical position absolute} + eVPR {X} = eCUD; {Vertical position relative} + eVTS {X} = 112; {vertical tabulation set} + eDECSTBM = 113; {dec private-set Top/Bottom margin} + + eENQ {X} = 114; {enquiry request} + eBEL {X} = 115; {sound bell} + eBS {X} = 116; {backspace} + eLF {X} = 117; {line feed command} + eCR {X} = 118; {carriage return} + eSO {X} = 119; {invoke G1 charset} + eSI {X} = 120; {invoke G0 charset} + eIND2 {X} = 121; {corrected eIND (<> eCUD, eDown) new term only} + eDECALN = 122; {DEC PRIVATE-screen alignment display} + eDECDHL = 123; {DEC PRIVATE-Double height line} + eDECDWL = 124; {DEC PRIVATE-Double width line} + eDECLL = 125; {DEC PRIVATE-load LEDs} + eDECREQTPARM = 126; {DEC PRIVATE-request terminal parameters} + eDECSWL = 127; {DEC PRIVATE-single width line} + eDECTST = 128; {DEC PRIVATE-Invoke confidence test} + eDECSCS = 129; {DEC PRIVATE-select charset} + + {Extended attributes} + eattrBlink = $01; + eattrInverse = $02; + eattrIntense = $04; + eattrInvisible = $08; + eattrUnderline = $10; + + {ANSI color constants} + emBlack = 0; + emRed = 1; + emGreen = 2; + emYellow = 3; + emBlue = 4; + emMagenta = 5; + emCyan = 6; + emWhite = 7; + emBlackBold = 8; + emRedBold = 9; + emGreenBold = 10; + emYellowBold = 11; + emBlueBold = 12; + emMagentaBold = 13; + emCyanBold = 14; + emWhiteBold = 15; + + {AnsiEmulator option flags} + teMapVT100 = $0001; + + {Misc} + MaxParams = 5; {Maximum parameters for our interpreter} + MaxQueue = 20; {Maximum characters in queue} + MaxOther = 11; {Maximum other data} + MaxParamLength = 5; {Maximum parameter length for interpreter} + KeyMappingLen = 20; {Maximum length of a keymapping} + +type + {AnsiEmulator's parser states} + TAnsiParser = (GotNone, GotEscape, GotBracket, GotSemiColon, GotParam, + GotCommand, GotControlSeqIntro, GotLeftBrace, GotRightBrace, + GotSpace, GotQuestionMark, GotQuestionParam); + + {Array used for internal queue} + TApQueue = Array[1..MaxQueue] of AnsiChar; // SWB + + {Emulator for PC ANSI codes} + PAnsiEmulator = ^TAnsiEmulator; + TAnsiEmulator = record + emuType : Cardinal; { Emulator Type } + emuFlags : Cardinal; + emuFirst : Bool; {True if first time thru} + emuAttr : Byte; + emuIndex : Cardinal; {Index into rcvd byte array} + emuParamIndex : Cardinal; {Parameter index} + emuQueue : TApQueue; {Queue of recvd bytes} // SWB + emuParamStr : array[1..MaxParams] of string[MaxParamLength]; + emuParamInt : array[1..MaxParams] of Integer; + emuParserState : TAnsiParser; {Current state} + emuOther : Pointer; + end; + +const + {Terminal window Cardinal} + gwl_Terminal = 0; + + {Terminal options} + tws_WantTab = $0001; {Process tabs internally} + tws_IntHeight = $0002; {Integral height} + tws_IntWidth = $0004; {Integral width} + tws_AutoHScroll = $0008; {Add/remove horiz scroll automatically} + tws_AutoVScroll = $0010; {Add/remove vert scroll automatically} + +type + {For general typecasting} + LH = record + L,H : Word; + end; + + {IniDBase (deprecated) consts and types} +const + MaxDBRecs = 999; {Maximum number of database records} + MaxNameLen = 21; {Maximum length of a profile string key} + MaxIndexLen = 31; {Maximum length of an index string} + NonValue = '#'; {Value of DB fields SPECIFICALLY left blank} + dbIndex = 'Index'; {Item index section heading} + dbDefaults = 'Defaults'; {Default value section heading} + dbNumEntries = '_Entries'; {Number of entries key name} + dbBogus = 'None'; {Bogus key name for creating sections} + +type + PIniDatabaseKey = ^TIniDatabaseKey; + TIniDatabaseKey = record + KeyName : PAnsiChar; + DataSize : Cardinal; + StrType : Bool; + Index : Bool; + Next : PIniDatabaseKey; + end; + + PIniDatabase = ^TIniDatabase; + TIniDatabase = record + FName : PAnsiChar; + DictionaryHead : PIniDatabaseKey; + DictionaryTail : PIniDatabaseKey; + NumRecords : Integer; + RecordSize : Cardinal; + DefaultRecord : Pointer; + Prepared : Bool; + end; + +const + ApdMaxTags = 5; {Maximum number of err corr or data comp tags} + ApdTagSepChar = ','; {Character that separates tags in a profile string} + +const + ApdModemNameLen = 31; {Length of a modem name string} + ApdCmdLen = 41; {Maximum length of a modem command} + ApdRspLen = 21; {Maximum length of a modem response} + ApdTagLen = 21; {Maximum length of a tag string} + ApdTagProfLen = 105; {Maximum length of a tag profile string} + ApdBoolLen = 5; {Maximum length of a boolean string} + ApdBaudLen = 7; {Maximum length of a baud rate string} + ApdConfigLen = 255; {Maximum length of a configuration string} + +type + {where these same variables are declared as Strings.} + TModemNameZ = array[0..ApdModemNameLen] of AnsiChar; //SZ: must probably be Ansi + TCmdStringZ = array[0..ApdCmdLen] of AnsiChar; + TRspStringZ = array[0..ApdRspLen] of AnsiChar; + TTagStringZ = array[0..ApdTagLen] of AnsiChar; + TTagProfStringZ = array[0..ApdTagProfLen] of AnsiChar; + TConfigStringZ = array[0..ApdConfigLen] of AnsiChar; + TBoolStrZ = array[0..ApdBoolLen] of AnsiChar; + TBaudStrZ = array[0..ApdBaudLen] of AnsiChar; + + TTagArrayZ = array[1..ApdMaxTags] of TTagStringZ; + + PModemBaseData = ^TModemBaseData; + TModemBaseData = record + Name : TModemNameZ; + InitCmd : TCmdStringZ; + DialCmd : TCmdStringZ; + DialTerm : TCmdStringZ; + DialCancel : TCmdStringZ; + HangupCmd : TCmdStringZ; + ConfigCmd : TConfigStringZ; + AnswerCmd : TCmdStringZ; + OkMsg : TRspStringZ; + ConnectMsg : TRspStringZ; + BusyMsg : TRspStringZ; + VoiceMsg : TRspStringZ; + NoCarrierMsg : TRspStringZ; + NoDialToneMsg : TRspStringZ; + ErrorMsg : TRspStringZ; + RingMsg : TRspStringZ; + end; + + PModemData = ^TModemData; + TModemData = record + Data : TModemBaseData; + NumErrors : Cardinal; + Errors : TTagArrayZ; + NumComps : Cardinal; + Compression : TTagArrayZ; + LockDTE : Bool; + DefBaud : Integer; + end; + + PModemXFer = ^TModemXFer; + TModemXFer = record + Data : TModemBaseData; + Errors : TTagProfStringZ; + Compress : TTagProfStringZ; + LockDTE : TBoolStrZ; + DefBaud : TBaudStrZ; + end; + + PModemDatabase = ^TModemDatabase; + TModemDatabase = record + DB : PIniDatabase; + end; + + +const + {keyboard shift state masks} + ksControl = $02; + ksAlt = $04; + ksShift = $08; + + {keyboard toggle state masks} + tsCapital = $02; + tsNumlock = $04; + tsScroll = $08; + + {keyboard INI file constants} + ApdKeyMapNameLen = 30; {Length of a KeyMap name string} + ApdMaxKeyMaps = 100; {Maximum possible key mapping per type} + + ApdKeyIndexName = 'EMULATOR'; + ApdKeyIndexMaxLen = 120; + +type + TKeyMapName = array[0..ApdKeyMapNameLen] of AnsiChar; + TKeyMapping = array[0..KeyMappingLen] of Ansichar; + TKeyMappingStr = string[KeyMappingLen]; + + + PKeyMapXFerRec = ^TKeyMapXFerRec; + TKeyMapXFerRec = record + Name : TKeyMapName; + Keys : array[1..ApdMaxKeyMaps] of TKeyMapping; + end; + + PVKeyMapRec = ^TVKeyMapRec; + TVKEyMapRec = record + KeyCode : Cardinal; + ShiftState: Cardinal; + Mapping : TKeyMappingStr; + end; + + PKeyEmulator = ^TKeyEmulator; + TKeyEmulator = record + kbKeyFileName : PChar; { current file name } + kbKeyName : TKeyMapName; { current key index name } + kbProcessAll : Bool; + kbProcessExt : Bool; + kbKeyNameList : array[0..ApdKeyIndexMaxLen] of Ansichar; + kbKeyMap : array[1..ApdMaxKeyMaps] of TVKeyMapRec; + kbKeyDataBase : PIniDataBase; { pointer to the INI data base file } + end; + +const + {---- Option codes for protocols ----} + apIncludeDirectory = $0001; {Set to include directory in file names} + apHonorDirectory = $0002; {Set to honor directory in file names} + apRTSLowForWrite = $0004; {Set to lower RTS during disk writes} + apAbortNoCarrier = $0008; {Set to abort protocol on DCD loss} + apKermitLongPackets = $0010; {Set to support long packets} + apKermitSWC = $0020; {Set to support SWC} + apZmodem8K = $0040; {Set to support 8K blocks} + apBP2KTransmit = $0080; {Set to support 2K transmit blocks} + apAsciiSuppressCtrlZ = $0100; {Set to stop transmitting on ^Z} + + {---- Default options for protocols ----} + DefProtocolOptions = 0; + BadProtocolOptions = apKermitLongPackets+apKermitSWC+apZmodem8K; + + {Block check codes} + bcNone = 0; {No block checking} + bcChecksum1 = 1; {Basic checksum} + bcChecksum2 = 2; {Two byte checksum} + bcCrc16 = 3; {16 bit Crc} + bcCrc32 = 4; {32 bit Crc} + bcCrcK = 5; {Kermit style Crc} + + {Convenient blockcheck string constants} + bcsNone = 'No check'; + bcsChecksum1 = 'Checksum'; + bcsChecksum2 = 'Checksum2'; + bcsCrc16 = 'Crc16'; + bcsCrc32 = 'Crc32'; + bcsCrck = 'CrcKermit'; + + {Constants for supported protocol types} + NoProtocol = 0; + Xmodem = 1; + XmodemCRC = 2; + Xmodem1K = 3; + Xmodem1KG = 4; + Ymodem = 5; + YmodemG = 6; + Zmodem = 7; + Kermit = 8; + Ascii = 9; + BPlus = 10; + + {Zmodem attention string length} + MaxAttentionLen = 32; + + {Zmodem file management options} + zfWriteNewerLonger = 1; {Transfer if new, newer or longer} + zfWriteCrc = 2; {Not supported, same as WriteNewer} + zfWriteAppend = 3; {Transfer if new, append if exists} + zfWriteClobber = 4; {Transfer regardless} + zfWriteNewer = 5; {Transfer if new or newer} + zfWriteDifferent = 6; {Transfer if new or diff dates/lens} + zfWriteProtect = 7; {Transfer only if new} + + {Convenient protocol string constants} + ProtocolString : array[NoProtocol..BPlus] of array[0..9] of AnsiChar= ( + 'None', 'Xmodem', 'XmodemCRC', 'Xmodem1K', 'Xmodem1KG', + 'Ymodem', 'YmodemG', 'Zmodem', 'Kermit', 'Ascii', 'B+'); + +type + {For holding lists of files to transmit} + PFileList = ^TFileList; + TFileList = array[0..65535-1] of Char; + +{Fax conversion} + +const + rw1728 = 1; {standard width} + rw2048 = 2; {extra wide} + + {Fax pixel widths} + StandardWidth = 1728; {Standard width in pixels} + WideWidth = 2048; {Allowed higher resolution} + + {Option flags for FAX page header} + ffHighRes = $0001; {Image stored in high-res mode} + ffHighWidth = $0002; {Image uses option high-width mode} + ffLengthWords = $0004; {Set if raster lines include length Cardinal} + + {Options for fax conversion} + fcDoubleWidth = $0001; {Double the horizontal width in std res} + fcHalfHeight = $0002; {Halve the vertical height in std res} + fcCenterImage = $0004; {Center graphics images horizontally} + fcYield = $0008; {Have the converter yield while converting} + fcYieldOften = $0010; {Increases the number of yields} + + {Flags passed to status function} + csStarting = $0001; + csEnding = $0002; + + {Font handles, same value as bytes-per-char} + SmallFont = 16; + StandardFont = 48; + + {Maximum number of tree records} + MaxTreeRec = 306; + + {Max size of decompress buffer} + MaxData = 4096; + + {Text conversion limits} + MaxLineLen = 144; + + {encoding/decoding table limits} + MaxCodeTable = 63; + MaxMUCodeTable = 39; + + {default extensions} + DefTextExt = 'TXT'; + DefTiffExt = 'TIF'; + DefPcxExt = 'PCX'; + DefDcxExt = 'DCX'; + DefBmpExt = 'BMP'; + DefApfExt = 'APF'; + +type + {Compression code tables} + TCodeRec = record + Code : Word; + Sig : Word; + end; + + TTermCodeArray = array[0..MaxCodeTable] of TCodeRec; + TMakeUpCodeArray = array[0..MaxMUCodeTable] of TCodeRec; + + PBufferedOutputFile = ^TBufferedOutputFile; + TBufferedOutputFile = record + BufPos : Word; + Buffer : PByteArray; + OutFile : File; + end; + + {For storing station IDs} + Str20 = string[20]; + + {Stores information about our fonts} + TFontRecord = record + Bytes : Byte; {# of bytes per char in font} + PWidth : Byte; {width of font in pixels} + Width : Byte; {width of font in bytes (e.g. 16-pixel-wide = 2)} + Height : Byte; {height of font in raster lines} + end; + + {Fax file signature array} + TSigArray = Array[0..5] of AnsiChar; + +const + {Default fax file signature, first 6 chars in an APF} + DefAPFSig : TSigArray = 'APF10'#26; + +type + {APRO fax file header record} + TFaxHeaderRec = packed record + Signature : TSigArray; {APRO FAX signature} + FDateTime : Integer; {Date and time in DOS format} + SenderID : Str20; {Station ID of sender} + Filler : Byte; {Alignment byte, unused} + PageCount : Word; {Number of pages in this file} + PageOfs : Integer; {Offset in file of first page} + Padding : Array[39..64] of Byte; {Expansion room} + end; + + {APRO fax page header record} + TPageHeaderRec = packed record + ImgLength : Integer; {Bytes of image data in this page} + ImgFlags : Word; {Image flags for width, res, etc} + Padding : Array[7..16] of Byte; {Expansion room} + end; + + {APRO fax server job header} + TFaxJobHeaderRec = packed record + ID : Integer; {APRO fax job signature} + Status : Byte; {0=none sent, 1=some sent, 2=all sent, 3=paused} + JobName : Str20; {Friendly name of fax job} + Sender : String[40]; {Name of sender (same as HeaderSender)} + SchedDT : TDateTime; {TDateTime the first job should be sent} + NumJobs : Byte; {Number of FaxJobInfoRecs for this job} + NextJob : Byte; {The index of the next FaxJobInfo to send} + CoverOfs : Integer; {Offset in file of text CoverFile data} + FaxHdrOfs: Integer; {Offset in file of TFaxHeaderRec} + Padding : Array[86..128] of Byte; {Expansion room} + end; + + {APRO fax server job recipient record } + TFaxRecipientRec = packed record + Status : Byte; {0=not sent, 1=sending, 2=sent, 3=paused} + JobID : Byte; {Unique ID for this job} + SchedDT : TDateTime; {TDateTime this job should be sent} + AttemptNum : Byte; {Retry number for this recipient} + LastResult : Word; {Last ErrorCode for this fax} + PhoneNumber : String[50]; {Phone number to dial for this job} + HeaderLine : String[100]; {Header line} + HeaderRecipient: String[30]; {Recipient's name} + HeaderTitle : String[30]; {Title of fax} + Padding : Array[228..256] of Byte;{Expansion room} + end; + + {Pcx header} + TPcxPalArray = Array[0..47] of Byte; + TPcxHeaderRec = packed record + Mfgr : Byte; + Ver : Byte; + Encoding : Byte; + BitsPixel : Byte; + XMin : Word; + YMin : Word; + XMax : Word; + YMax : Word; + HRes : Word; + VRes : Word; + Palette : TPcxPalArray; + Reserved : Byte; + Planes : Byte; + BytesLine : Word; + PalType : Word; + Filler : Array[1..58] of Byte; {pad to 128 bytes} + end; + + TDcxOfsArray = array[1..1024] of Integer; + + PDcxHeaderRec = ^TDcxHeaderRec; + TDcxHeaderRec = packed record + ID : Integer; + Offsets : TDcxOfsArray; + end; + + TTreeRec = record + Next0 : Integer; + Next1 : Integer; + end; + TTreeArray = array[0..MaxTreeRec] of TTreeRec; + PTreeArray = ^TTreeArray; + + {$IFNDEF DrvInst} + PAbsFaxCvt = ^TAbsFaxCvt; + + {callback function to open a converter input file} + TOpenFileCallback = function(Cvt : PAbsFaxCvt; FileName : string) : Integer; + + {callback function to close a converter input file} + TCloseFileCallback = procedure(Cvt : PAbsFaxCvt); + + {callback function converters use to get input raster} + TGetLineCallback = function(Cvt : PAbsFaxCvt; var Data; var Len : Integer; + var EndOfPage, MorePages : Bool) : Integer; + + {callback function converters use to output data} + TPutLineCallback = function(Cvt : PAbsFaxCvt; var Data; Len : Integer; + EndOfPage, MorePages : Bool) : Integer; + + + {callback function for status information} + TCvtStatusCallback = function(Cvt : PAbsFaxCvt; StatFlags : Word; + BytesRead, BytesToRead : Integer) : Bool; + + {base converter data} + TAbsFaxCvt = record + UseHighRes : Bool; {TRUE if for high-res mode} + DoubleWidth : Bool; {TRUE do double each pixel} + HalfHeight : Bool; {TRUE to discard each raster line} + Flags : Cardinal; {Options flags} + ByteOfs : Cardinal; {Byte offset in buffer} + BitOfs : Cardinal; {Bit offset in buffer} + ResWidth : Cardinal; {Width of current resolution in pels} + LeftMargin : Cardinal; {Left margin in pels} + TopMargin : Cardinal; {Top margin in pels} + CurrPage : Cardinal; {Current page being processed} + CurrLine : Cardinal; {Number of text/raster lines cvted} + LastPage : Cardinal; {Last page number used in file cvt} + CurPagePos : Integer; {file offset of current page} + CenterOfs : Cardinal; {Offset of center of bitmap} + UserData : Pointer; {Data needed by higher level cvters} + OtherData : Pointer; {Other, miscellaneous data} + BytesRead : Integer; + BytesToRead : Integer; + DataLine : PByteArray; {Buffered line of compressed data} + TmpBuffer : PByteArray; {Temp compression buffer} + GetLine : TGetLineCallback; {Callback function to get a raster line} + OpenCall : TOpenFileCallback; {To open the input file, if any} + CloseCall : TCloseFileCallback; {To close the input file, if any} + StatusFunc : TCvtStatusCallback; {Callback for status display} + StatusWnd : HWnd; {Handle of window receiving status msgs} + DefExt : string; // array[0..3] of AnsiChar; + InFileName : string; // array[0..255] of AnsiChar; + OutFileName : string; // array[0..255] of AnsiChar; + StationID : AnsiString; //array[0..20] of AnsiChar; + MainHeader : TFaxHeaderRec; {main header of fax output file} + PageHeader : TPageHeaderRec; {header for current output page} + OutFile : PBufferedOutputFile;{Output file} + PadPage : Bool; {True to pad text conversion to full page}{!!.04} + {$IFNDEF PrnDrv} + InBitmap : Graphics.TBitmap; + {$ENDIF} + end; + +{$IFNDEF PrnDrv} + +type + { moved from AdWUtil } {!!.06} + SunB = packed record {!!.06} + s_b1, s_b2, s_b3, s_b4 : AnsiChar; {!!.06} + end; {!!.06} + { moved from AdWUtil } {!!.06} + SunW = packed record {!!.06} + s_w1, s_w2 : Word; {!!.06} + end; {!!.06} + + { moved from AdWnPort and AdWUtil } {!!.06} + PInAddr = ^TInAddr; {!!.06} + TInAddr = packed record {!!.06} + case Integer of {!!.06} + 0 : (S_un_b : SunB); {!!.06} + 1 : (S_un_w : SunW); {!!.06} + 2 : (S_addr : Integer); {!!.06} + end; {!!.06} + + { XML support } +const + {The following constants are the tokens needed to parse an XML + document. The tokens are stored in UCS-4 format to reduce the + number of conversions needed by the filter.} + Xpc_BracketAngleLeft : array[0..0] of Integer = (60); {<} + Xpc_BracketAngleRight : array[0..0] of Integer = (62); {>} + Xpc_BracketSquareLeft : array[0..0] of Integer = (91); {[} + Xpc_BracketSquareRight : array[0..0] of Integer = (93); {]} + Xpc_CDATAStart : + array[0..5] of Integer = (67, 68, 65, 84, 65, 91); {CDATA[} + Xpc_CharacterRef : array[0..0] of Integer = (35); {#} + Xpc_CharacterRefHex : array[0..0] of Integer = (120); {x} + Xpc_CommentEnd : array[0..2] of Integer = (45, 45, 62); {-->} + Xpc_CommentStart : array[0..3] of Integer = (60, 33, 45, 45); {