Wednesday, December 06, 2006

Windows Registry

So, I've been working with the registry for the last few weeks using various languages (VB6.0, C++6.0, C#, C++2005, and Python). The current issues I'm having with this are using the Mark Hammond win32api module for Python. Actually, the biggest problem I have with Python is the lack of documentation. They have an amazing documentation system, where comments in the code are automatically search-able and help files are created automatically. This is different than Visual Studio, where a help file has to be created automatically.

Anyway...back to the registry. I remember when I was first learning how to program using Windows, and I started using .conf files. All of my programs had a CONF file which had no keys or sections, but just values. I had to write classes to read and write specific lines at a time, and ended up just parsing the whole thing, splitting on newlines, and then getting the offset. The problems with this are obvious. So, I read up on it, and realized there were some great INI parsing utilities with VB6.0. Once I used those in C++6.0, I read in depth on it, and realized that the reason the functions, i.e. GetPrivateProfilexxx, are the same, is because there used to be a windows.ini file, which all applications wrote to. Well...how's that for inane! I guess the idea is similar to the old school pre-DNS look-up tables.

So far, however, I've found that getting to the point of understanding what is necessary to even read values from the registry is to use AfxGetApp() (in C++ dialog based apps) in your MyApp class. Then, you can read and write as much as you want in InitInstance and ExitInstance. In Python, it's easier, but at least I understand what they want. In VB it's a joke. Just call "SaveSetting" or "GetSetting". Gah, I don't even know why I had a problem in the first place or what the point of this is other than to point out that although the API calls are all different (in different languages), accessing the registry is as easy as declaring that it exists, and providing the "path" or folder list to which keys you want to read.

It's good practice, however, to read from the HKEY_CURRENT_USER\Software folder, especially for settings related to the specific user. It's a better idea to use HKEY_LOCAL_MACHINE\Software if you want to store settings like database names, usernames and passwords, and things that are general settings and probably used for remote connections (also for IRC server lists, etc). Don't change HKEY_USERS, because this is the default setup for new users to the system, and HKEY_CLASSES_ROOT is just bizarre, and I don't want to get into it.

Back to Python!

Friday, October 06, 2006

Twisted Python

This will not be a tutorial or explanation about Twisted. I plan to leave that for a later time. This is going to be a short reflection on why I love Twisted. Twisted Python aka "Twisted Matrix Laboratories", is an asynchronous networking framework that works inside of Python, and works well. When I was writing network code in C++, there was a lot of sockets, forking, etc. Most of the techniques are either synchronous, or require multiple threads, or both. Twisted works on one thread, and is non-blocking, so that once data is received, the thread sends data to a temporary thread, and returns to the listening loop in case more data is received. The documentation on the site is lacking, but once you wrap your skull around it, it makes sense. The most difficult thing for me was the absense of code. I had to write almost nothing to get a working server.

However, my favorite reason for getting into this OpenSource stuff, is the commenting. For example, in t.p.log, I ran across the following (from release for Python 2.4):

class EscapeFromTheMeaninglessConfinesOfCapital:
def own(self, owner):
warnings.warn("Foolish capitalist! Your opulent toilet will be your undoing!!",
DeprecationWarning, stacklevel=2)
def disown(self, owner):
warnings.warn("The proletariat is victorious.",
DeprecationWarning, stacklevel=2)

logOwner = EscapeFromTheMeaninglessConfinesOfCapital()

Well, it goes on. I'll leave you to find more of this humor. In the meantime, I'll be writing my windows service in twisted with named pipes so I can control it (meaning the client part of the server..heh) from a VC++ GUI. Also, my server is interfacing with Microsoft SQL Server (bleh), and I wrote a custom protocol for Twisted in a few hours...that will only work for my application. All of this stuff would have taken me a few days if not weeks in VC++, but now I only have to write the GUI, and not mess with ADO, wtih threading, with ANYTHING backend, which makes me happy...and it should you and your boss too.

Tuesday, September 26, 2006

Twisted, Python, C++, ADO, ODBC, etc

Just an intro. I'm Benry. I'm an R&D Engineer at a company that makes tracking devices in Hayward, CA. I will discuss small elements of my designs, and found code that should be more easily distributed and for my future reference. I am most comfortable with C++ and Python, although I can do anything in Assembly (know Motorola, PIC, Rabbit, and TI), SQL, VHDL, and the list continues. I'm a programmer. I'm not a nerd or a geek, but I love to see things work and to fix problems. I write a lot of bugs, but so does everyone. I'm open to intepretation and suggestions as I'm using this as a learning tool. Currently, I'm writing a COM server to encapsulate a Twisted server, so that I can import it into a C++ with MFC or CLI GUI.

So, welcome to my interpreted world of programming!

My first code (I'll edit the code tags later) is using INI files (obviously in Windows). I don't know of an easier way to store settings for software unless it's directly in the registry. When I was learning how to use Windows and write code in it, I was wondering why they didn't use .conf files. I didn't know about the purpose of the registry, but now know that it's because Windows used to force all programs to keep their settings in windows.ini. This was a bad idea, for obvious reasons, so they structured it a bit different, gave it an interface (regedit) and a couple COM interfaces, so now all programs should be writing to the registry. I refuse. I learned on a Solaris box, then a Redhat box, and was forced into learning Windows when I couldn't find a job in the Linux/UNIX world out of college. Anyway. I use INI files. The example I'm going to show today is something that I came up with in VC++ with MFC to check various paths for the INI file. I made sure to check the path of the executible, the default path used during development (i.e. C:\). If the INI file didn't exist in either of these places, it will prompt the user for where to find the damn thing. Once it's found, the global variable representing the path to the INI file (keys to the kingdom) is set, and program execution continues as normal. I did this in Python this morning, but it was a lot easier and a bit different.

So here's the OnInitDialog()called when the application loads the main dialog.

BOOL CApplicationDlg::OnInitDialog()
{
CDialog::OnInitDialog();

m_pDialog = NULL;

char strTemp[MAX_ARRAY];
::GetCurrentDirectory(MAX_ARRAY, strTemp);
m_sFilePath.Format("%s\\", strTemp);

m_sErrorPath = m_sFilePath;

CheckFilePath();
...
}

Everything with an "m_" is a class member.

The function CheckFilePath() is below:

BOOL CApplicationDlg::CheckFilePath()
{
CFile testFile;
CString sFileTemp;

if(!testFile.Open(m_sFilePath + "app.ini",CFile::modeReadWrite)){
if(!testFile.Open("C:\\app.ini", CFile::modeReadWrite)){
if(!testFile.Open("C:\\Program Files\\AppPath\\app.ini", CFile::modeReadWrite)){

testFile.Abort();
testFile.Flush();

AfxMessageBox("Please choose the path of app.ini.");
m_cmnDialog1.SetFilter("INI Files (*.ini)|*.ini|");
m_cmnDialog1.ShowOpen();

//Check if it was cancelled first
if(m_cmnDialog1.GetCancelError() || m_cmnDialog1.GetFileName() == ""){
return FALSE;
}

// Check for a valid path name, and repeat loop.

if(m_cmnDialog1.GetFileName() != ""){
sFileTemp = m_cmnDialog1.GetFileName();
testFile.Open(sFileTemp,CFile::modeReadWrite); // Used to get the path
sFileTemp = testFile.GetFileName(); // Get's the file name to strip
m_sFilePath = testFile.GetFilePath(); // from the full path
m_sFilePath.TrimRight(sFileTemp); // and store it in sFilePath
}
}
else{
m_sFilePath = "C:\\Program Files\\AppPath\\";
}
}
else{
m_sFilePath = "C:\\";
}
}

testFile.Abort();
return TRUE;
}