Friday, November 14, 2008

Slow Load for Visual Studio

This week my Visual Studio started loading my solutions very slowly. It would take 10 minutes or more just to get everything up and ready. I suspected something network related since there was no real CPU or disk usage occurring.

After some digging, I found this interesting tidbit.

From: Never doubt thy debugger

It was handy finding out where the recent file list was. Mine didn't have network shares, but it did have some projects that had been moved to other directories. I deleted all the entries.

BTW, Visual Studio has to be shut down before the list is cleared. If not, it gets recreated with the in-memory copy when Visual Studio exits.

This helped some projects but not all. I still had one solution that was slow. After a bit, I noticed that a file on a network share was being checked for searches. While working I had dragged a file from a network share into my Visual Studio and didn't close it (I tend to keep a lot of files open at once). Once I closed all my files, things got better.

Monday, November 3, 2008

The Perfect Halloween

No jokes or sarcasm. Last Friday was a perfect Halloween. It was the perfect convergence of elements.

Here in Colorado Springs, Halloween has a weather reputation. It's usually bad. It is often cold and/or windy and if it isn't wet, it probably because it is snowing. I have been out with my daughters in all kinds of inclement weather. (My oldest is a die-hard)

So, the weather was perfect. It was 55-60 degrees, no wind and clear.

However, let's not forget that it was a Friday. No school the next day meant no homework and no strict bed time. The kids could trick-or-treat to their hearts content. And they did.

We had some friends come over. Each of my daughters had trick-or-treat buddies. Therefore there were no fights about taking a little sister.

My kids are in 3 of the 4 trick-or-treater groups. My oldest is a teenager. She wants to go fast and get as many doors as possible while being with friends. No adults, please. My second is in the sweet-spot. As a pre-teen, she went with friends and got a lot of candy. She also got a bonus, a friend she was able stay over for a sleep-over. The youngest got to go till she was tired and her bag was too heavy. She loved the decorations at houses as long as they weren't too scary. Halloween is magic at that age. The fourth group are the little kids that are carried or pushed in strollers. I don't have any of those any more, but I know that that age is all about being cute.

Last week was parent-teacher conferences. The kids were out of school Thursday and Friday. It was like an actual holiday. The kids had time to do all these fun things like decorate the yard and carve a big pumpkin.

My wife dressed up like Palin. She's a natural for it and looked good. She got a lot of comments on her costume. And there were lots of viewers because with the warm weather, everyone was out. She was very happy showing off as she handed out our candy.

After the rounds were all made by the kids they came home for the great trading session. Wall-street at home. This year, everything was sorted into tradeable and not-tradeable. The bartering began and then ended. There were no fights.

And for me? Well, I got chocolate.

Isn't that what truly makes a good holiday? Everyone was happy!

Tuesday, October 21, 2008

Frosting

It's birthday season in my house. All three of my children have their birthdays within a month of each other. With all the excitement and fun comes BIRTHDAY CAKE! Yum!

Over the years I have realized the purpose of cake. The purpose of cake is so you can eat frosting. It is merely a vehicle. It isn't that cake doesn't matter, because frankly frosting looks better on a cake, but the cake is secondary to the true treat.

This attitude works its way into all aspects of cake eating. When selecting a piece, go for the corner (if there is one). When eating cake, you need to carve out all the cake parts first in order to save the frosting husk to be savored last. Without any cake in the way, you can slowly eat slices of frosting goodness.

Cupcakes are a bit different. Eating the cake first just isn't very practical. So, my technique has evolved into something different. With cupcakes, you get all the frosting goodness up front by biting the top off. With practice, you can get it in one bite. However, after that you have a dilemma. What do you do with the cake? It has already fulfilled its mission of delivering frosting, so it is not really needed. I have known people who throw it out, but I will eat the cake part because it seems more proper.

I'm not sure I should be this revealing here...

Monday, October 20, 2008

Second-Child Syndrome

This is how it goes with parents. We can't really help it (or at least I can't). Your first child breaks all the new ground. They are lucky. Their parents are very focused on all their milestones. Every minute is photographed, every event lives on forever.

The second child gets the short end of the stick. Their events are celebrated, but... well sometimes the camera doesn't even come out.

What about the third child? Well, that depends. If it is the last child, then the get all the "Last Time" interest. "Oh, this is the last time one of our babies starts kindergarten." So, they don't get completely left out. However, they still get ignored for some things.

Now, just to complicate things, put those last two birth days two days apart. That is the situation in our house.

This year, #2 wanted a big party with lots of friends. So, she got it. The camera did come out and it will be remembered. However, it contributed to the current problem.

#3 turns 8 this year. In our church, 8 is a big deal. It is when our children are baptized. For #1 much thought and preparation went into it. It was a grand event. For #2, it was still grand but a little more last minute. For #3... well we have a date and time set, but we're still working out some of the details. Did I mention it is in 6 days?

I don't know if it is laziness or lack of novelty, but these things just creep up on you. I feel bad. I want each child to have as much grandeur as the older children have, but it just doesn't happen.

That brings up my second recurring thought about parenting. I feel like an amateur. I suspect this is common. There is no real training for parenthood. No study course or planning. You are told how to get one started, you do it, and then you wing it. There are books for various aspects to help you along the way, but these are usually after something has happened and tend to focus on one specific thing. Nothing trains you on how to be a parent.

The good thing is that your children don't know any better. To them, you are the greatest parents in the world (at least until they are teenagers in the "nobody understands me mode". Fortunately, I'm not there yet.) So, there is room for error.

Hmmm, I think I just hit on something. Parenting is sloppy. It involves a lot of guess work. Professionals couldn't get away with this. They train hard and make very little mistakes.

Ouch. Mistakes. I can only hope my children turn out ok.

There is one consolation. My parents were amateurs too... crap. I was going to end with "I turned out all right", but I'm not sure Mom counts as an amateur. She was a teacher and school counselor. She studied psychology. She may have had an edge.

Oh well.

Friday, October 10, 2008

Weather Forecasts

So, earlier I mentioned there was snow in the forecast. Well, that isn't the case anymore. The forecast is now 50% or so chance of precipitation. It just isn't going to get as cold as they thought.

Forecasting must be really hard and I must admit it is a topic that fascinates me. We all like to complain about the weather and forecasters, so maybe I'm just normal. However, I have noticed some interesting patterns in forecasting. (BTW, I am not really trying to trash forecasters. I think the front range of the Rockies is a very difficult area to predict weather.)

Pattern 1: Psych! There have been several times when major snow storms have been predicted and just didn't happen. I remember once schools let out early and we ended up with a few flurries (not enough to accumulate).

Pattern 2: Oops, missed that one. This is similar to the first pattern. Totally missed the boat but in the other direction. There have been days when nothing major was supposed to happen, but it did. I enjoy making the remark "I just shoveled 6 inches of partly cloudy off of my driveway."

Pattern 3: Rebound. This is a subtle pattern, but I have noticed it many times. The distant forecast (a week or more out) makes a prediction. As the day gets closer, the forecast changes (I assume as the information used for the predictions becomes more solid). And then, when the day comes and we see its actual weather, it was more like the early prediction than the late prediction. This is my hope for this weekend. It will actually get as cold as originally predicted and snow.

Pattern 4: Rut. Here in Colorado Springs, we have a fairly consistent weather pattern during the summer. Afternoon Thunderstorms. There is something about the mountains that produces a daily weather cycle where we have clear skies in the morning, developing storms in the afternoon, and then clearing skies in the evening. Many days are forecasted as a percentage chance of a thunderstorm or how big the storm will be. It gets monotonous. Even the weather people on TV see it and comment on it. "Yet another day of PM thunderstorms."

Anyway, that is my take on the weather. I guess now you don't need to ask :)

Thursday, October 9, 2008

Band Night

Tonight is band rehearsal. I love it!

When I was in high school, band was a huge part of it. Yes, I was one of those band nerds. I loved it. It was fun and the highlight of my day.

And then college came and I didn't continue band. I was busy in college and failed to realize the good it would have done me to continue music. It didn't help that I was not well motivated and didn't manage my time well. So, that was pretty much the end of playing in band.

At the beginning of the year, my Dad found an organization that allows you to play in band again. He was very enthusiastic and invited me and my family to his spring concert. When I went to the concert, I was struck by two things. First, it sounded just like high school. Second, I missed it and wanted to be on the stage playing.

At the end of the summer, my Dad invited me to a recruiting event for the band. He was very excited about it and at the time, Mom had said "no". So, I thought I would go and at least support Dad. Long story short, I signed up, arranged to borrow a tenor saxophone, and started playing.

The organization is called the New Horizons Band. I believe it is national and it was created for people just like me. Folks who stopped playing because school stopped and not because they wanted to stop playing. Here we have several bands depending on ability and availability. I rehearse once a week for 1 hour in the evening. It is an intermediate level group (8th-9th grade music), so it isn't too difficult. It has been perfect for relearning how to play.

I have been going for a month and there is one thing that is very clear. I love it. Even the rudimentary fundamental exercises (breathing, rhythms, scales, etc) are ok because I am in band again. After rehearsal, I come home happy.

Tuesday, October 7, 2008

More Personal

My previous entries have been very technical. That's not bad, but it isn't all that I am. My sister started her blog at GatheringHolly which reminded me that I can put other stuff here too since my original intent was to post stuff about me.

So, after my incredibly exciting topics on work things, I thought maybe I could tone things down and talk about the weather. Why? Because winter is coming and I LOVE winter. This weekend it could snow (at least here in Colorado Springs). I love snow. I don't know why, but I have been this way as long as I can remember. I tend to attribute the attitude to the fact that I grew up on tropical islands without any snow as a young child, but I am not sure that is completely true. I just am not a fan of the heat. I don't like sweating and I am one of those people that sweat a lot. So, bring on the cold!

Also, snow is just cool. The landscape becomes something new when it all turns white. The commute becomes a challenge. The kids get excited because they might miss school. Humidity is up and noise is down.

I think that is it. It is just different. It is not the normal routine (at least here) and I like it when something knocks you out of the rut of normal routine.

Thursday, August 21, 2008

InstallShield XML File Changes

InstallShield 2008 has an interesting quirk when editing XML File Changes. When changing the value of an XML tag by typing a new value in, it doesn't like to get saved. You need to do something else on that screen like check/uncheck a box before the new value is saved. Or you can select the new value from the list of string values.

One thing I don't do well is use the string values from InstallShield. I like to type in the values I want instead of just changing the value of a string. I had several XML files that needed the exact same change. If I had properly used the string values, I could have just made the change once.

Tuesday, August 5, 2008

InstallShield and Windows Services

To add a Windows Service to InstallShield, add the service file into a component. I have my executable as the only file in the component. Right click on the file and set it as the key file. The expand the Advanced Settings tab. There are two sections for NT Services.
In Install NT Services you set the properties. I set the User Name to [SERVICE_USER_NAME] and Password to [SERVICE_USER_PASSWORD]. Then you can set the user in InstallScript using MsiSetProperty.
In Control NT Services you do something very important. You allow the service to be uninstalled properly. You will need to add a service. Then add an event which I am not entirely sure means. But then you have a list of properties for installing and uninstalling. The ones I set to Yes are Uninstall Stop and Uninstall Delete. I also change Wait Type to "Wait for the event to complete".
This allows the service to be uninstalled. However, I did notice that if the services management console is up that the service won't get deleted there. It gets disabled and then gets deleted after the console is closed.

InstallShield and LogonAsService Right

I was somewhat perplexed by this one. I am installing a Windows NT Service (don't let the "NT" bother you, that is just the OS when services where introduced or something like that). I have configured the service in my components. I filled out the properties for NT Services and set properties for the user and password. Then I use the user dialog I mentioned in previous posts to get the user credentials for the service. This dialog can create a new user for this, which is typically the case for my project.
However, the installed service doesn't start. Instead I get an error that the service can't be started with the message being "Error 1069: The service did not start due to a logon failure." I went into the properties to the Log On tab to check things. The password is obscured, so I retyped it in and clicked Apply. Then I get the message "The account has been granted the Log On As A Service right." After that, the service works.
This is what I learned. Users, especially domain users, don't have this right typically. I am guessing that since the new user is specified in the format "DOMAIN\USER" it is considered a domain user even if the domain is the local system. The localsystem user already has this right granted to it.
For some reason, MSI or InstallShield doesn't allow you to grant this right when the user is created. There are some posts on the InstallShield forums that say this. There is also mention of the answer.
The answer is calling the utility NTRIGHTS.EXE. This is the Windows command-line utility for administrating rights for users. So, first you need to acquire the utility. It comes from the Windows Resource Kit. It is not installed as part of Windows, so you will need to download it and install it. After that, you have the utility. Next it needs to be included in your InstallShield project. I copied the utility for a folder where I have my support files (I have all my files together for easy source-control). I then added it to my support files inside my project as a language independent file. Then I run it using LaunchAppAndWait.

szProgName = SUPPORTDIR^"ntrights.exe";
szProgParams = " -u" + szUserName + " +r SeServiceLogonRight";
StatusBox("Executing '" + szProgName + szProgParams + "'", DEBUG);
if (LaunchAppAndWait(szProgName, szProgParams, WAIT) <>
MessageBox("Unable to launch " + szProgName + ". Retype the password for the the user in the workflow service properties.", WARNING);
endif;

BTW, I call it from a later event in my InstallScript, specifically OnFirstUIAfter. That may not be the best as it would also need to be in OnMaintUIAfter, but this is a first cut and I haven't got all the maintenance mode worked out yet. Also, I put the call in a function so that I can call it from wherever it needs. The point is that it needs to called AFTER the user is created which is after InstallShield's "Do Stuff" phase.
Problem Solved.

Monday, August 4, 2008

SdLogonUserInformation

I discovered a interesting tidbit today -- SdLogonUserInformation only works with one user. It has a single set of properties it uses to gather user information. If run this dialog more than once to get multiple users, the last set of credentials wins.

Friday, August 1, 2008

Quiet Install of an MSI

My project has AJAX Extensions as a prerequisite. So, it needs to run the APSAJAXExtSetup.msi. It needs to run it as a prereq for my install. Also, I don't want my users to see, I want it installed for all users and I don't want it to run if it exists.

First, I found this link which was helpful. That and running the MSI with /? to get the help list got me the following command line.

APSAJAXExtSetup.msi /quiet ALLUSERS=2

I guess I need to back up a moment. I had to create a prerequisite in IS before all this. There didn't seem to be a standard one for AJAX extensions. In the Redistributable view, I added one. I then added the MSI on the File To Include tab. Then on the Application to Run tab I selected the MSI. The parameters can then be put into command line box on the Application to Run tab.

In order to conditionally run the MSI, you need to set a condition on the conditions tab. You need to specifiy a registry key or a file to check for that shows the package exists. To find a something, I opened the AJAX MSI in InstallShield and started poking around. I looked at the Registry view and settled on the key

HKEY_CURRENT_USER\Software\Microsoft\ASP.NET\ASP.NET 2.0 AJAX Extensions

I set the condition that if the key does not exist, run the prerequisite.

*EDIT* I guess the install is not completely silent. InstallShield has a dialog with a status bar showing that a prerequisite is being installed and what the prereq is. But the actual dialogs from the MSI package don't show.

InstallShield LaunchAppAndWait and File Access

The Task: Grant access to the files I have installed to the users I have created.

In the Files & Folders view, you can right click on a folder and select properties to get access to the permissions for a file or folder. However, this doesn't work so well because you can't add permissions to a file, you can only replace them. I didn't want that as I didn't want to clear out the Administrators group access to my install folder. I just wanted to add a couple of users to the access list. The real answer is to use LaunchAppAndWait to run cacls.exe on the folder.

I have used LaunchAppAndWait in the past and have struggled with it. It is difficult to debug. So, there are some things I would recommend. First, add a MessageBox for debug that shows what you are going to run. If you are not getting desired results, copy exactly what is in your message into a console window on the target system with your files in place and see what happens. You might be surprised. LaunchAppAndWait tells you if it launched the program, but does not tell your if the program had errors.

Of course, that isn't the way I did it the first time. The first time I was convinced LaunchAppAndWait was messing up. So, I created a sanity-check app in Visual Studio and called it from LaunchAppAndWait.



It's very simple. Take the arguments from the command line and put them into a text file. This way, you can use whatever command parameters your real command needs. Just change the program to the test app.

To use LaunchAppAndWait, set up a variable for the program name and a variable for the parameters. Actually, here is my function.

function SetDirectoryPermissions(szDirectoryName, szUserName)
STRING szProgName;
STRING szProgParams;
STRING svTempString;
begin
// Remove any trailing slash from the directory name.
StrSub(svTempString, szDirectoryName, StrLength(szDirectoryName) - 1, 1);
if (svTempString = "\\") then
StrSub(svTempString, szDirectoryName, 0, StrLength(szDirectoryName) - 1);
szDirectoryName = svTempString;
endif;

szProgName = WINDIR^"system32\\cacls.exe";
szProgParams = " " + szDirectoryName + " /E /G " + szUserName + ":F";
if (LaunchAppAndWait(szProgName, szProgParams, WAIT) <>
MessageBox("Unable to launch cacls. File permissions will need to be set manually.", WARNING);
endif;
end;


With all that out there in the open, it shows the issue I had with cacls.exe. If you pass in INSTALLDIR, there is a trailing slash (IS always puts one there). cacls.exe throws an error saying that it can't find the file. So, I had to remove the trailing slash and IT WORKED!

BTW, the command it is running is

cacls.exe C:\InstallDir /e /g DOMAIN\USER:F

Which brings up my last point. You should include the domain with the user name. Windows needs that to properly locate the credentials for the user.

Ok, so my code samples are rough. I am still getting used to blogger.

Thursday, July 31, 2008

InstallShield and User Logon Information

I started working on a post that describes how to create a custom dialog in InstallShield. It will be a big post, so rather than wait for it to be done, I thought I would post some of the smaller items that I wanted to.

If you want to collect user information, InstallShield provides a standard dialog for this. It is called SdLogonUserInformation. It is a great dialog because it is tied into the system's users and the domain. So, you can use it to select a domain user or create one (if you have privileges). I have used it twice to create a user for special purposes. Once was for an identity for a COM+ object and the other for a user to run a Windows Service. This way, the person running the InstallShield can select or create a user during installation for these purposes.

In older versions of InstallShield (pre 2008), this dialog had a flaw. If it was run in an environment that had a lot of active directory entries (15k+) on the active directory server and the user clicked the browse button for the domain, the InstallShield would crash. I had the opportunity to work with Macrovision (now Acresso) on this to get it fixed for 2008. So these days it handles this situation just fine.

If you use that dialog, do not forget to call OnLogonUserSetMsiProperties() in your script after you show the dialog. Otherwise your information doesn't get propagated to the system. If you don't use this, your service install will fail because of invalid credentials or something like that.

Another item about users. Don't use the above dialog for simple users like SQL users. If you install a database and want to use SQL authentication (common for webserver connections to the database), then you need a non-system user. Unfortunately, InstallShield does not have a simple username/password dialog with the password box obscured. So, in a later post I will use that as an example of how to create a custom dialog.

Wednesday, July 30, 2008

Frustrations with InstallShield

I think I have a purpose to work towards for my next post or so. I have been working on a project using InstallShield and have learned some things. Some of them turned out harder than I thought they should be. So, I am going to write about some of my discoveries. I actually started typing them as my next post, but I realized they are going to take some time. So, I will post this "Post Of Intent" first and then post the others as I can.

The topics I have so far include creating a custom InstallShield dialog, discussing issues with conditionally installing web files, and an interesting glitch passing data to a .NET dll.

I suppose this information is available elsewhere, but as it says above, these posts are mostly for me.

Let's Get Started

Am I jumping on the band wagon? Am I venting? Am I sharing wisdom to the rest of the world? Am I extending my memory?

I don't know yet. A combination of events inspired me to start a blog. I am not sure how much history to cover. I'm getting old and there is too much to type. So, for now we will start with today.

I tried to get yevi.blogspot.com, but it was taken. That was a bit of a bummer. But Yevgenia had it first and had it since 2004, so, not much I can do about that.

My initial template is pink. There's a story there. The highlights are:
1. I'm a man.
2. Purple is my favorite color.
3. I have three daughters.
4. I played a gnome mage in World of Warcraft with pink hair.
The rest is sort of history. It would not have really worked for me if any of the above were not the case, but it sort of grew on me. Plus I like the shock value. Some sort of rule that straight guys don't do pink unless they wore it with gray slacks in the 80's.

BTW, I suck at diaries/journals. So, don't be surprised if you read this and nothing more.