Building Multimedia Databases

MediaDeveloper is a library of multimedia programming objects that let you incorporate video, sound, animation, graphics, and images into database apps. Michael uses Visual Basic, Q&E's VBX tool, and MediaDeveloper to develop a multimedia database.


November 01, 1994
URL:http://www.drdobbs.com/database/building-multimedia-databases/184409349

Figure 1


Copyright © 1994, Dr. Dobb's Journal

Figure 1


Copyright © 1994, Dr. Dobb's Journal

NOV94: Building Multimedia Databases

Building Multimedia Databases

Component software and OLE Automation lead to modular development

Michael Regelski

Michael is director of software development at Lenel Systems International, 290 Woodcliff Office Park, Fairport, NY 14450. He can be contacted on CompuServe at 71333,622.


Just a few years ago, PCs were capable of handling only alphanumeric information. But with the power and availability of graphical environments such as Windows, other types of information--graphics, animation, video, and audio--are finding their way into mainstream applications. In particular, database- management systems have benefited from the power of multimedia technology. A typical employee database, for example, provides a textual description that describes the employee, but it doesn't tell you what the employee looks like--and that's important information in secure areas of a building.

The Multimedia Information Management System (MIMS) is a Windows-based database system I designed for managing personnel databases. MIMS uses multimedia technology to capture, display, and print still and motion video. Furthermore, multimedia technology is combined with relational-database technology to create, store, and retrieve the multimedia information along with traditional textual information.

In building MIMS, I used Microsoft's Visual Basic as the primary development environment, Intersolv's Q&E database VBX for the database development, and Lenel Systems' MediaDeveloper for the multimedia components. Since the full-blown MIMS project is large, I'll focus here on how to integrate the capture and display of still and motion video into an application and how to store and retrieve multimedia information in a relational database. The complete source code for a minimal implementation of MIMS is available electronically; see "Availability," page 3.

MediaDeveloper

MediaDeveloper is a library of multimedia programming objects that enable you to design stand-alone software or modify existing apps that incorporate video, sound, animation, graphics, and images. In addition to Visual Basic, MediaDeveloper works with any Windows software that supports DLLs: Borland's Paradox for Windows, Informix's HyperScript, and Microsoft's Access.

MediaDeveloper-based applications can become an OLE Automation Server to other Windows apps. Thus, you can create reusable software components which can be programmatically accessed via these other applications. Consequently, end users can cut and paste multimedia data from apps that incorporate MediaDeveloper to other programs that support OLE. Because MediaDeveloper consists of a variety of interfaces--OLE Automation Server, DLL, C++ class library, and VBX--adding multimedia to an existing or new application is generally straightforward.

The MIMS employee database uses several MediaDeveloper functions: video capture from a video-overlay board, digital-video display, and image display. Each employee record has associated with it both a digital-video clip stored in Audio Video Interleaved (AVI) format and a still JPEG image.

There are two methods you can use for storing images. The first stores the image directly into a BLOB (Binary Large Object) field of the employee record. This method is okay for binding the information directly to the rest of the employee record, but it relies on the database system to support BLOB fields.

The second method (which I ultimately used with MIMS) is to have a text field in the data record which contains a path to the employee photo. I chose this method so as to allow migration to any database system (some databases don't support BLOB fields) and potential use of the photos outside of MIMS. If an employee photo is present, it is displayed in the upper-right corner of the screen via Open, which is called from UpdatePhoto in the file FEMP.FRM (available electronically). Note that MediaDeveloper objects are very polymorphic--one object can display graphics, animation, digital video, analog video, or audio simply by passing the filename or device name in to the Open method. MediaDeveloper takes care of the rest. This approach saves both resources and time since you don't have to purchase a separate control for each media type you want to use.

Although the video-capture portion of the MIMS system is not included in the minimal system I present here, it is an easy addition to the system. Since the MediaDeveloper Open method can open devices such as video-overlay boards, the overlay-board driver name can be passed into the method and the video board can be controlled instantly. MediaDeveloper provides methods to query the number and names of all video boards present on the system. Example 1 illustrates how you open a video-overlay board and capture a photo.

Adding Digital Video to MIMS

Adding digital-video playback to MIMS is also straightforward. If an employee record contains a digital-video clip of the employee, a button on the bottom of the employee search screen is enabled. The AVI digital-video format allows for 15 frames per second playback with audio on a standard 486 PC. No special hardware is required for the playback of digital video. A video-capture board is required for saving digital video to hard disk.

Once a digital-video clip is captured, the filename is stored with the employee record. The digital-video filename is stored in the field FldThumb, and all captured video files (still and digital video) are stored in a directory indicated by the variable g_config.CapDir.

To allow for control buttons such as Play, Rewind, and the like, I developed a special digital-video playback form to display digital-video files. See FVIDEO.FRM (Listing One) for complete details for implementing digital video.

When the digital-video playback form loads, a local MediaDeveloper object, m_dispobj, is created and initialized. The object is centered in the middle of the display screen. The digital-video file is then opened through the Open method. The methods Play, Rewind, and Stop are called from the digital-video playback form to give users control over video-file playback.

OLE Automation

OLE Automation, Microsoft's implementation of a reusable-component architecture, allows for libraries of code to be reused and shared by other tasks in a user's environment without language dependence or compile-time linking. The binding and communications between the client task and the server component is handled by the OLE 2.0 DLLs. OLE Automation allows for a smooth transition to Chicago and Windows NT by providing for 32-to-16 bit interoperability.

An Automation Server can be either an executable (*.EXE, called a "local server") or a DLL (*.DLL, or "in-process server"). When compared to a local server, an in-process server is faster to load and use because a DLL doesn't contain process-startup overhead. A DLL server also executes faster because no process-boundary marshaling takes place. The downside is that it can be more difficult to service many processes and to handle complicated user-interface details (updating menus and tool bars during process-idle time).

A local server is slower during the initial load of the executable. This can be minimized by loading the server process during the loading of your client process. A local server is also slower for parameter passing because the parameters must be marshaled across the process-boundary space; see Figure 1. A local server can easily handle multiple client processes and can be used in a distributed environment. It also has the advantage of not crashing the client application or affecting multiple clients when a general-protection fault occurs.

MediaDeveloper is a "local" automation server. This allows applications taking advantage of MediaDeveloper's user-interface elements to update during process-idle time.

An Automation Server provides the client application with components (objects). An automation object is composed of two parts: properties and methods. A property is analogous to a public data member of a C++ class library. The property or data can be both set and queried. If necessary, the object implementor may make some or all of the properties read-only for retrieving a Window Handles property of an object, for example. A method is similar to a method in a C++ class, which performs some action on or for the object.

This object-oriented flavor extends to traditionally nonobject environments such as Visual Basic. In Visual Basic, Automation Servers are much easier to use than a VBX. Example 2, for instance, shows how to create an Automation Server object. The first step is to declare an object variable. Note that under Visual Basic (as with C++), an object's lifetime is determined by the scope of the object. VB automatically terminates an automation object once it is out of scope. In a C++-like environment, a declared object may lose scope but it is not necessarily freed from memory. VB takes care of this housecleaning for you.

The first set of statements in Example 2 declares two MediaDeveloper Automation Server objects for you to use; see BDEMO.VCG (Listing Two). The second set of statements creates the objects and activates the Automation Server. The string MMDisplay is the registered name of the MediaDeveloper automation object you want to create. This name is provided by the automation-server vendor (Lenel Systems, in this case) and can be retrieved from the Windows registration database (see also the file BDEMO.VCM, available electronically).

After you create the object, properties can be set or queried and methods can be called. Deleting the object is not necessary since Visual Basic deletes the object after it loses scope. As Example 3 shows, getting and setting property values for an object is straightforward. The first five statements are properties for the global object g_dispobj, while the last statement calls a method which creates the window element of the object. Table 1 lists all of the properties available to DisplayObject, the MediaDeveloper OLE Automation Server interface.

With OLE Automation, software components allow you to plug your components into other components without knowing the details of how those components were built--you only need to know the capabilities supported by the component in order to use them. Consequently, the emerging generation of component-based applications will be more modular, revisable, customizable, and flexible.

Conclusion

Multimedia and software-component technologies are striding into the mainstream of software development. By combining these two technologies, I have been able to develop a large-scale security application while, at the same time, shortening the development cycle. Furthermore, tools such as those described here let you concentrate on the application content, while off-the-shelf components address your multimedia needs.

Example 1: Opening a video-overlay board and capturing a photo.

Dim CaptObj As Object Dim  DeviceName As String
  ' create media developer object
Set CaptObj = CreateObject ( "MMDisplay" ) '
  eliminate all user interface objects
CaptObj.SetUIOptions ( UI_OPTIONS_NO_UI ) '
  Set the parent window as the form
CaptObj.ParentHwnd ( Form1.hWnd )
  ' Set the MediaDeveloper Window styles
  CaptObj.WindowStyle ( WS_CHILD Or
  WS_VISIBLE ) ' Create The MediaDeveloper
  window
CaptObj.Create
' get the device name of the first video board available in the system
DeviceName = CaptObj.GetDeviceName ( VAL_VIDEO_BOARD , 1 )
  ' open the video board
CaptObj.Open ( DeviceName )
' save the current image as a JPEG file photo.jpg
CaptObj.Save ( "photo.jpg" )

Example 2: Creating an Automation Server object.

Global g_dispobj As Object
Global g_capobj As Object
Set g_capobj =
CreateObject("MMDisplay")
Set g_dispobj
= CreateObject("MMDisplay")

Example 3: Getting and setting property-object values.

g_dispobj.AutoCfg = False
g_dispobj.NotifyHwnd = PnlPic.hWnd
g_dispobj.ParentHwnd = PnlPic.hWnd
g_dispobj.WindowStyle = WS_CHILD
g_dispobj.UIOptions = UIOPTION_NO_UI
g.dispobj.Create

Figure 1 OLE Automation, local versus in-process server (LRPC = lightweight remote procedure call).

Table 1: MediaDeveloper OLE Automation Server interface.

Properties       Description

ParentHwnd       Window handle of the DisplayObject parent.
NotifyHwnd       Window handle for the DisplayObject to send
                     notification events to WIndowStyle. Style
                     flags for the creation/alteration of the
                     DisplayObject window; see the Windows 3.1
                     SDK for applicable values for window styles.
UIOptions        User-interface options for the DisplayObject.
NotificationMs   Flags for determining which events to monitor.
TimeFormat       Time format used by the MCI driver.
Top              Top coordinate of DisplayObject.
Left             Left coordinate of DisplayObject.
Width            Width of DisplayObject.
Height           Height of DisplayObject.
Stretch          Scales multimedia object to fit in dimensions of 
                     DisplayObject.
DragDrop         Enables file drag/drop from File Manager.
AutoSize         Automatically sizes DisplayObject to show entire 
                     object.
AutoCfg          Automatically reconfigures DisplayObject user 
                     interface for each new object type loaded.
UseSegmentMark   Limits the range of the MCI driver to the length 
                     of the media/segment.
StartSegment     Position of starting point of the defined segment.
EndSegment       Position of end point of the defined segment.
PreviewWidth     Width of Preview Window within DisplayObject window.
Preview Height   Height of Preview Window within DisplayObject window.
Visible          Shows/hides DisplayObject window.<
/pre>





Listing One


'FVIDEO.FRM: VBC Version
'Note: Header re-ordering can leave full-line comments out of order

Option Explicit

'======================= 'Form/Module Variables =======================
Dim m_dispobj As Object

Sub ButClose_Click ()
   Unload FVideo
End Sub
Sub ButPlay_Click ()
   If m_dispobj.WindowHandle <> 0 Then
      m_dispobj.Play
   End If
End Sub
Sub ButRwd_Click ()
   If m_dispobj.WindowHandle <> 0 Then
      m_dispobj.Rewind
   End If
End Sub
Sub ButStop_Click ()
   If m_dispobj.WindowHandle <> 0 Then
      m_dispobj.Stop
   End If
End Sub
Sub Form_Activate ()
   Dim l_fname As String
   Dim l_retval As Integer
   FMain.PnlInfo(0).Caption = "Loading Video..."
   DoEvents
   l_retval = m_dispobj.Open(FormatPath(g_config.CapDir, True) & LblFile)
   l_fname = FormatPath(g_config.CapDir, True) & LblFile
   FMain.PnlInfo(0).Caption = "Video loaded!"
End Sub
Sub Form_Load ()

'VBC ADVISORY: The following item(s) were found & handled as described
'unref variables (Removed): l_fname

   Dim l_retval As Integer

   FMain.PnlInfo(0).Caption = "Setting up hardware..."
   FMain.MousePointer = HOURGLASS

   Set m_dispobj = CreateObject("MMDisplay")
   m_dispobj.AutoCfg = False
   m_dispobj.NotifyHwnd = FVideo.hWnd
   m_dispobj.ParentHwnd = FVideo.hWnd
   m_dispobj.Width = PnlButs.Width / Screen.TwipsPerPixelX
   m_dispobj.Height = (Height - PnlButs.Height * 3) / Screen.TwipsPerPixelY
   m_dispobj.Width = 160
   m_dispobj.Height = 120

   m_dispobj.Left = ((FVideo.Width / Screen.TwipsPerPixelX) - 
                                                          m_dispobj.Width) / 2
   m_dispobj.Top = ((FVideo.Height / Screen.TwipsPerPixelY) - 
                                                    m_dispobj.Height) / 2 - 50
   m_dispobj.WindowStyle = WS_CHILD Or WS_BORDER Or WS_VISIBLE
   m_dispobj.UIOptions = UIOPTION_NO_UI
   l_retval = m_dispobj.Create()
   If l_retval = 0 Then
      FMain.MousePointer = DEFAULT
      MsgBox ERRMSG_PREFIX & " Could not create display object!  Error 
[30194001].", MB_ICONSTOP, ERRMSG_TITLE
      Exit Sub
   End If
End Sub
Sub Form_Resize ()
   If Width < PnlButs.Width + 100 Then
      Width = PnlButs.Width + 100
   End If
   If Height < PnlButs.Height + 100 Then
      Height = PnlButs.Height + 100
   End If
   PnlButs.Top = Height - PnlButs.Height * 2
   PnlButs.Left = (Width - PnlButs.Width) \ 2
End Sub
Sub Form_Unload (Cancel As Integer)
   m_dispobj.Destroy
End Sub


Listing Two


'BDEMO.VCG: VBC Consolidated Global File for BDEMO Project
'Note: Consolidation can leave full-line comments out of order

Option Explicit

' Visual Basic Constants used in this application!
'Key codes
Global Const KEY_PRIOR = &H21
Global Const KEY_NEXT = &H22
Global Const KEY_HOME = &H24
Global Const KEY_UP = &H26
Global Const KEY_DOWN = &H28

' Shift parameter masks
Global Const ALT_MASK = 4

' Button parameter masks
' MousePointer
Global Const Default = 0                      ' 0 - Default
Global Const HOURGLASS = 11                   ' 11 - Hourglass
Global Const APP_TITLE = "MediaDeveloper Application Demo"

'Privilege levels for security
Global Const PRIV_PROHIBITED = 0
Global Const PRIV_ADMINISTRATOR = 2

'Color definitions
Global Const COLR_WHITE = &HFFFFFF
Global Const COLR_LTGRAY = &HC0C0C0

'ASCII Key Codes
Global Const MAXPATHLEN = 256

'Editing modes
Global Const MODE_EDIT = &H1                  'Edit mode (fields are editable)
Global Const MODE_VIEW = &H2
Global Const MODE_QFIND = &H20
Global Const MODE_TXT_VIEW = " View"
Global Const MODE_TXT_QFIND = " Search"

'Predefined quick keys or short cut keys for database viewing
Global Const QKEY_SEARCH = 19
Global Const QKEY_CLEAR = 12

'Types of Q+E Operational Errors
Global Const QETYPE_NEW = 1
Global Const QETYPE_ADD = 2
Global Const QETYPE_MODIFY = 3
Global Const QETYPE_DELETE = 4
Global Const QETYPE_DISCARD = 5
Global Const QETYPE_ENDQUERY = 6
Global Const QETYPE_LOCK = 7
Global Const QETYPE_NEXT = 8
Global Const QETYPE_PREV = 9
Global Const QETYPE_QUERY = 10
Global Const QETYPE_TRANPEND = 11
Global Const QETYPE_NOTRANPEND = 12

'Error message constants used with prcTypicalQEErr ()
Global Const MSG_QUERYING = 1
Global Const MSG_QUERYCOMPLETE = 2
Global Const MSG_QUERYFAILED = 3
Global Const MSG_QUERYABORT = 4
Global Const MSG_BROWSEVIEW = 5
Global Const MSG_DETAILVIEW = 6
Global Const MSG_RECORD_ADDING = 7
Global Const MSG_RECORD_ADDED = 8
Global Const MSG_MAIN = 9

'Maximum number of records allowed to be retreived to use
'delete for single records (in any query!)
'Global Const MAXRECS_SINGLE_DELETE = 32000
'Global Const MAXRECS_IN_BROWSE = 1024
'This is the main query expression for employee records
Global Const EMP_WHERE_LINKS = "EMP.LOC = LOCATION.ID AND 
EMP.COUNTRY = COUNTRY.ID AND EMP.DIV = DIVISION.ID AND EMP.DEPT 
= DEPT.ID AND EMP.EMPTYPE = EMPTYP.ID AND EMP.EXT1 = EXT1.ID AND 
EMP.EXT2 = EXT2.ID AND EMP.ACTIVEBADG = BADGE.ID AND 
BADGE.STATUS = BADGSTAT.ID AND BADGE.TYPE = BADGETYP.ID"

Global Const UIOPTION_NO_UI = &HFF
Global Const ASCII_LF = 10

'This subroutine closes a Q+E Query, if open. If not open, nothing happens.
Global Const BROWSE_LASTRECNO = 2047999999 'Last possible record# (move to end)

'Default sizes for Browse grid
Global Const BROWSE_READAHEAD = 128
Global Const BROWSE_MAXSIZE = 32730
Global Const BROWSE_BUFSIZE = 300    'Number of rows in a grid before buffering
Global Const BROWSE_FLG_DEL = -1     'Delete flag in delete array of records

'Index positions of specific controls to expect in p_ctrls() array
Global Const BROWSE_CTRLSINDX_QRY = 0         'Index in p_ctrls() of Query 
control
Global Const BROWSE_CTRLSINDX_FLDS = 2  
                                  'First Index in p_ctrls() of field controls
'Directions for movment
Global Const BROWSE_BCK = -1                  'Move backwards
Global Const BROWSE_FWD = 1                   'Move forwareds

'Information structure used to associated printers to layouts
'Information structure for badge type association to layout name

Global Const TBL_EMP = "EMP"
Global Const TBL_IDS = "IDS"
Global Const TBL_LOC = "LOCATION"
Global Const TBL_DEPT = "DEPT"
Global Const TBL_DIV = "DIVISION"
Global Const TBL_EMPTYP = "EMPTYP"
Global Const TBL_BADGE = "BADGE"
Global Const TBL_BADGTYP = "BADGETYP"
Global Const TBL_BADGSTAT = "BADGSTAT"
Global Const TBL_EXT1 = "EXT1"
Global Const TBL_EXT2 = "EXT2"
Global Const TBL_COUNTRY = "COUNTRY"
Global Const TBL_PHOTOS = "PHOTOS"

'======================================================================='
'                          QeLink.txt                                   '
'                   Q+E Multilink/VB Version 2.0                        '
'                      Global Constants File                            '
'======================================================================='
'         Copyright: 1992-93 Q+E Software, Inc.                         '
'         This software contains confidential and proprietary           '
'           information of Q+E Software Systems, Inc.                   '
'======================================================================='  

Global Const QE_RECORD_NOT_FOUND = 31002
Global Const QE_RECORD_LOCKED = 31004

Global Const QE_NO_LOCK_ON_KEY_PRESS = &H1000 
' Do not lock records whenever a field changes

Global Const QE_NO_COMPARE_AFTER_LOCK = &H2000
' Do not compare fields before

Global Const BITSPIXEL = 12                   '  Number of bits per pixel
Global Const PLANES = 14                      '  Number of planes

' MessageBox() Flags
Global Const MB_YESNO = &H4

Global Const MB_ICONHAND = &H10
Global Const MB_ICONQUESTION = &H20
Global Const MB_ICONEXCLAMATION = &H30
Global Const MB_ICONASTERISK = &H40

' Dialog Box Command IDs
Global Const IDNO = 7

' Window Styles
Global Const WS_CHILD = &H40000000
Global Const WS_VISIBLE = &H10000000
Global Const WS_BORDER = &H800000

Global Const CHAR_BACKSLASH = "\"

Global Const ERRMSG_TITLE = "Demo Error Message"
Global Const ERRMSG_PREFIX = "ERROR! "       'Used to save space in heap space 
string declarations
Global Const INFOMSG_TITLE = "Demo Information"
Global Const APP_ABREV = "DEMO"

'dependent definitions
Global Const PRIV_DEFAULT = PRIV_ADMINISTRATOR
Global Const COLR_BG_VIEW = COLR_LTGRAY      'Background color used for 
fields during view
Global Const COLR_BG_EDIT = COLR_WHITE 'Background color for fields during edit

Global Const MB_ICONINFORMATION = MB_ICONASTERISK
Global Const MB_ICONSTOP = MB_ICONHAND

'================== Type Definitions ==================
'independent definitions
'This is the structure that each T_REC_? record type should
'contain.  This structure stores the field data that is to be displayed
'in the browse grid.  Not all columns must be used.
Type T_BROWSEROW
   Col01 As String
   Col02 As String
   Col03 As String
   Col04 As String
   Col05 As String
   Col06 As String
   Col07 As String
   Col08 As String
   Col09 As String
   Col10 As String
   Col11 As String
End Type

Type T_SIZEPOS
   Top As Long
   Left As Long
   Width As Long
   Height As Long
End Type
'Security information structure
Type T_SECURITY
   Default As Integer   'Default privilege level
   Logon As Integer     'True if logon required
   ExitPriv As Integer  'Minimum privilege for exiting (0 means logoff anytime)
End Type
Type T_PHOTOINFO
   Original As String   'Original photo in employee record
   LName As String      
                'Employee last name in photo database that is no longer in use 
                '(photo was selected for emp record). Used to find record to 
                'delete once emp record is saved
   FName As String
               'Employee first name in photos database that is no longer in 
               'use (photo was selected for emp record)
   Freeze As String
               'Name of photo that was frozen (in case user changes mind, 
               'needs to be deleted if not used)
   NewPhoto As String   
               'Name of photo user has selected to include in employee record.
End Type
Type T_USERINFO
   FName As String
   LName As String
   id As String
   logonid As String
   Privilege As Integer
End Type
'dependent definitions
Type T_REC_EMP
   BrowseRow As T_BROWSEROW
   AlphaID As String      'BrowseRow.Col01
   SSNo As String         'BrowseRow.Col02
   FName As String        'BrowseRow.Col03
   LName As String        'BrowseRow.Col04
   EmpTyp As String       'BrowseRow.Col05
   addr1 As String
   addr2 As String
   city As String
   state As String
   zip As String
   country As String
   bdate As String
   badgeno As String
   badgetype As String
   BadgeStat As String    'BrowseRow.Col06
   title As String
   dept As String
   div As String
   loc As String
   homephone As String
   ext As String
   Floor As String
   Building As String
   officephone As String
   Photo As String
   HasPhoto As String
End Type
Type T_BROWSEINFO
   SingleDelete As Integer 
                   'True if record numbers are maintained in a deleted() array 
                   '(Recs in query are less than max array size 32760)
   SameDataset As Integer        'False if new search occured
   Header As String              'This is the header that goes on the grid
   ReadAhead As Integer          
                   'Number of records to read into grid when scrolling past 
                   ' buffer size (Must  be < BufferSize)
   BufferSize As Integer         
                   'Maximum number of records stored in grid at any one time ()
   'AddRecs As Integer            
                   'Number of additional records in the m_added () array
   ModifyOK As Integer           
                   'This is false when no more room to store modified records 
                   'user must research
   DelRecs As Integer            
                   'Number of records marked as deleted in m_deleted()
   'RecNoCol As Integer           'Column in grid containing record number
   TopRec As Long                
                  'LOGICAL Record number (excluding delete) of top record 
                  'in browse grid (may not be the same as Q+E number!)
   Rec As Long    'Current LOGICAL record number - not actual record number 
                  '(takes into account deleted records)
   Recs As Long   'Number of records in query (not including deleted)
   'AddsIndx As Integer  'Index into m_added() array - declared by form!
   'Adds As Integer 'Upper bound (size) of m_added() array -declared by form!
   ModsIndx As Integer  
                  'Next open element in m_modified () array -declared by form!
   Mods As Integer
                 'Upper bound (size) of m_modified() array -declared by form!
   BrowseRecNos(1 To BROWSE_BUFSIZE) As Long    
                 'Record numbers corresponding to rows in grid
End Type
Type TYP_CONFIG
   CompanyName As String * 128      'Company name
   Logo As String * 128     'Filename to company logo
   internal As String * 64  'Type of Q+E database connection for internal files
   external As String * 64  'Type of Q+E database connection for external files
   intprefix As String * 256 'Prefix/direcotry to internal tables
   extprefix As String * 256 'Prefix/direcotry to external tables
   CapSizePos As T_SIZEPOS
   CapDir As String * 256    'Name of directory to store photo directories
   CapDirLimit As Integer    
             'Maximum number of files in sub photo directory before continuing.
   Security As T_SECURITY           'Security information structure
End Type
'====================== API/DLL Declarations ======================
Declare Function fDoQuery Lib "qelink.vbx" (queryCtl As Control) As Integer
Declare Function fEndQuery Lib "qelink.vbx" (queryCtl As Control) As Integer
Declare Function fRandom Lib "qelink.vbx" (queryCtl As Control, 
                                                   ByVal RecNumber&) As Integer
Declare Function fEnterQBE Lib "qelink.vbx" (queryCtl As Control) As Integer
Declare Function fDelete Lib "qelink.vbx" (queryCtl As Control, 
                                                    ByVal rowIndex%) As Integer
Declare Function fLogon Lib "qelink.vbx" (connectionCtl As Control) As Integer
Declare Function fLogoff Lib "qelink.vbx" (connectionCtl As Control) As Integer
' Extended Window Styles
Declare Function GetModuleHandle Lib "Kernel" (ByVal lpModuleName 
                                                         As String) As Integer
Declare Function GetModuleFileName Lib "Kernel" (ByVal hModule 
    As Integer, ByVal lpFileName As String, ByVal nSize As Integer) As Integer
'GDI Routines....
Declare Function GetDeviceCaps Lib "GDI" (ByVal hDC As Integer, 
                                           ByVal nIndex As Integer) As Integer
'================== Global Variables ==================
'independent definitions
Global g_retval As Integer
' DrawStyle
'Global Const SOLID = 0       '0 - Solid
'Global Variables (specific global structures in respective modules!)
'NOTE!  Globals for paint program are in Paint.BAS
Global g_cnct_int As ConnectClass     'Internal connection control
Global g_cnct_ext As ConnectClass     'External connection control
Global g_name_int As String           'Name of internal connection
Global g_name_ext As String           'Name of external connection
Global g_exe_path As String           'Path (without \) of executable directory
Global g_colors As Long               'Number of colors (current color mode)

Global g_develop As Integer      'Is 1 if development mode (set by commandline)
Global g_exit As Integer 
                  '1 if valid exit.  0 if user presses something like [Alt-F4].
Global g_dbinit As Integer        '1 if InitDB () successfully called
Global g_formreturn As Integer    'Return value after calling Load form...

Global g_dispobj As Object
Global g_capobj As Object
Global g_mediadev As Integer 
                          'True if the OLE capture object has been initialized!
Global g_capobjcreated As Integer             
                          'True if the OLE capture object has been created ()
'dependent definitions
Global g_config As TYP_CONFIG
Global g_photoinfo As T_PHOTOINFO
Global g_userinfo As T_USERINFO

Copyright © 1994, Dr. Dobb's Journal

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.