DWORD GetPortSize( __in PLCMINIPORT pIniPort, DWORD Level ) { DWORD cb = 0; switch (Level) { case 1: cb = (DWORD) (sizeof(PORT_INFO_1) + wcslen(pIniPort->pName)*sizeof(WCHAR) + sizeof(WCHAR)); break; case 2: { LPWSTR pszLocalMonitor = NULL; LPWSTR pszPortDesc = NULL; pszLocalMonitor = (LPWSTR)AllocSplMem((MAX_PATH + 1) * sizeof(WCHAR)); pszPortDesc = (LPWSTR)AllocSplMem((MAX_PATH + 1) * sizeof(WCHAR)); if (pszLocalMonitor && pszPortDesc) { LoadString(LcmhInst, IDS_LOCALMONITORNAME, pszLocalMonitor, MAX_PATH); LoadString(LcmhInst, IDS_LOCALMONITOR, pszPortDesc, MAX_PATH); cb = (DWORD) (wcslen(pIniPort->pName) + 1 + wcslen(pszLocalMonitor) + 1 + wcslen(pszPortDesc) + 1); cb *= sizeof(WCHAR); cb += sizeof(PORT_INFO_2); } if (pszLocalMonitor) { FreeSplMem(pszLocalMonitor); pszLocalMonitor = NULL; } if (pszPortDesc) { FreeSplMem(pszPortDesc); pszPortDesc = NULL; } } break; default: cb = 0; break; } return cb; }
BOOL BReleasePPData( _In_ PPRINTPROCESSORDATA * ppData ) { PPRINTPROCESSORDATA pData = NULL; if ( NULL == ppData || NULL == *ppData) { return FALSE; } pData = *ppData; pData->signature = 0; /* Release any allocated resources */ if (pData->hPrinter) ClosePrinter(pData->hPrinter); if (pData->hDC) DeleteDC(pData->hDC); if (pData->pDevmode) FreeSplMem(pData->pDevmode); if (pData->pPrinterNameFromOpenData) FreeSplStr(pData->pPrinterNameFromOpenData); if (pData->semPaused) CloseHandle(pData->semPaused); if (pData->pPrinterName) FreeSplStr(pData->pPrinterName); if (pData->pDatatype) FreeSplStr(pData->pDatatype); if (pData->pDocument) FreeSplStr(pData->pDocument); if (pData->pOutputFile) FreeSplStr(pData->pOutputFile); if (pData->pParameters) FreeSplStr(pData->pParameters); ZeroMemory ( pData, sizeof (PRINTPROCESSORDATA) ); FreeSplMem(pData); *ppData = pData = NULL; return TRUE; }
/*++ Title: DbgPrint Routine Description: Format the string similar to sprintf and output it in the debugger. Arguments: pszFmt pointer format string. .. variable number of arguments similar to sprintf. Return Value: 0 --*/ BOOL DebugPrint( _In_ PCH pszFmt, ... ) { LPSTR pszString = NULL; BOOL bReturn; va_list pArgs; va_start( pArgs, pszFmt ); pszString = vsntprintf( pszFmt, pArgs ); bReturn = !!pszString; va_end( pArgs ); if (pszString) { OutputDebugStringA(pszString); FreeSplMem(pszString); } return bReturn; }
BOOL FreeSplStr( LPTSTR lpStr ) { return lpStr ? FreeSplMem(lpStr) : FALSE; }
LPWSTR AllocSplStr( LPCWSTR pszSource ) { PWSTR pszRet = NULL; if (pszSource) { size_t len = 0; HRESULT hr = StringCchLength(pszSource, STRSAFE_MAX_CCH, &len); if (SUCCEEDED(hr)) { pszRet = (PWSTR)AllocSplMem((len + 1) * sizeof(WCHAR)); if (pszRet) { hr = StringCchCopy(pszRet, len + 1, pszSource); if (FAILED(hr)) { FreeSplMem(pszRet); pszRet = NULL; } } } } return pszRet; }
BOOL GetIniCommValues( _In_ LPWSTR pName, LPDCB pdcb, LPCOMMTIMEOUTS pcto ) { BOOL bRet = TRUE; LPWSTR pszEntry = NULL; if (bRet) { bRet = GetIniCommValuesFromRegistry (pName, &pszEntry); } if (bRet) { bRet = BuildCommDCB (pszEntry, pdcb); } if (bRet) { GetTransmissionRetryTimeoutFromRegistry (&pcto-> WriteTotalTimeoutConstant); pcto->WriteTotalTimeoutConstant*=1000; } FreeSplMem(pszEntry); return bRet; }
BOOL DeleteXcvPortEntry( __in PINIXCVPORT pIniXcvPort ) { PINILOCALMON pIniLocalMon = pIniXcvPort->pIniLocalMon; PINIXCVPORT pPort = NULL; PINIXCVPORT pPrevPort = NULL; for (pPort = pIniLocalMon->pIniXcvPort; pPort && pPort != pIniXcvPort; pPort = pPort->pNext){ pPrevPort = pPort; } if (pPort) { // found the port if (pPort == pIniLocalMon->pIniXcvPort) { pIniLocalMon->pIniXcvPort = pPort->pNext; } else { pPrevPort->pNext = pPort->pNext; } FreeSplMem(pPort); return TRUE; } else // port not found return FALSE; }
BOOL DllFreeSplStr( LPWSTR pStr ) { return pStr ? FreeSplMem(pStr) : FALSE; }
BOOL DeletePrinterHandle( PSPOOL pSpool ) { BOOL bRet = FALSE; SplInSem(); if (pSpool->pIniPrintProc) { pSpool->pIniPrintProc->cRef--; } if (pSpool->pDevMode) FreeSplMem(pSpool->pDevMode); FreeSplStr(pSpool->pUserName); FreeSplStr(pSpool->pMachineName); FreeSplStr(pSpool->pDatatype); SetSpoolClosingChange(pSpool); FreeSplStr(pSpool->pName); bRet = ObjectCloseAuditAlarm( szSpooler, pSpool, pSpool->GenerateOnClose ); // // If there is a WaitForPrinterChange outstanding, we can't free // the pSpool, since we may try and reference it. // if (pSpool->ChangeEvent) { pSpool->eStatus |= STATUS_PENDING_DELETION; } else { FreeSplMem(pSpool); } return TRUE; }
/* PortExists * * Calls EnumPorts to check whether the port name already exists. * This asks every monitor, rather than just this one. * The function will return TRUE if the specified port is in the list. * If an error occurs, the return is FALSE and the variable pointed * to by pError contains the return from GetLastError(). * The caller must therefore always check that *pError == NO_ERROR. */ BOOL PortExists( _In_opt_ LPWSTR pName, _In_ LPWSTR pPortName, _Out_ PDWORD pError ) { DWORD cbNeeded = 0; DWORD cReturned = 0; DWORD cbPorts = 0; LPPORT_INFO_1 pPorts = NULL; DWORD i = 0; BOOL Found = TRUE; *pError = NO_ERROR; if (!EnumPortsW(pName, 1, NULL, 0, &cbNeeded, &cReturned)) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { cbPorts = cbNeeded; pPorts = (LPPORT_INFO_1)AllocSplMem(cbPorts); if (pPorts) { if (EnumPortsW(pName, 1, (LPBYTE)pPorts, cbPorts, &cbNeeded, &cReturned)) { Found = FALSE; for (i = 0; i < cReturned; i++) { if (!lstrcmpi(pPorts[i].pName, pPortName)) { Found = TRUE; break; } } } } FreeSplMem(pPorts); } } else { Found = FALSE; } return Found; }
/*++ Title: vsntprintf Routine Description: Formats a string and returns a heap allocated string with the formated data. This routine can be used to for extremely long format strings. Note: If a valid pointer is returned the callng functions must release the data with a call to delete. Arguments: psFmt - format string pArgs - pointer to a argument list. Return Value: Pointer to formated string. NULL if error. --*/ LPSTR vsntprintf( IN LPCSTR szFmt, IN va_list pArgs ) { LPSTR pszBuff; UINT uSize = 256; for( ; ; ) { pszBuff = (LPSTR)AllocSplMem(sizeof(char) * uSize); if (!pszBuff) { break; } // // Attempt to format the string. If format succeeds, get out // of the loop. If it fails, increase buffer size and continue. // (assuming failure is due to less buffer size). // if (SUCCEEDED ( StringCchVPrintfA(pszBuff, uSize, szFmt, pArgs) ) ) { break; } FreeSplMem(pszBuff); pszBuff = NULL; // // Double the buffer size after each failure. // uSize *= 2; // // If the size is greater than 100k exit without formatting a string. // if (uSize > 100*1024) { break; } } return pszBuff; }
LPVOID ReallocSplMem( LPVOID pOldMem, DWORD cbOld, DWORD cbNew ) { LPVOID pNewMem; pNewMem=AllocSplMem(cbNew); if (pOldMem && pNewMem) { if (cbOld) { CopyMemory( pNewMem, pOldMem, min(cbNew, cbOld)); } FreeSplMem(pOldMem); } return pNewMem; }
BOOL DeletePortEntry( LPWSTR pPortName ) { DWORD cb; PINIPORT pPort, pPrevPort; cb = sizeof(INIPORT) + wcslen(pPortName)*sizeof(WCHAR) + sizeof(WCHAR); pPort = pIniFirstPort; while (pPort) { if (!lstrcmpi(pPort->pName, pPortName)) { if (pPort->Status & PP_FILEPORT) { pPrevPort = pPort; pPort = pPort->pNext; continue; } break; } pPrevPort = pPort; pPort = pPort->pNext; } if (pPort) { if (pPort == pIniFirstPort) { pIniFirstPort = pPort->pNext; } else { pPrevPort->pNext = pPort->pNext; } FreeSplMem(pPort); return TRUE; } else return FALSE; }
VOID FreeIniJob( __inout PINIJOB pIniJob ) /*++ Routine Description: Deletes a job entry. Arguments: pIniJob : Pointer to the IniJob structure to be deleted Return Value: None --*/ { SPLASSERT(pIniJob); if ( pIniJob->hPrinter ) ClosePrinter(pIniJob->hPrinter); FreeSplMem(pIniJob); }
BOOL LcmDeletePortEntry( __inout PINILOCALMON pIniLocalMon, __in LPWSTR pPortName ) { PLCMINIPORT pPort = NULL, pPrevPort = NULL; pPort = pIniLocalMon->pIniPort; while (pPort) { if (!lstrcmpi(pPort->pName, pPortName)) { if (pPort->Status & PP_FILEPORT) { pPrevPort = pPort; pPort = pPort->pNext; continue; } break; } pPrevPort = pPort; pPort = pPort->pNext; } if (pPort) { if (pPort == pIniLocalMon->pIniPort) { pIniLocalMon->pIniPort = pPort->pNext; } else { pPrevPort->pNext = pPort->pNext; } FreeSplMem(pPort); return TRUE; } else return FALSE; }
BOOL AbortThisJob( _In_ PLCMINIPORT pIniPort ) /*++ Tells if the job should be aborted. A job should be aborted if it has been deleted or it needs to be restarted. --*/ { BOOL bRet = FALSE; DWORD dwNeeded = 0; LPJOB_INFO_1 pJobInfo = NULL; dwNeeded = 0; GetJob(pIniPort->hPrinter, pIniPort->JobId, 1, NULL, 0, &dwNeeded); if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ) goto Done; pJobInfo = (LPJOB_INFO_1) AllocSplMem(dwNeeded); if ( !pJobInfo || !GetJob(pIniPort->hPrinter, pIniPort->JobId, 1, (LPBYTE)pJobInfo, dwNeeded, &dwNeeded)) goto Done; bRet = (pJobInfo->Status & JOB_STATUS_DELETING) || (pJobInfo->Status & JOB_STATUS_DELETED) || (pJobInfo->Status & JOB_STATUS_RESTART); Done: if ( pJobInfo ) FreeSplMem(pJobInfo); return bRet; }
BOOL DeletePortEntry( LPWSTR pPortName ) { DWORD cb; BOOL rc; PINIPORT pPort, pPrevPort; cb = sizeof(INIPORT) + wcslen(pPortName)*sizeof(WCHAR) + sizeof(WCHAR); EnterSplSem(); pPort = pIniFirstPort; while (pPort && wcscmp(pPort->pName, pPortName)) { pPrevPort = pPort; pPort = pPort->pNext; } if (pPort) { if (pPort == pIniFirstPort) { pIniFirstPort = pPort->pNext; } else { pPrevPort->pNext = pPort->pNext; } FreeSplMem (pPort, cb); rc = TRUE; } else rc = FALSE; LeaveSplSem(); return rc; }
BOOL FreeSplStr( _In_opt_ LPWSTR pStr ) /*++ Routine Description: This function will release the memory allocated with a call to AllocSplStr Arguments: pStr - Pointer to the string to release Return Value: TRUE memory was release, FALSE an error occurred, use GetLastError for extended error information. --*/ { return FreeSplMem(pStr); }
VOID CloseIrdaConnection( _In_ PLCMINIPORT pIniPort ) { PIRDA_INFO pIrda = (PIRDA_INFO) pIniPort->pExtra; int ret = 0; if ( (SOCKET)pIniPort->hFile != INVALID_SOCKET ) { ret = closesocket((SOCKET)pIniPort->hFile); pIniPort->hFile = (HANDLE)INVALID_SOCKET; } if ( pIrda ) { // // check if overlapped send is not complete yet // if ( pIrda->WsaOverlapped.hEvent ) { // // wait overlapped send to complete/cancel // if (ret == 0) { WaitForSingleObject (pIrda-> WsaOverlapped.hEvent, 5*60*1000); } WSACloseEvent(pIrda->WsaOverlapped.hEvent); pIrda-> WsaOverlapped.hEvent = NULL; } FreeSplMem(pIrda); pIniPort->pExtra = NULL; } }
LPBYTE CopyIniPortToPort( PINIPORT pIniPort, DWORD Level, LPBYTE pPortInfo, LPBYTE pEnd ) { LPWSTR *SourceStrings, *pSourceStrings; PPORT_INFO_2 pPort2 = (PPORT_INFO_2)pPortInfo; WCHAR szLocalMonitor[MAX_PATH+1], szPortDesc[MAX_PATH+1]; DWORD *pOffsets; DWORD Count; switch (Level) { case 1: pOffsets = PortInfo1Strings; break; case 2: pOffsets = PortInfo2Strings; break; default: DBGMSG(DBG_ERROR, ("CopyIniPortToPort: invalid level %d", Level)); return NULL; } for ( Count = 0 ; pOffsets[Count] != -1 ; ++Count ) { } SourceStrings = pSourceStrings = AllocSplMem(Count * sizeof(LPWSTR)); if ( !SourceStrings ) { DBGMSG( DBG_WARNING, ("Failed to alloc port source strings.\n")); return NULL; } switch (Level) { case 1: *pSourceStrings++=pIniPort->pName; break; case 2: *pSourceStrings++=pIniPort->pName; LoadString(hInst, IDS_LOCALMONITORNAME, szLocalMonitor, sizeof(szLocalMonitor)-1); LoadString(hInst, IDS_LOCALMONITOR, szPortDesc, sizeof(szPortDesc)-1); *pSourceStrings++ = szLocalMonitor; *pSourceStrings++ = szPortDesc; // How do i findout other types ??? pPort2->fPortType = PORT_TYPE_WRITE; // Reserved pPort2->Reserved = 0; break; default: DBGMSG(DBG_ERROR, ("CopyIniPortToPort: invalid level %d", Level)); return NULL; } pEnd = PackStrings(SourceStrings, pPortInfo, pOffsets, pEnd); FreeSplMem(SourceStrings); return pEnd; }
DWORD GetDriverMajorVersion( LPWSTR pFileName ) { DWORD dwSize = 0; LPVOID pFileVersion; UINT uLen = 0; LPVOID pMem; DWORD dwFileOS; DWORD dwFileVersionMS; DWORD dwFileVersionLS; DWORD dwProductVersionMS; DWORD dwProductVersionLS; if (!(dwSize = GetFileVersionInfoSize(pFileName, 0))) { DBGMSG(DBG_TRACE, ("Error: GetFileVersionInfoSize failed with %d\n", GetLastError())); DBGMSG(DBG_TRACE, ("Returning back a version # 0\n")); return(0); } if (!(pMem = AllocSplMem(dwSize))) { DBGMSG(DBG_TRACE, ("AllocMem failed \n")); DBGMSG(DBG_TRACE, ("Returning back a version # 0\n")); return(0); } if (!GetFileVersionInfo(pFileName, 0, dwSize, pMem)) { FreeSplMem(pMem); DBGMSG(DBG_TRACE, ("GetFileVersionInfo failed\n")); DBGMSG(DBG_TRACE, ("Returning back a version # 0\n")); return(0); } if (!VerQueryValue(pMem, L"\\", &pFileVersion, &uLen)) { FreeSplMem(pMem); DBGMSG(DBG_TRACE, ("VerQueryValue failed \n")); DBGMSG(DBG_TRACE, ("Returning back a version # 0\n")); return(0); } // // We could determine the Version Information // DBGMSG(DBG_TRACE, ("dwFileVersionMS = %d\n", ((VS_FIXEDFILEINFO *)pFileVersion)->dwFileVersionMS)); DBGMSG(DBG_TRACE, ("dwFileVersionLS = %d\n", ((VS_FIXEDFILEINFO *)pFileVersion)->dwFileVersionLS)); DBGMSG(DBG_TRACE, ("dwProductVersionMS = %d\n", ((VS_FIXEDFILEINFO *)pFileVersion)->dwProductVersionMS)); DBGMSG(DBG_TRACE, ("dwProductVersionLS = %d\n", ((VS_FIXEDFILEINFO *)pFileVersion)->dwProductVersionLS)); dwFileOS = ((VS_FIXEDFILEINFO *)pFileVersion)->dwFileOS; dwFileVersionMS = ((VS_FIXEDFILEINFO *)pFileVersion)->dwFileVersionMS; dwFileVersionLS = ((VS_FIXEDFILEINFO *)pFileVersion)->dwFileVersionLS; dwProductVersionMS = ((VS_FIXEDFILEINFO *)pFileVersion)->dwProductVersionMS; dwProductVersionLS = ((VS_FIXEDFILEINFO *)pFileVersion)->dwProductVersionLS; FreeSplMem(pMem); if (dwFileOS != VOS_NT_WINDOWS32) { DBGMSG(DBG_TRACE,("Returning back a version # 0\n")); return(0); } if (dwProductVersionMS == dwFileVersionMS) { // // This means this hold for all dlls Pre-Daytona // after Daytona, printer driver writers must support // version control or we'll dump them as Version 0 // drivers DBGMSG(DBG_TRACE,("Returning back a version # 0\n")); return(0); } // // Bug-Bug: suppose a third-party vendor uses a different system // methinks we should use the lower dword to have specific value // which implies he/she supports spooler version -- check with MattFe DBGMSG(DBG_TRACE,("Returning back a version # %d\n", dwFileVersionMS)); return(dwFileVersionMS); }
BOOL PrintRawJob( IN PPRINTPROCESSORDATA pData, _In_ IN LPWSTR pPrinterName) { DOC_INFO_1 DocInfo; DWORD Copies; DWORD NoRead, NoWritten; BOOL rc; HANDLE hPrinter; BYTE *ReadBuffer = NULL; BOOL bRet = FALSE; BOOL bStartDoc = FALSE; DocInfo.pDocName = pData->pDocument; /* Document name */ DocInfo.pOutputFile = pData->pOutputFile; /* Output file */ DocInfo.pDatatype = pData->pDatatype; /* Document data type */ /** Let the printer know we are starting a new document **/ if (!StartDocPrinter(pData->hPrinter, 1, (LPBYTE)&DocInfo)) { goto Done; } bStartDoc = TRUE; /** Allocate the read buffer, dynamically allocated to conserve stack space **/ ReadBuffer = (BYTE *)AllocSplMem(READ_BUFFER_SIZE); if (!ReadBuffer) { goto Done; } /** Print the data pData->Copies times **/ Copies = pData->Copies; while (Copies--) { /** Open the printer. If it fails, return. This also sets up the pointer for the ReadPrinter calls. **/ if (!OpenPrinter(pPrinterName, &hPrinter, NULL)) { goto Done; } /** Loop, getting data and sending it to the printer. This also takes care of pausing and cancelling print jobs by checking the processor's status flags while printing. **/ while ( ((rc = ReadPrinter(hPrinter, ReadBuffer, READ_BUFFER_SIZE, &NoRead)) != 0) && NoRead ) { /** If the print processor is paused, wait for it to be resumed **/ if (pData->fsStatus & PRINTPROCESSOR_PAUSED) { WaitForSingleObject(pData->semPaused, INFINITE); } /** If the job has been aborted, don't write anymore **/ if (pData->fsStatus & PRINTPROCESSOR_ABORTED) { break; } /** Write the data to the printer **/ WritePrinter(pData->hPrinter, ReadBuffer, NoRead, &NoWritten); } /** Close the printer - we open/close the printer for each copy so the data pointer will rewind. **/ ClosePrinter(hPrinter); } /* While copies to print */ bRet = TRUE; Done: /** Close the buffer we allocated **/ if (ReadBuffer) { FreeSplMem(ReadBuffer); } /** Let the printer know that we are done printing **/ if (bStartDoc) { EndDocPrinter(pData->hPrinter); } return bRet; }
BOOL InternalCopyFile( HANDLE hSourceFile, PWIN32_FIND_DATA pSourceFileData, LPWSTR lpNewFileName, BOOL bFailIfExists ) /*++ Routine Description: Arguments: hSourceFile - SourceFile Handle pSourceFileData - Pointer to WIN32_FIND_DATA for the source file lpNewFileName - Supplies the name where a copy of the existing files data and attributes are to be stored. bFailIfExists - Supplies a flag that indicates how this operation is to proceed if the specified new file already exists. A value of TRUE specifies that this call is to fail. A value of FALSE causes the call to the function to succeed whether or not the specified new file exists. Return Value: TRUE - The operation was successful. FALSE/NULL - The operation failed. Extended error status is available using GetLastError. --*/ { DWORD dwSourceFileAttributes; BOOL bReturnValue = FALSE; HANDLE hTargetFile = INVALID_HANDLE_VALUE; DWORD dwLowFileSize, dwHighFileSize; LPVOID pBuffer; DWORD cbBufferSize = BUFFER_SIZE; DWORD cbBytesRead; DWORD cbBytesWritten; DWORD dwSourceFilePointer; SPLASSERT( hSourceFile != NULL && hSourceFile != INVALID_HANDLE_VALUE && pSourceFileData != NULL && lpNewFileName != NULL ); #if DBG // <<<<< DEBUG ONLY >>>>>> // // ASSERTION Check Source File Pointer is Zero. // dwSourceFilePointer = SetFilePointer( hSourceFile, 0, NULL, FILE_CURRENT ); if ( dwSourceFilePointer != 0xffffffff ) { SPLASSERT( dwSourceFilePointer == 0 ); } #endif // DBG // // Alloc I/O Buffer // pBuffer = AllocSplMem( BUFFER_SIZE ); if ( pBuffer == NULL ) goto InternalCopyFileExit; // // Create TagetFile with same File Attributes // hTargetFile = CreateFile( lpNewFileName, GENERIC_WRITE, FILE_SHARE_EXCLUSIVE, NULL, bFailIfExists ? CREATE_NEW : CREATE_ALWAYS, pSourceFileData->dwFileAttributes | FILE_FLAG_SEQUENTIAL_SCAN, NULL ); if ( hTargetFile != INVALID_HANDLE_VALUE ) { // // Copy The Data // while (( bReturnValue = ReadFile( hSourceFile, pBuffer, cbBufferSize, &cbBytesRead, NULL )) && cbBytesRead != 0 ) { // // Add Code to Build CheckSum Here // bReturnValue = WriteFile( hTargetFile, pBuffer, cbBytesRead, &cbBytesWritten, NULL ); if ( bReturnValue == FALSE || cbBytesWritten != cbBytesRead ) { bReturnValue = FALSE; break; } } if ( bReturnValue ) { // // Set TargetFile Times to be the same as the Source File // bReturnValue = SetFileTime( hTargetFile, &pSourceFileData->ftCreationTime, &pSourceFileData->ftLastAccessTime, &pSourceFileData->ftLastWriteTime ); // // Verify that the file size is correct. // if ( bReturnValue ) { dwLowFileSize = GetFileSize( hTargetFile, &dwHighFileSize ); if ( dwLowFileSize != pSourceFileData->nFileSizeLow || dwHighFileSize != pSourceFileData->nFileSizeHigh ) { DBGMSG(DBG_ERROR, ("InternalCopyFile: sizes do not match for %ws: (%d %d) and (%d %d)", lpNewFileName, pSourceFileData->nFileSizeHigh, pSourceFileData->nFileSizeLow, dwHighFileSize, dwLowFileSize)); bReturnValue = FALSE; SetLastError(ERROR_FILE_INVALID); } } // // Add Code here to Verify the CheckSum is correct. // } CloseHandle( hTargetFile ); } FreeSplMem( pBuffer ); InternalCopyFileExit: if ( !bReturnValue ) { DBGMSG( DBG_WARN, ("InternalCopyFile hSourceFile %x %ws error %d\n", hSourceFile, lpNewFileName, GetLastError() )); SPLASSERT( GetLastError() != ERROR_SUCCESS ); } return bReturnValue; }
/*++ ******************************************************************* P r i n t T e x t J o b Routine Description: Prints a text data job. Arguments: pData => Data structure for this job pDocumentName => Name of this document Return Value: TRUE if successful FALSE if failed - GetLastError() will return reason. ******************************************************************* --*/ BOOL PrintTextJob( IN PPRINTPROCESSORDATA pData, __in IN LPWSTR pDocumentName) { DOCINFO DocInfo; LOGFONT LogFont; CHARSETINFO CharSetInfo; HFONT hOldFont, hFont = NULL; DWORD Copies; BOOL rc; DWORD NoRead; DWORD CurrentLine; DWORD CurrentCol; HANDLE hPrinter = NULL; BYTE *ReadBufferStart = NULL; PBYTE pLineBuffer = NULL; PBYTE pReadBuffer = NULL; PBYTE pReadBufferEnd = NULL; ULONG CharHeight, CharWidth, CharsPerLine, LinesPerPage; ULONG PageWidth, PageHeight; ULONG Length, TabBase; BOOL ReadAll; TEXTMETRIC tm; DWORD fdwFlags; DWORD Encoding; DWORD SplitSize; BOOL ReturnValue = FALSE; BOOL bAbortDoc = FALSE; DWORD dwNeeded; DWORD dwNoTranslate = 0; DWORD dwNoTranslateCR = 0; DWORD dwTransparent = 0; INT iBkMode = OPAQUE; DocInfo.lpszDocName = pData->pDocument; /* Document name */ DocInfo.lpszOutput = NULL; /* Output file */ DocInfo.lpszDatatype = NULL; /* Datatype */ DocInfo.cbSize = sizeof(DOCINFO); /* Size of the structure */ // // Go figure out the size of the form on the printer. We do this // by calling GetTextMetrics, which gives us the font size of the // printer font, then getting the form size and calculating the // number of characters that will fit. In other cases we treat it as ANSI text. // Currently the codepage context is fixed to the system default codepage. // Encoding = GetACP(); // // Create FIXED PITCH font and select // hOldFont = 0; ZeroMemory(&CharSetInfo, sizeof(CHARSETINFO)); if (TranslateCharsetInfo((PDWORD)UIntToPtr(Encoding), &CharSetInfo, TCI_SRCCODEPAGE)) { ZeroMemory(&LogFont, sizeof(LOGFONT)); LogFont.lfWeight = 400; LogFont.lfCharSet = (BYTE)CharSetInfo.ciCharset; LogFont.lfPitchAndFamily = FIXED_PITCH; hFont = CreateFontIndirect(&LogFont); hOldFont = (HFONT) SelectObject(pData->hDC, hFont); } if (!GetTextMetrics(pData->hDC, &tm)) { // Essential text processing computation failed goto Done; } CharHeight = tm.tmHeight + tm.tmExternalLeading; CharWidth = tm.tmAveCharWidth; if (!CharWidth || !CharHeight) { // Essential text processing computation failed goto Done; } // // Calculate most fittable characters' number to one line. // PageWidth = GetDeviceCaps(pData->hDC, DESKTOPHORZRES); PageHeight = GetDeviceCaps(pData->hDC, DESKTOPVERTRES); CharsPerLine = PageWidth / CharWidth; LinesPerPage = PageHeight / CharHeight; if (!CharsPerLine || !LinesPerPage) { // Essential text processing computation failed goto Done; } /** Allocate a buffer for one line of text **/ pLineBuffer = (PBYTE)AllocSplMem(CharsPerLine + 5); if (!pLineBuffer) { goto Done; } /** Let the printer know we are starting a new document **/ if (!StartDoc(pData->hDC, (LPDOCINFO)&DocInfo)) { goto Done; } ReadBufferStart = (BYTE *)AllocSplMem(READ_BUFFER_SIZE); if (!ReadBufferStart) { goto Done; } /** Print the data pData->Copies times **/ Copies = pData->Copies; while (Copies--) { /** Loop, getting data and sending it to the printer. This also takes care of pausing and cancelling print jobs by checking the processor's status flags while printing. The way we do this is to read in some data from the printer. We will then pull data, one tabbed line at a time from there and print it. If the last bit of data in the buffer does not make up a whole line, we call GetTabbedLineFromBuffer() with a non- zero Length, which indicates that there are chars left from the previous read. **/ TabBase = 0; Length = 0; fdwFlags = FLAG_TRANSLATE_CR | FLAG_TRANSLATE_LF; CurrentLine = 0; CurrentCol = 0; /** Open the printer. If it fails, return. This also sets up the pointer for the ReadPrinter calls. **/ if (!OpenPrinter(pDocumentName, &hPrinter, NULL)) { hPrinter = NULL; bAbortDoc = TRUE; goto Done; } // // Call GetPrinterData to see if the queue wants no LF/CR processing. // if( GetPrinterData( hPrinter, (LPWSTR)gszNoTranslateCRLF, NULL, (PBYTE)&dwNoTranslate, sizeof( dwNoTranslate ), &dwNeeded ) == ERROR_SUCCESS ){ if( dwNoTranslate ){ fdwFlags &= ~( FLAG_TRANSLATE_CR | FLAG_TRANSLATE_LF ); } } // // Call GetPrinterData to see if the queue wants no CR processing. // if( GetPrinterData( hPrinter, (LPWSTR)gszNoTranslateCR, NULL, (PBYTE)&dwNoTranslateCR, sizeof( dwNoTranslateCR ), &dwNeeded ) == ERROR_SUCCESS ){ if( dwNoTranslateCR ){ fdwFlags &= ~FLAG_TRANSLATE_CR; if( GetPrinterData( hPrinter, (LPWSTR)gszTransparency, NULL, (PBYTE)&dwTransparent, sizeof( dwTransparent ), &dwNeeded ) == ERROR_SUCCESS ){ if( dwTransparent ){ iBkMode = SetBkMode( pData->hDC, TRANSPARENT ); } } } } if (StartPage(pData->hDC) == SP_ERROR) { bAbortDoc = TRUE; goto Done; } /** ReadAll indicates if we are on the last line of the file **/ ReadAll = FALSE; /** This next do loop continues until we have read all of the data for the print job. **/ do { if (fdwFlags & FLAG_DBCS_SPLIT) { SplitSize = (DWORD)(pReadBufferEnd - pReadBuffer); memcpy(ReadBufferStart, pReadBuffer, SplitSize); fdwFlags &= ~FLAG_DBCS_SPLIT; } else { SplitSize = 0; } rc = ReadPrinter(hPrinter, (ReadBufferStart + SplitSize), (READ_BUFFER_SIZE - SplitSize), &NoRead); if (!rc || !NoRead) { ReadAll = TRUE; } else { /** Pick up a pointer to the end of the data **/ pReadBuffer = ReadBufferStart; pReadBufferEnd = ReadBufferStart + SplitSize + NoRead; } /** This loop will process all the data that we have just read from the printer. **/ do { if (!ReadAll) { /** Length on entry holds the length of any residual chars from the last line that we couldn't print out because we ran out of characters on the ReadPrinter buffer. **/ pReadBuffer = GetTabbedLineFromBuffer( pReadBuffer, pReadBufferEnd, pLineBuffer, CharsPerLine - CurrentCol, pData->TabSize, Encoding, &Length, &TabBase, &fdwFlags ); /** If pReadBuffer == NULL, then we have exhausted the read buffer and we need to ReadPrinter again and save the last line chars. Length holds the number of characters on this partial line, so the next time we call ReadPrinter we will pickup where we left off. The only time we'll get residual chars is if: 1. The last line ends w/o ff/lf/cr ("Hello\EOF") In this case we should TextOutA the last line and then quit. (In this case, don't break here; go ahead and print, then we'll break out below in the do..while.) 2. The ReadPrinter last byte is in the middle of a line. Here we should read the next chunk and add the new characters at the end of the chars we just read. (In this case, we should break and leave Length as it is so we will read again and append to the buffer, beginning at Length.) **/ if (!pReadBuffer || (fdwFlags & FLAG_DBCS_SPLIT)) break; } /** If the print processor is paused, wait for it to be resumed **/ if (pData->fsStatus & PRINTPROCESSOR_PAUSED) { WaitForSingleObject(pData->semPaused, INFINITE); } /** If the job has been aborted, clean up and leave **/ if (pData->fsStatus & PRINTPROCESSOR_ABORTED) { ReturnValue = TRUE; bAbortDoc = TRUE; goto Done; } /** Write the data to the printer **/ /** Make sure Length is not zero **/ /** TextOut will fail if Length == 0 **/ if (Length) { /** We may have a number of newlines pending, that may push us to the next page (or even next-next page). **/ while (CurrentLine >= LinesPerPage) { /** We need a new page; always defer this to the last second to prevent extra pages from coming out. **/ if (EndPage(pData->hDC) == SP_ERROR || StartPage(pData->hDC) == SP_ERROR) { bAbortDoc = TRUE; goto Done; } CurrentLine -= LinesPerPage; } #pragma prefast(suppress:__WARNING_ANSI_APICALL, "By design. This function is inherently handling only ANSI text print jobs.") if (TextOutA(pData->hDC, CurrentCol * CharWidth, CurrentLine * CharHeight, (LPCSTR)pLineBuffer, Length) == FALSE) { ODS(("TextOut() failed\n")); bAbortDoc = TRUE; goto Done; } CurrentCol += Length; } /** Even if the length is zero, increment the line. Should happen when the character is only 0x0D or 0x0A. **/ if (fdwFlags & FLAG_CR) { CurrentCol=0; fdwFlags &= ~FLAG_CR; } if (fdwFlags & FLAG_LF) { CurrentLine++; fdwFlags &= ~FLAG_LF; } /** We need a new page. Set the current line to the end of the page. We could do a End/StartPage sequence, but this may cause a blank page to get ejected. Note: this code will avoid printing out pages that consist of formfeeds only (if you have a page with a space in it, that counts as text). **/ if (fdwFlags & FLAG_FF) { CurrentLine = LinesPerPage; CurrentCol = 0; fdwFlags &= ~FLAG_FF; } /** We have done the text out, so these characters have been successfully printed. Zero out Length so these characters won't be printed again **/ Length = 0; /** We only terminate this loop if we run out of chars or we run out of read buffer. **/ } while (pReadBuffer && pReadBuffer != pReadBufferEnd); /** Keep going until we get the last line **/ } while (!ReadAll); if (EndPage(pData->hDC) == SP_ERROR) { bAbortDoc = TRUE; goto Done; } /** Close the printer - we open/close the printer for each copy so the data pointer will rewind. **/ ClosePrinter(hPrinter); hPrinter = NULL; } /* While copies to print */ /** Let the printer know that we are done printing **/ EndDoc(pData->hDC); ReturnValue = TRUE; Done: if (dwTransparent) SetBkMode( pData->hDC, iBkMode ); if (hPrinter) ClosePrinter(hPrinter); if (bAbortDoc) AbortDoc(pData->hDC); if (pLineBuffer) FreeSplMem(pLineBuffer); if (hOldFont) { SelectObject(pData->hDC, hOldFont); DeleteObject(hFont); } if (ReadBufferStart) { FreeSplMem(ReadBufferStart); } return ReturnValue; }
PUCHAR GetPrinterInfo(IN HANDLE hPrinter, IN ULONG StructLevel, OUT PULONG pErrorCode) { ULONG reqbytes, alloc_size; PUCHAR ptr_info, pTempPtr_info = NULL; USHORT retry = 2; alloc_size = BASE_PRINTER_BUFFER_SIZE; ptr_info = (PUCHAR)AllocSplMem(alloc_size); if (!ptr_info) { *pErrorCode = ERROR_NOT_ENOUGH_MEMORY; return NULL; } while (retry--) { if (GetPrinter( hPrinter, StructLevel, (PUCHAR)ptr_info, alloc_size, &reqbytes) == TRUE) { *pErrorCode = 0; return (PUCHAR)ptr_info; } // // GetPrinter failed - if not because of insufficient buffer, fail // the call. Otherwise, up our hint, re-allocate and try again. // *pErrorCode = GetLastError(); if (*pErrorCode != ERROR_INSUFFICIENT_BUFFER) { FreeSplMem(ptr_info); return NULL; } // // Reallocate the buffer and re-try (note that, because we // allocated the buffer as LMEM_FIXED, the LMEM_MOVABLE does // not return a movable allocation, it just allows realloc // to return a different pointer. // FreeSplMem(ptr_info); ptr_info = NULL; pTempPtr_info = (PUCHAR)AllocSplMem(reqbytes); alloc_size = reqbytes; if (pTempPtr_info) { ptr_info = pTempPtr_info; pTempPtr_info = NULL; } else { // // If the realloc failed we break out of the loop so that we // can cleanup and return error code. // break; } } if (ptr_info) { FreeSplMem(ptr_info); } *pErrorCode = ERROR_NOT_ENOUGH_MEMORY; return NULL; }
BOOL EnumGeneric( IN PROC fnEnum, IN DWORD Level, IN PBYTE *ppEnumData, IN DWORD cbBuf, OUT LPDWORD pcbReturned, OUT LPDWORD pcReturned, IN PVOID Arg1, IN PVOID Arg2, IN PVOID Arg3 ) { BOOL rc; BOOL UnknownFunction = FALSE; DWORD cbRealloc; if( fnEnum == (PROC)EnumPrinters ) rc = EnumPrinters( (DWORD)Arg1, (LPTSTR)Arg2, COMMON_ARGS ); // Flags Name else if( fnEnum == (PROC)EnumJobs ) rc = EnumJobs( (HANDLE)Arg1, (DWORD)Arg2, (DWORD)Arg3, COMMON_ARGS ); // hPrinter FirstJob NoJobs else if( fnEnum == (PROC)EnumPrinterDrivers ) rc = EnumPrinterDrivers( (LPTSTR)Arg1, (LPTSTR)Arg2, COMMON_ARGS ); // pName pEnvironment else if( fnEnum == (PROC)EnumForms ) rc = EnumForms( (HANDLE)Arg1, COMMON_ARGS ); // hPrinter else if( fnEnum == (PROC)EnumMonitors ) rc = EnumMonitors( (LPTSTR)Arg1, COMMON_ARGS ); // pName else if( fnEnum == (PROC)EnumPorts ) rc = EnumPorts( (LPTSTR)Arg1, COMMON_ARGS ); // pName else if( fnEnum == (PROC)EnumPrintProcessors ) rc = EnumPrintProcessors( (LPTSTR)Arg1, (LPTSTR)Arg2, COMMON_ARGS ); // pName pEnvironment else if( fnEnum == (PROC)EnumPrintProcessorDatatypes ) rc = EnumPrintProcessorDatatypes( (LPTSTR)Arg1, (LPTSTR)Arg2, COMMON_ARGS ); // pName pPrintProcessorName else { *ppEnumData = NULL; UnknownFunction = TRUE; DBGMSG( DBG_ERROR, ( "EnumGeneric called with unknown function\n" ) ); rc = FALSE; } if( ( rc == FALSE ) && ( UnknownFunction == FALSE ) ) { if( GetLastError( ) == ERROR_INSUFFICIENT_BUFFER ) { cbRealloc = *pcbReturned; DBGMSG( DBG_TRACE, ( "EnumGeneric: Reallocating %d (0x%x) bytes @%08x\n", cbBuf, cbBuf, *ppEnumData ) ); if( cbBuf == 0 ) *ppEnumData = AllocSplMem( cbRealloc ); else *ppEnumData = ReallocSplMem( *ppEnumData, cbRealloc ); cbBuf = cbRealloc; if( *ppEnumData ) { DBGMSG( DBG_TRACE, ( "EnumGeneric: %d (0x%x) bytes reallocated @%08x\n", cbBuf, cbBuf, *ppEnumData ) ); if( fnEnum == (PROC)EnumPrinters ) rc = EnumPrinters( (DWORD)Arg1, (LPTSTR)Arg2, COMMON_ARGS ); // Flags Name else if( fnEnum == (PROC)EnumJobs ) rc = EnumJobs( (HANDLE)Arg1, (DWORD)Arg2, (DWORD)Arg3, COMMON_ARGS ); // hPrinter FirstJob NoJobs else if( fnEnum == (PROC)EnumPrinterDrivers ) rc = EnumPrinterDrivers( (LPTSTR)Arg1, (LPTSTR)Arg2, COMMON_ARGS ); // pName pEnvironment else if( fnEnum == (PROC)EnumForms ) rc = EnumForms( (HANDLE)Arg1, COMMON_ARGS ); // hPrinter else if( fnEnum == (PROC)EnumMonitors ) rc = EnumMonitors( (LPTSTR)Arg1, COMMON_ARGS ); // pName else if( fnEnum == (PROC)EnumPorts ) rc = EnumPorts( (LPTSTR)Arg1, COMMON_ARGS ); // pName else if( fnEnum == (PROC)EnumPrintProcessors ) rc = EnumPrintProcessors( (LPTSTR)Arg1, (LPTSTR)Arg2, COMMON_ARGS ); // pName pEnvironment else if( fnEnum == (PROC)EnumPrintProcessorDatatypes ) rc = EnumPrintProcessorDatatypes( (LPTSTR)Arg1, (LPTSTR)Arg2, COMMON_ARGS ); // pName pPrintProcessorName /* If things haven't worked out, free up the buffer. * We do this because otherwise the caller will not know * whether the pointer is valid any more, * since ReallocSplMem might have failed. */ if( rc == FALSE ) { if( *ppEnumData ) FreeSplMem( *ppEnumData ); *ppEnumData = NULL; *pcbReturned = 0; *pcReturned = 0; } /* Don't rely on pcbReturned having the same value * that was passed in: */ else *pcbReturned = cbRealloc; } } else { if( *ppEnumData ) FreeSplMem( *ppEnumData ); *ppEnumData = NULL; *pcbReturned = 0; *pcReturned = 0; rc = FALSE; } } else *pcbReturned = cbBuf; return rc; }
BOOL GetGeneric( IN PROC fnGet, IN DWORD Level, IN PBYTE *ppGetData, IN DWORD cbBuf, OUT LPDWORD pcbReturned, IN PVOID Arg1, IN PVOID Arg2 ) { BOOL rc = FALSE; BOOL UnknownFunction = FALSE; DWORD cbRealloc; if( fnGet == (PROC)GetPrinter ) rc = GetPrinter( (HANDLE)Arg1, GET_ARGS ); // hPrinter else { *ppGetData = NULL; UnknownFunction = TRUE; } if( ( rc == FALSE ) && ( UnknownFunction == FALSE ) ) { if( GetLastError( ) == ERROR_INSUFFICIENT_BUFFER ) { cbRealloc = *pcbReturned; *ppGetData = ReallocSplMem( *ppGetData, cbRealloc ); cbBuf = cbRealloc; if( *ppGetData ) { if( fnGet == (PROC)GetPrinter ) rc = GetPrinter( (HANDLE)Arg1, GET_ARGS ); // hPrinter /* If things haven't worked out, free up the buffer. * We do this because otherwise the caller will not know * whether the pointer is valid any more, * since ReallocSplMem might have failed. */ if( rc == FALSE ) { if( *ppGetData ) FreeSplMem( *ppGetData ); *ppGetData = NULL; *pcbReturned = 0; } } } else { if( *ppGetData ) FreeSplMem( *ppGetData ); *ppGetData = NULL; *pcbReturned = 0; rc = FALSE; } } else *pcbReturned = cbBuf; return rc; }
LPBYTE CopyIniPortToPort( __in PLCMINIPORT pIniPort, DWORD Level, __out LPBYTE pPortInfo, __inout LPBYTE pEnd ) { LPWSTR *SourceStrings = NULL; LPWSTR *pSourceStrings = NULL; PPORT_INFO_2 pPort2 = (PPORT_INFO_2)pPortInfo; LPWSTR pszLocalMonitor = NULL; LPWSTR pszPortDesc = NULL; DWORD *pOffsets = NULL; DWORD Count = 0; LPBYTE pReturnPointer = NULL; switch (Level) { case 1: pOffsets = LcmPortInfo1Strings; break; case 2: pOffsets = LcmPortInfo2Strings; break; default: goto Done; } for ( Count = 0 ; pOffsets[Count] != -1 ; ++Count ) { } SourceStrings = pSourceStrings = (LPWSTR *)AllocSplMem(Count * sizeof(LPWSTR)); if ( !SourceStrings ) { goto Done; } switch (Level) { case 1: *pSourceStrings++=pIniPort->pName; break; case 2: { pszLocalMonitor = (LPWSTR)AllocSplMem((MAX_PATH + 1) * sizeof(WCHAR)); pszPortDesc = (LPWSTR)AllocSplMem((MAX_PATH + 1) * sizeof(WCHAR)); if (pszLocalMonitor && pszPortDesc) { *pSourceStrings++=pIniPort->pName; LoadString(LcmhInst, IDS_LOCALMONITORNAME, pszLocalMonitor, MAX_PATH); LoadString(LcmhInst, IDS_LOCALMONITOR, pszPortDesc, MAX_PATH); *pSourceStrings++ = pszLocalMonitor; *pSourceStrings++ = pszPortDesc; pPort2->fPortType = PORT_TYPE_WRITE | PORT_TYPE_READ; // Reserved pPort2->Reserved = 0; } else { goto Done; } } break; default: goto Done; } pEnd = LcmPackStrings(Count, SourceStrings, pPortInfo, pOffsets, pEnd); pReturnPointer = pEnd; Done: if (SourceStrings) { FreeSplMem(SourceStrings); SourceStrings = NULL; } if (pszLocalMonitor) { FreeSplMem(pszLocalMonitor); pszLocalMonitor = NULL; } if (pszPortDesc) { FreeSplMem(pszPortDesc); pszPortDesc = NULL; } return pReturnPointer; }
PINIPORT CreatePortEntry( __in LPTSTR pszPortName ) /*++ Routine Description: Creates a IniPort entry for a port. Needs to be called inside monitor critical section. Arguments: pszPortName : Name of the port Return Value: On success pointer to the IniPort stucture. On failure NULL --*/ { PINIPORT pIniPort = NULL; HANDLE DoneWriting = NULL; HANDLE DoneReading = NULL; HANDLE WakeUp = NULL; LPWSTR pszString = NULL; SplInSem(); DoneWriting = CreateEvent(NULL, FALSE, TRUE, NULL); if (!DoneWriting) { goto Fail; } WakeUp = CreateEvent(NULL, FALSE, FALSE, NULL); if (!WakeUp) { goto Fail; } // // manual-reset event, initially signal state // DoneReading = CreateEvent(NULL, TRUE, TRUE, NULL); if (!DoneReading) { goto Fail; } pIniPort = (PINIPORT) AllocSplMem(sizeof(*pIniPort)); if (!pIniPort) { goto Fail; } pszString = AllocSplStr(pszPortName); if (!pszString) { goto Fail; } pIniPort->pNext = NULL; pIniPort->signature = PJ_SIGNATURE; pIniPort->DoneWriting = DoneWriting; pIniPort->DoneReading = DoneReading; pIniPort->WakeUp = WakeUp; pIniPort->hUstatusThread= NULL; pIniPort->pszPortName = pszString; pIniPort->pNext = pIniFirstPort; pIniFirstPort = pIniPort; return pIniPort; Fail: if (DoneWriting) { CloseHandle (DoneWriting); } if (DoneReading) { CloseHandle (DoneReading); } if (WakeUp) { CloseHandle (WakeUp); } FreeSplMem (pszString); FreeSplMem (pIniPort); return NULL; }
VOID DeletePortEntry( __in PINIPORT pIniPort ) /*++ Routine Description: Deletes a port entry. Needs to be called inside monitor critical section Arguments: pIniPort : Pointer to the IniPort structure to be deleted Return Value: --*/ { SplInSem(); if ( pIniPort == pIniFirstPort ) { pIniFirstPort = pIniPort->pNext; } else { PINIPORT pPort; pPort = pIniFirstPort; while ( pPort && pPort->pNext != pIniPort ) pPort = pPort->pNext; if (pPort) { pPort->pNext = pIniPort->pNext; } else { DBG_MSG(DBG_ERROR, ("pjlmon: DeletePortEntry port not found\n")); return; } } if (pIniPort-> DoneWriting) { CloseHandle(pIniPort->DoneWriting); pIniPort->DoneWriting = NULL; } if (pIniPort-> DoneReading) { CloseHandle(pIniPort->DoneReading); pIniPort->DoneReading = NULL; } if (pIniPort-> WakeUp) { CloseHandle(pIniPort->WakeUp); pIniPort->WakeUp = NULL; } if (pIniPort-> hUstatusThread) { CloseHandle (pIniPort-> hUstatusThread); pIniPort->hUstatusThread = NULL; } FreeIniJobs(pIniPort); FreeSplStr(pIniPort->pszPortName); pIniPort->pszPortName = NULL; FreeSplMem(pIniPort); return; }