/*++ Copyright (c) 1998 Microsoft Corporation Module Name: twain.c Abstract: Enumeration routines for TWAIN data sources. Author: Jim Schmidt (jimschm) 13-Aug-1998 Revision History: --*/ #include "pch.h" VOID pSplitDataIntoWords ( IN PCTSTR Data, OUT PWORD LeftWord, OUT PWORD RightWord ) { INT a, b; PCTSTR p; a = _ttoi (Data); p = _tcschr (Data, TEXT('.')); if (!p) { b = 0; } else { b = _ttoi (p + 1); } *LeftWord = (WORD) a; *RightWord = (WORD) b; } BOOL pGetDsInfo16 ( IN PCTSTR DsPath, OUT TW_IDENTITY *Id ) { CHAR CmdLine[MAX_CMDLINE]; STARTUPINFO si; PROCESS_INFORMATION pi; BOOL ProcessResult; DWORD rc; PSTR Data; Data = CmdLine; // // Launch TWID.EXE // wsprintf (CmdLine, TEXT("\"%s\\TWID.EXE\" %s"), g_UpgradeSources, DsPath); ZeroMemory (&si, sizeof (si)); si.cb = sizeof (si); si.dwFlags = STARTF_FORCEOFFFEEDBACK; ProcessResult = CreateProcessA ( NULL, CmdLine, NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE, NULL, g_WinDir, &si, &pi ); if (ProcessResult) { CloseHandle (pi.hThread); } else { LOG ((LOG_ERROR, "Cannot start %s", CmdLine)); return FALSE; } rc = WaitForSingleObject (pi.hProcess, 10000); if (rc != WAIT_OBJECT_0) { TerminateProcess (pi.hProcess, 0); } CloseHandle (pi.hProcess); // // If process terminated, look for win.ini section // if (rc == WAIT_OBJECT_0) { ZeroMemory (Id, sizeof (TW_IDENTITY)); GetProfileString ( TEXT("$TWAINDSINFO$"), TEXT("Version"), TEXT("1.0"), Data, 32 ); pSplitDataIntoWords (Data, &Id->Version.MajorNum, &Id->Version.MinorNum); GetProfileString ( TEXT("$TWAINDSINFO$"), TEXT("Locale"), TEXT(""), Data, 32 ); pSplitDataIntoWords (Data, &Id->Version.Language, &Id->Version.Country); GetProfileString ( TEXT("$TWAINDSINFO$"), TEXT("VersionInfo"), TEXT(""), Id->Version.Info, sizeof (Id->Version.Info) ); GetProfileString ( TEXT("$TWAINDSINFO$"), TEXT("Mfg"), TEXT(""), Id->Manufacturer, sizeof (Id->Manufacturer) ); GetProfileString ( TEXT("$TWAINDSINFO$"), TEXT("Family"), TEXT(""), Id->ProductFamily, sizeof (Id->ProductFamily) ); GetProfileString ( TEXT("$TWAINDSINFO$"), TEXT("Name"), TEXT(""), Id->ProductName, sizeof (Id->ProductName) ); // // Delete the INI data // WriteProfileString ( TEXT("$TWAINDSINFO$"), NULL, NULL ); return *(Id->ProductName) != 0; } return FALSE; } DWORD g_OrgEsp; DWORD g_OrgEbp; #if _MSC_FULL_VER >= 13008827 && defined(_M_IX86) #pragma warning(push) #pragma warning(disable:4731) // EBP modified with inline asm #endif BOOL pGetDsInfo32 ( IN PCTSTR DsPath, OUT TW_IDENTITY *Id ) { HINSTANCE DsLib = NULL; DSENTRYPROC DsEntry; TW_UINT16 TwainRc; __try { // // Open the DS as a 32-bit library // DsLib = LoadLibrary (DsPath); if (!DsLib) { return FALSE; } // // Get the DS entry point // DsEntry = (DSENTRYPROC) GetProcAddress (DsLib, "DS_Entry"); if (!DsEntry) { FreeLibrary (DsLib); return FALSE; } // // Get the TW_IDENTITY struct, and preserve the stack for poorly // written DSes. // __asm { mov eax, esp mov [g_OrgEsp], eax mov [g_OrgEbp], ebp } TwainRc = DsEntry (NULL, DG_CONTROL, DAT_IDENTITY, MSG_GET, Id); __asm { mov eax, [g_OrgEsp] mov esp, eax mov ebp, [g_OrgEbp] } } __except (TRUE) { TwainRc = ERROR_NOACCESS; } if (DsLib) { FreeLibrary (DsLib); } return TwainRc == ERROR_SUCCESS; } #if _MSC_FULL_VER >= 13008827 #pragma warning(pop) #endif BOOL EnumFirstTwainDataSource ( OUT PTWAINDATASOURCE_ENUM EnumPtr ) { ZeroMemory (EnumPtr, sizeof (EnumPtr)); EnumPtr->State = TE_INIT; return EnumNextTwainDataSource (EnumPtr); } BOOL EnumNextTwainDataSource ( IN OUT PTWAINDATASOURCE_ENUM EnumPtr ) { TCHAR Path[MAX_TCHAR_PATH]; TW_IDENTITY Id; while (EnumPtr->State != TE_DONE) { switch (EnumPtr->State) { case TE_INIT: EnumPtr->State = TE_BEGIN_ENUM; EnumPtr->Dir = TEXT("TWAIN\0TWAIN_32\0TWAIN32\0"); break; case TE_BEGIN_ENUM: wsprintf (Path, TEXT("%s\\%s"), g_WinDir, EnumPtr->Dir); if (!EnumFirstFileInTree (&EnumPtr->Enum, Path, TEXT("*.DS"), TRUE)) { EnumPtr->State = TE_END_ENUM; } else { EnumPtr->State = TE_EVALUATE; } break; case TE_EVALUATE: if (EnumPtr->Enum.Directory) { EnumPtr->State = TE_NEXT; } else if (pGetDsInfo16 (EnumPtr->Enum.FullPath, &Id)) { EnumPtr->State = TE_RETURN; } else if (pGetDsInfo32 (EnumPtr->Enum.FullPath, &Id)) { EnumPtr->State = TE_RETURN; } else { EnumPtr->State = TE_NEXT; } break; case TE_RETURN: EnumPtr->State = TE_NEXT; __try { StackStringCopy (EnumPtr->Manufacturer, Id.Manufacturer); StackStringCopy (EnumPtr->ProductFamily, Id.ProductFamily); StackStringCopy (EnumPtr->DisplayName, Id.ProductName); StackStringCopy (EnumPtr->DataSourceModule, EnumPtr->Enum.FullPath); } __except (TRUE) { break; } return TRUE; case TE_NEXT: if (!EnumNextFileInTree (&EnumPtr->Enum)) { EnumPtr->State = TE_END_ENUM; } else { EnumPtr->State = TE_EVALUATE; } break; case TE_END_ENUM: EnumPtr->Dir = GetEndOfString (EnumPtr->Dir) + 1; if (*EnumPtr->Dir) { EnumPtr->State = TE_BEGIN_ENUM; } else { EnumPtr->State = TE_DONE; } break; } } return FALSE; } VOID AbortTwainDataSourceEnum ( IN OUT PTWAINDATASOURCE_ENUM EnumPtr ) { if (EnumPtr->State != TE_DONE) { AbortEnumFileInTree (&EnumPtr->Enum); EnumPtr->State = TE_DONE; } }