Welcome to Foxite.COM Community Weblog Sign in | Join | Help

I am changing my application to be Vista compatible. I need to run an external EXE and wait for until it terminate. Beside, I also need to run this EXE with Admin privilege under certain condition.

To run external application and wait till it terminate, I found the code as below.

loShell = CREATEOBJECT("WScript.Shell")
loShell.Run("C:\MyApp\MyApp.exe", 1, 1)

However, it doesn't support elevation.

To run application via elevation process, I can

DECLARE INTEGER ShellExecute IN "Shell32.dll" ;
	INTEGER hwnd, STRING lpVerb, STRING lpFile, STRING lpParameters, ;
	STRING lpDirectory, LONG nShowCmd

ShellExecute(0, "runas", "C:\MyApp\MyApp.exe", "", "", 1)

Unfortunately, ShellExecute() doesn't wait but return control back to calling program immediately.

In order to have both features, I found ShellExecuteEX ...

DECLARE LONG ShellExecuteEx IN Shell32 STRING @SHELLEXECUTEINFO

DECLARE INTEGER WaitForSingleObject IN kernel32;
	INTEGER hHandle, INTEGER dwMilliseconds

LOCAL loSHELLEXECUTEINFO AS SHELLEXECUTEINFO OF SHELLEXECUTEINFO.prg, ;
		lcStructure AS String

loSHELLEXECUTEINFO = NEWOBJECT("SHELLEXECUTEINFO", "SHELLEXECUTEINFO.prg")
loSHELLEXECUTEINFO.fld("lpVerb") = "runas" + CHR(0)
loSHELLEXECUTEINFO.fld("lpFile") = "C:\MyApp\MyApp.exe" + CHR(0)
loSHELLEXECUTEINFO.fld("nShow") = 1
loSHELLEXECUTEINFO.fld("lpParameters") = CHR(0)

**********************************************
* Required in order to get process id returned
**********************************************
loSHELLEXECUTEINFO.fld("fMask") = SEE_MASK_NOCLOSEPROCESS

lcStructure = loSHELLEXECUTEINFO.Structure 

ShellExecuteEx(@lcStructure)
loSHELLEXECUTEINFO.Structure = lcStructure

***********************************************************
* Wait for application termination (-1)
***********************************************************
WaitForSingleObject(loSHELLEXECUTEINFO.fld("hProcess"), -1)

**************************************************************
* Define SHELLEXECUTEINFO strucuture using class Struct
* from http://fox.wikis.com/wc.dll?Wiki~ApiStructureClass~VFP
**************************************************************

DEFINE CLASS SHELLEXECUTEINFO AS Struct OF Struct.prg

	#IF .F.
		LOCAL THIS AS SHELLEXECUTEINFO OF SHELLEXECUTEINFO.prg
	#ENDIF

	PROCEDURE INIT()
	
		THIS.AddField("cbSize", "LONG", 60)
		THIS.AddField("fMask", "LONG", 0)
		THIS.AddField("hwnd", "LONG", 0)
		THIS.AddField("lpVerb", "@STRING", CHR(0))
		THIS.AddField("lpFile", "@STRING", CHR(0))
		THIS.AddField("lpParameters", "@STRING", CHR(0))
		THIS.AddField("lpDirectory", "@STRING", CHR(0))

		THIS.AddField("nShow", "LONG", 0)
		THIS.AddField("hInstApp", "LONG", 0)
		THIS.AddField("lpIDList", "@STRING", CHR(0))
		THIS.AddField("lpClass", "@STRING", CHR(0))
		THIS.AddField("hkeyClass", "@STRING", CHR(0))
		THIS.AddField("dwHotKey", "LONG", 0)
		THIS.AddField("hIcon", "LONG", 0)
		THIS.AddField("hProcess", "LONG", 0)

	ENDPROC	

ENDDEFINE

I used ApiStructureClass to create structure that required by ShellExecuteEx. It makes job much easier.

I like to use NEWOVBJECT() to initiate object so that I don't have to care about SET PROCEDURE TO / SET CLASSLIB TO.

Recently, I am re-writing my company application update program. That is a method that loop thru all the necessary directory and files and store the file info (as per array content returned by ADIR()) into collection. The file details are stored as object based (I have class called FileInfo). FileInfo object is created using NEWOBJECT("FileInfo", "FileInfo.prg") function.

During the testing, I found the program takes 6.6 secs to check for 1200 files. The code of NEWOBJECT("FileInfo", "FileInfo.prg") was hit 2400 times due to the same function being called for source and target file. Each hit take average 0.0027 secs. That meant program spent 6.47 secs just to create FileInfo objects. This is unacceptable.

I changed my code SET PROCEDURE TO FileInfo.prg ADDITIVE at program startup and replace NEWOBJECT() with CREATEIBJECT(). Hey, the program now only take 1.5 secs to do the same thing. Therefore, we got to use NEWOBJECT() with care otherwise it might kill your application.

 

Technorati tags: ,

Craig has posted a screencast that demonstrate his current work to use Visual Studio IDE for VFP code editing.

It is amazing. Once again, thank Craig.

Technorati tags: , ,

As I am automating VFP build process as mentioned, I always need to execute VFP code from non-VFP environment. In order to have "full" power of VFP, I choose to use OLE automation using VBscript.

There are two ways to run VFP code from VBScript which I use frequently:

  • Writing some code in prg. This is a very straight forward appraoch
Set oFox = CreateObject("VisualFoxPro.Application")
oFox.DoCmd("DO myPrg WITH '" & MyParameter & "'")
  • Pass VFP code string
'USE myTable
'SCAN
'    IF myField = 'A'
'        ?myField
'    ENIDF
'ENDSCAN

Set oFox = CreateObject("VisualFoxPro.Application") 
oFox.DoCmd("EXECSCRIPT('" & sCommand & "')")

This approach is very useful if we allow other user to enter VFP code in UI which involve multiple lines of code, without need of VFP IDE.It seem very simple, right? Yes, it is. However, I just hit one error "Runtime Error" when we try to run the code above. It is because the VFP code string contains CRLF. The workaround I found is:

oFox.SetVar "lcCode", sCommnad
oFox.DoCmd("EXECSCRIPT(lcCode)")
Do you have any other way to do this?
 
Technorati tags: ,

I just found that is "really" written in C/C++. When I try to replace string from "myfolder\" to "myfolder\trunk" using Find and Replace dialog, VFP would replace my text as below

..\myfolder\myfile.prg ==> ..\myfolder\{TAB}runk\myfile.prg

VFP treat "\t" is tab identifier with is normally used in C/C++ type of language. For workaround, just put one more "\" in replace string column, "myfolder\\trunk".

 

Technorati tags: ,

VFP allow us to edit project version info from build dialog.

We also can edit it programmatically as below.

Both ways is working fine, except VFP IDE is required.

I have written a simple class to enable Project and Version Info edition programmatically without need of VFP IDE. This class would open pjx file, read/write content to DevInfo column.

USE myProj.pjx

loDevInfo = NEWOBJECT("DevInfo", "DevInfo.prg")
loDevInfo.VersionMajor = TRANSFORM(THIS.Major)
loDevInfo.VersionMinor = TRANSFORM(THIS.Minor)
loDevInfo.VersionRevision = TRANSFORM(THIS.Revision)

LOCATE FOR type = "H"
REPLACE DevInfo WITH loDevInfo.GetDevInfo()

** Author	0x00-0x2D
** Company	0x2E-0x5B
** Address	0x5C-0x89
** City		0x8A-0x9E
** State		0x9F-0xA4
** Postcode	0xA5-0xAF
** Country	0xB0-0xDD
** Comment	0xDE-0x1DC
** Company	0x1DD-0x2DB
** Descr		0x2DC-0x3DA
** (C)		0x3DB-0x4D9
** Trade		0x4DA-0x5D8
** Product	0x5d9-0x6D7
** Major		0x6D8-0X6DC
** Minor		0x6DD-0x6E1
** Revision	0x6E2-0x6E6
** Language	0x6E7-0x702

#DEFINE	AUTHOR_LENGTH				0X2D - 0X00 + 1
#DEFINE	COMPANY_LENGTH				0X5B - 0X2E + 1
#DEFINE	ADDRESS_LENGTH				0X89 - 0X5C + 1
#DEFINE	CITY_LENGTH					0X9E - 0X8A + 1
#DEFINE	STATE_LENGTH				0XA4 - 0X9F + 1
#DEFINE	POSTCODE_LENGTH			0XAF - 0XA5 + 1
#DEFINE	COUNTRY_LENGTH				0XDD - 0XB0 + 1
#DEFINE	COMMENTS_LENGTH			0X1DC - 0XDE + 1
#DEFINE	COMPANYNAME_LENGTH		0X2DB - 0X1DE + 1
#DEFINE	FILEDESCRIPTION_LENGTH	0X3DA - 0X2DD + 1
#DEFINE	COPYRIGHT_LENGTH			0X4D9 - 0X3DB + 1
#DEFINE	TRADEMARKS_LENGTH			0X5D8 - 0X4DA + 1
#DEFINE	PRODUCTNAME_LENGTH		0X6D7 - 0X5DA + 1
#DEFINE	VERSIONMAJOR_LENGTH		0X6DC - 0X6D8 + 1
#DEFINE	VERSIONMINOR_LENGTH		0X6E1 - 0X6DD + 1
#DEFINE	VERSIONREVISION_LENGTH	0X6E6 - 0X6E2 + 1
#DEFINE	LANGUAGEID_LENGTH			0X702 - 0X6E7 + 1

#DEFINE	AUTHOR_POSITION	 			1
#DEFINE	COMPANY_POSITION	 			0X2E + 1
#DEFINE	ADDRESS_POSITION	 			0X5C + 1
#DEFINE	CITY_POSITION	 				0X8A + 1
#DEFINE	STATE_POSITION	 				0X9F + 1
#DEFINE	POSTCODE_POSITION	 			0XA5 + 1
#DEFINE	COUNTRY_POSITION	 			0XB0 + 1
#DEFINE	COMMENTS_POSITION	 			0XDE + 1
#DEFINE	COMPANYNAME_POSITION	 		0X1DE + 1
#DEFINE	FILEDESCRIPTION_POSITION	0X2DD + 1
#DEFINE	COPYRIGHT_POSITION	 		0X3DB + 1
#DEFINE	TRADEMARKS_POSITION	 		0X4DA + 1
#DEFINE	PRODUCTNAME_POSITION	 		0X5DA + 1
#DEFINE	VERSIONMAJOR_POSITION	 	0X6D8 + 1
#DEFINE	VERSIONMINOR_POSITION	 	0X6DD + 1
#DEFINE	VERSIONREVISION_POSITION	0X6E2 + 1
#DEFINE	LANGUAGEID_POSITION	 		0X6E7 + 1

DEFINE CLASS DevInfo AS Line

	#IF .F.
		LOCAL THIS AS DevInfo OF DevInfo.prg
	#ENDIF

	Author = ""
	Company = ""
	Address = ""
	City = ""
	State = ""
	Postcode = ""
	Country = ""
	Comments = ""
	CompanyName = ""
	FileDescription = ""
	Copyright = ""
	Trademarks = ""
	ProductName = ""
	VersionMajor = ""
	VersionMinor = ""
	VersionRevision = ""
	LanguageID = ""

	PROCEDURE Parse(tcDevInfo AS String)
	
		THIS.Author = STRTRAN(SUBSTR(tcDevInfo, AUTHOR_POSITION, AUTHOR_LENGTH), CHR(0), "")
		THIS.Company = STRTRAN(SUBSTR(tcDevInfo, COMPANY_POSITION, COMPANY_LENGTH), CHR(0), "")
		THIS.Address = STRTRAN(SUBSTR(tcDevInfo, ADDRESS_POSITION, ADDRESS_LENGTH), CHR(0), "")
		THIS.City = STRTRAN(SUBSTR(tcDevInfo, CITY_POSITION, CITY_LENGTH), CHR(0), "")
		THIS.State = STRTRAN(SUBSTR(tcDevInfo, STATE_POSITION, STATE_LENGTH), CHR(0), "")
		THIS.Postcode = STRTRAN(SUBSTR(tcDevInfo, POSTCODE_POSITION, POSTCODE_LENGTH), CHR(0), "")
		THIS.Country = STRTRAN(SUBSTR(tcDevInfo, COUNTRY_POSITION, COUNTRY_LENGTH), CHR(0), "")
		THIS.Comments = STRTRAN(SUBSTR(tcDevInfo, COMMENTS_POSITION, COMMENTS_LENGTH), CHR(0), "")
		THIS.CompanyName = STRTRAN(SUBSTR(tcDevInfo, COMPANYNAME_POSITION, COMPANYNAME_LENGTH), CHR(0), "")
		THIS.FileDescription = STRTRAN(SUBSTR(tcDevInfo, FILEDESCRIPTION_POSITION, FILEDESCRIPTION_LENGTH), CHR(0), "")
		THIS.Copyright = STRTRAN(SUBSTR(tcDevInfo, COPYRIGHT_POSITION, COPYRIGHT_LENGTH), CHR(0), "")
		THIS.Trademarks = STRTRAN(SUBSTR(tcDevInfo, TRADEMARKS_POSITION, TRADEMARKS_LENGTH), CHR(0), "")
		THIS.ProductName = STRTRAN(SUBSTR(tcDevInfo, PRODUCTNAME_POSITION, PRODUCTNAME_LENGTH), CHR(0), "")
		THIS.VersionMajor = STRTRAN(SUBSTR(tcDevInfo, VERSIONMAJOR_POSITION, VERSIONMAJOR_LENGTH), CHR(0), "")
		THIS.VersionMinor = STRTRAN(SUBSTR(tcDevInfo, VERSIONMINOR_POSITION, VERSIONMINOR_LENGTH), CHR(0), "")
		THIS.VersionRevision = STRTRAN(SUBSTR(tcDevInfo, VERSIONREVISION_POSITION, VERSIONREVISION_LENGTH), CHR(0), "")
		THIS.LanguageID = STRTRAN(SUBSTR(tcDevInfo, LANGUAGEID_POSITION, LANGUAGEID_LENGTH), CHR(0), "")
		
	ENDPROC
	
	PROCEDURE GetDevInfo() AS String
	
		LOCAL lcDevInfo AS String
		
		lcDevInfo = "" 

		lcDevInfo = lcDevInfo + PADR(THIS.Author, AUTHOR_LENGTH, CHR(0))
		lcDevInfo = lcDevInfo + PADR(THIS.Company, COMPANY_LENGTH, CHR(0))
		lcDevInfo = lcDevInfo + PADR(THIS.Address, ADDRESS_LENGTH, CHR(0))
		lcDevInfo = lcDevInfo + PADR(THIS.City, CITY_LENGTH, CHR(0))
		lcDevInfo = lcDevInfo + PADR(THIS.State, STATE_LENGTH, CHR(0))
		lcDevInfo = lcDevInfo + PADR(THIS.Postcode, POSTCODE_LENGTH, CHR(0))
		lcDevInfo = lcDevInfo + PADR(THIS.Country, COUNTRY_LENGTH, CHR(0))
		lcDevInfo = lcDevInfo + PADR(THIS.Comments, COMMENTS_LENGTH, CHR(0)) + CHR(0x20)
		lcDevInfo = lcDevInfo + PADR(THIS.CompanyName, COMPANYNAME_LENGTH, CHR(0)) + CHR(0x20)
		lcDevInfo = lcDevInfo + PADR(THIS.FileDescription, FILEDESCRIPTION_LENGTH, CHR(0))
		lcDevInfo = lcDevInfo + PADR(THIS.Copyright, COPYRIGHT_LENGTH, CHR(0))
		lcDevInfo = lcDevInfo + PADR(THIS.Trademarks, TRADEMARKS_LENGTH, CHR(0)) + CHR(0x20)
		lcDevInfo = lcDevInfo + PADR(THIS.ProductName, PRODUCTNAME_LENGTH, CHR(0))
		lcDevInfo = lcDevInfo + PADR(THIS.VersionMajor, VERSIONMAJOR_LENGTH, CHR(0))
		lcDevInfo = lcDevInfo + PADR(THIS.VersionMinor, VERSIONMINOR_LENGTH, CHR(0))
		lcDevInfo = lcDevInfo + PADR(THIS.VersionRevision, VERSIONREVISION_LENGTH, CHR(0))
		lcDevInfo = lcDevInfo + PADR(THIS.LanguageID, LANGUAGEID_LENGTH, CHR(0))
	
		RETURN lcDevInfo
		 
	ENDPROC
	
ENDDEFINE
Technorati tags: ,

I was setting up Automate Build for my VFP project. I get a copy of FinalBuilder and use it as my starting point for Daily Build and Continuous Integration. I choose FinalBuilder is because it is easy use, good support and easy installation. FYI, FinalBuilder is an automated build and release management solution (ABRM) for Windows software developers and SCM professionals. It is just one of the automate build tools in market. Other product like MS Build, NAnt, VSTS Team System and many more.

Automate Build

By using automate build tool, we could define, debug, maintain, run and schedule reliable and repeatable build processes with minimal coding required. Build process doesn't meant only compile project, it also include activities like Get Latest Source File, run database script, copy files to deployment server, package deployment files, run automated testing and etc Once build process is automated, we only need to have single mouse click to establish build process. After this implementation, I have shorten time spent to deploy new version of application from two hours to ten minutes.

Before we start to automate our build process, it is recommended to sit down, take some papers to draft out current manual build process, just like writing program. The draft could be in pseudo code, flow chart, point form or whatever format. It would definitely help and save our time without keep revising the automated build process during implementation. I wasted a lot of time to revise my Build Process.

Automated Build Management Solution - FinalBuilder

FinalBuilder, as other ABRM tool, provides a lot of predefined common actions to perform varies tasks such as get latest source files, compile projects, execute setup scripts, copy files, FTP and etc. We could use each of action by simple configuration. Below is the IDE screenshot of FinalBuilder and overview of my automate build process.

Figure 1 Screenshot of Build Process defined in FinalBuilder

Automate Build for VFP Project

During this implementation, I was facing some issues. The main issue is, FinalBuilder doesn't natively support VFP (as most vendors). That is no VFP compiler available. No VFP Compiler, are you kididng? This is the main tasks for automate build! Yes, you didn't hear wrongly.

Fortunately , FinalBuilder come with Action Studio, allow us to create custom actions for any specific usage via ActiveX Script (VB Script/JScript), .NET interop and COM.

VFP Compiler Custom Action

To write custom action, I did some researches and found article posted in CODE magazine titled Integrating VFP into VSTS Team Projects by John Miller.  John shared his code to rebuild VFP project file (PJX) from PJM file and BUILD EXE from project. I copied, customized posted code to create my "VFP Compiler" action, called from FinalBuilder. I added feature to explicitly compile all .prg files excluded from project, since I found that don't know why excluded .prg files are not compiled using BUILD EXE command.

At the beginning, I tried to use COM to wrapper my build project code, however, as you might already known BUILD command is not supported during run-time. VFP doesn't complain for this exception either. I spent a lot of time to troubleshoot this, as it is not documented in Help file (as least I couldn't find it :'(). The workaround is either call VFP via command line or OLE Automation. I choose the 2nd way, automate VFP IDE using VB Script.

Set oFox = CreateObject("VisualFoxPro.Application")
oFox.DoCmd("*** BUILD EXE")

'Do some other things

oFox.Quit

The "VFP Compiler" Custom Action created and allowed us to do configuration, and currently it only accept settings such as project to be built, output destination, runtime version, SET PATH list and strict date level.

Steps to setup

  1. Download the custom action here.
  2. Extract it, and copy FoxProFBCustomActions.fbp5 to "<Final Builder Path>\ActionDefs" folder. Copy ProjectBuilder.prg to any folder.
  3. Launch Final Builder IDE.  Action "Build Project and EXE" would be shown in Action Types List under category Visual FoxPro (Figure 2).
  4. Drag and drop action from action types list to action list (Figure 3).
  5. Action property page is shown.
  6. Specify any name as Build Name.
  7. Specify Project Name (PJM), with path. PJM extension could be omitted.
  8. Specify output destination and file name of project executable file. EXE extension could be omitted. If this field left blank, EXE would be built and store at same location and name of project file (PJM), with EXE extension
  9. Select runtime version to build the EXE and project (Figure 4).
  10. Specify search path list. Remember to include location that stored the ProjectBuilder.prg (Figure 5).
  11. Specify environment settings. Currently only support Strict Date Level (Figure 6).
  12. Click OK to confirm.
  13. New action would be added to action list (Figure 7).

Possible Enhancements

Some future enhancements I can think of :

  1. Ability to type VFP code in action property page, and run it at Before/After Compile event; either full VFP code or just a function call.
  2. Full set of environment settings available in VFP option dialog.
  3. Ability to VFP related actions global settings such as common library path list in FinalBuilder options page.

Figure 2 Some VFP Custom Actions



Figure 3  Drag action to action list

Figure 4 Build Project Settings

Figure 5 Set Path Settings

Figure 6 Environment Settings

Figure 7 Action to Compile Projects

Amazing!!! Craig Boyd shown us a simple way to implement FoxPro control design time support. IOW, you can execute any custom code if any changes to control's property, size and etc. Craig also posted screencast to show it live, and source code is available!

Visual FoxPro - Designer Ideas and a Screencast

Thank you, Craig.

Technorati Tags: ,

I posted blog entry about how to show image in grid based on control source in last month. I received few comments/emails and inform me that my sample is not working.

First of all, thank you for your interest of reading my blog. OK, I read my previous blog again and agree that my explanation is not clear enough. I miss out some steps to mention. I repost it here with sample attached.

1. Create new class (CREATE CLASS ?)

2. Place an image control on the container class. Adjust image position accordingly. (Set Image.anchor = 15 if using VFP9). Set mycontainer.backstyle = 0 - Transparent, mycontainer.borderwidth = 0, myimage.backstyle = 0 - Transparent.

3. Select container object, select “Edit Property/Method …” from menu as shown below.

4. Edit Property/Method dialog form will be shown. Select BackStyle from the list and check “Assign Method” and “Access Method” checkbox and click Apply.

5. Open mycontainer.backstyle_access method and put your code.

6. Save your class.

7. Create a form, place your grid control and place mycontainer class into column. (Remember to delete the existing column.textbox control).

8. Set column.sparse = .F.

9. Add your code to open table/create cursor.

10. Set "mycursor.cimage" to grid.column1.controlsource; "mycursor.cdescr" to grid.column2.controlsource.

11. Save your form and run it.

Do you get the same result?

Technorati tags: , ,

I was asked how to GET rss feed from a web site. During research, I found couple of ways to do it in .NET. Below is the simplest way as I can get.

///Sample using System.Net

WebRequest wr = HttpWebRequest.Create(@"http://msdn.microsoft.com/globalrss/en-us/global-msdn-en-us.xml");
WebResponse ws = wr.GetResponse();

StreamReader sr = new StreamReader(ws.GetResponseStream());
string str = sr.ReadToEnd();
this.textBox1.Text = str;

///Sample using System.Data

DataSet ds = new DataSet()
ds.ReadXml(@"http://msdn.microsoft.com/globalrss/en-us/global-msdn-en-us.xml");
string str = ds.GetXml()
this.textBox1.Text = str;
I feel so excited when I found that I can read web content using DataSet. Amazing!!

I has couple of .NET 1.1 web applications use web.config to store most of the application settings. While releasing new version, I need to ship new settings with default value (with comments), and also retain existing customer settings.

Below is my prototype code to update web.config from another.

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Collections.Specialized;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            ConfigManager loConfig = new ConfigManager();
            ConfigManager loConfig2 = new ConfigManager();

            loConfig.ReadKeysFromConfig(@"c:\Web.config");
            loConfig2.ReadKeysFromConfig(@"c:\web1.config");

            foreach (string lo in loConfig2.AppSettings.Keys)
            {
                string lcvalue = loConfig2.AppSettings[lo];

                if (lcvalue != "")
                {
                    loConfig.AppSettings[lo] = lcvalue;
                }

                Console.WriteLine("Key=" + lo + " value=" + loConfig.AppSettings[lo]);
            }

            loConfig.WriteKeysToConfig(@"c:\Web.config");

            Console.ReadLine();
        }
    }

    public class ConfigManager
    {
        NameValueCollection _ConfigKeys = new NameValueCollection();

        public NameValueCollection AppSettings
        {
            get
            {
                return _ConfigKeys;
            }
        }

        public void ReadKeysFromConfig(string tcConfigFile)
        {
            string lcKey = "";
            string lcValue = "";

            try
            {
                XmlDocument _xdoc = new XmlDocument();
                _xdoc.Load(tcConfigFile);
                XmlNode xmlnode = _xdoc.SelectSingleNode("/configuration/appSettings");

                foreach (XmlNode loNode in xmlnode.ChildNodes)
                {
                    if (loNode.Name != "#comment")
                    {
                        try
                        {
                            lcKey = loNode.Attributes["key"].InnerText;
                            lcValue = loNode.Attributes["value"].InnerText;

                            _ConfigKeys.Add(lcKey, lcValue);
                        }
                        catch (XmlException ex)
                        {
                            throw ex;
                        }
                    }
                }
            }
            catch (XmlException ex)
            {
                throw ex;
            }
        }

        public void WriteKeysToConfig(string tcConfigFile)
        {
            XmlNode xmlnode = null;

            try
            {
                XmlDocument _xdoc = new XmlDocument();
                _xdoc.Load(tcConfigFile);

                foreach (string lckey in _ConfigKeys.Keys)
                {
                    xmlnode = _xdoc.SelectSingleNode(@"/configuration/appSettings/add[@key='" + lckey + "']");

                    if (xmlnode == null)
                    {
                        xmlnode = _xdoc.CreateNode(XmlNodeType.Element, "add", null);
                        XmlAttribute xmlkeyattr = _xdoc.CreateAttribute("key");
                        xmlkeyattr.Value = lckey;
                        XmlAttribute xmlvalueattr = _xdoc.CreateAttribute("value");
                        xmlvalueattr.Value = _ConfigKeys[lckey];

                        xmlnode.Attributes.Append(xmlkeyattr);
                        xmlnode.Attributes.Append(xmlvalueattr);

                        XmlNode xmlparent = _xdoc.SelectSingleNode(@"/configuration/appSettings");

                        if (xmlparent == null)
                        {
                            XmlNode AppSettingNode = _xdoc.CreateNode(XmlNodeType.Element, "appSettings", null);
                            xmlparent.AppendChild(AppSettingNode);
                        }

                        xmlparent.AppendChild(xmlnode);
                    }
                    else
                    {
                        xmlnode.Attributes.GetNamedItem("value").Value = _ConfigKeys[lckey];
                    }
                }

                _xdoc.Save(tcConfigFile);
            }
            catch (XmlException ex)
            {
                throw ex;
            }
        }
    }
}

It is my first touch to XMLDocument. It looks complex, but actually not that difficult :)

Reference:

West-wind Configuration Class

A month ago, I attended IASA synbosium which held at Kuala Lumpur, Malaysia. It is an event that talk about enterprise architecture. I was so lucky to win a book titled "Refactoring Database" from IBM lucky draw and got chance to have photo with the author, Scott W.Ambler. :D



Signature from Scott: Data doesn't have to be in "Four Letters" words anymore!

Updated:

TechEd2007 is one of the must attend event. Mark your calander to attend this event on 10-13 Sept 2007 at KLCC convention center, Kuala Lumpur, Malaysia. See you there!

Tech•Ed SEA 2007, Microsoft’s premier & largest annual conference in the South East Asia region, focuses on newly released products such as of Microsoft Office along with content about upcoming releases such as Windows Server code name "Longhorn". For four days in September, you can get technical training, information and resources to help you build, deploy, secure, mobilize, and manage solutions.

Tech•Ed SEA 2007 features:

More than 120 breakout sessions
This year’s event will feature even more speakers from Microsoft Corporation allowing you to hear about your favorite technologies from the sources who develop them. Create a personal learning program from 6 technical tracks with more than 120 breakout sessions.

Hands-on experiences
Tech•Ed offers opportunities to evaluate products both from Microsoft and from 250 of our most important industry partners. Additionally, based on attendee feedback from last year, we will be more than doubling the number of Instructor Led Lab sessions as well as introducing a whole host of new self-paced Hands On Lab content.

 Networking with your peers
Walking around Tech•Ed are more than 2,000 minds just like yours. 2,000 IT pros and developers to meet. 2,000 opinions to consider. Add to the mix Microsoft product team members and industry gurus and you will immediately see why a Tech•Ed crowd is like no other.

Tech•Ed is a one-of-a-kind experience!

 

Technorati tags: ,

Few days ago, my friend called me. He said that he has a field stored the path of some images. He want to show these images in grid. I followed Craig Boyd tip and posted the intructions which I sent to my friend at here if anyone might interested.

1. Create new class (CREATE CLASS ?)

2. Place an image control on the container class. (Set Image.anchor = 15 if using VFP9)

3. Select container object, select “Edit Property/Method …” from menu as shown below.

4. Edit Property/Method dialog form will be shown. Select BackStyle from the list and check “Assign Method” and “Access Method” checkbox and click Apply.

5. Open backstyle_access method and put your code.

6. Save your class.

7. Create a form, place your grid control and place your container class into column. (Remember to delete the existing column.textbox control).

8. Set controlsource to your column.

Below is the screenshot to show images in grid I received from him.

Recently, I play around with anchoring feature in .NET. I found that .NET anchoring is more "accurate" in this scenario compare to VFP.

Let assume we have few controls placed at the center of form. There may be some situations we don't want to have anchoring at all because it make our screen look ugly, combobox become too long and etc. We want these controls retain at the center with same size even though the form is maimized. 

Lets turn off anchor for all controls - set 0 (ZERO) to anchor property (VFP); set None to anchor property (.NET).

 

Figure 1 VFP Form at design time

 

Figure 2 .NET Form at design time

Let resize the form and see what will happen.

 

Figure 3 VFP Form at runtime

 

Figure 4 .NET Form at runtime

As we can see here, VFP controls retain at the same position. However, .NET controls's has been moved to center of form. From this testing, we can say that, VFP always use "Left, Top" anchoring if we set anchoring off. Do you agree?

 

Technorati tags: ,
More Posts Next page »