What's wrong with this picture?
This is a postcard a coworker received from our freshly re-elected governor.
I like the attempt to include us yoopers. Unfortunately, well, I dunno. I've lived here a while, and something just doesn't seem right. Let's consult maps of Michigan at Google Images. (Go look.)
What really thrills my coworker is the shear number of hands this photo must have gone through before getting printed and *NOBODY* noticed it. Show anyone here in the U.P. this picture and they catch what's wrong instantly.
Now, I wasn't impressed with either candidate in this last election, but, well, who the heck is representing us?
UPDATE: I got a better copy of the picture...
Technorati Tags: michigan, upper peninsula, granholm, christmas card, mitten, politics, governor
Thursday, December 21, 2006
Friday, November 17, 2006
VS2005 Pro FxCop Integration
This is mostly for my own "Hey, don't forget this link" purposes, but it's also for any of you whom, like me, aren't cool enough to have VS2005 Team Edition:
Integrating FxCop into VS2005 Professional Edition
Pretty nifty!
Integrating FxCop into VS2005 Professional Edition
Pretty nifty!
Monday, September 25, 2006
T.E.D.D.Y.
James sent me a link to a video demonstration of something called "T.E.D.D.Y." -- a simple 3D modeling program.
The link James sent me linked back to another blog that had found TEDDY, and that blog had a link to the original work, which can be found by clicking here.
Check out the video of TEDDY in action:
The link James sent me linked back to another blog that had found TEDDY, and that blog had a link to the original work, which can be found by clicking here.
Check out the video of TEDDY in action:
Wednesday, August 30, 2006
Thursday, August 17, 2006
Classical Music Remixes
I'm in no way a music aficionado, and I have very specific likes and dislikes. Sometimes I like certain songs by a certain band, but really dislike the majority of other music in the same genre. It's weird.
One type of music I like almost 100% across the board is classical. I'm not a huge fan of overly-chamber-ish classical, and I don't really go outta my way to listen to classical. It's just decent background music. (No vocals == good background noise as far as I'm concerned.)
Now, remixed classical? I really like that. Check out this YouTube video for an example:
I'd really like to hear more remixes by this guy. Does anybody have any leads?
UPDATE: I found this YouTube vid because of digg.com, click here to digg-it. In the comments, someone has a link to JerryC's website. (I thought it was JerryL.). Anyway:
JerryC (mostly-English)
Collection of all his vides.
One type of music I like almost 100% across the board is classical. I'm not a huge fan of overly-chamber-ish classical, and I don't really go outta my way to listen to classical. It's just decent background music. (No vocals == good background noise as far as I'm concerned.)
Now, remixed classical? I really like that. Check out this YouTube video for an example:
I'd really like to hear more remixes by this guy. Does anybody have any leads?
UPDATE: I found this YouTube vid because of digg.com, click here to digg-it. In the comments, someone has a link to JerryC's website. (I thought it was JerryL.). Anyway:
JerryC (mostly-English)
Collection of all his vides.
Wednesday, July 19, 2006
Debugging Threads In VS2005? Woe To Thee!
Ok folks, this is mostly a post for my own personal use. Basically, so the next time I run into the problem, I'll remember that I wrote this post. :)
While the title is misleading -- debugging in VS2005, especially debugging when debugging multithreaded apps. I've just ran into a problem though.
See, I'd set a breakpoint inside some code that's executing on another thread. When the breakpoint hits, VS2005 just sits there for about 10 seconds. It's like it's dead. Then, after it comes-to, if I try to step-through, or step-into any code after the breakpoint weird things happen. Like, it doesn't step-forward into the code. And while the IDE indicates the app is still in a 'paused' state, it certainly doesn't have any instruction pointer, nor does the "Threads" debugger panel indicate that your extra thread even exists anymore! Hitting "F5" and letting it go about it's business doesn't help either -- the app is now in some sort of voodoo-ized state.
The only solution is to stop the app and restart it.
This still doesn't help the fact that I can't debug any code running on a non-main/UI thread!
What to do?
Off to the MSDN forums for me!
Here's a post that helped me: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=285644&SiteID=1
That post links to this post:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=147707&SiteID=1
And that post links to this blog:
http://blogs.msdn.com/greggm/archive/2005/11/18/494648.aspx
Basically, what's happening is the debugger is trying to peek at all the local variables in order to 'help you' debug. Unfortunately, access the GUI objects created on the main/UI thread from another thread is bad juju, and the debugger hangs when it hits a breakpoint while trying to probe values from objects owned by the UI thread. Why it screws everything else up, I don't know.
BUT, I've come up with a solution not listed in the above links -- disable/close/don't-look-at the "Locals" debugging panel. If that panel isn't visible, the debugger won't waste time poking-n-prodding all the objects found in the current scope, and you'll avoid the problem entirely. :)
While the title is misleading -- debugging in VS2005, especially debugging when debugging multithreaded apps. I've just ran into a problem though.
See, I'd set a breakpoint inside some code that's executing on another thread. When the breakpoint hits, VS2005 just sits there for about 10 seconds. It's like it's dead. Then, after it comes-to, if I try to step-through, or step-into any code after the breakpoint weird things happen. Like, it doesn't step-forward into the code. And while the IDE indicates the app is still in a 'paused' state, it certainly doesn't have any instruction pointer, nor does the "Threads" debugger panel indicate that your extra thread even exists anymore! Hitting "F5" and letting it go about it's business doesn't help either -- the app is now in some sort of voodoo-ized state.
The only solution is to stop the app and restart it.
This still doesn't help the fact that I can't debug any code running on a non-main/UI thread!
What to do?
Off to the MSDN forums for me!
Here's a post that helped me: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=285644&SiteID=1
That post links to this post:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=147707&SiteID=1
And that post links to this blog:
http://blogs.msdn.com/greggm/archive/2005/11/18/494648.aspx
Basically, what's happening is the debugger is trying to peek at all the local variables in order to 'help you' debug. Unfortunately, access the GUI objects created on the main/UI thread from another thread is bad juju, and the debugger hangs when it hits a breakpoint while trying to probe values from objects owned by the UI thread. Why it screws everything else up, I don't know.
BUT, I've come up with a solution not listed in the above links -- disable/close/don't-look-at the "Locals" debugging panel. If that panel isn't visible, the debugger won't waste time poking-n-prodding all the objects found in the current scope, and you'll avoid the problem entirely. :)
Tuesday, June 27, 2006
SQL MythBusters – MSDE/SQL Express has a 5 concurrent user limit
Having worked with various versions of MS SQL Server for a number of years now, (6.5, 7.0, 2000, 2005,) and the verious MSDE and 'Express' editions of the product, I found this following link interesting:
Euan Garden's BLOG : SQL MythBusters – MSDE/SQL Express has a 5 concurrent user limit
That '5 Concurrent User' limit has always been difficult to explain to our users...mostly because what we were explaining was never clearly explained to us... But anyway, I won't ramble on forever.
Euan Garden's BLOG : SQL MythBusters – MSDE/SQL Express has a 5 concurrent user limit
That '5 Concurrent User' limit has always been difficult to explain to our users...mostly because what we were explaining was never clearly explained to us... But anyway, I won't ramble on forever.
Wednesday, April 05, 2006
Use Firefox? Hate the memory leak?
Found this, and figured it was worth sharing.
This May Help Your Firefox Memory Leak
Technorati Tags: firefox, memory leak, tweak
This May Help Your Firefox Memory Leak
Technorati Tags: firefox, memory leak, tweak
Monday, April 03, 2006
System.Runtime.Serialization.SerializationInfo -- .KeyExists()?
The Problem:
There are a number of collection-like objects in the .NET Framework that allow you to 'key' the data you enter into them. Dictionary<TKey,TValue> comes to mind almost immediately. Dictionary<TKey,TValue> contains a Dictionary<TKey,TValue>.ContainsKey(T key) method that makes key-existance determination trivial.
But what about the SerializationInfo object?
When an object implements ISerializable the ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) method adds the object's data to the serialization stream in a key/value style:
info.AddValue("MyObjectsValueKey", this._MyValue);
Then, during deserialization, the constructor that meets the ISerializable implied-constructor signature:
MyObject(SerializationInfo info, StreamingContext context)
is called, and the object is supposed to bootstrap itself from the data contained in the SerializationInfo instance.
How? By retrieving values based on the previously used string-keys, of course.
So, why isn't there a SerializationInfo.KeyExists(string key) method?
I hear some of you saying "Well, it's the serialization of an object, you had better know what's was serialized in the first place!" True, very true. But, consider a versioning issue that might arise:
Example (version 1):
Assume you have a business object that implements ISerializable. For this example, let's call that business object MyObject. In your first version of MyObject, you have some code that looks like this (large portions of code left out to save space):
As you can see, MyObject has an internal List<T> of OtherObject's. It exposes a property that returns whatever the 'current' OtherObject is, based upon a private index into the _MyOtherObjects List<T>.
The serialization code is fairly straight forward.
Now, let's say, somewhere in the development of the version 2, we find a bug related to _CurrentOtherObjectIndex not being updated properly when instances OtherObject are being inserted into the _OtherObjects List<T> at various locations, thereby possibly invalidating the OtherObject pointed to by _CurrentOtherObjectIndex.
Instead of updating the various code locations that would need to update _CurrentOtherObjectIndex we decide it would be better to just replace _CurrentOtherObjectIndex with an OtherObject instance. ie:
Ahhhh, but making this change would break the compatiblity between version 1 and version 2 of MyObject. Oh, but wait, we're handling the serialization ourselves, we should be able to code around it.
[Let's ignore any possible versioning issues involved with strong-naming, let's just assume the version 2 code tries to deserialize a version 1 MyObject.]
So, ideally, we could change the ISerializable implementation to look like this:
Unfortunately, we can't do this because there is no SerializationInfo.ContainsKey(string key) method! What we have to do is this:
We have to rely on an exception as part of our 'normal' code path. This feels 'icky' to me. ("Icky" being a highly technical term that means many things at different times. In this case, 'icky' means "goes against my 'best-practices' sense". Exceptions should be exactly that: an unexpected error condition. In the course of a normal deserialization, we have decided that being able to deserialize v1 MyObject instances into v2 MyObject instances is a completely normal operation. We should not have to rely on an Exception to perform normal work. And if we have a situation where v2 MyObject code may be deserializing a large amount of v1 MyObjects, we can expect it to be much slower as well because the Exception handling system carries a heavy tax.
One Possible Solution
One solution is to have any object that implements ISerializable also serialize some for of version information. Whether this version information is culled from the assembly versioning info, or is a private field of the class is completely up to your implementation. In the following modification to MyObject, MyObject will store it's own versioning information.
So, again from the top, version 1 of MyObject:
And the updated version 2 of MyObject:
Tada. Clean, deterministic deserialization of version 1 and 2 MyObject instances.
Wrap-Up
So, does anyone out there know why there isn't a
SerializationInfo.ContainsKey(string key)
method? As with many things that I've learned about the .NET Framework, what at first seems obtuse to me usually has a very good explanation behind it.
I gotta give thanks to Mr. DotNet who has helpd me through those mentally-obtuse times. He really knows his stuff. I was hoping to be able to use his SyntaxHighlighter (*nudge*-*nudge*) to make my code a bit more readable. Maybe in a future update!
Technorati Tags: iserializable, serializable, versioning, visual studio 2005, dotnet
There are a number of collection-like objects in the .NET Framework that allow you to 'key' the data you enter into them. Dictionary<TKey,TValue> comes to mind almost immediately. Dictionary<TKey,TValue> contains a Dictionary<TKey,TValue>.ContainsKey(T key) method that makes key-existance determination trivial.
But what about the SerializationInfo object?
When an object implements ISerializable the ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) method adds the object's data to the serialization stream in a key/value style:
info.AddValue("MyObjectsValueKey", this._MyValue);
Then, during deserialization, the constructor that meets the ISerializable implied-constructor signature:
MyObject(SerializationInfo info, StreamingContext context)
is called, and the object is supposed to bootstrap itself from the data contained in the SerializationInfo instance.
How? By retrieving values based on the previously used string-keys, of course.
So, why isn't there a SerializationInfo.KeyExists(string key) method?
I hear some of you saying "Well, it's the serialization of an object, you had better know what's was serialized in the first place!" True, very true. But, consider a versioning issue that might arise:
Example (version 1):
Assume you have a business object that implements ISerializable. For this example, let's call that business object MyObject. In your first version of MyObject, you have some code that looks like this (large portions of code left out to save space):
[Serializable]
public sealed class MyObject : ISerializable {
private List<OtherObject> _OtherObjects;
private Int32 _CurrentOtherObjectIndex;
public OtherObject CurrentOtherObject {
get { return this._OtherObjects[_CurrentOtherObjectIndex]; }
set { this._CurrentOtherObjectIndex = this._OtherObjects.IndexOf(value); }
}
private const string OTHEROBJECTS_KEY = "___otherobjetskey___";
private const string INDEX_KEY = "___indexkey___";
private MyObject(SerializationInfo info, StreamingContext context) {
this._OtherObjects = (List<OtherObject>)info.GetValue(OTHEROBJECTS_KEY, typeof(List<OtherObject>));
this._CurrentOtherObjectIndex = info.GetInt32(INDEX_KEY);
}
private void GetObjectData(SerializationInfo info, StreamingContext context) {
info.AddValue(OTHEROBJECTS_KEY, this._OtherObjects);
info.AddValue(INDEX_KEY, this._CurrentOtherObjectIndex);
}
}
As you can see, MyObject has an internal List<T> of OtherObject's. It exposes a property that returns whatever the 'current' OtherObject is, based upon a private index into the _MyOtherObjects List<T>.
The serialization code is fairly straight forward.
Now, let's say, somewhere in the development of the version 2, we find a bug related to _CurrentOtherObjectIndex not being updated properly when instances OtherObject are being inserted into the _OtherObjects List<T> at various locations, thereby possibly invalidating the OtherObject pointed to by _CurrentOtherObjectIndex.
Instead of updating the various code locations that would need to update _CurrentOtherObjectIndex we decide it would be better to just replace _CurrentOtherObjectIndex with an OtherObject instance. ie:
[Serializable]
public sealed class MyObject : ISerializable {
private List<OtherObject> _OtherObjects;
private OtherObject _CurrentOtherObject;
public OtherObject CurrentOtherObject {
get { return this._CurrentOtherObject; }
set { this._CurrentOtherObject = value; }
}
}
Ahhhh, but making this change would break the compatiblity between version 1 and version 2 of MyObject. Oh, but wait, we're handling the serialization ourselves, we should be able to code around it.
[Let's ignore any possible versioning issues involved with strong-naming, let's just assume the version 2 code tries to deserialize a version 1 MyObject.]
So, ideally, we could change the ISerializable implementation to look like this:
private const string OTHEROBJECTS_KEY = "___otherobjetskey___";
private const string INDEX_KEY = "___indexkey___"; // we need the v1 key
private const string CURRENTOTHEROBJECT_KEY = "___currentotherobjectkey___";
private MyObject(SerializationInfo info, StreamingContext context) {
this._OtherObjects = (List<OtherObject>)info.GetValue(OTHEROBJECTS_KEY, typeof(List<OtherObject>));
if (info.ContainsKey(INDEX_KEY)) {
// we're deserializing a version-1 MyObject. Update it to version-2
Int32 tmpIndex = info.GetInt32(INDEX_KEY);
this._CurrentOtherObject = this._OtherObjects[tmpIndex];
} else {
// we're deserializing a version-2 MyObject. Just get the deserialize the CurrentOtherObject
this._CurrentOtherObject = (OtherObject)info.GetValue(CURRENTOTHEROBJECT_KEY, typeof(OtherObject));
}
}
private void GetObjectData(SerializationInfo info, StreamingContext context) {
info.AddValue(OTHEROBJECTS_KEY, this._OtherObjects);
info.AddValue(CURRENTOTHEROBJECT_KEY, this._CurrentOtherObject);
}
Unfortunately, we can't do this because there is no SerializationInfo.ContainsKey(string key) method! What we have to do is this:
private MyObject(SerializationInfo info, StreamingContext context) {
this._OtherObjects = (List<OtherObject>)info.GetValue(OTHEROBJECTS_KEY, typeof(List<OtherObject>));
try {
this._CurrentOtherObject = (OtherObject)info.GetValue(CURRENTOTHEROBJECT_KEY, typeof(OtherObject));
} catch (SerializationException) {
// we're deserializing a version-1 MyObject. Update it to version-2
Int32 tmpIndex = info.GetInt32(INDEX_KEY);
this._CurrentOtherObject = this._OtherObjects[tmpIndex];
}
}
We have to rely on an exception as part of our 'normal' code path. This feels 'icky' to me. ("Icky" being a highly technical term that means many things at different times. In this case, 'icky' means "goes against my 'best-practices' sense". Exceptions should be exactly that: an unexpected error condition. In the course of a normal deserialization, we have decided that being able to deserialize v1 MyObject instances into v2 MyObject instances is a completely normal operation. We should not have to rely on an Exception to perform normal work. And if we have a situation where v2 MyObject code may be deserializing a large amount of v1 MyObjects, we can expect it to be much slower as well because the Exception handling system carries a heavy tax.
One Possible Solution
One solution is to have any object that implements ISerializable also serialize some for of version information. Whether this version information is culled from the assembly versioning info, or is a private field of the class is completely up to your implementation. In the following modification to MyObject, MyObject will store it's own versioning information.
So, again from the top, version 1 of MyObject:
[Serializable]
public sealed class MyObject : ISerializable {
private static Int32 Version = 1;
private List<OtherObject> _OtherObjects;
private Int32 _CurrentOtherObjectIndex;
public OtherObject CurrentOtherObject {
get { return this._OtherObjects[_CurrentOtherObjectIndex]; }
set { this._CurrentOtherObjectIndex = this._OtherObjects.IndexOf(value); }
}
private const string VERSION_KEY = "___version___";
private const string OTHEROBJECTS_KEY = "___otherobjetskey___";
private const string INDEX_KEY = "___indexkey___";
private MyObject(SerializationInfo info, StreamingContext context) {
this._OtherObjects = (List<OtherObject>)info.GetValue(OTHEROBJECTS_KEY, typeof(List<OtherObject>));
// version 1 doesn't care about the VERSION_KEY value because it is the first version
this._CurrentOtherObjectIndex = info.GetInt32(INDEX_KEY);
}
private void GetObjectData(SerializationInfo info, StreamingContext context) {
info.AddValue(VERSION_KEY, MyObject.Version);
info.AddValue(OTHEROBJECTS_KEY, this._OtherObjects);
info.AddValue(INDEX_KEY, this._CurrentOtherObjectIndex);
}
}
And the updated version 2 of MyObject:
[Serializable]
public sealed class MyObject : ISerializable {
private static Int32 Version = 2;
private List<OtherObject> _OtherObjects;
private OtherObject _CurrentOtherObject;
public OtherObject CurrentOtherObject {
get { return this._CurrentOtherObject; }
set { this._CurrentOtherObject = value; }
}
private MyObject(SerializationInfo info, StreamingContext context) {
Int32 streamVersion = info.GetInt32(VERSION_KEY);
this._OtherObjects = (List<OtherObject>info.GetValue(OTHEROBJECTS_KEY, typeof(List<OtherObject>
if (streamVersion == 2) {
this._CurrentOtherObject = (OtherObject)info.GetValue(CURRENTOTHEROBJECT_KEY, typeof(OtherObject));
} else {
Int32 tmpIndex = info.GetInt32(INDEX_KEY);
this._CurrentOtherObject = this._OtherObjects[tmpIndex];
}
}
private void GetObjectData(SerializationInfo info, StreamingContext context) {
info.AddValue(VERSION_KEY, MyObject.Version);
info.AddValue(OTHEROBJECTS_KEY, this._OtherObjects);
info.AddValue(CURRENTOTHEROBJECT_KEY, this._CurrentOtherObject);
}
Tada. Clean, deterministic deserialization of version 1 and 2 MyObject instances.
Wrap-Up
So, does anyone out there know why there isn't a
SerializationInfo.ContainsKey(string key)
method? As with many things that I've learned about the .NET Framework, what at first seems obtuse to me usually has a very good explanation behind it.
I gotta give thanks to Mr. DotNet who has helpd me through those mentally-obtuse times. He really knows his stuff. I was hoping to be able to use his SyntaxHighlighter (*nudge*-*nudge*) to make my code a bit more readable. Maybe in a future update!
Technorati Tags: iserializable, serializable, versioning, visual studio 2005, dotnet
Friday, March 31, 2006
The Top 10 weirdest keyboards ever - Fosfor Gadgets
I know I've blogged about weird keyboards before, so why not again? :)
The Top 10 weirdest keyboards ever - Fosfor Gadgets
I think #6 looks interesting, and I wouldn't mind trying it once, but for normal use? No thanks.
A couple coworkers have bad wrist problems and have keyboard #8.
What am I using right now? A Microsoft Ergonomic 4000.
It's relatively similar to the original Microsoft Natural, but the key layout is slightly modified -- more relaxed I guess. I like the sexy-black color and the soft foamy wrist wrest. I'm not sure about all the extra buttons on the keyboard though. At least they're kept to a relative minimum, and are out of the way, on this keyboard.
Anyway....
Technorati Tags: weird, ergonomic, keyboards
The Top 10 weirdest keyboards ever - Fosfor Gadgets
I think #6 looks interesting, and I wouldn't mind trying it once, but for normal use? No thanks.
A couple coworkers have bad wrist problems and have keyboard #8.
What am I using right now? A Microsoft Ergonomic 4000.
It's relatively similar to the original Microsoft Natural, but the key layout is slightly modified -- more relaxed I guess. I like the sexy-black color and the soft foamy wrist wrest. I'm not sure about all the extra buttons on the keyboard though. At least they're kept to a relative minimum, and are out of the way, on this keyboard.
Anyway....
Technorati Tags: weird, ergonomic, keyboards
Wednesday, March 29, 2006
Problem during ClickOnce deployment.
I just finished figuring out a problem I was having with a ClickOnce deployment for a project I've been working on.
This project has a reference to ADODB.dll -- a Primary Interop Reference provided by Microsoft in the .NET Framework SDK. Unfortunately, that PIA isn't provided in the .NET Framework redistributable. Also, unfortunately, setting the adodb.dll to copy-local during the project-build process didn't help during ClickOnce deployment -- the ADODB.dll was specified as needing to be installed into the GAC before my app would install.
I did some searching around, and stumbled upon this post as the MSDN ClickOnce forums:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=323832&SiteID=1
You can find my response there, but if you're averse to clicking, read-on.
Basically, the problem boils down to the default ClickOnce publishing behavior for the ADODB PIA. For whatever reason, it marks the ADODB PIA as a pre-requisite in the applications .manifest file. This means that ClickOnce requires the ADODB PIA to be installed into the GAC before it will allow my app to be installed. Unfortunately, none of the bootstrapper pre-reqs installed the PIA into the GAC, (making one of those pre-req bootstrapper installers is a possible solution, and I mention it in the reply, but it's not the easiest solution.)
What fixes is the problem is modifying the 'Publish Status' of the ADODB.dll
in the project's ClickOnce publishing settings. You change ADODB.dll's publish-status from the default "Include (Auto)" to "Include".
Yes.
Change it from one setting to another setting that appears to be the exact same setting.
Re-publish. The applications .manifest now specifies ADODB.dll to 'install' -- which will cause ClickOnce to copy it to the install folder, instead of requiring it be installed into the GAC.
Here's a couple screen shots for ya:
Bring up your Project Properties Page, and go to the Publish tab. Click the "Application Files..." button:
In the dialog that pops up, set ADODB.dll's Publish Status to Include:
This project has a reference to ADODB.dll -- a Primary Interop Reference provided by Microsoft in the .NET Framework SDK. Unfortunately, that PIA isn't provided in the .NET Framework redistributable. Also, unfortunately, setting the adodb.dll to copy-local during the project-build process didn't help during ClickOnce deployment -- the ADODB.dll was specified as needing to be installed into the GAC before my app would install.
I did some searching around, and stumbled upon this post as the MSDN ClickOnce forums:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=323832&SiteID=1
You can find my response there, but if you're averse to clicking, read-on.
Basically, the problem boils down to the default ClickOnce publishing behavior for the ADODB PIA. For whatever reason, it marks the ADODB PIA as a pre-requisite in the applications .manifest file. This means that ClickOnce requires the ADODB PIA to be installed into the GAC before it will allow my app to be installed. Unfortunately, none of the bootstrapper pre-reqs installed the PIA into the GAC, (making one of those pre-req bootstrapper installers is a possible solution, and I mention it in the reply, but it's not the easiest solution.)
What fixes is the problem is modifying the 'Publish Status' of the ADODB.dll
in the project's ClickOnce publishing settings. You change ADODB.dll's publish-status from the default "Include (Auto)" to "Include".
Yes.
Change it from one setting to another setting that appears to be the exact same setting.
Re-publish. The applications .manifest now specifies ADODB.dll to 'install' -- which will cause ClickOnce to copy it to the install folder, instead of requiring it be installed into the GAC.
Here's a couple screen shots for ya:
Bring up your Project Properties Page, and go to the Publish tab. Click the "Application Files..." button:
In the dialog that pops up, set ADODB.dll's Publish Status to Include:
Subscribe to:
Posts (Atom)