REDMOND, Wash. -- Jan. 27, 2004 -- Microsoft Corp. today announced the availability of SQL Server (TM) 2000 Reporting Services. Reporting Services provides companies with a powerful new reporting tool that can increase business insight by providing real-time information from any data source to any device. As a result, employees at every level will have better access to information that will increase their ability to make more-informed decisions and provide more business value to their company. With the addition of Reporting Services, SQL Server, a part of the Microsoft® Windows Server System (TM) , provides the single most comprehensive data management and business intelligence (BI) platform on the market, with integrated analytics that include online analytical processing; data mining; data warehousing; extract, transform and load tools; and reporting functionality. This integrated, end-to-end approach helps companies make better decisions faster while lowering their total cost of ownership.

"Reporting Services is an enterprise-level reporting solution that is more affordable than competitive solutions in the marketplace today. It builds on the success of SQL Server 2000 to provide an integrated and scalable solution whether it is used to send interactive reports to five or 50,000 subscribers," said Paul Flessner, senior vice president of Enterprise Servers at Microsoft. "With Reporting Services, our customers benefit from a cost-effective, easy-to-use reporting solution that enables them to better leverage data from their disparate systems for smarter business decisions."

Industry Acclaims Microsoft's Comprehensive, Cost-Effective BI Offering

SQL Server 2000 offers a broad business intelligence platform that helps enable customers and partners to easily build custom business intelligence applications. This flexibility and interoperability provide users with powerful business intelligence solutions tailored to their specific needs. Customers such as ASB Bank Ltd., Best Buy Company Inc., Coldwater Creek Inc., Cox Communications Inc., IS Partners Co., Long & Foster Companies, Mary Kay Inc., PREMIER Bankcard, RF Micro Devices Inc., Scout-Master and TSYS have already started to implement Reporting Services solutions.

"In six short weeks, Reporting Services helped PREMIER Bankcard develop an enterprisewide business intelligence reporting solution that will result in a workload reduction equivalent of at least three full-time employees, giving those employees time to work on other, more-proactive projects," said Dan Zerfas, vice president of application development at PREMIER Bankcard. "Reporting Services is the perfect combination of flexibility, scalability and performance required to support the high-growth rate that we have been enjoying. With just 40 report authors across three business units, we look to deliver 400 BI reports to 500 users at all levels."

Reporting Services provides an open and extensible reporting platform industry partners can use to broaden their offerings without investing in building reporting infrastructure. Microsoft is collaborating with companies including ActiveViews Inc., Aspirity LLC, Comprehensive Software Systems, Configuresoft, Fenestrae, Geac Computer Corporation Ltd., Hitachi Consulting Corp., IntelligentApps Ltd., Intellinet Corp., OutlookSoft Corp., MaxQ Technologies Inc., MIS AG, Professional Advantage, ProClarity Corp., Solutions Consulting Group, Silvon Software Inc., SPSS Inc., Trax Retail Solutions Inc. and Unisys.

Industry analysts have also expressed high expectations for the value Reporting Services will bring to customers and partners. According to Giga Information Group analysts Philip Russom and Keith Gile, Reporting Services has the potential to reshape the niche market for reporting, just as SQL Server's Analysis Services has for online analytic processing (OLAP) and Data Transformation Services (DTS) has for extraction, transformation and load (ETL). Educational efforts by Microsoft will raise the profile of reporting technologies and the realization of their usefulness, while bringing usability and cost within the technical and budgetary grasp of far more companies.1

A valid SQL Server 2000 license is required for each server on which Reporting Services is deployed. It is available in nine languages including traditional and simplified Chinese, English, French, German, Italian, Japanese, Korean and Spanish.

About SQL Server

Microsoft SQL Server, part of the Windows Server System, is the complete database and analysis offering for rapidly delivering the next generation of scalable e-commerce, line-of-business and business intelligence solutions. It dramatically reduces the time required to bring these applications to market while offering the scalability needed for the most-demanding environments. More information on Microsoft SQL Server can be found at http://www.microsoft.com/sql/.


 
Categories: ADO.NET | News

The Authorization and Profile Application Block provides you with an infrastructure for role-based authorization and access to profile information. The block allows you to:
? Authorize a user of an application or system.
? Use multiple authorization storage providers.
? Plug in business rules for action validation.
? Map multiple identities to a single user.
? Access profile information that can be stored in multiple profile stores.

http://www.microsoft.com/downloads/details.aspx?familyid=ba983ad5-e74f-4be9-b146-9d2d2c6f8e81&displaylang=en


 
Categories: Security

January 8, 2004
@ 01:43 AM

Unfortunately to do so, it must rely on an exception to detect a invalid value which is a little bit of a performance hit.

public static bool IsCurrency(object value)
{
  bool returnValue = false;
  try
    {
      double check = double.Parse(value.ToString(), NumberStyles.Currency, 
NumberFormatInfo.CurrentInfo);
      returnValue = true;
    }
  catch
    {}
  return returnValue;
}

I would excpect this code to work in normal C# applications too.

Tip Submitted By: David McCarter


 
Categories: Csharp | Compact Framework

January 8, 2004
@ 01:40 AM

Unfortunately to do so, it must rely on an exception to detect a invalid value which is a little bit of a performance hit.

public static bool IsNumeric(object value) 
{ 
  bool returnValue = false;
  try
    {
      double check = double.Parse(value.ToString(), NumberStyles.Any, 
NumberFormatInfo.CurrentInfo);
      returnValue = true;
    }
  catch
    {}
  return returnValue;
}

I would think that this would also work in normal C# applications.

Tip Submitted By: David McCarter


 
Categories: Csharp | Compact Framework

The Timer's "roll-over" point is 24 hours. Since Timer only returns seconds, using GetTickCount also gives you a much higher resolution.

Declare

Declare Function GetTickCount Lib "User"() As Long

Usage

Dim lTimer1 as Long
lTimer1 = GetTickCount()

 

This tip is reprinted from the VB Tips & Tricks Volume 1 book.

Compatible With: Visual Basic 3.0, Visual Basic 4.0 16-bit


 
Categories: VB

January 8, 2004
@ 01:21 AM
  • xFile - The filename (it copies from the application's own directory)
  • xDest - The destination directory

Declare

Declare Function GetVersion Lib "Kernel" () As Long
Declare Function GetFileVersionInfo% Lib "VER.DLL" (ByVal lpszFileName$, ByVal handle As Any, ByVal cbBuf&, ByVal lpvData$)

Code

Sub CheckFile(xFile As String, xDest As String)
On Error Resume Next
Dim retS%
Dim retD%
     If Right(xDest, 1) <> "\" Then xDest = xDest + "\"
     Form2.lblSource.Caption = App.Path + "\" + xFile
     Form2.lblDestination.Caption = xDest + xFile
     If Dir(xFile) = "" Then
           FileCopy App.Path + "\" + xFile, xDest + xFile
     Else
           'Check version
           retS% = GetFileVersionInfo(App.Path + "\" + xFile, 0&, 254, version)
           retD% = GetFileVersionInfo(xDest + xFile, 0&, 254, version)
           If retS% >= retD% Then
                 FileCopy App.Path + "\" + xFile, xDest + xFile
           End If
     End If
 
     'Just wait for a sec
     For i = 1 To 1000
           DoEvents
     Next i
 
End Sub

 

Tip Submitted By: Jeff Williams

 


 
Categories: VB

This value gets passed between the database and the application effortlessly. The problem arises when inevitably you want to export the tables into a flat file. It exports just fine except that the Chr$(13) & Chr$(10) get converted back to the effects of an enter keystroke and cause your export file to be out of whack. Then, when you want to import the file into the new (or old) tables, you get import errors galore and the import process halt's.

The work around is not pretty, but it is effective. This is a two stage process with the first stage looking similar to the above tip. First, we have to convert all the Chr$(13) & Chr$(10)'s into something that DOS won't treat any different than a regular character. We cannot use a keyboard character as our token as inevitably, no matter how obscure you make the symbol, someone will type it in. I chose Chr$(6) which is nothing in particular except an unprintable character.

MySet("Comments") = ReplaceEnter(txtComments.Text)
Function ReplaceEnter (ByVal ParseText As String) As String
Dim Offset as Integer, x as integer
    ParseText = LTrim$(Trim$(ParseText))
    x = InStr(ParseText, Chr$(13))
    If x = 0 Then
        ReplaceEnter = ParseText & " " ' Takes care of the Access zero length string problem
        Exit Function
    End If
    Offset = 1
    Do While x > 0
        ParseText = Left$(ParseText, x - 1) & Chr$(6) & Mid$(ParseText, x + 2)
        Offset = x + 1
        x = InStr(Offset, ParseText, Chr$(13))
    Loop
    ReplaceEnter = ParseText
End Function

So, we do the update on the database but there comes a time when you want to redisplay the contents of the field. Now, you have to reverse the process and convert the Chr$(6)'s into Chr$(13) & Chr$(10)'s:

txtComments.Text = ReplaceChr6(MySet("Comments") & "")
Function ReplaceChr6 (ByVal ParseText As String) As String
Dim Offset as Integer, x as integer
    x = InStr(ParseText, Chr$(6))
    If x = 0 Then
        ReplaceChr6 = ParseText
        Exit Function
    End If
    Offset = 1
    Do While x > 0
        ParseText = Left$(ParseText, x - 1) & Chr$(13) & Chr$(10) & Mid$(ParseText, x + 1)
        Offset = x
        x = InStr(Offset, ParseText, Chr$(6))
    Loop
    ReplaceChr6 = ParseText
End Function

As I said at the beginning, it isn't pretty, but it does get you around a problem you may not be aware of until your user decides to export the file so he/ she can do something with it.

 

Tip Submitted By: Paul A. Birkbeck


 
Categories: VB

January 8, 2004
@ 01:13 AM

The best way to deal with this problem is to use the built-in & operator to concatenate a blank string to each field as you read it. Concatenate 0 for numeric fields.

Sample Code

Dim dbBiblio As Database
Dim rsData As Recordset
Dim sYear As String
Dim sHireDate As Date
Dim lReports As Long
  Set dbBiblio = OpenDatabase("Northwind.mdb")
  Set rsData = dbBiblio.OpenRecordset("Employees")
  'Concatenate empty string ("") here with null values
  sYear = rsData![Title] & vbNullString
  'Concatenate zero so it does not error
  sHireDate = rsData![HireDate] & 0
  lReports = rsData![ReportsTo] & 0


 


 
Categories: VB

Although only one function is presented here, you may notice a gold mine of other associated and required functions that may be used for a multitude of purposes.

Code

Public Function GetUniqueFileName(ThisEXT As String, Optional ThisPath As String) As String
    Dim retval As String, varTmp As String
    varTmp = NormalizePath(GetTEMPdir(True))
    Do
        If LTrim(RTrim(ThisPath)) <> "" Then
            If DirExistCreate(ThisPath, False) Then
                retval = NormalizePath(ThisPath) & UniqueFileName & "." & ThisEXT
            ElseIf DirExistCreate(varTmp, True) Then
                retval = varTmp & UniqueFileName
            End If
        ElseIf DirExistCreate(varTmp, True) Then
            retval = varTmp & UniqueFileName
        End If
           DoEvents      'give someone else a chance...
    Loop While FindFile(retval)
    GetUniqueFileName = retval
End Function
Public Function UniqueFileName() As String
    On Local Error GoTo ufnError
    Dim retval As String
    
    'This example uses the Rnd function to generate a random integer value from 10000 to 32000.
    retval = "~" & Str(Int((32000 * Rnd) + 10000))
ufnOut
    UniqueFileName = retval
    Exit Function
ufnError
    retval = ""
    Resume ufnOut
End Function
Public Function GetTEMPdir(CreateOne As Boolean, Optional tVar As String) As String
    Dim wTmp As String
    On Local Error Resume Next
    
    wTmp = Environ$("TEMP")
    If wTmp = "" Then
        If CreateOne Then
            If LTrim(RTrim(tVar)) = "" Then tVar = "C\TEMP"
            MkDir tVar
            wTmp = tVar
        End If
    End If
    
    wTmp = NormalizePath(wTmp)
    GetTEMPdir = wTmp
 
End Function
Public Function FindFile(ThisFile As String, Optional SetAttribute As Variant) As Boolean
    On Local Error GoTo ffError
    Dim retval As Boolean, tAttr As Integer
    tAttr = vbNormal        'tattr=0
    If Trim(ThisFile) = "" Then
        Exit Function
    End If
    Do While tAttr <= 39
        If Len(Dir(ThisFile, tAttr)) > 0 Then
            If Not IsMissing(SetAttribute) Then
                SetAttr ThisFile, CInt(SetAttribute)
            End If
            retval = True
            Exit Do
        Else
            tAttr = tAttr + 1
            '1 -> 7 valid for files
            If tAttr = 8 Then tAttr = 32
            '32 -> 39 valid for files
            If tAttr = 40 Then
                retval = False
                Exit Do
            End If
        End If
    Loop
ffOut
    FindFile = retval
    Exit Function
ffError
    retval = False
    Msg = "Find File Error " & Error(Err) & vbCrLf
    Msg = Msg & ThisFile
    MsgBox Msg, vbExclamation, App.EXEName
    Err = 0
    Resume ffOut
End Function
Public Function DirExistCreate(ThisDir As String, Optional CreateIt As Variant) As Boolean
    On Local Error GoTo DEerror
    Dim Retval As Boolean, varCreateIt As Boolean
    Dim ThisTest As String, c As Integer, p As String, i As Integer
    Dim b As Integer
TestDiragain
    If Trim(ThisDir) <> "" Then
        If Not IsMissing(CreateIt) Then varCreateIt = CBool(CreateIt)
        
        If Len(Dir(ThisDir, 16)) > 0 Then
            Retval = True
        Else
            'does not exist so create it by parsing
            ThisDir = NormalizePath(ThisDir)
            c = InStr(ThisDir, "\")
            If c <= 0 Then b = 1 Else b = c + 2
            For i = b To Len(ThisDir)
                p = Mid(ThisDir, i, 1)
                If p = "\" Then
                    ThisTest = Left(ThisDir, i - 1)
                    If Len(Dir(ThisTest, 16)) <= 0 Then
                        MkDir ThisTest
                    End If
                End If
            Next
            GoTo TestDiragain
        End If
    End If
DEout
    DirExistCreate = Retval
    Exit Function
DEerror
    Retval = False
    LogError Err, "Unable to create directory " & ThisDir
    Err = 0
    Resume DEout
End Function
Public Function NormalizePath(ThisPath As String) As String
    If Right(ThisPath, 1) <> vbNullChar Then
        If Right(ThisPath, 1) <> "\" Then
            NormalizePath = ThisPath & "\"
        Else
            NormalizePath = ThisPath
        End If
    Else
        NormalizePath = ThisPath
    End If
End Function

 

Tip Submitted By: Dick Wilson


 
Categories: VB

January 8, 2004
@ 01:08 AM

Supposedly, RecordCount is set correctly when you first open a snapshot, but the ListBox test showed otherwise.
Try it yourself. Here is the solution code with my debug lines commented out.

Sub CopyRows () 
Dim i As Integer 
Dim db As Database
Dim snap As Snapshot
Dim tbl As Table
Dim wSQL As String
    Set db = OpenDatabase("MYDATA.MDB", False, False) 
    Set tbl = db.OpenTable("Table1")
    ' select the rows to be copied into a snapshot object 
    'List1.Clear 'Mark's debug code
    wSQL = "Select * from Table1 where Field1 = 'A'" 
    'I also changed your SQL statement a 
    'little, removed characters I don't use, but I don't
    'think it made any difference.
    Set snap = db.CreateSnapshot(wSQL) 
    snap.MoveLast '<===== MoveLast initializes RecordCount of snap
    snap.MoveFirst '<===== Need to MoveFirst
    'List1.AddItem snap.RecordCount 'Mark's debug code 
    'List1.AddItem "**" 'Mark's debug code
    ' loop through all rows in the snapshot 
    Do Until snap.EOF
        tbl.AddNew
        ' copy each field in the snapshot row to the table row
        For i = 0 To snap.Fields.Count - 1
            tbl.Fields(i).Value = snap.Fields(i).Value
        Next i
        ' change the value of the other field
        tbl.Fields("Field2").Value = "B"
        ' insert the new row into the table
        tbl.Update
        ' Ack! Here's the problem. This "tbl.Update" also is
        ' updating the contents of the snapshot. Meaning the
        ' "snap.MoveNext" will never get to EOF!
        'List1.AddItem snap.RecordCount 'Mark's debug code
        'List1.Refresh 'Mark's debug code
        'DoEvents 'Mark's debug code
        snap.MoveNext 
    Loop
    ' close everything 
    snap.Close 
    tbl.Close
    db.Close
End Sub

 

Tip By: Kyle Lutes


 
Categories: VB

January 8, 2004
@ 01:07 AM

This prompted me to do a little digging and I found out that it couldn't access the file to check because it was open in MS Access 2. As a result I rewrote my routine to take into account file sharing, but it struck me that I could use the old routine to check if a database file was in use.

Some routines that check for the existence of a file might not work with a Microsoft Access 2.0 database that is in use. To check for the file, you must open it as shared. This could be used to check a database file before it’s compacted or repaired.

Function FileExists(Filename As String) As Integer
     On Error Resume Next
     Open Filename For Input Access Read Shared As #1
     FileExists = (Err = 0)
     Close #1
End Function

Also, you can use the following code to check to see if a database file is in use.

Function DBFileInUse(Filename As String) As Integer
     On Error Resume Next
     Open Filename For Input As #1
     DBFileInUse = (Err <> 0)
     Close #1
End Function

 

This tip is reprinted from the VB Tips & Tricks Volume 1 book.
Parts of this tip was submitted by: Grahm Jones


 
Categories: VB

January 8, 2004
@ 01:04 AM

Rather than looping manually through every TextBox on the Form, I came up with the following: A function with the Form as a single argument. Loop through each control on the Form, (using "For Each Control etc") and if it's a TextBox which is empty, it returns Err.Number = 0. If this is true, I change the BackColor of the offending TextBox to light pink, and the function returns True. (If the TextBox is not empty, and it's BackColor is light pink, I return the BackColor to white. One can store the original color and restore it.) Then call Err. Clear, and continue in the loop. All TextBoxes which are empty will show up as light pink.

To test, create a Form with several TextBoxes on it; their names are immaterial, and they can even be in some container, like a Frame. Create a Command Button, named TestEmpty. Following is the code:

Private Sub TestEmpty_Click()
  If IsEmpty(Me) Then
    MsgBox "Some textboxes are still empty"
  End If
End Sub
Function IsEmpty(Frm As Form) As Boolean
Dim tmpControl As Control
  On Error Resume Next
  IsEmpty = False
  For Each tmpControl In Frm.Controls
    If Trim(tmpControl.Text) = "" Then
      If Err.Number = 0 Then
        IsEmpty = True
        tmpControl.BackColor = &HFFC0FF 'light pink
      End If
      Err.Clear
    Else
      If tmpControl.BackColor = &HFFC0FF Then
        tmpControl.BackColor = QBColor(15) 'White
      End If
    End If
  Next tmpControl
End Function

Run the program. Fill in some of the TextBoxes, and click on the Command Button, You will see the empty TextBoxes BackColor change to light pink. If you fill these in and click again, their BackColor will change to white.  Note: If the procedure is in a Module, then the argument is the Form name.

 

Tip Submitted By: Yehuda Hilewitz


 
Categories: VB