Archive for the 'Workaround' Category

Find and Replace in Word using C# .NET

Saturday, July 3rd, 2010

Heads up, this article contains high quantity of geek content. Non-geeks should move along.

I’ve been trying to use Microsoft.Office.Interop.Word to perform a global bulk search and replace operations across an entire document. The problem was, however, if a document contained a floating text box, which manifested itself as a shape object of type textbox, the find and replace wouldn’t substitute the text for that region. Even using Word’s capability to record a macro and show the VBA code wasn’t helpful, as the source code in BASIC wasn’t performing the same operation as inside the Word environment.

What I wanted was a simple routine to replace text anywhere inside of a document. If you Google for this you’ll get the wrong kind of textbox, the wrong language, people telling you not to use floating textboxes, and all kinds of weird story iterators.

One site seemed to have the solution; many kind thanks to Doug Robbins, Greg Maxey, Peter Hewett, and Jonathan West for coming up with this solution and explaining it so well.

However, the solution was in Visual Basic for Applications, and I needed a C# solution for a .NET project. Here’s my port, which works with Office 2010 and Visual Studio 2010 C#/.NET 4.0. I’ve left a lot of redundant qualifiers and casting on to help people searching for this article.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using Microsoft.Office.Interop.Word;

// BEGIN: Somewhere in your code
Application app = null;
Document doc = null;
try
{
  app = new Microsoft.Office.Interop.Word.Application();

  doc = app.Documents.Open(filename, Missing, Missing, Missing, Missing, Missing, Missing, Missing, Missing, Missing);

  FindReplaceAnywhere(app, find_text, replace_text);

  doc.SaveAs(outfilename, Missing, Missing, Missing, Missing, Missing, Missing, Missing, Missing, Missing);
}
finally
{
  try
  {
      if (doc != null) ((Microsoft.Office.Interop.Word._Document) doc).Close(true, Missing, Missing);
  }
  finally { }
  if (app != null) ((Microsoft.Office.Interop.Word._Application) app).Quit(true, Missing, Missing);
}
// END: Somewhere in your code             

// Helper
private static void searchAndReplaceInStory(Microsoft.Office.Interop.Word.Range rngStory, string strSearch, string strReplace)
{
    rngStory.Find.ClearFormatting();
    rngStory.Find.Replacement.ClearFormatting();
    rngStory.Find.Text = strSearch;
    rngStory.Find.Replacement.Text = strReplace;
    rngStory.Find.Wrap = WdFindWrap.wdFindContinue;

    object arg1 = Missing; // Find Pattern
    object arg2 = Missing; //MatchCase
    object arg3 = Missing; //MatchWholeWord
    object arg4 = Missing; //MatchWildcards
    object arg5 = Missing; //MatchSoundsLike
    object arg6 = Missing; //MatchAllWordForms
    object arg7 = Missing; //Forward
    object arg8 = Missing; //Wrap
    object arg9 = Missing; //Format
    object arg10 = Missing; //ReplaceWith
    object arg11 = WdReplace.wdReplaceAll; //Replace
    object arg12 = Missing; //MatchKashida
    object arg13 = Missing; //MatchDiacritics
    object arg14 = Missing; //MatchAlefHamza
    object arg15 = Missing; //MatchControl

    rngStory.Find.Execute(ref arg1, ref arg2, ref arg3, ref arg4, ref arg5, ref arg6, ref arg7, ref arg8, ref arg9, ref arg10, ref arg11, ref arg12, ref arg13, ref arg14, ref arg15);
}

// Main routine to find text and replace it,
//   var app = new Microsoft.Office.Interop.Word.Application();
public static void FindReplaceAnywhere(Microsoft.Office.Interop.Word.Application app, string findText, string replaceText)
{
    // http://forums.asp.net/p/1501791/3739871.aspx
    var doc = app.ActiveDocument;

    // Fix the skipped blank Header/Footer problem
    //    http://msdn.microsoft.com/en-us/library/aa211923(office.11).aspx
    Microsoft.Office.Interop.Word.WdStoryType lngJunk = doc.Sections[1].Headers[WdHeaderFooterIndex.wdHeaderFooterPrimary].Range.StoryType;

    // Iterate through all story types in the current document
    foreach (Microsoft.Office.Interop.Word.Range rngStory in doc.StoryRanges)
    {

        // Iterate through all linked stories
        var internalRangeStory = rngStory;

        do
        {
            searchAndReplaceInStory(internalRangeStory, findText, replaceText);

            try
            {
                //   6 , 7 , 8 , 9 , 10 , 11 -- http://msdn.microsoft.com/en-us/library/aa211923(office.11).aspx
                switch (internalRangeStory.StoryType)
                {
                    case Microsoft.Office.Interop.Word.WdStoryType.wdEvenPagesHeaderStory: // 6
                    case Microsoft.Office.Interop.Word.WdStoryType.wdPrimaryHeaderStory:   // 7
                    case Microsoft.Office.Interop.Word.WdStoryType.wdEvenPagesFooterStory: // 8
                    case Microsoft.Office.Interop.Word.WdStoryType.wdPrimaryFooterStory:   // 9
                    case Microsoft.Office.Interop.Word.WdStoryType.wdFirstPageHeaderStory: // 10
                    case Microsoft.Office.Interop.Word.WdStoryType.wdFirstPageFooterStory: // 11

                        if (internalRangeStory.ShapeRange.Count > 0)
                        {
                            foreach (Microsoft.Office.Interop.Word.Shape oShp in internalRangeStory.ShapeRange)
                            {
                                if (oShp.TextFrame.HasText != 0)
                                {
                                    searchAndReplaceInStory(oShp.TextFrame.TextRange, findText, replaceText);
                                }
                            }
                        }
                        break;

                    default:
                        break;
                }
            }
            catch
            {
                // On Error Resume Next
            }

            // ON ERROR GOTO 0 -- http://www.harding.edu/fmccown/vbnet_csharp_comparison.html

            // Get next linked story (if any)
            internalRangeStory = internalRangeStory.NextStoryRange;
        } while (internalRangeStory != null); // http://www.harding.edu/fmccown/vbnet_csharp_comparison.html
    }

}

Let me know if it worked for you; bug fixes and enhancements welcome.

ModRewrite Woes (Solved!)

Wednesday, June 24th, 2009

While working on a project, I stumbled into some of the weirdest Apache2 mod_rewrite problems that I’d ever seen.

The goal was to make a URL like http//www.nowhere.com/item/1234 turn into http://www.nowhere.com/item.php?id=1234. Trivial, and I’ve done it all the time.

RewriteEngine on
RewriteRule ^item/(.+)$ item.php?id=$1 [L]

This time it wasn’t working the way I expected. When I used the human-readable version, my page got delivered by I had no images, no css, no javascript. Yet, if I used the computer-friendly long form with parameters, it worked just fine.

A little examination with Safari’s activity window showed me that in the initial case the browsers were looking at all relative URLs as if they were prefixed with /item/. This make sense, because the URL redirect knows how to play rewrite games with the rules to get to my page, but the relative links on those pages, to css, graphics, and js, had no clue this was a fake base url.

Many thanks to richardk who pointed out multiple solutions back in 2005.

  • Don’t use /, and there isn’t a problem.
  • Use absolute paths, though you have to edit all the links on your page; if using PHP, consider a variable for the base path.
  • Use a RewriteRule to hack off the offensive directory that doesn’t exist.
  • Or, use the <BASE …> tag.

Well, that rendered the page prettier, but I realized my argument wasn’t being passed in. Yet, the re-write rule was correct.

So I tried http//www.nowhere.com/item, which should not have matched and should not have brought up a page. Yet it did.

A little experimentation showed that any page that had a known extension was getting delivered.

What this meant was that the moment the browser saw /item it found the item.php page and delivered it without ever going through Apache’s rewrite module, and hence no parameters.

Luckily, I’ve encountered this symptom before in a different context. The offender: MultiViews. This is the bugger that deals with multiple language support; you know, where you have a zillion internationalized instances based on filename extensions….

Turning that off instantly solved the problem of delivering a file without an extension:
# Options Indexes FollowSymLinks MultiViews
Options Indexes FollowSymLinks

That also meant that the mod-rewrite rules worked. And that meant the parameters were passed correctly. And that meant I was was happy, because the code was working.

Hiding Image Files in TextMate

Sunday, March 22nd, 2009

TextMateTextMate, perhaps the best generic programming editor that I’ve ever encountered (though I’d be willing to entertain reader suggestions), has the ability to open an entire directory at once, which is great for making bulk changes to automatically generated website files.

However, there’s one trick that I keep having to look up each time I do it, and that’s how to get that side-bar directory listing of the project files not to display image files. The reason you might want to do this is for efficient global replace options across all text-based site files.

The solution is to click the top-level directory in the project, and press the I button in the bottom right corner of the drawer.

This opens a Folder Information dialog box. In the area labeled Recursively Include Contents Matching there are two fields, one for files and one for folders. In the File Pattern field, enter this regular expression: !\.(jpg|png|gif)$

When you close the Folder Information dialog box, all files with the extensions listed will no longer be displayed.

Safari 4 Beta – OS X Users: Wait

Wednesday, February 25th, 2009

Yesterday I downloaded a copy of Safari 4 Beta for Windows, and I have to say that the speed increase was obvious. Just a little playing around with the browser [especially in developer mode] tells me that Apple has something good. Real good.

However, my experience when installing the Safari4.0BetaLeo.dmg version on OS X wasn’t as hot. Well it was, but the collateral damage was unexpected.

In short, the browser worked great, just like on Windows. The speed up was there, but certainly not as dramatic as when you’ve got Internet Explorer to compare it to.

Safari 4 Beta Kills MailMy problem, however, was that when I went to open up OS X’s Mail, the Mail program crashed. Hard.

Repeated attempts did the same thing. Open Mail, it shows the cached list of old messages, it attempts to download from the IMAP servers, and clicking anywhere causes the Mail application to implode.

It was certainly repeatable.

Two things about the crash impressed me, though.

Number one, Mail was blaming it on a Growl extension. That’s nice to know that an application can tell where it’s detecting a fault.

Number two, after a few repeated failures, it was just like Apple to automatically sense my frustration and have mail automatically ask me if I’d like to reset my preferences and try launching again.

I did. And, it didn’t work.

So, after logging a few problem reports, I decided to uninstall Safari using the Safari4.0BetaUninstall.pkg.

No surprise, Mail returned to normal, and my Growl extensions were functioning just fine.

This raises the question about what the new Safari is doing that affect Mail to begin with.

But the real point here is that this software really seems to be beta. Good beta. But still beta. If OS X Mail stops working and you don’t know why, revert to your original Safari install. I bet it’ll help.

Can any other OS X users confirm or deny this is happening to them?

CONFIRMED WITH SOLUTION: Thanks to reader comments and feedback, it’s clear the problem is with current Growl extensions not being compatible; simply remove them (see comments on how) and wait for Growl to come out with an update.

OS X Mail’s Strange Log Messages

Thursday, January 1st, 2009

A while back I installed a pretty neat Mail extension called MailTags, which was used to tag mail messages with additional information. Cool concept.

However, at the time the usage I was personally getting out of it didn’t warrant the price for the app, and I uninstalled the application after the trial period was over.

Unfortunately, things didn’t end there, because I kept getting repeated log messages like this when I looked at the console:

1/1/09 2:52:05 PM Mail[362] Cannot restore width of table column with identifier 24

It was really obvious (and annoying), as I use GeekTools to monitor my console on my desktop in order to keep a bird’s eye view on what’s happening in the background.

I found out that I was not the only other user having this problem, and the MailTags site had a solution invoked from the Terminal:

$ defaults delete com.apple.mail TableColumns

I’d done this before, but the problem resurfaced. Not sure why. And, doing it again seems to have fixed the problem, again. My log is back to normal.

Meanwhile, I discovered that that MailTags has a new version out, and perhaps I’ll give them a second chance.

I just tend to get worried when an extension appears to go deep, especially when we know Apple is about to revamp things with the next release of the OS, and cruft somehow got left behind before.

Garmin WebUpdater

Sunday, November 2nd, 2008

I own a Garmin GPSmap 60CSx in order to geoencode my photography using HoudahGeo.

Garmin now has a means up updating the firmware in their GPSs by using a WebUpdater, of which I use the version for the Mac.

I Got Myself Into Trouble
In retrospect, I got myself into trouble by starting the program, it failed to detect the GPS, to which I turn on the GPS, and plugged it into the USB port. While the WebUpdater saw the device and went to update, it stayed in the “Erasing… Do Not Unplug” state for about two hours before I got brave.

What I Did, And Boy Was I Lucky
I couldn’t cancel. I couldn’t Quit. So I had to Force Quite by using Command-Option-Escape, that at least got WebUpdater to stop. The GPS was still stating “Loader Loading…” when I pulled the USB, and when that didn’t change anything, I turned off the power to it. I wasn’t so sure I was going to see much of anything when I powered it back on.

I got lucky. I turn the power back on and I was still at the old revision. Then plugged in the USB to the computer. Then started WebUpdater, which again noticed the GPS version, downloaded the firmware again, and had no problems installing it. Seems doing things in this order works just fine.

My Plans If I Was Unlucky
Over on Bill Turner’s site, he’s written an article about Fixing a Dead Garmin GPSMap 60CSx. It seems he’s learned holding down the Power Button and the Up Arrow at the same time while starting the WebUpdater software (I think he has three hands to pull this off), he’s able to force the GPS to identify itself to the updater. Problem is, according to his instructions, you have to keep holding down these button chord during the update; some comments on the blog state it isn’t necessary, and there’ve been mixed results as to whether this works universally or not.

I’m not sure I would have had the bravery to just go killing processes plain outright, but since Bill did such a nice job of providing an alternative, I felt it was worth the risk — even if I didn’t have to go that route. Thanks Bill for blogging your GPS recovery notes.

Is AVG killing windows Remote Desktop?

Friday, September 26th, 2008

This morning Anti-Virus Guard,AVG (not the free version), decided that TRMSRV.DLL in the System32 directory was threat and copied it out of the directory.

The result was that Terminal Service no longer works. That means that software like Remote Desktop Connection 2 (RDC), can’t connect, although the machine responds to pings and Samba requests.

Placing a exception in AVG to not check that directory (sounds bad, eh?), and restoring the file from another machine seems to have temporarily address the problem.

I wonder if AVG knows about this.

We’re also seeing that Cygwin and the System Restore Point is also among the collateral damage.

UPDATE 11-Nov-2008: Looks like AVG is now flagging Windows as a virus.

LIBLDAP2 Not Installable

Wednesday, September 17th, 2008

Warning this is a very geeky entry aimed at apt-get users of Ubuntu, readers seeking humorous content should skip this post. Remember, this is a technical blog.

If you’re still with me, then I suspect you’ve just been plagued by the message:

Depends: libldap2 (>= 2.1.17-1) but it is not installable

I’m using Ubuntu 8.04 LTS Server Hardy Heron, specifically on a 64-bit AMD system.

Normally, when I do an $ sudo apt-get update things go very smoothly, but not today. Here’s what I got.

The following packages have been kept back:
alpine dovecot-common dovecot-imapd dovecot-pop3d libpq5 postgresql-8.3 texlive-base-bin trac

The following packages have unmet dependencies:
alpine: Depends: libldap2 (>= 2.1.17-1) but it is not installable
dovecot-common: Depends: libldap2 (>= 2.1.17-1) but it is not installable
Depends: libpq4 (>= 8.1.4) but it is not installable
libpq5: Depends: libldap2 (>= 2.1.17-1) but it is not installable
postgresql-8.3: Depends: libldap2 (>= 2.1.17-1) but it is not installable
texlive-base-bin: Depends: libpoppler0c2 (>= 0.4.2) but it is not installable
trac: Depends: python-genshi (>= 0.5) but it is not going to be installed
E: Broken packages

Unfortunately, where ever I went, I didn’t find a solution. [1] [2] [3]

The ‘recommended’ solution is: $ sudo apt-get -f install
This did not work for me, nor others.

Neither did: $ sudo apt-get dist-upgrade

At this point, I went on an apt-get remove and apt-get autoremove binge. This didn’t help either.

This got me into a horrible loop, where packages sysvinit-utils, sysvinit, and initscripts needed to be installed, but could not because:
Unpacking sysvinit-utils (from …/sysvinit-utils_2.86.ds1-47~bpo40+1_amd64.deb) …

dpkg: error processing /var/cache/apt/archives/sysvinit-utils_2.86.ds1-47~bpo40+1_amd64.deb (–unpack):
trying to overwrite `/usr/share/man/man1/mesg.1.gz’, which is also in package sysvutils

I even tried manually installing packages one at a time. Didn’t work. I was even so desperate as to move the file mesg.1.gz elsewhere. That didn’t work.

Then I tried the following and things got a little better:

$ sudo apt-get clean
$ sudo apt-get autoclean
$ sudo apt-get check
$ sudo apt-get purge
$ apt-get -f upgrade

But I now had a problem where packages, specifically alpine, depended on on libdlap2, and it was telling me that it couldn’t install it, so upgrading wasn’t possible.

I made the mistake of $ sudo apt-get remove alpine, which would not let me undo that mistake by reinstalling.

My hunt brought me to libldap2-dev, but while this installed, it didn’t help alpine’s dependencies.

Even with the super-duper do-everything command, nothing helped:

$ sudo apt-get update && sudo apt-get upgrade -y && sudo apt-get dist-upgrade -y

Then it dawned on me, perhaps some of the repositories that I added to /etc/apt/sources.list were giving conflicting dependencies. Luckily, I annotated heavily what I had ever added to this file.

There were only two things: Subversion, and Mono. Here they are. You want to comment out these lines:

## Subversion obtained from https://edge.launchpad.net/~clazzes.org/+archive
deb http://ppa.launchpad.net/clazzes.org/ubuntu hardy main
deb-src http://ppa.launchpad.net/clazzes.org/ubuntu hardy main

## Mono added by request of FogBugz installation
## http://www.fogcreek.com/FogBugz/docs/60/topics/setup/UnixGettingYourServerRead.html#deb
deb http://www.backports.org/debian etch-backports main contrib non-free

Then, I did a $ sudo apt-get updatee, followed by a $ sudo apt-get dist-upgrade, then a $ sudo apt-get dist-upgrade.

All of my problems were solved. No package dependency problems what-so-ever, and I was able to install alpine, and all the others, bringing me up to the latest and greatest.

Finally, I uncommented my sources.list file back to the way it was and tried the upgrade again. No errors. Everything was fine.

The solution was that something, and I don’t know which one, was causing conflicts. Reverting back to the virgin sources.list file state was enough to get Ubuntu happy to do the upgrades.

Unfortunately, since re-commenting the lines didn’t reintroduce the problem, I’m unable to tell you which repository caused the problem in the first place.

Macbook Pro Screen Goes Dark on Wakeup

Friday, June 13th, 2008

Today I learned that there’s a nifty little utility called Maintenance 3.8 out on Apple’s site. You can find it by going to Apple / Mac OS X Software…, and when the web page pops up, type Maintenance in the search box.

It’s an automator script to repair permissions, verify preferences, updating prebindings, do cleanup, update databased, rebuild indexes, empty Trash, and so forth. My guess is it’s much like Onyx.

Deciding to give it a try, I downloaded it, opened the .DMG file, and double clicked the automator icon, selecting Restart when done. And while I got a very little in the confirmation department that things were working, I saw a lot of CPU activity running utilities I was familiar with.

So, with the laptop plugged in, I left to to chug away. I heard the restart sound several minutes later. And, I ignored it.

Later, I picked up my laptop and went to login.

Nothing.

The “breathing LED” on the front was off, and nothing was responding keyboard or mouse wise. The screen was black.

So, I decided to check the battery. Full power.

But then I noticed something. At the steep angle, in the near pitch black of my LCD screen, I saw the login window. What was happening: the backlight wasn’t coming on. Fiddling with the brightness control didn’t help either.

Sure enough, I could make out the cursor once I located where it was.

I tried opening and closing the lid. Nope. Backlight still off.

So, I restarted (as I mentioned, it was operational, I could barely make out the GUI).

The machine sprang to life, showed me the blue background, and right before it went to the login screen, the backlight cut out again, leaving me in pitch black.

Titling the screen back again (with the keyboard sticking up in the air and the screen flat on the table), again I could make out the login box and mouse. I did a restart again.

This time I held down Command-V as it booted. And I watched as it came up, lots of normal diagnostic messages, and then the blue background, and right as the login screen appeared, back to pitch black.

Annoying. But now I’m wondering if all the times I’ve ever woken my laptop after a case where the lid didn’t quite clasp perfectly, was this what was happening — could the machine be up, but the backlight off?

So, one last time, I restarted. Only I held down Command-Option-P-R (four fingers) to reset the power management settings. Several chimes later, I let go, and the machine booted perfectly, and the login box appeared, backlight and all.

I’m hoping that my experience may lead to an additional piece of the puzzle about the Mac waking up funny. I would have never have noticed anything on the screen if I looked at it dead on, as I always do.

It’s fairly well known that if you close the Mac’s lid, but down engage it fully, the lid will pop back up, but not after putting the machine to sleep. At that point, it becomes a little dance with the lid, trying to get the lid back down, so that the machine can see it re-open, and that usually wakes it. But sometimes the screen is still dark, and you have to play with the power button (and if frustrated, hold it down to restart).

Sometimes this same problem manifests when you wake the machine, enter your password, and suddenly everything goes dark. You wiggle the cursor and hit the keys and nothing happens. Caps Lock toggles, but it feels like it’s gone back to sleep.

Well no more. From now on, I’m going to tilt my screen back and see if I’m operational. That way I won’t lose data from an unnecessary restart.

Loathing Dell, Hating Symantec

Thursday, May 1st, 2008

In trying to repair a Windows laptop which was acting really slow and appeared to be riddled with problems, I discovered it was running Norton / Symantec Anti-Virus.

Ugh.

It’s been shown with benchmarks that this software kills PC performance. And, in other tests, AVG, which costs less, catches more, without being a resource hog.

So, I go to uninstall Symantec, which can be a chore unto itself. But this time I was greeted with a new source of irritation.

I got a dialog box which said “Please enter the uninstall password”. Great. Just great.

So, given that this OEM laptop had paid support by Dell, I figured I’d ask.

The answer I got back was “I wasn’t aware there was a password to uninstall.”

While Dell was dodging the support question, I found this very helpful article:

http://www.mydigitallife.info/2007/05/05/hack-to-removeuninstall-symantec-norton-antivirus-sav-client-without-password/

In it, it said change the value of this registry key, HKEY_LOCAL_MACHINE\SOFTWARE\INTEL\LANDesk\VirusProtect6\CurrentVersion\Administrator Only\Security\, from 1 to 0 with RegEdit.

I tried it. It worked. No problems. Problem solved.

So, I tell the Dell Support person the point is moot, I got past it, and shared the link with him so that future customers with the same problem could have the problem solved. Isn’t that how it’s supposed to be? Learn something, and share — that way others don’t waste time down the path you traveled?

Dell’s tone instantly changed, they didn’t seem happy I got past it. And, then he tells me that Dell support doesn’t give passwords, or tell how to override them, even for OEM installed stuff; they would not be sharing the information, no matter how useful.

So, did they know about the password and just feed me a line? I was certainly left with that impression.

Incidentally, I’ve been told by an IT person, the next time I encounter the password box, enter: symantec

You’ve got to be kidding me.


Bad Behavior has blocked 391 access attempts in the last 7 days.