Level Extreme platform
Subscription
Corporate profile
Products & Services
Support
Legal
Français
Detecting a scanner
Message
From
08/09/2008 17:48:05
 
 
To
08/09/2008 17:32:41
Elyse Pomerantz
Dynamic Data Concepts, Inc.
Brooklyn, New York, United States
General information
Forum:
Visual FoxPro
Category:
Coding, syntax & commands
Environment versions
Visual FoxPro:
VFP 8 SP1
OS:
Windows XP SP2
Network:
Windows 2003 Server
Database:
Visual FoxPro
Miscellaneous
Thread ID:
01345907
Message ID:
01345910
Views:
15
>I just implemented the ability to control a scanner from within my VFP application using the EZTWAIN dll. But how can I tell if the user has a scanner attached or has the dll so I know if I should enable the Scan button or not?
>
>Thanks,
Look at Download# 26456 too. I don't remember if the copy out there includes USB devices, but it might.

Is it a USB HID device?
#DEFINE MAX_PATH                260
#DEFINE ERROR_NO_MORE_ITEMS     259
#DEFINE INVALID_HANDLE_VALUE    -1
#DEFINE DIGCF_DEVICEINTERFACE   0x0010
#DEFINE DIGCF_PRESENT           0x0002
#DEFINE DIGCF_ALLCLASSES		0x0004

#DEFINE GUID_Size  16
#DEFINE SP_DEVICE_INTERFACE_DATA_Size  28
#DEFINE SP_DEVICE_INTERFACE_DETAIL_DATA_Size  5
#Define ERROR_INSUFFICIENT_BUFFER			122
#Define ERROR_NO_MORE_ITEMS					259
#Define INVALID_HANDLE_VALUE				-1

#Define SPDRP_ADDRESS						0x001C
#Define SPDRP_BUSTYPEGUID					0x0013
#Define SPDRP_CAPABILITIES					0x000F
#Define SPDRP_CHARACTERISTICS				0x001B
#Define SPDRP_CLASS							0x0007
#Define SPDRP_CLASSGUID						0x0008
#Define SPDRP_COMPATIBLEIDS					0x0002
#Define SPDRP_CONFIGFLAGS					0x000A
#Define SPDRP_DEVICE_POWER_DATA				0x000E
#Define SPDRP_DEVICEDESC					0x0000
#Define SPDRP_DEVTYPE						0x0019
#Define SPDRP_DRIVER						0x0009
#Define SPDRP_ENUMERATOR_NAME				0x0016
#Define SPDRP_FRIENDLYNAME					0x000C
#Define SPDRP_HARDWAREID					0x0001
#Define SPDRP_LOCATION_INFORMATION			0x000D
#Define SPDRP_LOWERFILTERS					0x0012
#Define SPDRP_MFG							0x000B
#Define SPDRP_PHYSICAL_DEVICE_OBJECT_NAME	0x000E
#Define SPDRP_REMOVAL_POLICY				0x001F
#Define SPDRP_REMOVAL_POLICY_HW_DEFAULT		0x0020
#Define SPDRP_REMOVAL_POLICY_OVERRIDE		0x0021
#Define SPDRP_SECURITY						0x0017
#Define SPDRP_SECURITY_SDS					0x0018
#Define SPDRP_SERVICE						0x0004
#Define SPDRP_UI_NUMBER						0x0010
#Define SPDRP_UI_NUMBER_DESC_FORMAT			0x001E
#Define SPDRP_UPPERFILTERS					0x0011

#Define INVALID_HANDLE_VALUE		-1
#DEFINE ERROR_NO_MORE_ITEMS        259
#DEFINE ERROR_INVALID_PARAMETER     87
#DEFINE ERROR_INVALID_FLAGS       1004
#DEFINE ERROR_INSUFFICIENT_BUFFER  122
#DEFINE DIGCF_INTERFACEDEVICE       16           && 0x00000010
#DEFINE DIGCF_PRESENT                2           && 0x00000002
#define DIGCF_ALLCLASSES             4

LOCAL ls_GUID, lh_DevInfo
PRIVATE iLoop, llOnce
iLoop = 0
llOnce = .F.

DECLARE LONG GetLastError IN Kernel32
DECLARE LONG CloseHandle IN Kernel32 LONG hObject
DECLARE LONG CreateFile IN Kernel32 ;
	STRING cFileName, LONG dwDesiredAccess, LONG dwShareMode, ;
	STRING @ lpSecurityAttributes, LONG dwCreationDisposition, ;
	LONG dwFlagsAndAttributes, LONG hTemplateFile

DECLARE HidD_GetHidGuid IN HID ;
	STRING @ O_sHidGuid

DECLARE LONG HidD_GetProductString IN HID ;
	LONG hHidDeviceObject, STRING @ O_cBuffer, LONG nBufferLength

DECLARE LONG SetupDiDestroyDeviceInfoList IN SetupAPI ;
	LONG hDeviceInfoSet

DECLARE LONG SetupDiGetClassDevs IN SetupAPI ;
	STRING @ sGUID, STRING Enumerator, LONG nhWnd, LONG nFlags

DECLARE LONG SetupDiEnumDeviceInterfaces IN SetupAPI ;
	LONG hDeviceInfo, STRING @ sDeviceInfoData, ;
	STRING @ sInterfaceClassGuid, LONG MemberIndex, ;
	STRING @ O_sDeviceInterfaceData

DECLARE LONG SetupDiGetDeviceInterfaceDetail IN SetupAPI ;
	LONG hDeviceInfo, STRING @ sDeviceInterfaceData, ;
	STRING @ O_sDeviceInterfaceDetailData, LONG DeviceInterfaceDetailDataSize, ;
	LONG @ O_nRequiredSize, STRING @ O_sDeviceInfoData

DECLARE INTEGER SetupDiEnumDeviceInfo IN setupapi;
	INTEGER DeviceInfoSet,;
	INTEGER MemberIndex,;
	STRING @DeviceInfoData

Declare Integer SetupDiGetDeviceRegistryProperty In setupapi;
	Integer DeviceInfoSet,;
	String @DeviceInfoData,;
	Integer _Property,;
	String @PropertyRegDataType,;
	String @PropertyBuffer,;
	Integer PropertyBufferSize,;
	String @RequiredSize

****************************************
** Main
PUBLIC devicearray
DIMENSION devicearray(1,8)
FOR i = 1 TO ALEN(devicearray,2)
	devicearray(1,i) = []
	devicearray(1,1) = 0
ENDFOR
ls_HidGuid = SPACE( GUID_Size )
HidD_GetHidGuid( @ls_HidGuid )
*!* GUID_DEVCLASS_PRINTER, 0x4D36E979, 0xE325, 0x11CE, 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18
*!* {4D36E979-E325-11CE-BFC1-08002BE10318}
*  GUID_DEVCLASS_HIDCLASS, 0x745A17A0, 0x74D3, 0x11D0, 0xB6, 0xFE, 0x00, 0xA0, 0xC9, 0x0F, 0x57, 0xDA 
#DEFINE GUID_DEVCLASS_HIDCLASS ;
	CHR(0xA0) + CHR(0x17) + CHR(0x5A) + CHR(0x74) + ;
	CHR(0xD3) + CHR(0x74) + CHR(0xD0) + CHR(0x11) + ;
	CHR(0xB6) + CHR(0xFE) + CHR(0x00) + CHR(0xA0) + ;
	CHR(0xC9) + CHR(0x0F) + CHR(0x57) + CHR(0xDA)
#DEFINE GUID_DEVCLASS_PRINTER ;
	CHR(0x79) + CHR(0xE9) + CHR(0x36) + CHR(0x4D) + ;
	CHR(0xE3) + CHR(0x25) + CHR(0x11) + CHR(0xCE) + ;
	CHR(0xBF) + CHR(0xC1) + CHR(0x08) + CHR(0x00) + ;
	CHR(0x2B) + CHR(0xE1) + CHR(0x03) + CHR(0x18)
*!* GUID_DEVCLASS_DISKDRIVE, 0x4d36e967L, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18
#DEFINE GUID_DEVCLASS_DISKDRIVE ;
	CHR(0x67) + CHR(0xE9) + CHR(0x36) + CHR(0x4D) + ;
	CHR(0x25) + CHR(0xE3) + ;
	CHR(0xCE) + CHR(0x11) + ;
	CHR(0xBF) + CHR(0xC1) + CHR(0x08) + CHR(0x00) + CHR(0x2B) + CHR(0xE1) + CHR(0x03) + CHR(0x18)
*cguid = [{36FC9E60-C465-11CF-8056-444553540000}]
*!* GUID_DEVCLASS_USB, 0x36FC9E60, 0xC465, 0x11CF, 0x80, 0x56, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 )
#DEFINE GUID_DEVCLASS_USB ;
	CHR(0x60) + CHR(0x9E) + CHR(0xFC) + CHR(0x36) + ;
	 CHR(0x65) + CHR(0xC4) + ;
	 CHR(0xCF) + CHR(0x11) + ;
	 CHR(0x80) + CHR(0x56) + CHR(0x44) + CHR(0x45) + CHR(0x53) + CHR(0x54) + CHR(0x00) + CHR(0x00)

*GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED
#DEFINE GUID_DEVINTERFACE_USB_DEVICE ;
	CHR(0x10) + CHR(0xBF) + CHR(0xDC) + CHR(0xA5) + ;
	CHR(0x30) + CHR(0x65) + ;
	CHR(0xD2) + CHR(0x11) + ;
	CHR(0x90) + CHR(0x1F) + CHR(0x00) + CHR(0xC0) + CHR(0x4F) + CHR(0xB9) + CHR(0x51) + CHR(0xED)
USBGUID = GUID_DEVINTERFACE_USB_DEVICE
*ls_hidGuid = GUID_DEVCLASS_DISKDRIVE
*ls_hidGuid = GUID_DEVCLASS_PRINTER
*ls_hidGuid = GUID_DEVCLASS_HIDCLASS
ls_hidGuid = GUID_DEVINTERFACE_USB_DEVICE
*!*	lh_DevInfo = SetupDiGetClassDevs( ls_HidGuid, 0, 0, ;
*!*		DIGCF_PRESENT + DIGCF_DEVICEINTERFACE )
IF !EMPTY( ls_HidGuid )

	cGuid = ls_HidGuid
	cPassValue = DIGCF_PRESENT + DIGCF_DEVICEINTERFACE
	DO WHILE .T.
		lldestroy = .F.
		lh_DevInfo =  setupdigetclassdevs(@cGuid, 0, 0, cPassValue)
		m.lnpointer = lh_DevInfo
		IF TYPE('m.lnpointer') <> "N" .OR. m.lnpointer = INVALID_HANDLE_VALUE
			? [SetupDiGetClassDevs FAILED]
			EXIT
		Endif
		lldestroy = .T.
		lndeviceinfoset = lnpointer
	*	lh_DevInfo = SetupDiGetClassDevs( ls_HidGuid, 0, 0, ;
	*	DIGCF_ALLCLASSES)
		IF (lh_DevInfo != INVALID_HANDLE_VALUE)
			CLEAR
			*EnumerateDevices( lh_DevInfo, ls_HidGuid )
			EnumerateDevices( lh_DevInfo, cGuid )
			IF SetupDiDestroyDeviceInfoList( lh_DevInfo ) <> 0
				lldestroy = .F.
			ENDIF
*			IF cPassValue == DIGCF_ALLCLASSES
				EXIT
*			ENDIF
		ELSE
			EXIT
		ENDIF
	ENDDO
ENDIF
IF lldestroy
	*--Cleanup
	?'=================================================='
	?'Cleaning Up...'
	DECLARE INTEGER SetupDiDestroyDeviceInfoList IN setupapi;
	    INTEGER DeviceInfoSet
	llokay = SetupDiDestroyDeviceInfoList(lnpointer)
	?'        Releasing the handle - SetupDiDestroyDeviceInfoList Result: '
	?? llokay
	?'        Last Error: '
	?? GetLastError()
ENDIF
IF !llOnce
	?"***********************************************************"
	?" Error Using SetupDiEnumDeviceInterfaces ---------->>>>>>>>"
	?"***********************************************************"
ENDIF
RETURN
* Clear Dlls


*********************************************************************************
** Procedures
*********************************************************************************

*********************************************************************************
PROCEDURE EnumerateDevices( th_DevInfo, ts_Guid )
	*********************************************************************************
	LOCAL ls_DiData, ls_DiDetailData, lh_Device
	LOCAL ln_Error, ln_Index, ln_ReqSize
	LOCAL lc_DeviceName, lw_Buffer, lc_Buffer

	STORE 0 TO ln_Error, ln_Index, ln_ReqSize
	ls_DiData = PADR( BINTOC( SP_DEVICE_INTERFACE_DATA_Size, '4rs' ), ;
		SP_DEVICE_INTERFACE_DATA_Size, CHR(0) )

	m.lnRetVal  = -1
	m.lnRetVal2 = -1
	iloop = 0

	Do While (m.lnRetVal <> 0 .or. m.lnRetVal2 <> 0) 
	*.and.  (ln_Error != ERROR_NO_MORE_ITEMS)
	
		m.lcDeviceInfoData = PADR(BINTOC(28, [4RS]), 4, CHR(0)) + REPLICATE(CHR(0), 24)
		m.lnDeviceInfoSet = th_DevInfo
		m.lnRetVal2 = SetupDiEnumDeviceInfo( ;
			th_DevInfo, ;
			iLoop, ;
			@m.lcDeviceInfoData)

		lifoundit = .F.
		iLoop = iLoop + 1
		
		IF m.lnRetVal2 <> 0
			lifoundit = .T.
			m.lnx = iLoop - 1
			DIMENSION devicearray(iLoop,8)

			&&& extract the interface data here ... (CTOBIN, SUBSTR)
			devicearray(m.iLoop,1) = m.lnx
			?[Device: ], m.lnx
			m.lcDeviceProperty = GetRegistryProperty(m.lnDeviceInfoSet, m.lcDeviceInfoData, SPDRP_CLASS)
			IF ! ("ERROR" $ m.lcDeviceProperty)
				?[Property:], [CLASS: ], m.lcDeviceProperty
			ENDIF
			devicearray(m.iLoop,2) = m.lcDeviceProperty

			m.lcDeviceProperty = GetRegistryProperty(m.lnDeviceInfoSet, m.lcDeviceInfoData, SPDRP_DEVICEDESC)
			IF ! ("ERROR" $ m.lcDeviceProperty)
				?[Property:], [DEVICEDESC: ], m.lcDeviceProperty
			ENDIF
			devicearray(m.iLoop,3) = m.lcDeviceProperty

			m.lcDeviceProperty = GetRegistryProperty(m.lnDeviceInfoSet, m.lcDeviceInfoData, SPDRP_ENUMERATOR_NAME)
			IF ! ("ERROR" $ m.lcDeviceProperty)
				?[Property:], [ENUMERATOR_NAME: ], m.lcDeviceProperty
			ENDIF
			devicearray(m.iLoop,4) = m.lcDeviceProperty

			m.lcDeviceProperty = GetRegistryProperty(m.lnDeviceInfoSet, m.lcDeviceInfoData, SPDRP_FRIENDLYNAME)
			IF ! ("ERROR" $ m.lcDeviceProperty)
				?[Property:], [FRIENDLYNAME: ], m.lcDeviceProperty
			ENDIF
			devicearray(m.iLoop,5) = m.lcDeviceProperty

			m.lcDeviceProperty = GetRegistryProperty(m.lnDeviceInfoSet, m.lcDeviceInfoData, SPDRP_HARDWAREID)
			IF ! ("ERROR" $ m.lcDeviceProperty)
				?[Property:], [HARDWAREID: ], m.lcDeviceProperty
			ENDIF
			devicearray(m.iLoop,6) = m.lcDeviceProperty

			m.lcDeviceProperty = GetRegistryProperty(m.lnDeviceInfoSet, m.lcDeviceInfoData, SPDRP_MFG)
			IF ! ("ERROR" $ m.lcDeviceProperty)
				?[Property:], [MFG: ], m.lcDeviceProperty
			ENDIF
			devicearray(m.iLoop,7) = m.lcDeviceProperty

			m.lcDeviceProperty = GetRegistryProperty(m.lnDeviceInfoSet, m.lcDeviceInfoData, SPDRP_PHYSICAL_DEVICE_OBJECT_NAME)
			IF ! ("ERROR" $ m.lcDeviceProperty)
				?[Property:], [PHYSICAL_DEVICE_OBJECT_NAME: ], m.lcDeviceProperty
			ENDIF
			devicearray(m.iLoop,8) = m.lcDeviceProperty
			
*!*				?"*****************************************************"
*!*				?" Success using SetupDiGetDeviceRegistryProperty"
			?"*****************************************************"

		ENDIF

		m.lnRetVal = SetupDiEnumDeviceInterfaces( th_DevInfo, 0, ts_Guid, ln_Index, @ls_DiData )
		
		IF m.lnRetVal == 0

			ln_Error = GetLastError()
			IF (ln_Error != ERROR_NO_MORE_ITEMS)
				ShowError( ln_Error, ln_Index, 'SetupDiEnumDeviceInterfaces()' )
			ELSE
				? [ No More Devices]
			ENDIF
			IF lifoundit
				ln_Index = ln_Index + 1
				LOOP
				EXIT
			ENDIF
		ELSE

			llOnce = .T.	&& SetupDiEnumDeviceInterfaces worked at least once
			
			SetupDiGetDeviceInterfaceDetail( th_DevInfo, ls_DiData, ;
				0, 0, @ln_ReqSize, 0 )
			ls_DiDetailData = PADR( BINTOC( SP_DEVICE_INTERFACE_DETAIL_DATA_Size, '4rs' ), ;
				ln_ReqSize, CHR(0) )
			ln_Result = SetupDiGetDeviceInterfaceDetail( th_DevInfo, ls_DiData, ;
				@ls_DiDetailData, ln_ReqSize, @ln_ReqSize, 0 )

			IF (ln_Result == 1)
				lc_DeviceName = SUBSTR( ls_DiDetailData, 5 )
				ln_Pos = AT( CHR(0), lc_DeviceName )
				IF (ln_Pos > 0)
					lc_DeviceName = LEFT( lc_DeviceName, ln_Pos - 1 )
				ENDIF
				?lc_DeviceName
				lh_Device = CreateFile( lc_DeviceName, 0x80000000, 0x1, 0, 3, 0x20000000, 0 )
				IF (lh_Device != INVALID_HANDLE_VALUE)
					lw_Buffer = SPACE( MAX_PATH )
					IF (HidD_GetProductString( lh_Device, @lw_Buffer, MAX_PATH ) == 1)
						lc_Buffer = MakeANSI( lw_Buffer )
						? 'Product Name: ' + lc_Buffer
					ENDIF
					CloseHandle( lh_Device )
				ELSE
					ShowError( GetLastError(), ln_Index, 'CreateFile()' )
				ENDIF
			ELSE
				ShowError( GetLastError(), ln_Index, 'SetupDiGetDeviceInterfaceDetail()' )
			ENDIF
			ln_Index = ln_Index + 1
		ENDIF
	ENDDO
ENDPROC
RETURN


*********************************************************************************
PROCEDURE ShowError( tn_Error, tn_Index, tc_Message )
	*********************************************************************************
	IF "CREATEFILE" $ UPPER(tc_MESSAGE)
*		?"Error using CreateFile with this device."
	ENDIF
*	? tc_Message + ' ERROR !!'
	IF (VARTYPE( tn_Index ) == 'N')
*		? 'Member index:', tn_Index
	ENDIF
*	? 'Error No:', tn_Error
ENDPROC


*********************************************************************************
PROCEDURE MakeANSI( tw_String )
	*********************************************************************************
	LOCAL lc_String, ln_Pos

	lc_String = STRCONV( STRCONV( tw_String, 6 ), 2 )
	ln_Pos = AT( CHR(0), lc_String )
	IF (ln_Pos > 0)
		lc_String = LEFT( lc_String, ln_Pos - 1 )
	ENDIF

	RETURN lc_String
ENDPROC

*********************************************************************************
PROCEDURE GetRegistryProperty
	*********************************************************************************

	LPARAMETERS tnDeviceInfoSet, tcDeviceInfoData, tnProperty

	LOCAL lnRetVal, lcPropertyBuffer, lcRequiredSize

	m.lcPropertyBuffer = SPACE(0)
	m.lcRequiredSize = SPACE(4)
	m.PropertyRegDataType = SPACE(4)

	*!*	"The SetupDiGetDeviceRegistryProperty function retrieves the specified device property."
	*!* We don't know the size of the required string buffer for the property until we call the
	*!* function, so we first call it with a null string to get the required buffer size, then
	*!* we call again with the proper buffer size

	m.lnRetVal = SetupDiGetDeviceRegistryProperty( ;
		m.tnDeviceInfoSet, ;
		@m.tcDeviceInfoData, ;
		m.tnProperty, ;
		@m.PropertyRegDataType, ;
		@m.lcPropertyBuffer, ;
		LEN(m.lcPropertyBuffer), ;
		@m.lcRequiredSize)

	IF m.lnRetVal = 0 AND GetLastError() = ERROR_INSUFFICIENT_BUFFER THEN
		m.lcPropertyBuffer = SPACE(CTOBIN(m.lcRequiredSize, [4RS]))

		m.lnRetVal = SetupDiGetDeviceRegistryProperty( ;
			m.tnDeviceInfoSet, ;
			@m.tcDeviceInfoData, ;
			m.tnProperty, ;
			0, ;
			@m.lcPropertyBuffer, ;
			LEN(m.lcPropertyBuffer), ;
			@m.lcRequiredSize)
	ENDIF

	IF m.lnRetVal = 0 THEN
*		? [SetupDiGetDeviceRegistryProperty ERROR]
		*m.lcPropertyBuffer = [SetupDiGetDeviceRegistryProperty ERROR]
		m.lcPropertyBuffer = []
	ELSE
		m.lcPropertyBuffer = LEFT(m.lcPropertyBuffer, AT(CHR(0), m.lcPropertyBuffer) - 1)
	ENDIF

	RETURN m.lcPropertyBuffer

**************************************************************************************
* These values are for future use
00000000  -  7B 34 44 33 36 45 39 37 39 2D 45 33 32 35 2D 31  -  {4D36E979-E325-1
00000010  -  31 43 45 2D 42 46 43 31 2D 30 38 30 30 32 42 45  -  1CE-BFC1-08002BE
00000020  -  31 30 33 31 38 7D 00                             -  10318}.         
{4D36E979-E325-11CE-BFC1-08002BE10318}

/* f18a0e88-c30c-11d0-8815-00a0c906bed8 */
DEFINE_GUID(GUID_DEVINTERFACE_USB_HUB,    0xf18a0e88, 0xc30c, 0x11d0, 0x88, 0x15, 0x00, \
             0xa0, 0xc9, 0x06, 0xbe, 0xd8);

/* A5DCBF10-6530-11D2-901F-00C04FB951ED */
DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, \
             0xC0, 0x4F, 0xB9, 0x51, 0xED);

/* 3ABF6F2D-71C4-462a-8A92-1E6861E6AF27 */
DEFINE_GUID(GUID_DEVINTERFACE_USB_HOST_CONTROLLER, 0x3abf6f2d, 0x71c4, 0x462a, 0x8a, 0x92, 0x1e, \
             0x68, 0x61, 0xe6, 0xaf, 0x27);
             
/* 4E623B20-CB14-11D1-B331-00A0C959BBD2 */
DEFINE_GUID(GUID_USB_WMI_STD_DATA, 0x4E623B20L, 0xCB14, 0x11D1, 0xB3, 0x31, 0x00,\
             0xA0, 0xC9, 0x59, 0xBB, 0xD2);

/* 4E623B20-CB14-11D1-B331-00A0C959BBD2 */
DEFINE_GUID(GUID_USB_WMI_STD_NOTIFICATION, 0x4E623B20L, 0xCB14, 0x11D1, 0xB3, 0x31, 0x00,\
             0xA0, 0xC9, 0x59, 0xBB, 0xD2);        
.·*´¨)
.·`TCH
(..·*

010000110101001101101000011000010111001001110000010011110111001001000010011101010111001101110100
"When the debate is lost, slander becomes the tool of the loser." - Socrates
Vita contingit, Vive cum eo. (Life Happens, Live With it.)
"Life is not measured by the number of breaths we take, but by the moments that take our breath away." -- author unknown
"De omnibus dubitandum"
Previous
Next
Reply
Map
View

Click here to load this message in the networking platform