// ------------------------------------------------ // // FUNCTION: sys_GetRegKey( PA_PluginParameters params ) // // PURPOSE: Get a key from the registry. // // DATE: MJG 12/4/03 (3.5.6) // void sys_GetRegKey( PA_PluginParameters params ) { LONG_PTR returnValue, regKey, retErr, dataSize, arraySize, expandDataSize; LONG_PTR i, len; char regSub[MAXBUF]; char regName[MAXBUF]; char *returnDataBuffer, *ptrData; HKEY hRootKey; HKEY hOpenKey; DWORD dwDataType; DWORD dwReturnLong; PA_Variable paReturnArray; // AMS2 12/9/14 #41400 Initalized the dataSize variable. In 64 bit environments this can be randomly initalized to a size in bytes // that is larger than malloc can allot, causing it to return null and crash when returning to 4D. Remember to always initialize your size variables. dataSize = 0; returnValue = regKey = retErr = arraySize = expandDataSize = 0; hRootKey = hOpenKey = 0; ptrData = returnDataBuffer = NULL; memset(regSub, 0, MAXBUF); memset(regName, 0, MAXBUF); // Get the function parameters. regKey = PA_GetLongParameter( params, 1 ); PA_GetTextParameter( params, 2, regSub ); PA_GetTextParameter( params, 3, regName ); // Convert the 4d registry constant into a Windows registry key. hRootKey = getRootKey( regKey ); // Open the registry key. retErr = RegOpenKeyEx(hRootKey, regSub, 0, KEY_READ, &hOpenKey); if(retErr == ERROR_SUCCESS){ // Get the value type and size. retErr = RegQueryValueEx(hOpenKey, regName, NULL, &dwDataType, NULL, &dataSize); if(retErr == ERROR_SUCCESS){ switch(dwDataType){ case REG_BINARY: returnDataBuffer = malloc(dataSize); retErr = RegQueryValueEx(hOpenKey, regName, NULL, NULL, (LPBYTE) returnDataBuffer, &dataSize); if(retErr == ERROR_SUCCESS){ PA_SetBlobParameter(params, 4, returnDataBuffer, dataSize); returnValue = 1; } free(returnDataBuffer); break; case REG_DWORD: case REG_DWORD_BIG_ENDIAN: dataSize = sizeof(dwReturnLong); retErr = RegQueryValueEx(hOpenKey, regName, NULL, NULL, (LPBYTE) &dwReturnLong, &dataSize); if(retErr == ERROR_SUCCESS){ PA_SetLongParameter(params, 4, dwReturnLong); returnValue = 1; } break; case REG_EXPAND_SZ: returnDataBuffer = malloc(dataSize); retErr = RegQueryValueEx (hOpenKey, regName, NULL, NULL, returnDataBuffer, &dataSize); if(retErr == ERROR_SUCCESS) { regExpandStr(&returnDataBuffer); PA_SetTextParameter(params, 4, returnDataBuffer, strlen(returnDataBuffer)); returnValue = 1; } free(returnDataBuffer); break; case REG_MULTI_SZ: returnDataBuffer = malloc(dataSize); paReturnArray = PA_GetVariableParameter( params, 4 ); retErr = RegQueryValueEx(hOpenKey, regName, NULL, NULL, returnDataBuffer, &dataSize); if(retErr == ERROR_SUCCESS) { arraySize = regGetNumElements(returnDataBuffer); PA_ResizeArray(&paReturnArray, arraySize); for(i = 1, ptrData = returnDataBuffer; i <= arraySize; i++) { len = strlen(ptrData); PA_SetTextInArray(paReturnArray, i, ptrData, len); ptrData+=len+1; } returnValue = 1; PA_SetVariableParameter( params, 4, paReturnArray, 0 ); } free(returnDataBuffer); break; case REG_SZ: returnDataBuffer = (char*)malloc(dataSize); retErr = RegQueryValueEx(hOpenKey, regName, NULL, NULL, returnDataBuffer, &dataSize); if(retErr == ERROR_SUCCESS){ PA_SetTextParameter(params, 4, returnDataBuffer, dataSize-1); returnValue = 1; } free(returnDataBuffer); break; } } } RegCloseKey( hOpenKey ); PA_ReturnLong( params, returnValue ); }
void sys_LogonUser(PA_PluginParameters params) { HANDLE hToken = NULL; BOOL bStatus = FALSE; char chUserID[MAXBUF] = ""; // String to hold the username char chDomain[MAXBUF] = ""; // String to hold the domain char chPassword[MAXBUF] = ""; // String to hold the password // Make sure that we've cleared out any previous errors SetLastError(0); // Get our parameters PA_GetTextParameter(params, 1, chUserID); PA_GetTextParameter(params, 2, chDomain); PA_GetTextParameter(params, 3, chPassword); // Authenticate the user bStatus = LogonUser(chUserID, chDomain, chPassword, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &hToken); if(bStatus) { // Authenticated // Close the handle if (hToken != NULL) { CloseHandle(hToken); hToken = NULL; } } PA_ReturnLong(params, (LONG_PTR)bStatus); }
void sys_DirectoryExists(PA_PluginParameters params){ char *directory = NULL; LONG_PTR length; WIN32_FIND_DATA FindFileData; HANDLE hFindFile; LONG ret = 0; // assume directory doesn't exist // WJF 6/30/16 Win-21 LONG_PTR -> LONG // retrieve the directory manual length = PA_GetTextParameter(params, 1, 0L); if (length > 0) { directory = malloc(length + 1); // WJF 7/13/16 Win-21 Removed typecasting on malloc to follow C best practices if (directory != NULL) { memset(directory, 0, length + 1); PA_GetTextParameter(params, 1, directory); } } // if the directory ends with a backslash it will fail and needs to be removed // if the directory is a disk root it will fail handle here in special case if (NULL != directory){ if ((':' == directory[1]) && (length <= 3)) { // REB 8/2/10 #24474 Changed ( 3 == length) to (length <= 3) // drive since has only 3 chars, handle here ret = GetFileAttributes(directory); if (ret != INVALID_FILE_ATTRIBUTES){ // REB 8/2/10 #24474 Added check for invalid attributes. ret = (0 != (GetFileAttributes(directory) & FILE_ATTRIBUTE_DIRECTORY)); // set exists free(directory); directory = NULL; // we have a result so avoid to normal handler } } else if ('\\' == directory[length - 1]){ directory[length - 1] = '\0'; } } if (NULL != directory){ hFindFile = FindFirstFile(directory, &FindFileData); // if a valid handle we should test whether it's a directory if (INVALID_HANDLE_VALUE != hFindFile){ ret = (0 != (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)); // set exists FindClose(hFindFile); // close handle } freeTextParameter(directory); } PA_ReturnLong(params, ret); }
// ------------------------------------------------ // // FUNCTION: sys_GetEnv( PA_PluginParameters params ) // // PURPOSE: Get the value of an environment variable. // // DATE: MJG 12/2/03 (3.5.6) // void sys_GetEnv( PA_PluginParameters params ) { LONG_PTR returnValue; LONG_PTR envLength; char envName[MAXBUF], *envValue; envValue = NULL; memset(envName, 0, MAXBUF); envLength = PA_GetTextParameter( params, 1, envName ); if(envLength > 0) envValue = getenv(envName); if(envValue == NULL) { returnValue = 0; PA_SetTextParameter(params, 2, "", 0); } else { returnValue = 1; PA_SetTextParameter(params, 2, envValue, strlen(envValue)); } PA_ReturnLong( params, returnValue ); }
// ------------------------------------------------ // // FUNCTION: sys_GetEnv( PA_PluginParameters params ) // // PURPOSE: Set the value of an environment variable. // // DATE: MJG 12/2/03 (3.5.6) // void sys_SetEnv( PA_PluginParameters params ) { LONG_PTR returnValue; char envName[MAXBUF], envValue[MAXBUF]; returnValue = 0; memset(envName, 0, MAXBUF); memset(envValue, 0, MAXBUF); PA_GetTextParameter( params, 1, envName ); PA_GetTextParameter( params, 2, envValue ); strncat(envName, "=", MAXBUF); strncat(envName, envValue, MAXBUF); returnValue = !(putenv(envName)); PA_ReturnLong( params, returnValue ); }
// FUNCTION: sys_LoggingStart(PA_PluginParameters params) // // PURPOSE: Start logging Win32API commands // // COMMENTS: // // DATE: 7/11/16 Win-20 void sys_LoggingStart(PA_PluginParameters params) { LONG returnValue = 0; // WJF 7/11/16 Win-20 PA_GetTextParameter(params, 1, szLogsPath); lNumDays = PA_GetLongParameter(params, 2); returnValue = logOpenFile(); PA_ReturnLong(params, returnValue); // WJF 7/11/16 Win-20 }
// ------------------------------------------------ // // FUNCTION: sys_GetRegType( PA_PluginParameters params ) // // PURPOSE: Get a key from the registry. // // DATE: MJG 12/4/03 (3.5.6) // void sys_GetRegType( PA_PluginParameters params ) { LONG_PTR returnValue, regKey, retErr; char regSub[MAXBUF]; char regName[MAXBUF]; char *returnDataBuffer; HKEY hRootKey; HKEY hOpenKey; DWORD dwDataType; returnValue = regKey = retErr = 0; hRootKey = hOpenKey = 0; returnDataBuffer = NULL; memset(regSub, 0, MAXBUF); memset(regName, 0, MAXBUF); // Get the function parameters. regKey = PA_GetLongParameter( params, 1 ); PA_GetTextParameter( params, 2, regSub ); PA_GetTextParameter( params, 3, regName ); // Convert the 4d registry constant into a Windows registry key. hRootKey = getRootKey( regKey ); // Open the registry key. retErr = RegOpenKeyEx(hRootKey, regSub, 0, KEY_READ, &hOpenKey); if(retErr == ERROR_SUCCESS){ // Get the value type and size. retErr = RegQueryValueEx(hOpenKey, regName, NULL, &dwDataType, NULL, NULL); if(retErr == ERROR_SUCCESS){ returnValue = get4dRegType(dwDataType); } } RegCloseKey( hOpenKey ); PA_ReturnLong( params, returnValue ); }
LONG_PTR getTrayIconParams( PA_PluginParameters params, LONG_PTR *pAction, LONG_PTR *pFlags, LONG_PTR *pIconID, LONG_PTR *pProcessNbr, LONG_PTR *pIconHndl, char* szTipParam, char* szBalloonInfo, char* szBalloonTitle ) { LONG_PTR szTipParam_len, szBalloonInfo_len, szBalloonTitle_len, returnValue = 0; *pAction = PA_GetLongParameter( params, 1 ); if (*pAction != 0) returnValue++; *pFlags = PA_GetLongParameter( params, 2 ); if (*pFlags != 0) returnValue++; *pIconID = PA_GetLongParameter( params, 3 ); if (*pIconID != 0) returnValue++; *pProcessNbr = PA_GetLongParameter( params, 4 ); if (*pProcessNbr != 0) returnValue++; *pIconHndl = PA_GetLongParameter( params, 5 ); if (*pIconHndl != 0) returnValue++; szTipParam_len = PA_GetTextParameter( params, 6, szTipParam ); if (szTipParam_len > 59) { szTipParam_len = 60; } szTipParam[szTipParam_len] = '\0'; if (szTipParam_len) returnValue++; szBalloonInfo_len = PA_GetTextParameter( params, 7, szBalloonInfo ); if (szBalloonInfo_len > 254) { szBalloonInfo_len = 255; } szBalloonInfo[szBalloonInfo_len] = '\0'; if (szBalloonInfo_len) returnValue++; szBalloonTitle_len = PA_GetTextParameter( params, 8, szBalloonTitle ); if (szBalloonTitle_len > 59) { szBalloonTitle_len = 60; } szBalloonTitle[szBalloonTitle_len] = '\0'; if (szBalloonTitle_len) returnValue++; return returnValue; }
// ------------------------------------------------ // // FUNCTION: sys_IsAppLoaded( PA_PluginParameters params ) // // PURPOSE: Check if a program is loaded // // COMMENTS: Win98 uses different approach than NT4 and up // Function pointers used for OS specific functions. // // DATE: dcc 08/23/02 // // MODIFICATIONS: // void sys_IsAppLoaded( PA_PluginParameters params ) { LPFNENUMPROC lpfnEnumProc = NULL; LPFNENUMPROCMODS lpfnEnumProcMods = NULL; LPFNGETMODFNAME lpfnGetModFName = NULL; HINSTANCE hPSapiDLL; BOOL bFuncReturn, bUseToolHelp = FALSE; char appName[100]; LONG_PTR appName_len; appName_len = PA_GetTextParameter( params, 1, appName ); appName[appName_len] = '\0'; hPSapiDLL = (HINSTANCE) getPSapiPointers(&lpfnEnumProc, &lpfnEnumProcMods, &lpfnGetModFName); bFuncReturn = reviewProcesses(hPSapiDLL, lpfnEnumProc, lpfnEnumProcMods, lpfnGetModFName, appName, bUseToolHelp); PA_ReturnLong( params, bFuncReturn); }
// ------------------------------------------------ // // FUNCTION: sys_GetRegEnum( PA_PluginParameters params ) // // PURPOSE: Get a key from the registry. // // DATE: MJG 12/4/03 (3.5.6) // void sys_GetRegEnum( PA_PluginParameters params ) { LONG_PTR returnValue, regKey, retErr; char regSub[MAXBUF]; LONG_PTR regBufSize = MAX_REG_SIZE; CHAR regBuf[MAX_REG_SIZE]; FILETIME ftLastWriteTime; HKEY hRootKey; HKEY hOpenKey; DWORD dwSubKeys; DWORD dwValues; DWORD i, j; PA_Variable paReturnArray1; PA_Variable paReturnArray2; dwSubKeys = dwValues = 0; returnValue = regKey = retErr = 0; hRootKey = hOpenKey = 0; memset(regSub, 0, MAXBUF); // Get the function parameters. regKey = PA_GetLongParameter( params, 1 ); PA_GetTextParameter( params, 2, regSub ); paReturnArray1 = PA_GetVariableParameter( params, 3 ); paReturnArray2 = PA_GetVariableParameter( params, 4 ); PA_ResizeArray(&paReturnArray1, 0); PA_ResizeArray(&paReturnArray2, 0); // Convert the 4d registry constant into a Windows registry key. hRootKey = getRootKey( regKey ); // Open the registry key. retErr = RegOpenKeyEx(hRootKey, regSub, 0, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE , &hOpenKey); if(retErr == ERROR_SUCCESS){ retErr = RegQueryInfoKey(hOpenKey, NULL, NULL, NULL, &dwSubKeys, NULL, NULL, &dwValues, NULL, NULL, NULL, NULL); if( retErr == ERROR_SUCCESS) { // Enumerate the subkey names. if (dwSubKeys) { retErr = ERROR_SUCCESS; PA_ResizeArray(&paReturnArray1, dwSubKeys); for (i=0,j=0; i<dwSubKeys; i++) { regBufSize = MAX_REG_SIZE; retErr = RegEnumKeyEx(hOpenKey, i, regBuf, ®BufSize, NULL, NULL, NULL, &ftLastWriteTime); if (retErr == ERROR_SUCCESS) { PA_SetTextInArray(paReturnArray1, ++j, regBuf, regBufSize); } } } // Enumerate the key value names. if (dwValues) { retErr = ERROR_SUCCESS; PA_ResizeArray(&paReturnArray2, dwValues); for (i=0,j=0; i<dwValues; i++) { regBufSize = MAX_REG_SIZE; regBuf[0] = '\0'; retErr = RegEnumValue(hOpenKey, i, regBuf, ®BufSize, NULL, NULL, NULL, NULL); if (retErr == ERROR_SUCCESS ) { PA_SetTextInArray(paReturnArray2, ++j, regBuf, regBufSize); } } } returnValue = 1; } } PA_SetVariableParameter( params, 3, paReturnArray1, 0 ); PA_SetVariableParameter( params, 4, paReturnArray2, 0 ); RegCloseKey( hOpenKey ); PA_ReturnLong( params, returnValue ); }
// ------------------------------------------------ // // FUNCTION: gui_RespectToolBar( PA_PluginParameters params ) // // PURPOSE: Function to intecept maximize event in the // ProToolsProc. There the window maximized // size is reduced by the number of pixels // passed into the function. // // COMMENTS: This has been experimented with but should be tested // more thoroughly. Some situations still cause a max'd // window to resize under a toolbar. Noticed in particular // when a new process window pops up over another process's // max'd window. This is left for an excersize for some adventurous // soul. // // DATE: dcc 01/16/03 (3.5.4) // // MODIFICATIONS: // void gui_RespectToolBar( PA_PluginParameters params ) { LONG_PTR position_len = 0, tbRestriction = 0; LONG_PTR trackingRestriction = 0, processNbr; char position[2]; INT_PTR theChar; tbRestriction = PA_GetLongParameter( params, 1); position_len = PA_GetTextParameter( params, 2, position ); position[position_len] = '\0'; if (position_len > 1) { position[1] = '\0'; } _strlwr(position); if (position_len == 0) { // pass a negative in and turns it all off toolBarRestrictions.toolBarOnDeck = 0; //restoreOrig4DWindowProcess(); // MJG 3/26/04 The 4D window will remain subclassed until the plug-in is unloaded. PA_ReturnLong( params, toolBarRestrictions.toolBarOnDeck); return; } trackingRestriction = PA_GetLongParameter( params, 3); toolBarRestrictions.trackingRestriction = trackingRestriction; if ((tbRestriction != 0) && (strpbrk(position, "ltrb") != NULL)) { toolBarRestrictions.toolBarOnDeck = 1; theChar = (INT_PTR) position[0]; } processNbr = PA_GetCurrentProcessNumber(); switch (theChar) { case 'l' : toolBarRestrictions.left = tbRestriction; toolBarRestrictions.leftProcessNbr = processNbr; break; case 't' : toolBarRestrictions.top = tbRestriction; toolBarRestrictions.topProcessNbr = processNbr; break; case 'r' : toolBarRestrictions.right = tbRestriction; toolBarRestrictions.rightProcessNbr = processNbr; break; case 'b' : toolBarRestrictions.bottom = tbRestriction; toolBarRestrictions.bottomProcessNbr = processNbr; break; } toolBarRestrictions.appBeingMaxed = 0; //if (processHandles.wpFourDOrigProc == NULL) { // processHandles.wpFourDOrigProc = (WNDPROC) SetWindowLong(windowHandles.fourDhWnd, GWL_WNDPROC, (LONG) newProc); //} // MJG 3/26/04 Replaced code above with function call. subclass4DWindowProcess(); PA_ReturnLong( params, toolBarRestrictions.toolBarOnDeck); }
void sys_KillProcessByName( PA_PluginParameters params ) { HANDLE hProcessSnap; // Handle to the process snapshot HANDLE hProcess; // Handle to the process itself PROCESSENTRY32 pe32; // ProcessEntry to get info about processes char processName[MAXBUF] = ""; // String to hold the printerName param ($1) LONG_PTR lMode = 1; // Long to hold the working mode ($2) // 1 = just first process matching name // 2 = all processes matching name BOOL bCleanFirst = FALSE; // Boolean to see if we should try to cleanly close the app // before killing it mercilessly BOOL bOrigCleanFirst = FALSE; // Keeps track of original bCleanFirst value // to reset between loop iterations ($3) BOOL bDone = FALSE; // This will keep track of whether or not we are finished // Looping through processes. // Get the function parameters. PA_GetTextParameter(params, 1, processName); lMode = PA_GetLongParameter(params, 2); bOrigCleanFirst = (PA_GetLongParameter(params, 3) == 1 ? TRUE : FALSE); // Take a snapshot of all processes in the system. // If we fail, return the error code hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if(hProcessSnap == INVALID_HANDLE_VALUE) { PA_ReturnLong(params, (LONG_PTR)GetLastError()); return; } // Set the size of the structure before using it. pe32.dwSize = sizeof( PROCESSENTRY32 ); // Retrieve information about the first process, // If we can't do it, then return the error code if(!Process32First( hProcessSnap, &pe32)) { CloseHandle( hProcessSnap ); // Must clean up the snapshot object! PA_ReturnLong(params, (LONG_PTR)GetLastError()); return; } // Now walk the snapshot of processes, and // display information about each process in turn do { // Check the name if (strcmp(pe32.szExeFile, processName) == 0) { bCleanFirst = bOrigCleanFirst; // Get the process // We need to make sure that we have the TERMINATE right hProcess = OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE, FALSE, pe32.th32ProcessID); // Couldn't get the process // Clean up the handle // and return the error if(hProcess == NULL) { CloseHandle(hProcessSnap); PA_ReturnLong(params, (LONG_PTR)GetLastError()); return; } if(bCleanFirst) { // TerminateClean() posts WM_CLOSE to all windows whose PID // matches your process's. EnumWindows((WNDENUMPROC)TerminateClean, (LPARAM) pe32.th32ProcessID) ; if(WaitForSingleObject(hProcess, 500)!=WAIT_OBJECT_0) { bCleanFirst = TRUE; } } if(!bCleanFirst) { // Kill the process if(TerminateProcess(hProcess, 1)) {; // Success! // If we're in mode 1 then we are finished // If not, then we will need to keep going if(lMode == 1) { bDone = TRUE; } // end } else { // Fail! // Clean up and return the error CloseHandle(hProcess); CloseHandle(hProcessSnap); PA_ReturnLong(params, (LONG_PTR)GetLastError()); return; } } // Close our handle CloseHandle(hProcess); } // end if Process32Next(hProcessSnap, &pe32); // WJF 6/2/15 #42839 Moved out of while condition } while((GetLastError()!=18) && (!bDone)); // WJF 6/2/15 #42839 Added GetLastError Check, corrected logical or syntax, and added inversion to bDone // Close the handle and return success CloseHandle(hProcessSnap); PA_ReturnLong(params, -1 * (LONG_PTR)bCleanFirst); }
void sys_PrintDirect2Driver( PA_PluginParameters params ) { PRINTDLG pd; // Structure to hold information about printer DOCINFO di; // Structure to hold "document" information char printerName[MAXBUF] = ""; // String to hold the printerName param ($1) char data[MAXLABELBUF] = ""; // String to hold the data param ($2) REB 6/5/08 #17022 Changed MAXBUF to MAXLABELBUF which is twice as big. char *origDefault; // String to hold the original default printer INT_PTR printerName_len; // Int to hold maximum length of printer name INT_PTR ret; // Int to hold return value of functions INT_PTR iErrCode = 0; // Int to hold the error code. ULONG_PTR ulBytesNeeded; // Holds size information // Set needed bytes to default value ulBytesNeeded = MAXLABELBUF; // REB 6/5/08 #17022 Changed MAXBUF to MAXLABELBUF // Set this to 255. printerName_len = 255; // Get the function parameters. PA_GetTextParameter(params, 1, printerName); PA_GetTextParameter(params, 2, data); // Allocate memory for Storing string for Original Default Printer & pBuf origDefault = (char *)malloc(ulBytesNeeded); memset(origDefault, 0, ulBytesNeeded); // Get name of current Default Printer GetDefaultPrinter(origDefault, &ulBytesNeeded); // Set the new Default Printer to our label printer, with the name obtained from the registry ret = SetDefaultPrinter((char *)printerName); // We set the default printer just fine, now let's do the printing. if (ret != 0) { // Allocate memory for PRINTDLG structure memset( &pd, 0, sizeof( pd ) ); // Define properties of the PRINTDLG structure pd.lStructSize = sizeof( pd ); // PD_RETURNDEFAULT causes the PrintDlg function to automatically use the properties from // the default printer. PD_RETURNDC causes the function to return the device context // for the printer. This device context allows us to print a label pd.Flags = PD_RETURNDEFAULT | PD_RETURNDC; // These two structures must be NULL to use the PD_RETURNDC flag. // Do this explicitly, just in case pd.hDevMode = NULL; pd.hDevNames = NULL; // Retrieve the Device Context. It will be accessible as a member of the PRINTDLG structure if(!PrintDlg( &pd )) { // Get the error from the common dialog box // Error code will not work properly with FormatMessage, so use this instead. iErrCode = CommDlgExtendedError(); } if(iErrCode == 0) { // Initialize the DOCINFO structure memset(&di, 0, sizeof(di)); di.cbSize = sizeof(DOCINFO); di.lpszDocName = "Label"; di.lpszOutput = (LPTSTR) NULL; di.lpszDatatype = "raw"; di.fwType = 0; // Start a document in the print spooler if(!StartDoc(pd.hDC, &di)) { iErrCode = GetLastError(); } // end if } if(iErrCode == 0) { // Start a new page in the print spooler if(!StartPage(pd.hDC)) { iErrCode = GetLastError(); } // end if ! } if(iErrCode == 0) { if(!TextOut(pd.hDC, 1, 1, data, strlen(data))) { iErrCode = GetLastError(); } } // De-allocate commandList // Let the print spooler know that the page is done EndPage(pd.hDC); // Let the print spooler know that the document is done EndDoc(pd.hDC); // Delete the Device Context DeleteDC(pd.hDC); // Now reset our default printer. // Set the Default Printer back to the original. ret = SetDefaultPrinter(origDefault); PA_ReturnLong(params, (LONG_PTR)iErrCode); } else { PA_ReturnLong(params, (LONG_PTR)GetLastError()); } // end if }//end function