

#include "stdafx.h"
#include "SystemInfo.h"
#include <atlsafe.h>
#include "PIXDFLT.H"
#include <mutex>     

std::mutex mutex;



STDMETHODIMP CSystemInfo::InterfaceSupportsErrorInfo(REFIID riid)
{
	static const IID* const arr[] =
	{
		&IID_ISystemInfo
	};

	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		if (InlineIsEqualGUID(*arr[i], riid))
			return S_OK;
	}
	return S_FALSE;
}


STDMETHODIMP CSystemInfo::GetInstalledScanners(SAFEARRAY** ppResult)
{
	USES_CONVERSION;
	CComSafeArray<BSTR> sa;
	auto empty = true;
	for each (auto driver in m_driverList)
	{
		sa.Add(::SysAllocString(A2W(driver->SelectionName)), 0);
		empty = false;
	}
	if (!empty)
	{
		sa.CopyTo(ppResult);
	}
	else
	{
		*ppResult = nullptr;
	}
	return S_OK;
}

STDMETHODIMP CSystemInfo::GetConnectedScanners(SAFEARRAY** ppResult)
{
	std::unique_lock<std::mutex> lock(mutex, std::defer_lock);
	lock.lock();
	{
		USES_CONVERSION;
		CComSafeArray<BSTR> sa;
		auto empty = true;
		for each (auto driver in m_scannerList)
		{
			sa.Add(::SysAllocString(A2W(driver->SelectionName)), 0);
			empty = false;
		}
		if (!empty)
		{
			sa.CopyTo(ppResult);
		}
		else
		{
			*ppResult = nullptr;
		}
		return S_OK;
	}
	lock.unlock();
}

void CSystemInfo::InitScannerList()
{
	std::unique_lock<std::mutex> lock(mutex, std::defer_lock);
	lock.lock();
	{
		int  rc;
		PIXSELECTION PIXSelection;
		char drvpath[PIX_FILE_MAXLEN + 1];
		PIXSELECTIONITERATE myIteration;
		PIXDRIVERINFO driverInfo;

		const auto iCount = PixSelectionConnectedInit(&PIXSelection, PIXCONNECTED_ALLSCANNERS);
		if (iCount <= 0)
		{
			PixSelectionConnectedDone(&PIXSelection);
		}
		else
		{
			
			while (!(rc = PixSelectionConnectedBuild(&PIXSelection, drvpath, sizeof(drvpath))))
			{
				
			}

			if (rc > 0)
			{
				rc = PixSelectionIterateConnectedInit(&PIXSelection, &myIteration, &driverInfo);
			}
			if (PIX_SUCCESS == rc)
			{
				do
				{
					m_scannerList.push_back(new PIXDRIVERINFO(driverInfo));
					
				} while (PIX_SUCCESS == PixSelectionIterateConnectedNext(&myIteration, &driverInfo));
			}
			PixSelectionIterateConnectedDone(&myIteration);
			PixSelectionConnectedDone(&PIXSelection);
			
		}
	}
	lock.unlock();

}

void CSystemInfo::InitDriverList()
{
	int  rc;
	PIXSELECTION PIXSelection;
	char drvpath[PIX_FILE_MAXLEN + 1];
	PIXSELECTIONITERATE myIteration;
	PIXDRIVERINFO driverInfo;

	const auto iCount = PixSelectionInit(&PIXSelection, PIXSELECTION_MAINLIST, nullptr);
	if (iCount <= 0)
	{
		PixSelectionDone(&PIXSelection);
	}
	else
	{
		
		while (!(rc = PixSelectionBuild(&PIXSelection, drvpath, sizeof(drvpath))))
		{
			
		}

		if (rc > 0)
		{
			rc = PixSelectionIterateInit(&PIXSelection, &myIteration, &driverInfo);
		}
		if (PIX_SUCCESS == rc)
		{
			do
			{
				m_driverList.push_back(new PIXDRIVERINFO(driverInfo));
				
			} while (PIX_SUCCESS == PixSelectionIterateNext(&myIteration, &driverInfo));
		}
		PixSelectionIterateDone(&myIteration);
		PixSelectionDone(&PIXSelection);
		
	}

}

bool CSystemInfo::IsScannerPresent(BSTR ScannerName) const
{
	USES_CONVERSION;
	auto name = std::string(W2A(ScannerName));

	for each (auto scanner in m_scannerList)
	{
		if (name == scanner->SelectionName)
		{
			return true;
		}
	}
	return false;
}

void _stdcall OnConnectedScannerListChanged(void FAR* pvCustomParam)

{
	auto that = static_cast<CSystemInfo*>(pvCustomParam);
	that->InitScannerList();
}

void CSystemInfo::StartMonitoring()
{
	PixConnectedScannerMonitorStart(&m_pRegMonitor, OnConnectedScannerListChanged, PIXCONNECTED_ALLSCANNERS, this);
}


STDMETHODIMP CSystemInfo::DriverDescriptionToDriverName(BSTR driverDescription, BSTR* pResult)
{
	USES_CONVERSION;
	::SysFreeString(*pResult);

	auto szDesc =  W2A(driverDescription);
	if (szDesc != nullptr)
	{
		for each (auto driver in m_driverList)
		{
			if (!strcmp(driver->SelectionName, szDesc))
			{
				*pResult = ::SysAllocString(A2W(driver->DriverName));
				return S_OK;
			}
		}
	}
	return AtlReportError(GetObjectCLSID(), "Driver not found", GUID_NULL, E_FAIL);
}
