Silicon Thumb

Since the 1980s, I've worked with computers, watched them grow, shrink, change and improve. I've worked with a lot of users and solved a lot of problems in that time too, so I thought this would be a good place to share some of the random things I've found and solved. If you have some odd problem, email me. If I can figure it out I'll post the answer here.

My Photo
Location: Mansfield, Texas, United States

I am a veteran computer geek, but I prefer the term 'Hired Gun', since that gives the (misleading) impression that I know what I'm talking about. I have worked on all sizes of system as an engineer, developer, technical support and operations, and at all levels from Operator to CIO.
I have some certifications, but what they are depends on what Microsoft is calling them this week.

If you have a question, and don't mind the answer being posted, email me here, removing the spam stopper.

Thursday, November 23, 2006

Thanksgiving problems

My Great Aunt-in-law waited until after dinner to spring her computer problem on me. As a side note, I'd like to add that this lady is in her seventies, married, and spends her free time playing Dungeon Siege and Neverwinter Nights. I checked through the stack of games that she had conquered and they read like a top 50 of the 21st centuries greatest PC games. I mean she is a serious computer user and had already gone through the standard things to solve her problem which was this:

On one of the login IDs on her computer, there was no toolbar, and no way to access it. Not with the Winkey button, ctrl-esc, changing the screen size, F11 or any of the usual suspects.

Solving computer problems is a half and half again process. Is it Hardware or Software? Software, because its on one ID and not the others. Is it a Feature or Malicious? A feature because she has virus software which is current, operating, and McAfee.

System restore is one option, but a little more drastic than most people realize. So it came down to Googling different permutations of Toolbar disappeared Windows XP

Which, fortunately turned up this awesome, simple solution:

I downloaded it, viewed it to make sure that it wasn't something nasty, then ran it.

As if by magic, the toolbar appeared. This problem was about 30 minutes to solve. The one I will tell you tomorrow was a lot lot scarier...


Happy Turkey Day! Since year end is coming up, you are probably going to see less posting (not its been a week since my last one), but the ones I do post maybe be more SAP oriented.

Since today is Thanksgiving, and we'll all be consuming lots of Turkey, I thought I would show you and example of how SAP can consume XML :) (Sorry, best segue i could come up with :>)

Using XML as a way of import information into SAP is something that you are going to see a lot more of in the future. There is some help on the subject and what I am posting below is a mixture of that help and a working ABAP program constructed from it. So although putting it together and making it work was me, the real credit goes to the whomever at SAP wrote this in the first place. You should be able to copy and paste this into a new program in SE38, and just rename the xml file as needed.

If all of the above is greek to you, go enjoy some Turkey, 'cos it ain't about to get any better :>

REPORT (sy-repid) MESSAGE-ID z_pay_common LINE-SIZE 255 LINE-COUNT 65

* Note: This is all from

* com/saphelp_nw2004s/helpdata/en/47/b5413acdb62f70e10000000a114084
* /frameset.htm

* iXML ABAP Objects Jumpstart
* Next step after this is Casting up and down the DOM Hierarchy.

* In order to enable the iXML library, you have to add the following
* lines to your code:

type-pools: ixml.
class cl_ixml definition load.

*The next step is creating the main factory for the iXML library:

data: g_ixml type ref to if_ixml.
g_ixml = cl_ixml=>create( ).

* You will need only one such factory in a program, so it makes sense to
* place the statement above in the initialization section of your
* program and make g_ixml a global variable. If you try to instantiate
* the iXML factory more than once in a program, you'll only get
* references to the first instance created (singleton).

* Now you are already done. The iXML library is ready for use and the
* next steps depend on what you actually want to accomplish.

* Usually your program will require some form of input or output. The
* iXML library therefore provides a number of different streams you can
* use for XML document I/O. The object that constructs these streams is
* an cl_ixml_stream_factory object, which can be created by the iXML
* factory with the following statement:

data: streamFactory type ref to if_ixml_stream_factory.
streamFactory = g_ixml->create_stream_factory( ).

* Now you are ready to create e.g. an input stream that can be used to
* read from a file in your machine's file system:

data iStream type ref to if_ixml_istream.

* Or you can wrap an internal (unstructured) table into a stream to pass
* it to the parser. The table is then assumed to contain a line-wrapped
* XML document:

TYPES: BEGIN OF xml_line,
data(256) type X,
END OF xml_line.

data: xml_table type table of xml_line,
xml_table_size type i.


* When parsing an XML document you will simply pass the stream to the
* parser. The actual source behind the stream doesn't matter. For a list
* of available streams check the if_ixml_stream_factory interface.

* iStream = streamFactory->create_istream_uri( "file://c:\test.xml" ).
* iStream = streamFactory->create_istream_uri( "
* gov/data/current_obs/KDFW.xml" ).




* upload a file from the client's workstation

call function 'WS_UPLOAD'
filename = '\\VAUGHAN_LAPTOP\C$\test.xml'
filetype = 'BIN'
filelength = xml_table_size
data_tab = xml_table
others = 11.

* wrap the table containing the file into a stream

istream = streamFactory->create_istream_itable( table = xml_table
size = xml_table_size ).

* You can of course have several cl_ixml_document objects in parallel.

* Now you are ready to get your hands dirty and parse an XML document.
* The next section will tell you how...

* Creating a document

* No matter whether you parse an XML document or create one from scratch
* with your program and then render it into a stream, you always need
* some object to store the document for you while you handle it with
* your code. The object you need is an cl_ixml_document object and it's
* easy to get one from the iXML factory:

data: document type ref to if_ixml_document.
document = g_ixml->create_document( ).

* As mentioned earlier, parsing an XML document can be done in two ways:
* either creating a DOM representation of the XML document, or by the
* parser firing events as logical elements are encountered in a run
* through an XML document. This section covers DOM-based parsing.

* What you will need to create a DOM representation of an XML document
* are the following objects:

* As always, you will need the cl_ixml main factory. In addition to that
* we will need a cl_ixml_stream_factory object to create the input
* stream from. Then there must be place to store the DOM-tree in. A
* cl_ixml_document object is the answer. The previous section Basic
* steps in your program tells you how to create these objects.

* In order to parse a document, you will also need a cl_ixml_parser
* object. The Parser can be obtained from the iXML factory by the
* following call:

data: parser type ref to if_ixml_parser.

parser = g_ixml->create_parser( stream_factory = streamFactory
istream = iStream
document = document ).

* A cl_ixml_parser object is a "use once and throw away" object. That
* means that you create a new cl_ixml_parser, call it to parse one
* document and then throw the parser object away. There is no way of
* reusing the parser for an additional XML document.

* Our goal was to parse an XML document into a DOM tree, so here we go
* now:

* parser->parse( ).

* That's it. If there haven't been any errors in the XML document we
* just parsed from the input stream provided, then the document object
* we passed to the factory method of the parser will now contain the DOM
* representation we were looking for.

* Since errors usually happen, we should try to play this game a little
* bit safer, do some error checking and print out diagnostic messages:

if parser->parse( ) ne 0.

if parser->num_errors( ) ne 0.

data: parseError type ref to if_ixml_parse_error,
str type string,
i type i,
count type i,
index type i.

count = parser->num_errors( ).

write: count, ' parse errors have occured:'.

index = 0.
while index < parseerror =" parser-">get_error( index = index ).
i = parseError->get_line( ).
write: 'line: ', i.
i = parseError->get_column( ).
write: 'column: ', i.
str = parseError->get_reason( ).
write: str.
index = index + 1.



*Getting access to the root element
*As you have seen in the previous sections, a cl_ixml_documentinstance
*always holds the complete DOM tree. One of the immediate child nodes
* of the cl_ixml_document is the root element of the XML document. The
* following call will give you access to this node:

data: element type ref to if_ixml_element.
element = document->get_root_element( ).

* Now you have a good starting point to look at the rest of the document
* content.

* Getting access to a node's children
* There are two ways to traverse the child nodes of a node, e.g. the
* cl_ixml_elementnodes of an cl_ixml_element node. One is to first
* navigate to the first child node and then ask this node to return the
* next (sibling) node. This approach looks like that:

* data: child type ref to if_ixml_node.
* child = element->get_first_child( ).

* while not child is initial.
** do something with the node
* child = child->get_next( ).
* endwhile.

* The W3C DOM also defined a method to return a list of nodes, a
* cl_ixml_node_listinstance providing index-based access to the child
* nodes of a node:

data: nodes type ref to if_ixml_node_list,
child type ref to if_ixml_node.

data attribute type ref to if_ixml_attribute.

nodes = element->get_children( ).

index = 0.

while index <>get_length( ).

child = nodes->get_item( index ).
attribute ?= child->query_interface( ixml_iid_attribute ).
* do something with the node

index = index + 1.


* Even though index-based access is guaranteed to perform in constant
* time (O(1)) for sequential indizes (e.g. 1,2,3,..,n or n,..,3,2,1),
* using cl_ixml_node_list for random-access will usually degrade to
* linear lookup (O(n)).

* Recursively using one of the two approaches above will of course allow
* you to traverse the whole DOM tree.

* Now you can do whatever you want with the cl_ixml_documentobject you
* passed to the parser.

Thursday, November 16, 2006

Right Aligning Text in an html text box

This one was bugging me yesterday. Since it took a while to find the answer I figured this is a good example of what is supposed to be in this blog.

As long as you are not using an early version of Netscape, this should work. Basically this is what we do:

[input type="text" style="TEXT-ALIGN: right" size="30" value="This is a right aligned Text Box"]

(The PRE and < tags don't work in Blogspot, so just replace the [ with a < and the > with a ] )

The key piece is style='text-align: right;'. There is basically a mini-style sheet inside the Text Box. Why do we care? Well if you have cells with numbers it can mean that you can now format and enter numbers the way users expect to see them, like this:

...instead of like this:

Enjoy your Thursday :)

Tuesday, November 14, 2006

Creating CSV Files out of Thin Air

CSV (Comma Separated Values) are handy if you want to quickly import information into Excel, Access etc. If you have your own web server, or a co-located server, then it is relatively easy to create CSV files from your database on the fly, although it can be a bit of a pain to manage if you have a lot of hits on your server.

If you don't have as much control over the webserver, or simply want an easy way to produce a file for a single user regardless of how many people are using the server, there is an easy way to do this with ASP.

Most ASP users are familiar with Response.Write and Response.Redirect, but there are other cool methods associated with it that don't get as much play as they probably should. In the case below we are going to use Response.ContentType and Response.AddHeader to easily generate a csvFile on the fly.

First let's connect to our database and loop through the values, storing them in a variable called csvFile:

Option Explicit
Dim conn, SQL, rs, csvFile
Set conn = Server.CreateObject("ADODB.Connection")

' Change to your Parameters
conn.Open "DSN=myDSN;DATABASE=MyDatabase;UID=myUserid;PWD=myPassword"
Set rs = Server.CreateObject("ADODB.RecordSet")
' Create a Header Record
csvFile = "Name, Cell, Work" & vbCrLf
rs.Open SQL, conn, 1, 3

Do while not rs.EOF
csvFile = csvFile & rs("name") & "," & rs("cell") & rs("workphone") & vbcrlf
rs.MoveNext: Loop

Set conn = Nothing
set rs = Nothing

Once the data has been collected and store in the variable csvFile we write to the screen for the first time.

Response.ContentType = "application/csv"
Response.AddHeader "content-disposition", "inline; filename=export.csv"

The above lines let the web browser know that what it is about to receive should not be handle as a web page, but instead should be treated like another type of file (in this case, CSV). If you have a handler set for CSV Files (And if you use Microsoft Office, the chances are you do, and that it is Excel) then instead of a web page being displayed, you will get and Open/Save box, similar to this:

Click Open, and the file will be loaded directly into Excel. The end user will still need to adjust columns and make the headings look pretty, but it gives them 90% of what they need and the rest should be under their control anyway, IMHO.

Wednesday, November 08, 2006

Creating an Access Database with VB .NET

VB .NET is a very cool language, although I had a hard time switching over from plain old Visual Basic. I persevered, and once I got used to the change in syntax, I was staggered by the ease with which all kinds of things could be done.

Earlier this week for example, A user came to me wanting to load a 30 megabyte text file in Access, split into three different tables. This is something they need to do every quarter. The problems were many and commonplace: multiple formats in the file; duplicate lines that needed to be deleted; superfluous columns; trailing minus signs on numbers (e.g. 123.45- ). Who ever came up with that format by the way should be beaten to death with a baseball bat.

Well once I'd written a program to parse the file and fix the various issues, I needed a way to create and access database, create the tables and insert the records into the table as I parsed them.

Unfortunately, there isn't well documented or supported way to do this, since neither ADO.NET nor ActiveX Data Object (ADO) offer a way to do this simple thing.

It can be done though, by using the Microsoft Jet OLE DB Provider and Microsoft ADO Ext. 2.7 (or 2.8) for DDL and Security (ADOX) with the COM Interop layer.

In Visual Studio, add a references to Microsoft ADO Ext. 2.x for DDL and Security in your project, then you can easily create a database using a simple function. The code example below came from, and was adapated only a little. Change the database dbtable.mdb to whatever you want:

Function createAccessDatabase(ByVal DatabaseFullPath As String) As Boolean

Dim bAns As Boolean
Dim cat As New ADOX.Catalog()

'Make sure the folder
'provided in the path exists. If file name w/o path
'is specified, the database will be created in your
'application folder.

Dim sCreateString As String
sCreateString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=dbtable.mdb"
bAns = True
Catch Excep As System.Runtime.InteropServices.COMException
bAns = False
'do whatever else you need to do here, log,
'msgbox etc.

cat = Nothing

End Try

Return bAns

End Function

After that, you'll want to create the tables inside the database, and this can be done with the following code:

Sub createTable(ByVal tableName As String)

' shown below

Dim oleDbCreateCommand As System.Data.OleDb.OleDbCommand
oleDbCreateCommand = New System.Data.OleDb.OleDbCommand()

' This will be where you set your table specs.
' Change as needed.
oleDbCreateCommand.CommandText = _
"create table " & tableName &amp;amp;amp;amp; " (fld1 varchar(7),fld2 varchar(5), fld3 varchar (5),fld4 int,fld5 double);"

oleDbCreateCommand.Connection = OleDbConnection

accessDataAdapter = New System.Data.OleDb.OleDbDataAdapter()
accessDataAdapter.UpdateCommand = oleDbCreateCommand

' shown below

End Sub

Sub Connect()
OleDbConnection = New System.Data.OleDb.OleDbConnection()
OleDbConnection.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=dbtable.mdb;"

Catch ex As Exception
End Try

End Sub

Sub Disconnect()

Catch ex As Exception
End Try

End Sub

Now you have the Database and table(s) created, the rest is just opening the text file, parsing it, cleaning it and doing an insert for each record.If you aren't sure how to do that, let me know and I'll post the text read and access insert pieces of the code.TTFN :)

Tuesday, November 07, 2006

Ok, well here's one I found that is suitable for the mid terms elections:

1) In windows XP, do start, run, notepad
2) In notepad, type bush hid the facts
3) Do file, save and pick any file name.
4) Close the file
5) Open the file.


Sunday, November 05, 2006

Sending SMS Messages to any cellphone

Being the main techy in the family, I am responsible for all technology, upgrades, networking and technical support. Naturally end up with the dregs of computing for my own use, since I have to sacrifice the good bits of my own computer so that others might surf the web. My desktop therefore is now a sad, heavily customized, bastardized and (let's face it) sodomized duct-taped beast that is reasonably functional, totally dependable, and slower than Christmas.

The same rule applies to cell phones. For the last nine years, my cellphone has been a hand me down from my wife.

My current one is a Samsung VGA-100, and it's my webcam phone, so consequently I've taken lost of pictures and sent them to various friends and relatives.

One problem I have with this phone though is its refusal to do text messaging. Instead it has a 'Short Mail' function which is basically slow and horrendous. So if someone sends me a text message, it ends up going to an online Sprint PCS account, and I have to use my in-phone web browser to retrieve it. Not easy, and certainly not fun. What is particularly confusing about this is that all Sprint phones have the ability to receive SMS messages. Sprint (and the other telecoms) simply 'choose' to make this available on some phones and not others.

There is a way round this however, if you and your friends are phone savvy. Sending shortmail messages is fortunately very easy and since they can be sent to email accounts, you can ask your friends to just send messages to your phone's SMS email address instead of the phone number itself.

The following list gives the email address format for most cellphones in the use. Just pick your carrier and change the phone number to yours.

AT&T Wireless
Sprint PCS

You can test it by sending an email to yourself. I use this for sending systems messages when a monitored system has an issue. Remember, however, that these are text messages, and you will be charged for them at whatever horrendous rate please your carrier.

Happy texting :)

Friday, November 03, 2006

Excel's Blank Look

Hello everyone,

This blog is going to be a collection of odd, (what I hope will be) useful and sometimes funny stuff I've found (and continue to find) when dealing with computers and their users. Whether this log ends up being mainly informative or more for entertainment is anyone's guess, but your feedback will help.

To give an example of the kind of things I will be writing here, I will start with something that happened just the other day.

The cash manager at work called me as I walk past his office to show me his horrible nightmare. An Excel workbook with 30 consolidated spreadsheets that had a #VALUE in one cell for no good reason at all.

He had a statement which basically did a simple formula pulling a cell from each of the sheets and adding them up:

Sheet1!L41+Sheet2!L41+Sheet3!L41... etc

What made it interesting was that all of the cells referred to in the formula appeared to be blank, so why wasn't the consolidated sum showing zero?

Now the first thing to remember about EXCEL is that things are not always what they seem. the concept "What You See is What You Get" may be accurate to an extent, but with Excel you should probably add "...But What You See Ain't Necessarily What You Think It Is."

In this particular instance, the first assumption - that the cells were blank - was wrong. Well that's not true. They were blank, just not empty. In fact most of them were empty, but one actually had a blank (ASCII 32 or Space Bar depending upon your level of geekiness) in it.

Now, for reasons known only to Microsoft, Excel handles space characters differently depending on how you add numbers together:

If you use the sum() function, it will ignore them or treat them as zero.
If you use arithmetic operators (+,- etc) it balks at them and treats them as a character.

Here is an example of what I'm talking about:

Click to enlarge

As you can see in the above example, Excel will not do a successful addition if one of the cells being added is a Space, unless you use the sum() function.

In the cash manager's case, using sum() wasn't an option as he was going across multiple worksheets, so we had to go through each worksheet and remove the blank wherever we found it. Fun stuff, but when we got to the consolidated worksheet, sure enough it worked!

Ok, well I guess that'll do for this first entry. Leave a comment if you feel like it. I will post more next week. Have a great weekend, TGIF!

First Post

This is a test post while I get the template set up. Just go on about your business and pay no attention to the man behind the curtain...