31 de enero de 2005

Conociendo un poco más WMI

La idea de este artículo, es para realizar un acercamiento más de WMI (Windows Management Instrumentation) y Visual FoxPro.



Conociendo un poco más WMI
(Windows Management Instrumentation)

Clases WMI-CIMv2-WIN32 y MS Visual FoxPro.

Manifestando el apoyo a la comunidad de desarrolladores de MS Visual FoxPro.
Antonio Muñoz de Burgos y Caravaca.
www.emans.com


Breve introducción

La idea de este artículo, es para realizar un acercamiento más de WMI y VFP, tener la información correspondiente, y poder aprovechar, lo que nos puede proporcionarWMI en la explotación del entorno administrativo, en algún caso o momento determinado.

WMI, no es más, que un componente del Sistema operativo MS Windows, que esta basado en la iniciativa WBEM (Web-Based Enterprise Management)

WMI, nos proporciona acceso a la información de los objetos del entorno administrativo, donde el abanico es realmente extenso, en este artículo me centraré en la sección de ClasesWMI y dentro de estas clases en la que hace referencia a las clases Win32.

El sub-apartado de clases Win32, nos representa el esquema de clases, que se obtiene a partir del espacio nombres (namespace) [rootcimv2]

La clase Win32 nos proporciona las siguientes categorías de clases:

Computer system hardware:
clase que representa los objetos relacionados con el hardware.
Operating system:
clase que representa los objetos relativos al sistema.
Installed applicaciones:
clase que representa los objetos relativos al software
WMI service management:
clases usadas por el administrador WMI.
Performance counters:
clase que representa la estructuración y actuación de datos.

Si miramos la infraestructura de WMI, encontramos WQL (WMI Query Language), donde WQL no es más que un subset de SQL (ANSI standard Structured Query Language (SQL) con sus especificaciones de extensión.

Debemos de tener en cuenta que WQL, es el lenguaje de consulta de WMI, pero de solo lectura, por lo tanto no es posible realizar inserciones, modificaciones, o borrados en el repositorio de datos WMI o en el proveedor que estemos actuando. Por medio de WQL solamente podremos recibir (explotar) la información.

Nota:
cuando menciono que es de "solo lectura" hago referencia exclusiva al sistema de consulta WQL, diferencia clara que tenemos con SQL,no confundir con la exposición e interacción con el modelo de objetos, puede ser de lectura y escritura.

Retomando el origen de este artículo, para la explotación de la información que nos proporciona WMI dentro la clase Win32, debemos de partir del siguiente (namespace) [rootCIMv2]

Para información detallada de CIM (Common Information Model)
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmi/common_information_model.asp

A continuación expongo la lista de las clases WMI que parte del (namespace - espacio de nombre) CIMv2.

En esta lista de clase WIN32, se acompaña cada una, con un ejemplo en VFP para ver su funcionamiento, consulta WQL y propiedades.
 

Entendiendo; como están expuestos los ejemplos de cada una las clase

 

Los ejemplos, están expuestos realizando la consulta WQL sin cláusula WHERE, con el fin de explotar todos los datos posibles, como es lógico; eso es para la representación del ejemplo, pero la aplicación de una cláusula WHERE es simple, ya que cada ejemplo va acompañado de sus correspondientes propiedades.
 

Detallemos un poco el caso:

La primera clase WMI dentro de nuestra lista (ordenada alfabéticamente) es: CMI_DataFile

Esta clase, nos proporciona, como su propio nombre nos indica, todos los ficheros del ordenador (PC) al que realizamos la solicitud.

En el ejemplo, que expongo sobre esta clase, como he comentado, no existe cláusula WHERE, esta es la sintaxis:


lcWQL = "SELECT * FROM CIM_DataFile"
Por lo tanto si ejecutamos el ejemplo, nos retornará toda la información que se encuentre en el PC.


Como aplicar una cláusula WHERE a cualquiera de los ejemplos que expongo, bien, la podemos aplicar por la propiedad desea, las propiedades están expuestas en todos los ejemplos.

Como podemos ver en el ejemplo de la clase:
CIM_DataFile, una de las propiedades es [Drive], si aplicamos esta propiedad como filtro para la consulta, la sintaxis sería la siguiente:


lcWQL = "SELECT * FROM CIM_DataFile WHERE Drive = 'E:' "

 


Otro ejemplo: utilicemos la clase : Win32_DiskDrive

Esta clase, nos proporciona, información de los discos duros (HHD) del ordenador (PC) al que realizamos la solicitud.

En el ejemplo que expongo, al igual que el caso comentado anteriormente, se retornará la información de todos los discos, con todas las propiedades correspondientes, que son las siguientes:

.Availability
.BytesPerSector
.Capabilities
.CapabilityDescriptions
.Caption
.CompressionMethod
.ConfigManagerErrorCode
.ConfigManagerUserConfig
.CreationClassName
.DefaultBlockSize
.Description
.DeviceID
.ErrorCleared
.ErrorDescription
.ErrorMethodology
.Index
.InstallDate
.InterfaceType
.LastErrorCode
.Manufacturer
.MaxBlockSize
.MaxMediaSize
.MediaLoaded
.MediaType
.MinBlockSize
.Model
.Name
.NeedsCleaning
.NumberOfMediaSupported
.Partitions
.PNPDeviceID
.PowerManagementCapabilities
.PowerManagementSupported
.SCSIBus
.SCSILogicalUnit
.SCSIPort
.SCSITargetId
.SectorsPerTrack
.Signature
.Size
.Status
.StatusInfo
.SystemCreationClassName
.SystemName
.TotalCylinders
.TotalHeads
.TotalSectors
.TotalTracks
.TracksPerCylinder

Como aplicar una cláusula WHERE en este caso, pues de igual forma que en el anterior, supongamos que deseamos filtrar por los disco que tenga el interface del tipo [IDE], para ello haremos uso de la propiedad : [InterfaceType]

lcWQL = "SELECT * FROM CIM_DataFile WHERE InterfaceType = 'IDE' "


Otro ejemplo: utilicemos la clase : Win32_NetworkConnection

Esta clase, nos proporciona, información sobre las conexiones de Red del ordenador (PC) al que realizamos la solicitud.

En el ejemplo que expongo, al igual que el los casos anteriores, se retornará la información de todos las conexiones.

Podemos aplicar una cláusula WHERE por alguna de sus propiedades, según se indican en el ejemplo, si filtramos por [localName] de la conexión, se corresponde con la [unidad], si lo hacemos por [Name] es el nombre del recurso compartido

lcWQL = "SELECT * FROM CIM_DataFile WHERE LocalName = 'Z:' "
lcWQL = "SELECT * FROM CIM_DataFile WHERE Name = '
ServidorRecurso_Compartido' "
Aquí aplicamos la nomenclatura UNC.

 


CONSIDERACIÓN IMPORTANTE:

La propiedades como es lógico, retornan valores de diferentes tipos, ya pueden ser de tipo "string", "fecha", "numérico", etc, pero si es importante tener en cuenta, que hay propiedades que retornan [ARRAY] u objetos, por supuesto eso no representa problema alguno, ya que lo podemos tratar según el caso de forma fácil con VFP.

Concretamente, en el ejemplo que he expuesto de la Clase: Win32_DiskDrive, tenemos una propiedad que nos retorna un [ARRAY], que es la propiedad ".Capabilities"

Tal como esta puesta en el ejemplo, dará un error de incompatibilidad de tipos, debería tener algo como esto:

FOR lnIndi = 1 TO ALEN( loItem.Capabilities )
    ?loItem.Capabilities( lnIndi )
ENDFOR

El realizar esta mención;
es porque en los ejemplos no hago tratamiento del tipo,
simplemente por comodidad efectuó la visualización de valor si es posible.

Para ello se debe anular la línea ON ERROR


Como os podéis dar cuenta, aquí lo importante y fundamental es:

(1) Saber, que existe una clase WMI que realiza una determinada acción.
(2) Saber, como realizar la consulta a la clase WMI con WQL.
(3) Saber las propiedades de la clase WMI.

A partir de ahí, el cambiar el código, para explotar una información concreta, ya no es un problema.


En esta publicación sobre WMI, las Clases WIN32 y VFP,
creo
se cumplen los tres puntos que he mencionado,
para poder aprovechar al máximo la información.
 


Para más detalles sobre los comandos y/o palabras (SQL for WMI)
 
SQL for WMI
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmi/sql_for_wmi.asp

 

NOTA

Cada clase referenciada aquí, tiene su ejemplo correspondiente.

Todas se encuentran en PortalFox, en el sistema
de programación de tareas.
Es decir, que se irán publicando día tras día dentro de la programación,
establecida por los SysOps.

Lo ejemplos también se encontrarán mi Web: www.emans.com

Exactamente en esta publicación se hace referencia
a [437] Clases WMI y sus [437] ejemplos.
Basado en el espacio de nombre (namespace) de CIMv2.

Donde, entran todas las categorías citadas:
Computer system hardware.
Operating system.
Installed applicaciones.
Performance counters.

 


 

Lista de Clases WMI a partir de CIMv2 (ordenadas alfabéticamente)

 

 
CMI_DataFile
CMI_DirectoryContainsFile
CMI_ProcessExecutable
CIM_VideoControllerResolution
Msft_Providers
Msft_WmiProvider_Counters
NetDiagnostics
Win32_1394Controller
Win32_1394ControllerDevice
Win32_AccountSID
Win32_ActionCheck
Win32_ActiveRoute
Win32_AllocatedResource
Win32_ApplicationCommandLine
Win32_ApplicationService
Win32_AssociatedBattery
Win32_AssociatedProcessorMemory
Win32_AutochkSetting
Win32_BaseBoard
Win32_Battery
Win32_Binary
Win32_BindImageAction
Win32_BIOS
Win32_BootConfiguration
Win32_Bus Win32_CacheMemory
Win32_CDROMDrive
Win32_CheckCheck
Win32_CIMLogicalDeviceCIMDataFile
Win32_ClassicCOMApplicationClasses
Win32_ClassicCOMClass
Win32_ClassicCOMClassSetting
Win32_ClassicCOMClassSettings
Win32_ClassInforAction
Win32_ClientApplicationSetting
Win32_CodecFile
Win32_COMApplicationSettings
Win32_COMClassAutoEmulator
Win32_ComClassEmulator
Win32_CommandLineAccess
Win32_ComponentCategory
Win32_ComputerSystem
Win32_ComputerSystemProcessor
Win32_ComputerSystemProduct
Win32_ComputerSystemWindowsProductActivationSetting
Win32_Condition
Win32_ConnectionShare
Win32_ControllerHastHub
Win32_CreateFolderAction
Win32_CurrentProbe
Win32_DCOMApplication
Win32_DCOMApplicationAccessAllowedSetting
Win32_DCOMApplicationLaunchAllowedSetting
Win32_DCOMApplicationSetting
Win32_DependentService
Win32_Desktop
Win32_DesktopMonitor
Win32_DeviceBus
Win32_DeviceMemoryAddress
Win32_Directory
Win32_DirectorySpecification
Win32_DiskDrive
Win32_DiskDrivePhysicalMedia
Win32_DiskDriveToDiskPartition
Win32_DiskPartition
Win32_DiskQuota
Win32_DisplayConfiguration
Win32_DisplayControllerConfiguration
Win32_DMAChanner
Win32_DriverForDevice
Win32_DriverVXD
Win32_DuplicateFileAction
Win32_Environment
Win32_EnvironmentSpecification
Win32_ExtensionInfoAction
Win32_Fan
Win32_FileSpecification
Win32_FloppyController
Win32_FloppyDrive
Win32_FontInfoAction
Win32_Group
Win32_GroupDomain
Win32_GroupUser
Win32_HeatPipe
Win32_IDEController
Win32_IDEControllerDevice
Win32_ImplementedCategory
Win32_InfraredDevice
Win32_IniFileSpecification
Win32_InstalledSoftwareElement
Win32_IP4PersistedRouteTable
Win32_IP4RouteTable
Win32_IRQResource
Win32_Keyboard
Win32_LaunchCondition
Win32_LoadOrderGroup
Win32_LoadOrderGroupServiceDependencies
Win32_LoadOrderGroupServiceMembers
Win32_LocalTime
Win32_LoggedOnUser
Win32_LogicalDisk
Win32_LogicalDiskRootDirectory
Win32_LogicalDiskToPartition
Win32_LogicalFileAccess
Win32_LogicalFileAuditing
Win32_LogicalFileGroup
Win32_LogicalFileOwner
Win32_LogicalFileSecuritySetting
Win32_LogicalMemoryConfiguration
Win32_LogicalProgramGroup
Win32_LogicalProgramGroupDirectory
Win32_LogicalProgramGroupItem
Win32_LogicalProgramGroupItemDataFile
Win32_LogicalShareAccess
Win32_LogicalShareAuditing
Win32_LogicalShareSecuritySetting
Win32_LogonSession
Win32_LogonSessionMappedDisk
Win32_MappedLogicalDisk
Win32_MemoryArray
Win32_MemoryArrayLocation
Win32_MemoryDevice
Win32_MemoryDeviceArray
Win32_MemoryDeviceLocation
Win32_MIMEInfoAction
Win32_MotherboardDevice
Win32_MoveFileAction
Win32_NamedJobObject
Win32_NamedJobObjectActgInfo
Win32_NamedJobObjectLimit
Win32_NamedJobObjectLimitSetting
Win32_NamedJobObjectProcess
Win32_NamedJobObjectSecLimit
Win32_NamedJobObjectSecLimitSetting
Win32_NamedJobObjectStatistics
Win32_NetworkAdapter
Win32_NetworkAdapterConfiguration
Win32_NetworkAdapterSetting
Win32_NetworkClient
Win32_NetworkConnection
Win32_NetworkLoginProfile
Win32_NetworkProtocol
Win32_NTDomain
Win32_NTEventlogFile
Win32_NTLogEvent
Win32_NTLogEventComputer
Win32_NTLogEvnetLog
Win32_NTLogEventUser
Win32_ODBCAttribute
Win32_ODBCDataSourceAttribute
Win32_ODBCDataSourceSpecification
Win32_ODBCDriverAttribute
Win32_ODBCDriverSoftwareElement
Win32_ODBCDriverSpecification
Win32_ODBCSourceAttribute
Win32_ODBCTranslatorSpecification
Win32_OnBoardDevice
Win32_OperatingSystem
Win32_OperatingSystemAutochkSetting
Win32_OperatingSystemQFE
Win32_OSRecoveryConfiguración
Win32_PageFile
Win32_PageFileElementSetting
Win32_PageFileSetting
Win32_PageFileUsage
Win32_ParallelPort
Win32_Patch
Win32_PatchFile
Win32_PatchPackage
Win32_PCMCIAControler
Win32_PerfFormattedData_ASP_ActiveServerPages
Win32_PerfFormattedData_ASPNET_114322_ASPNETAppsv114322
Win32_PerfFormattedData_ASPNET_114322_ASPNETv114322
Win32_PerfFormattedData_ASPNET_2040607_ASPNETAppsv2040607
Win32_PerfFormattedData_ASPNET_2040607_ASPNETv2040607
Win32_PerfFormattedData_ASPNET_ASPNET
Win32_PerfFormattedData_ASPNET_ASPNETApplications
Win32_PerfFormattedData_aspnet_state_ASPNETStateService
Win32_PerfFormattedData_ContentFilter_IndexingServiceFilter
Win32_PerfFormattedData_ContentIndex_IndexingService
Win32_PerfFormattedData_DTSPipeline_SQLServerDTSPipeline
Win32_PerfFormattedData_Fax_FaxServices
Win32_PerfFormattedData_InetInfo_InternetInformationServicesGlobal
Win32_PerfFormattedData_ISAPISearch_HttpIndexingService
Win32_PerfFormattedData_MSDTC_DistributedTransactionCoordinator
Win32_PerfFormattedData_NETCLRData_NETCLRData
Win32_PerfFormattedData_NETCLRNetworking_NETCLRNetworking
Win32_PerfFormattedData_NETDataProviderforOracle_NETCLRData
Win32_PerfFormattedData_NETDataProviderforSqlServer_NETDataProviderforSqlServer
Win32_PerfFormattedData_NETFramework_NETCLRExceptions
Win32_PerfFormattedData_NETFramework_NETCLRInterop
Win32_PerfFormattedData_NETFramework_NETCLRJit
Win32_PerfFormattedData_NETFramework_NETCLRLoading
Win32_PerfFormattedData_NETFramework_NETCLRLocksAndThreads
Win32_PerfFormattedData_NETFramework_NETCLRMemory
Win32_PerfFormattedData_NETFramework_NETCLRRemoting
Win32_PerfFormattedData_NETFramework_NETCLRSecurity
Win32_PerfFormattedData_NTFSDRV_ControladordealmacenamientoNTFSdeSMTP
Win32_PerfFormattedData_Outlook_Outlook
Win32_PerfFormattedData_PerfDisk_LogicalDisk
Win32_PerfFormattedData_PerfDisk_PhysicalDisk
Win32_PerfFormattedData_PerfNet_Browser
Win32_PerfFormattedData_PerfNet_Redirector
Win32_PerfFormattedData_PerfNet_Server
Win32_PerfFormattedData_PerfNet_ServerWorkQueues
Win32_PerfFormattedData_PerfOS_Cache
Win32_PerfFormattedData_PerfOS_Memory
Win32_PerfFormattedData_PerfOS_Objects
Win32_PerfFormattedData_PerfOS_PagingFile
Win32_PerfFormattedData_PerfOS_Processor
Win32_PerfFormattedData_PerfOS_System
Win32_PerfFormattedData_PerfProc_FullImage_Costly
Win32_PerfFormattedData_PerfProc_Image_Costly
Win32_PerfFormattedData_PerfProc_JobObject
Win32_PerfFormattedData_PerfProc_JobObjectDetails
Win32_PerfFormattedData_PerfProc_Process
Win32_PerfFormattedData_PerfProc_ProcessAddressSpace_Costly
Win32_PerfFormattedData_PerfProc_Thread
Win32_PerfFormattedData_PerfProc_ThreadDetails_Costly
Win32_PerfFormattedData_RemoteAccess_RASPort
Win32_PerfFormattedData_RemoteAccess_RASTotal
Win32_PerfFormattedData_RSVP_RSVPInterfaces
Win32_PerfFormattedData_RSVP_RSVPService
Win32_PerfFormattedData_Spooler_PrintQueue
Win32_PerfFormattedData_TapiSrv_Telephony
Win32_PerfFormattedData_Tcpip_ICMP
Win32_PerfFormattedData_Tcpip_IP
Win32_PerfFormattedData_Tcpip_NBTConnection
Win32_PerfFormattedData_Tcpip_NetworkInterface
Win32_PerfFormattedData_Tcpip_TCP
Win32_PerfFormattedData_Tcpip_UDP
Win32_PerfFormattedData_TermService_TerminalServices
Win32_PerfFormattedData_TermService_TerminalServicesSession
Win32_PerfFormattedData_W3SVC_WebService
Win32_PerfRawData_ASP_ActiveServerPages
Win32_PerfRawData_ASPNET_114322_ASPNETAppsv114322
Win32_PerfRawData_ASPNET_114322_ASPNETv114322
Win32_PerfRawData_ASPNET_2040607_ASPNETAppsv2040607
Win32_PerfRawData_ASPNET_2040607_ASPNETv2040607
Win32_PerfRawData_ASPNET_ASPNET
Win32_PerfRawData_ASPNET_ASPNETApplications
Win32_PerfRawData_aspnet_state_ASPNETStateService
Win32_PerfRawData_ContentFilter_IndexingServiceFilter
Win32_PerfRawData_ContentIndex_IndexingService
Win32_PerfRawData_DTSPipeline_SQLServerDTSPipeline
Win32_PerfRawData_Fax_FaxServices
Win32_PerfRawData_InetInfo_InternetInformationServicesGlobal
Win32_PerfRawData_ISAPISearch_HttpIndexingService
Win32_PerfRawData_MSDTC_DistributedTransactionCoordinator
Win32_PerfRawData_NETCLRData_NETCLRData
Win32_PerfRawData_NETCLRNetworking_NETCLRNetworking
Win32_PerfRawData_NETDataProviderforOracle_NETCLRData
Win32_PerfRawData_NETDataProviderforSqlServer_NETDataProviderforSqlServer
Win32_PerfRawData_NETFramework_NETCLRExceptions
Win32_PerfRawData_NETFramework_NETCLRInterop
Win32_PerfRawData_NETFramework_NETCLRJit
Win32_PerfRawData_NETFramework_NETCLRLoading
Win32_PerfRawData_NETFramework_NETCLRLocksAndThreads
Win32_PerfRawData_NETFramework_NETCLRMemory
Win32_PerfRawData_NETFramework_NETCLRRemoting
Win32_PerfRawData_NETFramework_NETCLRSecurity
Win32_PerfRawData_NTFSDRV_ControladordealmacenamientoNTFSdeSMTP
Win32_PerfRawData_Outlook_Outlook
Win32_PerfRawData_PerfDisk_LogicalDisk
Win32_PerfRawData_PerfDisk_PhysicalDisk
Win32_PerfRawData_PerfNet_Browser
Win32_PerfRawData_PerfNet_Redirector
Win32_PerfRawData_PerfNet_Server
Win32_PerfRawData_PerfNet_ServerWorkQueues
Win32_PerfRawData_PerfOS_Cache
Win32_PerfRawData_PerfOS_Memory
Win32_PerfRawData_PerfOS_Objects
Win32_PerfRawData_PerfOS_PagingFile
Win32_PerfRawData_PerfOS_Processor
Win32_PerfRawData_PerfOS_System
Win32_PerfRawData_PerfProc_FullImage_Costly
Win32_PerfRawData_PerfProc_Image_Costly
Win32_PerfRawData_PerfProc_JobObject
Win32_PerfRawData_PerfProc_JobObjectDetails
Win32_PerfRawData_PerfProc_Process
Win32_PerfRawData_PerfProc_ProcessAddressSpace_Costly
Win32_PerfRawData_PerfProc_Thread
Win32_PerfRawData_PerfProc_ThreadDetails_Costly
Win32_PerfRawData_RemoteAccess_RASPort
Win32_PerfRawData_RemoteAccess_RASTotal
Win32_PerfRawData_RSVP_RSVPInterfaces
Win32_PerfRawData_RSVP_RSVPService
Win32_PerfRawData_Spooler_PrintQueue
Win32_PerfRawData_TapiSrv_Telephony
Win32_PerfRawData_Tcpip_ICMP
Win32_PerfRawData_Tcpip_IP
Win32_PerfRawData_Tcpip_NBTConnection
Win32_PerfRawData_Tcpip_NetworkInterface
Win32_PerfRawData_Tcpip_TCP
Win32_PerfRawData_Tcpip_UDP
Win32_PerfRawData_TermService_TerminalServices
Win32_PerfRawData_TermService_TerminalServicesSession
Win32_PerfRawData_W3SVC_WebService
Win32_PhysicalMedia
Win32_PhysicalMemory
Win32_PhysicalMemoryArray
Win32_PhysicalMemoryLocation
Win32_PingStatus
Win32_PNPAllocatedResource
Win32_PnPDevice
Win32_PnPEntity
Win32_PnPSignedDriver
Win32_PnPSignedDriverCIMDataFile
Win32_PointingDevice
Win32_PortableBattery
Win32_PortConnector
Win32_PortResource
Win32_POTSModem
Win32_POTSModemToSerialPort
Win32_Printer
Win32_PrinterConfiguration
Win32_PrinterController
Win32_PrinterDriver
Win32_PrinterDriverDll
Win32_PrinterSetting
Win32_PrinterShare
Win32_PrintJob
Win32_Process
Win32_Processor
Win32_Product
Win32_ProductCheck
Win32_ProductResource
Win32_ProductSoftwareFeatures
Win32_ProgIDSpecification
Win32_ProgramGroup
Win32_ProgramGroupContents
Win32_Property
Win32_ProtocolBinding
Win32_Proxy
Win32_PublishComponentAction
Win32_QuickFixEngineering
Win32_QuotaSetting
Win32_Refrigeration
Win32_Registry
Win32_RegistryAction
Win32_RemoveFileAction
Win32_RemoveIniAction
Win32_ReserveCost
Win32_ScheduledJob
Win32_SCSIController
Win32_SCSIControllerDevice
Win32_SecuritySettingOfLogicalFile
Win32_SecuritySettingOfLogicalShare
Win32_SelfRegModuleAction
Win32_SerialPort
Win32_SerialPortConfiguration
Win32_SerialPortSetting
Win32_ServerConnection
Win32_ServerSession
Win32_Service
Win32_ServiceControl
Win32_ServiceSpecification
Win32_ServiceSpecificationService
Win32_SessionConnection
Win32_SessionProcess
Win32_Share
Win32_ShareToDirectory
Win32_ShortcutAction
Win32_ShortcutFile
Win32_ShortcutSAP
Win32_SID
Win32_SoftwareElement
Win32_SoftwareElementAction
Win32_SoftwareElementCheck
Win32_SoftwareElementCondition
Win32_SoftwareElementResource
Win32_SoftwareFeature
Win32_SoftwareFeatureAction
Win32_SoftwareFeatureCheck
Win32_SoftwareFeatureParent
Win32_SoftwareFeatureSoftwareElements
Win32_SoundDevice
Win32_StartupCommand
Win32_SubDirectory
Win32_SystemAccount
Win32_SystemBIOS
Win32_SystemBootConfiguration
Win32_SystemDesktop
Win32_SystemDevices
Win32_SystemDriver
Win32_SystemDriverPNPEntity
Win32_SystemEnclosure
Win32_SystemLoadOrderGroups
Win32_SystemLogicalMemoryConfiguration
Win32_SystemNetworkConnections
Win32_SystemOperatingSystem
Win32_SystemPartitions
Win32_SystemProcesses
Win32_SystemProgramGroups
Win32_SystemResources
Win32_SystemServices
Win32_SystemSlot
Win32_SystemSystemDriver
Win32_SystemTimeZone
Win32_SystemUsers
Win32_TapeDrive
Win32_TCPIPPrinterPort
Win32_TemperatureProbe
Win32_Terminal
Win32_TerminalService
Win32_TerminalServiceSetting
Win32_TerminalServiceToSetting
Win32_TerminalTerminalSetting
Win32_Thread
Win32_TimeZone
Win32_TSAccount
Win32_TSClientSetting
Win32_TSEnvironmentSetting
Win32_TSGeneralSetting
Win32_TSLogonSetting
Win32_TSNetworkAdapterListSetting
Win32_TSNetworkAdapterSetting
Win32_TSPermissionsSetting
Win32_TSRemoteControlSetting
Win32_TSSessionDirectory
Win32_TSSessionDirectorySetting
Win32_TSSessionSetting
Win32_TypeLibraryAction
Win32_UninterruptiblePowerSupply
Win32_USBController
Win32_USBControllerDevice
Win32_USBHub
Win32_UserAccount
Win32_UserDesktop
Win32_UserInDomain
Win32_UTCTime
Win32_VideoController
Win32_VideoSettings
Win32_VoltageProbe
Win32_VolumeQuotaSetting
Win32_WindowsProductActivation
Win32_WMIElementSetting
Win32_WMISetting
 

 
 

Requerimientos mínimos, en cuando a la disponibilidad en el Sistema Operativo y componentes WMI

 
 
WMI, se encuentra incluido en MS Windows 2000 o superior, MS Windows XP, y MS Windows Millenniun Edition (Me).
Para MS Windows 95 (OSR2), MS Windows 98 o MS Windows NT 4.0, puedes realizar la descarga de la siguiente URL:
 
Windows Management Instrumentation (WMI) CORE 1.5 (Windows 95/98)
http://www.microsoft.com/downloads/details.aspx?FamilyId=98A4C5BA-337B-4E92-8C18-A63847760EA5&displaylang=en
 
 

Zona de descarga en la Web de Microsoft

 
Management (WMI) Extensions for Visual Studio .NET 2003 Server Explorer
http://www.microsoft.com/downloads/details.aspx?FamilyID=62d91a63-1253-4ea6-8599-68fb3ef77de1&DisplayLang=en
 
Management (WMI) Extensions for Visual Studio .NET 2002 Server Explorer (RTM)
http://www.microsoft.com/downloads/details.aspx?FamilyId=EF7594D3-4907-4AF6-B7D8-6E22115FFAF0&displaylang=en
 
WMI Administrative Tools
http://www.microsoft.com/downloads/details.aspx?FamilyId=6430F853-1120-48DB-8CC5-F2ABDC3ED314&displaylang=en
 
Windows Management Instrumentation Tutorial
http://www.microsoft.com/downloads/details.aspx?FamilyId=720F0CAE-64A7-457F-BB95-E4F33E0CBC55&displaylang=en
 
 
Windows Management Instrumentation (WMI) SNMP Provider 1.5 Build 1085.0005 (Windows NT 4.0 and 2000)
http://www.microsoft.com/downloads/details.aspx?FamilyId=C6B30755-6D20-4107-82C5-089E3DFE4FEE&displaylang=en
 
 
Información detallada de WMI en la plataforma [SDK: Windows Management Instrumentation]

  

Antonio Muñoz de Burgos y Caravaca
www.emans.com  (Web realizada en vFoxPro)
Sevilla - España
Manifestando el apoyo a la comunidad de desarrolladores de MS Visual FoxPro.
 

Todas las marcas aquí mencionadas, están registradas por sus respectivos fabricantes.

24 de enero de 2005

El nuevo tipo de datos BLOB en VFP 9.0

Introducción

Visual FoxPro 9.0 incluye un nuevo tipo de datos llamado BLOB (Binary Large OBject). Este tipo de datos sirve para almacenar datos binarios de cualquier tipo y de longitud variable, como por ejemplo un archivo ejecutable, archivos de imágenes, cadenas de bytes, etc. El tipo de datos Blob es particularmente útil para almacenar imágenes desde un SQL Server.

En el siguiente ejemplo para Visual FoxPro 9, lo utilizaremos en un cursor con un campo tipo Blob, en el cual almacenaremos archivos de imágenes. Este ejemplo es solo ilustrativo e intenta simular un cursor que puede haber sido creado por una cláusula SELECT a una tabla de SQL Server, o bien por un comando XMLTOCURSOR() con datos recibidos de una fuente externa como un Servicio Web.

Conceptos previos

Estos son algunos conceptos que debemos tener en cuenta al utilizar el nuevo tipo de datos Blob:
  • Los datos tipos Blob se pueden utilizar en contenedores de bases de datos, tablas libres, cursores y vistas.
  • Puede haber múltiples campos de tipo Blob en una misma tabla.
  • Los valores Blob se almacenan en un archivo Memo (.ftp).
  • En los campos de tipo Blob no se realiza ninguna traducción del código de página.
  • El límite de un campo Blob esta dado por la memoria disponible y/o por el límite de 2 GB en el tamaño del archivo.
  • Se puede visualizar el contenido de un campo Blob con el control Cuadro de Edición (EditBox), Cuadro de Texto (TextBox) en una Cuadrícula (Grid) o con el comando MODIFY MEMO <CampoBlob>. En todos los casos los valores son de Solo Lectura.
  • En los Cuadros de Edición, los valores Blob se muestran como valores hexadecimales sin el prefijo "0h".
  • En las Cuadrículas, los valores Blob se muestran con la cadena "blob" si el campo está vacío, o con la cadena "Blob" si el campo contiene datos. Con un doble click en el campo de la cuadrícula se puede visualizar su contenido en una ventana de edición de solo lectura.
  • No están soportadas las claves de índices sobre campos de tipo Blob.
El formulario de ejemplo

En el formulario del ejemplo, en el método Init creamos un cursor Alumnos con un campo Blob en el que almacenaremos las imágenes que se encuentran en la carpeta Samples\Data\Graphics del directorio raíz de la instalación de Visual FoxPro 9.0. (Figura 1)


Figura 1: Imagenes de la carpeta "Samples\Data\Graphics\"

El formulario contiene un control Cuadrícula con todos los campos del cursor Alumnos, un control Cuadro de Edición con el contenido del campo Blob, y un control Imagen en el que configuramos la propiedad PictureVal (nueva en VFP 9.0) con el contenido del campo Blob cada vez que nos movemos de registro en el control Cuadrícula. (Figura 2)


Figura 2: Vista del formulario del ejemplo

Este formulario de ejemplo se puede descargar desde el siguiente enlace:blob.zip (2,87 KB)

A continuación se expone el código del formulario, para correrlo se debe copiar el código en un archivo .PRG y ejecutarlo desde Visual FoxPro 9.0.

PUBLIC oMiForm
oMiForm = NEWOBJECT("MiForm")
oMiForm.SHOW
RETURN

DEFINE CLASS MiForm AS FORM
  HEIGHT = 336
  WIDTH = 728
  DOCREATE = .T.
  AUTOCENTER = .T.
  CAPTION = "Ejemplo de un campo Blob"
  BINDCONTROLS = .F.
  NAME = "MiForm"

  ADD OBJECT edtFoto AS EDITBOX WITH ;
    COMMENT = "", ;
    HEIGHT = 216, ;
    LEFT = 296, ;
    TABINDEX = 2, ;
    TOP = 8, ;
    WIDTH = 216, ;
    CONTROLSOURCE = "Alumnos.Foto", ;
    NAME = "edtFoto"

  ADD OBJECT imgFoto AS IMAGE WITH ;
    STRETCH = 1, ;
    HEIGHT = 216, ;
    LEFT = 520, ;
    TOP = 8, ;
    WIDTH = 192, ;
    NAME = "imgFoto"

  ADD OBJECT grdAlumnos AS MiGrid

  ADD OBJECT lblgrid AS LABEL WITH ;
    WORDWRAP = .T., ;
    BACKSTYLE = 0, ;
    CAPTION = [Cursor con un campo Blob. Con "Doble Click" en el campo Blob ] +;
    [visualizamos el contenido en una ventana de edición de solo lectura.'], ;
    HEIGHT = 72, ;
    LEFT = 32, ;
    TOP = 232, ;
    WIDTH = 232, ;
    FORECOLOR = RGB(0,0,0), ;
    NAME = "lblGrid"

  ADD OBJECT lbleditbox AS LABEL WITH ;
    WORDWRAP = .T., ;
    BACKSTYLE = 0, ;
    CAPTION = [Cuadro de Edición de solo lectura con el contenido del campo Blob.], ;
    HEIGHT = 72, ;
    LEFT = 304, ;
    TOP = 232, ;
    WIDTH = 192, ;
    FORECOLOR = RGB(0,0,255), ;
    NAME = "lblEditBox"

  ADD OBJECT lblimage AS LABEL WITH ;
    WORDWRAP = .T., ;
    BACKSTYLE = 0, ;
    CAPTION = [Control Imagen con la propiedad PictureVal configurada con ] +;
    [el contenido del campo Blob.] , ;
    HEIGHT = 72, ;
    LEFT = 528, ;
    TOP = 232, ;
    WIDTH = 176, ;
    FORECOLOR = RGB(255,0,0), ;
    NAME = "lblImage"

  ADD OBJECT cmdmodifymemo AS COMMANDBUTTON WITH ;
    TOP = 304, ;
    LEFT = 48, ;
    HEIGHT = 24, ;
    WIDTH = 216, ;
    CAPTION = "MODIFY MEMO <CampoBlob>", ;
    NAME = "cmdModifyMemo"

  ADD OBJECT label1 AS LABEL WITH ;
    WORDWRAP = .T., ;
    BACKSTYLE = 0, ;
    CAPTION = "Botón con el cláusula MODIFY MEMO Alumnos.Foto", ;
    HEIGHT = 16, ;
    LEFT = 272, ;
    TOP = 310, ;
    WIDTH = 408, ;
    FORECOLOR = RGB(0,128,0), ;
    NAME = "Label1"

  PROCEDURE INIT
    LOCAL lcRuta, lcFoto, ln
    *-- Creo el cursor Alumnos
    CREATE CURSOR Alumnos (Numero i, Nombre c(10), Foto w)
    *-- Recorro las imágenes de SAMPLES\DATA\GRAPHICS
    lcRuta = HOME(2) + "DATA\GRAPHICS\"
    lcFoto = SYS(2000,lcRuta + "*.GIF")
    ln = 1
    DO WHILE NOT EMPTY(lcFoto)
      INSERT INTO Alumnos (Numero, Nombre, Foto) ;
        VALUES (ln, JUSTSTEM(lcFoto), FILETOSTR(lcRuta + lcFoto))
      lcFoto = SYS(2000, lcRuta + "*.GIF", 1)
      ln = ln + 1
    ENDDO
    GO TOP IN Alumnos
    *-- Enlazo los controles
    THISFORM.BINDCONTROLS = .T.
  ENDPROC

  PROCEDURE grdAlumnos.AFTERROWCOLCHANGE
    LPARAMETERS nColIndex
    THISFORM.imgFoto.PICTUREVAL = Alumnos.Foto
    THISFORM.edtFoto.REFRESH
  ENDPROC

  PROCEDURE cmdmodifymemo.CLICK
    MODIFY MEMO Alumnos.Foto
  ENDPROC

ENDDEFINE

DEFINE CLASS MiGrid AS GRID
  COLUMNCOUNT = 3
  DELETEMARK = .F.
  HEIGHT = 216
  LEFT = 16
  PANEL = 1
  READONLY = .T.
  RECORDSOURCE = "Alumnos"
  RECORDSOURCETYPE = 1
  SCROLLBARS = 2
  TABINDEX = 1
  TOP = 8
  WIDTH = 272
  HIGHLIGHTSTYLE = 2
  NAME = "grdAlumnos"
  Column1.CONTROLSOURCE = "Alumnos.numero"
  Column1.WIDTH = 75
  Column1.READONLY = .T.
  Column1.VISIBLE = .T.
  Column1.NAME = "Column1"
  Column2.CONTROLSOURCE = "Alumnos.Nombre"
  Column2.WIDTH = 111
  Column2.READONLY = .T.
  Column2.VISIBLE = .T.
  Column2.NAME = "Column2"
  Column3.CONTROLSOURCE = "Alumnos.Foto"
  Column3.WIDTH = 53
  Column3.READONLY = .T.
  Column3.NAME = "Column3"

  PROCEDURE INIT
    THIS.Column1.Header1.ALIGNMENT = 2
    THIS.Column1.Header1.CAPTION = "Numero"
    THIS.Column1.Header1.NAME = "Header1"
    THIS.Column2.Header1.ALIGNMENT = 2
    THIS.Column2.Header1.CAPTION = "Nombre"
    THIS.Column2.Header1.NAME = "Header1"
    THIS.Column3.Header1.ALIGNMENT = 2
    THIS.Column3.Header1.CAPTION = "Blob"
    THIS.Column3.Header1.NAME = "Header1"
  ENDPROC

ENDDEFINE

Comentarios

Como enunciamos al comienzo, esto es solo un simple ejemplo que ilustra una de las tantas utilidades que podemos darle a este nuevo tipo de datos en Visual FoxPro 9.0.

Hasta la próxima.

Luis María Guayán

21 de enero de 2005

Resolución General 1702 de la AFIP (Argentina)

La Resolución General 1702 de la AFIP (Argentina) entrará en vigencia a principios del año 2005, por lo que en muchos foros de desarrolladores en Visual FoxPro se planteó la inquietud de que si con informes de Visual FoxPro y las rutinas y fuentes True Type del artículo de PortalFox "Codigos de barras en informes de VFP" se puede cumplimentar ésta resolución.

La respuesta es SI. Solo se debe modificar ligeramente la rutina correspondiente al código de barra "Interleaved 2 of 5" para que ésta retorne la cadena codificada lista para imprimir con la tipografía elegida, el dígito verificador y la cadena apta para la lectura humana. De todos modos existe en el artículo mencionado la fuente "PF Interleavev 2 of 5 Text" que contiene la cadena con lectura humana en su parte inferior.

Para el retorno de estos valores, lo mejor es crear una clase que llene los valores correspondientes en propiedades para poder ser utilizados. Para ello, la clase tiene las siguientes 3 propiedades:

  • DigitoVerificador: El dígito verificador de la cadena generada.
  • CodigoBarra: La cadena codificada lista para imprimir con la fuente True Type "PF Interleaved 2 of 5".
  • LecturaHumana: La cadena apta para la lectura humana.

La clase y un simple ejemplo de como utilizarla es el siguiente:

LOCAL lo
lo = CREATEOBJECT("I2of5")
lo.Codificar("201688627180100011234567890123420041231")
? SPACE(1) + lo.DigitoVerificador
? SPACE(1) + lo.CodigoBarra FONT "PF Interleavev 2 of 5 Text",36
? SPACE(4) + lo.CodigoBarra FONT "PF Interleaved 2 of 5",36
? SPACE(12) + lo.LecturaHumana FONT "Arial",13
lo = Null

*------------------------------------------------------------
* CLASS I2of5 AS CUSTOM 
*------------------------------------------------------------
* Clase que codifica una cadena a INTERLEAVED 2 OF 5
* METODOS: Codificar(tcTexto)
* PROPIEDADES: 
*   CodigoBarra: Texto para se impreso con fuente True Type 
*     "PF Interleaved 2 of 5" ó "PF Interleavev 2 of 5 Text"
*   DigitoVerificador = Digito verificador
*   LecturaHumana = Texto para Lectura Humana
* USO: 
*   lo = CREATEOBJECT("I2of5")
*   lo.Codificar("201688627180100011234567890123420041231")
*   ? lo.DigitoVerificador
*   ? lo.CodigoBarra FONT "PF Interleavev 2 of 5 Text",36
*   ? lo.CodigoBarra FONT "PF Interleaved 2 of 5",36
*   ? lo.LecturaHumana FONT "Arial", 13
*   lo = Null
*   RELEASE lo 
*------------------------------------------------------------
DEFINE CLASS I2of5 AS CUSTOM
  CodigoBarra = ""
  DigitoVerificador = ""
  LecturaHumana = ""
  PROCEDURE Codificar(tcTexto)
    LOCAL lcStart, lcStop, lcLH, lcCB, ;
      lnLong, lnI, lnCont, lnSum, lnAux
    lcStart = CHR(40)
    lcStop = CHR(41)
    lcLH = ALLTRIM(tcTexto)
    *--- Genero dígito de control
    lnLong = LEN(lcLH)
    lnSum = 0
    lnCont = 1
    FOR lnI = lnLong TO 1 STEP -1
      lnSum = lnSum + VAL(SUBSTR(lcLH,lnI,1)) * ;
        IIF(MOD(lnCont,2) = 0,1,3)
      lnCont = lnCont + 1
    ENDFOR
    lnAux = MOD(lnSum,10)
    lcDV = ALLTRIM(STR(IIF(lnAux = 0,0,10 - lnAux)))
    lcLH = lcLH + lcDV
    lnLong = LEN(lcLH)
    *--- La longitud debe ser par
    IF MOD(lnLong,2) # 0
      lcLH = '0' + lcLH
      lnLong = LEN(lcLH)
    ENDIF
    *--- Convierto los pares a caracteres
    lcCB = ''
    FOR lnI = 1 TO lnLong STEP 2
      IF VAL(SUBS(lcLH,lnI,2)) < 50
        lcCB = lcCB + CHR(VAL(SUBS(lcLH,lnI,2)) + 48)
      ELSE
        lcCB = lcCB + CHR(VAL(SUBS(lcLH,lnI,2)) + 142)
      ENDIF
    ENDFOR
    THIS.DigitoVerificador = lcDV
    THIS.LecturaHumana = lcLH
    THIS.CodigoBarra = lcStart + lcCB + lcStop
  ENDPROC
ENDDEFINE
*------------------------------------------------------------

NOTA: Recordar que las fuentes True Type deben estár instaladas en la PC para que los ejemplos funcionen correctamente. Las fuentes "PF Interleaved 2 de 5" se pueden descargar de: FuentesI2OF5.ZIP (17,10 KB)

La Resolución General 1702 de la AFIP (Argentina), (que se puede leer desde el sitio de la AFIP http://www.afip.gov.ar/afip/resol170204.html), establece que los datos que debe contener la cadena que debe ser impresa en los distintos tipos de comprobantes son:

  • C.U.I.T. (Clave Unica de Identificación Tributaria) del emisor (11 caracteres).
  • Código de tipo de comprobante (2 caracteres).
  • Punto de venta (4 caracteres).
  • C.A.I. (Código de Autorización de Impresión) (14 caracteres).
  • Fecha de vencimiento (8 caracteres).
  • Dígito verificador (1 caracter).

Esta cadena debe estar codificada con el código de barras Interleaved 2 of 5 (Entrelazado 2 de 5) y debe contener en la parte inferior la cadena completa y apta para lectura humana.

Un proyecto de ejemplo en VFP, con un formulario con el ingreso de los datos, un informe y la clase arriba descripta lo pueden descargar de RG1702.ZIP (10,10 KB)

Estas son las imágenes del proyecto de ejemplo de la descarga:

Espero que este ejemplo haya sido ilustrativo y útil para cumplimentar la R.G.1702 con un informe en Visual FoxPro. Si necesita mas información sobre códigos de barras en informes de VFP puede acceder al siguiente artículo: Codigos de barras en informes de VFP

Hasta la próxima.

Luis María Guayán

20 de enero de 2005

¿Que es un Framework?

Navegando en el historial de Google.Groups me encontré con este mensaje que nos dá una excelente cátedra sobre lo que es un framework. Centrándose principalmente en CodeBook y COMCodebook. Aunque lo aquí tratado aplica a cualquier Framework de cualquier lenguaje (es decir, suele ser universal el concepto).

***************************************
*Autor:Claudio Campos (infox@ciudad.com.ar)
*Asunto:Re: Proyecto de FrameWork en Español
*Grupos de noticias:microsoft.public.es.vfoxpro
*Fecha:2000-10-10 17:49:37 PST
***************************************

Un framework es una abstraccion de una maquina/artefacto (de construccion basada en ciclos de experiencia) para resolver un problema en UN contexto (ojo no confundir con pattern que es para resolver un problema en CUALQUIER contexto).

Y es por eso que en realidad no deberias pensar mucho en sus detalles, un framework condensa experiencia. Vos debes limitarte a instanciar esa maquina (framework) pero no tienes necesidad inmediata de conocer cada detalle de ella (estudiar cada clase por ejemplo).

El lado bueno es que (ademas de obtener un feedback de alimentacion de conocimientos, es decir 'ver' una arquitectura o poder 'copiar' o aprender como funciona una maquina), son los tiempos de desarrollo. Alguien que tiene que sacar un proyecto 'rapidamente' y quizas en un lenguaje que no conoce, podria facilmente aprender un framework (mas economico que armarse uno) ademas del lenguaje por supuesto y focalizarce en la solucion del problema del dominio (ojo no confundir usar un frameworks con usar wizards, builders o generadores).

Eso NO significa que NO podes hacer 'adaptaciones' o 'extensiones' a esa maquina, o de repente cambiar sus partes. Pero para eso hay tiempo y es cuando ya tenes TU 'maquina' funcionando y has hecho tus ciclos de experiencia con el framework, es ahi donde podes empezar a descubrir sus intestinos.

No obstante una salvedad con respecto a los frameworks: el costo/riezgo de instanciar algo muy abstracto es mucho mas grande a medida que subis en grados de abstraccion. (clonar es mucho mas economico que instanciar, instanciar un objeto de una clase concreta es mas economico que uno de una clase mas abstracta, instanciar un objeto a partir de una clase es mucho mas economico que instanciar un framework... y asi sucesivamente... arriba de todos estan los patterns). Es por eso que usar una 'maquina' construida por otro nos obliga a jugar con ciertas reglas.

Mi consejo: Cuando alguien esta 'jugado' para sacar una aplicacion en 3 o 4 meses y encima no conoce la herramienta/ambiente, lo mejor es usar un framework junto con una base de capacitacion en el lenguaje que esta construido. Si vos optas por armarte un framework vas a estar minimo 1 año tratando de estabilizar algo que ya esta 'hecho' y quizas mejor.

Riesgos: Cuando identificas los riesgos de tu proyecto puede ser que entre otros te encuentres con que la tecnologia es demasiado compleja, esto te impacta en los costos y te genera retrasos, la solucion: centrarte en la arquitectura de tu aplicacion (no los detalles del lenguaje o frameworks por ejemplo) y comprar competencias externas para asesoramiento.

Finalmente la respuesta a tu pregunta: Con guia podes aprender un framework con la complejidad de codebook en una semana (full gas), sin guia quiza te lleve algunos meses (si encontrar el camino correcto, es decir la forma de 'aprender' a usar esa abstraccion), o quizas desistas.

COM Codebook es algo totalmente diferente a Codebook, aunque la arquitectura de COM Codebook se puede usar perfectamente para 'reemplazar' al Codebook anterior.

Cuando vos comenzas un desarrollo tenes dos tipos de complejidades: la accidental y la esencial. El problema del Codebook (original) creo yo es no
haber pensado mucho en la complejidad accidental que tienen los proyectos cuyas tools no se adecuan muy bien a un determinado paradigma (por ejemplo object-ORIENTED).

El esquema de las bases de datos relacionales no tiene la 'expresividad' suficiente para describir de manera directa la compleja relacion entre datos
y conducta en el mundo de la orientacion a objetos, este es el caso mas extendido de complejidad 'accidental': impedance mismatch.

Entonces podriamos decir que COM Codebook es un framework de persistencia para base de datos relacionales.

Saludos !

Claudio Campos
Rafaela, Santa Fe

13 de enero de 2005

Usando la clase Empty (VFP8 y VFP9)

Un pequeño ejemplo de cómo podemos darle uso a la clase Empty, y usarlo a nuestra conveniencia...
*---------------------------------------------------------------------
* EmptyObject(fieldsList)
* Receives a list of fields separated by comma
* Returns an empty object with empty properties
* Recibe una lista de campos sepados por comas
* Retorna un objeto Empty con propiedades basadas 
* en objetos empty
*---------------------------------------------------------------------

* Test:
Customer = EmptyObject("Name,Address,Phone,Contacts[5]")
Customer.Address = EmptyObject("Street,City,State,Zip,Country")
Customer.Name  = "John Doe"
Customer.Phone = "555-1234"
Customer.Address.City  = "Sunny Beach"
Customer.Address.State = "FL"
Customer.Address.Zip   = "12345"
Customer.Contacts[1]   = "Jane Doe"
Customer.Contacts[2]   = "Jim Doe"
*** Revise el objeto Customer
Set Step On && Check out Customer object
Return Customer

*---------------------------------------------------------------------
Function EmptyObject
    LParameters fieldsList As String

    If Empty(fieldsList) Then
        Return Null
    Endif

    Local Array fieldsArray[1]
    Alines(fieldsArray,fieldsList,.T.,",")

    Local oEmpty
    oEmpty = NewObject("Empty")

    Try
        For Each item In fieldsArray
            AddProperty(oEmpty,item,"")
        Endfor
    Catch
        oEmpty = Null
    Endtry

    Return oEmpty
EndFunc
*--------------------------------------------------------------------- 
Esta función fué tomada de los newsgroups de VFP en ingles (con permiso de su autor):
********************************************
* Subject: Empty Objects
* From: George Nava
* Date: 03/01/2005 7:39
* newsgroup: microsoft.public.fox.programmer.exchange
********************************************
Espero que les sea de utilidad.

Espartaco Palma, México

12 de enero de 2005

Usando AutoCompletar en Textboxs de VFP 9

En Visual FoxPro 9 contamos con algunas nuevas propiedades en los textboxs, en este articulo tratare de explicar el Uso del Autocompletar

Básicamente se compone de 3 propiedades

AutoCompSource: Nos Permite especificar el nombre con el que se buscara los posibles datos de referencia, util si queremos utilizar la misma lista en uno o mas textboxs, por default el dato usado es el nombre del textbox, pero podemos especificarle el propio usando esta propiedad.

AutoCompTable: Indica el nombre de la tabla en la cual se almacenaran los datos que sean introducidos en el textbox, por default la tabla que se usa para almacenar estos valores es: Autocomp.DBF almacenada en el directorio de datos del usuario actual (home(7)) pero podemos indicarle por medio de esta propiedad en que ruta y archivo queremos que se almacene.

AutoComplete: Nos permite indicar los diferentes comportamientos del autocompletar en el textbox, los posibles valores son:
  • 0 - Deshabilitado: No activa el autocompletar
  • 1 - Alfabético: Ordena los elementos Alfabéticamente
  • 2 - Mas Frecuentemente usado (MFU): Ordena las opciones basándose en la cantidad usada de cada opcion y luego la ordena por la opcion mas recientemente actualizada
  • 3 - Mas usada Recientemente: Ordena las opciones basadas en el campo "Updated" de la tabla usada para autocompletar, el cual es actualizado cada vez que se selecciona una opción.
  • 4 - Personalizado: usa el Campo "Weight" de la tabla utilizada para autocompletar, el desarrollador es responsable de actualizar el campo con su propio algoritmo para especificar el ordenamiento, las opciones con el valor mas alto en el campo "Weight" son mostradas primero.
A continuacion un ejemplo (copie y pegue en un archivo PRG y ejecute):
PUBLIC oFrm
oFrm=NEWOBJECT("frm_autocompletar")
oFrm.SHOW
RETURN
DEFINE CLASS frm_autocompletar AS FORM
  AUTOSIZE = .T.
  HEIGHT = 236
  WIDTH = 447
  DOCREATE = .T.
  CAPTION = "Usando Autocompletar"
  MAXBUTTON = .F.
  MINBUTTON = .F.
  NAME = "frm_autoCompletar"

  ADD OBJECT txt1 AS Txt WITH ;
    TOP = 30, ;
    AutoComplete = 1, ;
    AutoCompSource = "txtDemo"

  ADD OBJECT txt2 AS Txt WITH ;
    TOP = 80, ;
    AutoComplete = 2, ;
    AutoCompSource = "txtDemo"

  ADD OBJECT txt3 AS Txt WITH ;
    TOP = 133, ;
    AutoComplete = 3, ;
    AutoCompSource = "txtDemo"

  ADD OBJECT txt4 AS Txt WITH ;
    LEFT = 23, ;
    TOP = 192, ;
    WIDTH = 169, ;
    AutoComplete = 4

  ADD OBJECT txt5 AS Txt WITH ;
    LEFT = 203, ;
    TOP = 190, ;
    WIDTH = 169, ;
    AutoComplete = 4

  ADD OBJECT lbl4 AS Lbl WITH ;
    CAPTION = "Ordenamiento Por codigo (AutoComplete = 4)", ;
    TOP = 170

  ADD OBJECT lbl3 AS Lbl WITH ;
    CAPTION = "Ordenamiento Por ultima vez usado (AutoComplete = 3)", ;
    TOP = 114

  ADD OBJECT lbl2 AS Lbl WITH ;
    CAPTION = "Ordenamiento Por mas usado (AutoComplete = 2)", ;
    TOP = 61

  ADD OBJECT lbl1 AS Lbl WITH ;
    CAPTION = "Ordenamiento Alfabetico (AutoComplete = 1)", ;
    TOP = 10

  PROCEDURE txt4.VALID
    IF DODEFAULT()
      UPDATE (THIS.AutocompTable) SET weight = 1 WHERE ALLTRIM(UPPER(SOURCE)) = ;
        IIF(EMPTY(THIS.AutocompSource),ALLTRIM(UPPER(THIS.NAME)),ALLTRIM(UPPER(THIS.AutocompSource)))
      UPDATE (THIS.AutocompTable) SET weight = 0 WHERE ALLTRIM(UPPER(DATA)) = ;
        ALLTRIM(UPPER(THIS.VALUE)) AND ALLTRIM(UPPER(SOURCE)) = ;
        IIF(EMPTY(THIS.AutocompSource),ALLTRIM(UPPER(THIS.NAME)),ALLTRIM(UPPER(THIS.AutocompSource)))
      USE IN (THIS.AutocompTable)
    ENDIF
  ENDPROC

  PROCEDURE txt5.VALID
    IF DODEFAULT()
      UPDATE (THIS.AutocompTable) SET weight = 0 WHERE ALLTRIM(UPPER(SOURCE)) = ;
        IIF(EMPTY(THIS.AutocompSource),ALLTRIM(UPPER(THIS.NAME)),ALLTRIM(UPPER(THIS.AutocompSource)))
      UPDATE (THIS.AutocompTable) SET weight = 1 WHERE ALLTRIM(UPPER(DATA)) = ;
        ALLTRIM(UPPER(THIS.VALUE)) AND ALLTRIM(UPPER(SOURCE)) = ;
        IIF(EMPTY(THIS.AutocompSource),ALLTRIM(UPPER(THIS.NAME)),ALLTRIM(UPPER(THIS.AutocompSource)))
      USE IN (THIS.AutocompTable)
    ENDIF
  ENDPROC
ENDDEFINE

DEFINE CLASS Lbl AS LABEL
  AUTOSIZE = .T.
  BACKSTYLE = 0
  LEFT = 24
ENDDEFINE

DEFINE CLASS Txt AS TEXTBOX
  HEIGHT = 25
  LEFT = 24
  WIDTH = 265
  AutocompTable = "AutoCompletar"
ENDDEFINE

Para ver el efecto en acción, pruebe a ingresar en el primer textbox, 3 nombres: Juan, Pedro y Jose, (asegúrese de presionar la tecla Enter luego de terminar de escribir el nombre) luego Escriba Pedro (o Seleccionelo de la lista cuando se lo sugiera) 2 veces, Luego Escriba Jose si va al segundo Textbox luego de esto, al dar click en el control, le mostrara como primer elemento Pedro, ya que es el que mas se ha utilizado (dos veces mas que los otros en este ejemplo) ya que el segundo textbox utiliza la opcion "2- Mas Frecuentemente usado", (no presione Enter borre el contenido del segundo textbox de preferencia), Luego dirijase al tercer textbox y al dar click en el control podrá observar que el primer elemento sera Jose, ya que este utiliza la opción "3- Mas usada recientemente".

Ahora si Se Fija en los otros 2 textbox (el cuarto y quinto) estos utilizan la opcion "4- Personalizado", así que tienen código en el evento Valid para ajustar el campo "Weight" (peso en ingles) para ajustar el orden, el 4 textbox coloca el ultimo valor escrito o seleccionado en la ultima posición mientras que el quinto textbox coloca el ultimo valor escrito o seleccionado al inicio.

Saludos

Jorge Mota
Guatemala

10 de enero de 2005

Creando Formas irregulares con el Objeto Shape en VFP 9

A partir de VFP 9 podemos crear Shapes basandonos en poligonos, el cual se basa en un arreglo de cualquier dimension conteniendo las coordenadas X y Y en el orden en que debera ser dibujado.

La propiedad que se debe establecer hacia el arreglo que contenga las coordenadas es PolyPoints.

A continuación un Ejemplo de como usar esta nueva propiedad:
Public oFrm_Shape
oFrm_Shape=Newobject("frm_shape")
oFrm_Shape.Show
Return
Define Class frm_shape As Form
 DataSession = 2
 Top = 0
 Left = 0
 Height = 354
 Width = 592
 DoCreate = .T.
 Caption = "Creando Shapes Complejos"
 Name = "frm_shape"
 Dimension apuntos[1]
 Add Object shape1 As Shape With ;
  Top = 19, ;
  Left = 260, ;
  Height = 314, ;
  Width = 319, ;
  BackStyle = 1, ;
  BorderWidth = 3, ;
  BackColor = Rgb(0,128,255), ;
  BorderColor = Rgb(255,255,255), ;
  Name = "Shape1"
 Add Object spinner1 As Spinner With ;
  Height = 24, ;
  KeyboardHighValue = 50, ;
  KeyboardLowValue = 1, ;
  Left = 137, ;
  SpinnerHighValue =  50.00, ;
  SpinnerLowValue =   1.00, ;
  Top = 24, ;
  Width = 117, ;
  Value = 1, ;
  NullDisplay = "0", ;
  Name = "Spinner1"
 Add Object grid1 As Grid With ;
  ColumnCount = 3, ;
  FontSize = 8, ;
  DeleteMark = .F., ;
  Height = 284, ;
  Left = 3, ;
  Panel = 1, ;
  RecordSource = "cPuntos", ;
  RowHeight = 17, ;
  ScrollBars = 2, ;
  Top = 51, ;
  Width = 252, ;
  Name = "Grid1", ;
  Column1.FontSize = 8, ;
  Column1.ControlSource = "Recno()", ;
  Column1.Width = 94, ;
  Column1.Name = "Column1", ;
  Column2.FontSize = 8, ;
  Column2.ControlSource = "cPuntos.nPosX", ;
  Column2.Width = 53, ;
  Column2.Name = "Column2", ;
  Column3.FontSize = 8, ;
  Column3.ControlSource = "cPuntos.NPosY", ;
  Column3.Width = 55, ;
  Column3.Name = "Column3"
 Procedure odibujar
  Local nValor, nReg
  nReg=Recno("cPuntos")
  Select Count(nPosx) As Conteo From cPuntos Where !Deleted() Into Cursor cC
  nValor = cC.Conteo
  Use In Select('cC')
  Select cPuntos
  Copy To Array apuntos For !Deleted('cPuntos')
  Acopy(apuntos,Thisform.apuntos)
  Thisform.shape1.Polypoints=[thisform.apuntos]
  Go (nReg) In cPuntos
 Endproc
 Procedure Load
  Create Cursor cPuntos (nPosx N(3,0),nPosY N(3,0))
  Set Deleted On
 Endproc
 Procedure Init
  With This.grid1
   .Column1.header1.Caption = [Posición]
   .Column2.header1.Caption = [X]
   .Column3.header1.Caption = [Y]
   .SetAll([alignment],2,[Header])
  Endwith
  This.spinner1.Value = 19
  Local apuntos
  Dimension apuntos[19,2]
  Select cPuntos
  apuntos[1,1] = 5 
  apuntos[1,2] = 4
  apuntos[2,1] = 24
  apuntos[2,2] = 4
  apuntos[3,1] = 24
  apuntos[3,2] = 23
  apuntos[4,1] = 11
  apuntos[4,2] = 23
  apuntos[5,1] = 11
  apuntos[5,2] = 46
  apuntos[6,1] = 5
  apuntos[6,2] = 46
  apuntos[7,1] = 5
  apuntos[7,2] = 4
  apuntos[8,1] = 37
  apuntos[8,2] = 4
  apuntos[9,1] = 37
  apuntos[9,2] = 13
  apuntos[10,1] = 29
  apuntos[10,2] = 13
  apuntos[11,1] = 29
  apuntos[11,2] = 26
  apuntos[12,1] = 37
  apuntos[12,2] = 26
  apuntos[13,1] = 37
  apuntos[13,2] = 35
  apuntos[14,1] = 30
  apuntos[14,2] = 35
  apuntos[15,1] = 30
  apuntos[15,2] = 46
  apuntos[16,1] = 20
  apuntos[16,2] = 46
  apuntos[17,1] = 20
  apuntos[17,2] = 23
  apuntos[18,1] = 24
  apuntos[18,2] = 23
  apuntos[19,1] = 24
  apuntos[19,2] = 4
  Append From Array apuntos
  Thisform.odibujar()
 Endproc

 Procedure spinner1.InteractiveChange
  Thisform.LockScreen = .T.
  Local nReg, nValor,nDel
  Set Deleted Off
  Select Count(nPosx) As Conteo From cPuntos Where Deleted() Into Cursor cC
  nDel = cC.Conteo
  Use In Select('cC')
  Select cPuntos
  nReg=Reccount('cPuntos')-nDel
  nValor = This.Value
  If nReg >nValor
   Delete From cPuntos Where Recno()>nValor
  Else
   For nCiclo =  1 To Abs(nReg-nValor)
    Locate For Deleted('cPuntos')
    If Found()
     Recall
    Else
     Insert Into cPuntos (nPosx,nPosY) Values (1,20)
    Endif
   Endfor
  Endif
  Set Deleted On
  Copy To Array apuntos For !Deleted('cPuntos')
  Dimension Thisform.apuntos[Alen(apuntos,1),2]
  Acopy(apuntos,Thisform.apuntos)
  Thisform.Refresh
  Thisform.LockScreen = .F.
 Endproc

 Procedure grid1.AfterRowColChange
  Lparameters nColIndex
  DoDefault(nColIndex)
  Thisform.odibujar()
 Endproc
Enddefine
Saludos

Jorge Mota, Guatemala