Wednesday, December 26, 2007

Why does my shared clipboard not work?





I used to have an issue where my clipboard would stop working. I would eventualy have to reboot my computer to fix it. I would work with remote desktop alot and the mstsc was the cause of my problems. That write up explains exactly how the clipboard would lock up.




I uncovered a program that would show me the process containing the lock and allow you to kill it. I would love to link that program, but I cant track it down. I did find another one that a microsoft MVP posted that I think does the same thing. Here is a copy of that post.




Hassan,


This has to do with some application that's having a lock over the Windows Clipboard. David Candy's application should determine the Process that's causing the problem. Download GetOpenClipboardWindow.zip from here: http://windowsxp.mvps.org/temp/GetOpenClipboardWindow.zip Unzip and run the tool. Post back what it reports. For best results, run this utility during the time you encounter the Copy<=>Paste problem.




-- Ramesh, Microsoft MVP


Windows XP Shell/User




In the end, upgrading to the RDP 6.0 client also fixes this problem in mstsc. Now that I have upgraded it, I no longer have this issue.

Monday, December 24, 2007

No accessible 'Main' method with an appropriate signature was found

I was working in a project that was a windows application, but I decided to change it to a console application instead. I changed the type to console and selected Sub Main as my startup object. When I compiled it I got the fallowing error: Error 54 No accessible 'Main' method with an appropriate signature was found.

I expected problems because I knew I did not have the Sub Main defined in my project. I added a class file and entered the fallowing code:

Public Class Main

Public Shared Sub Main()

Application.Run(New Form1)

End Sub

End Class




Several examples I saw had main defined with (ByVal args() As String) as the parameter. One thread on the subject indicated that you can add a module instead of a class. Here is the syntax for that.

Module Main

Public Sub Main(ByVal args() As String)

Application.Run(New Form1)

End Sub

End Module




You will notice that the shared keyword is left off inside the module.

Saturday, December 22, 2007

Mapping a drive with custom name

When mapping a drive, the full path of the share is displayed as the name of the drive. We have some very long path names and didn't want our users to see the details they didn't need. So I had to write a script to give those drives custom names.

Our login scripts contained lots of net use statements in *.BAT or *.CMD files. The command looked like this:
NET USE H: //server/share/directory1/directory2/directory3


and it would show in explorer like this:
directory3 on //server/share/directory1/directory2 (H:)


My goal was to make a script just as easy to use at NET USE. That is exactly what I ended up with. The new command looks like this:
Map.vbs H: //server/share/directory1/directory2/directory3 "My directory3"


and it would map like this:
My directory3 (H:)

By making the command simple the scripts are easy to read and modify by others on my team. Now that you know what we are doing, lets take a look at the code needed to make this work.

We are going to save this code with the name Map.vbs. Its a VBScript file executed by the windows scripting host. To make the script more usable, it needs to read the variables from the command line. The first 3 lines populate the variables we will use later.

strDriveLetter = WScript.Arguments(0)
strPath = WScript.Arguments(1)
strDisplayName = WScript.Arguments(2)


The next 2 lines I am going to show you display how to map the drive.

Set objNetwork = CreateObject("WScript.Network")
objNetwork.MapNetworkDrive strDriveLetter, strPath, true


This will map the path strPath to the drive strDriveLetter. The true as the 3rd param is the same as using the /PERSIST param of NET USE. It saves the mapping in the profile.

Now we need to change the name of the mapping. This takes an existing share by drive letter and gives it a custom display name. This was one of the hardest pieces of code to find. The next 2 lines do just that.

Set oShell = CreateObject("Shell.Application")
oShell.NameSpace(strDriveLetter & "\").Self.Name = strDisplayName


If you put that all together you have a bare bones script to map a drive and rename it from the command line via a VBScript. In my next post, I plan on going more in depth into my map.vbs. I will show you how to check for an existing mapping on that letter and all the validation I added.

Tuesday, December 18, 2007

.NET accessing embeded files in your project

I had some files that I wanted to embed into my project and access in code. I needed both images and xml files.



First you have to add the files to the project. I create the images in paint before importing them. The xml files were created within Visual Studio. Things started to look a little cluttered, so I created folders in the project to group them up.



Once the files are in place you need to open the properties for each one. Change the build action to "Embedded Resource". Now we can access the file streams from code.




image warningImage = new Bitmap(this.GetType().Assembly.GetManifestResourceStream("Application1.images.warning.bmp"));


StreamReader xmlFile = new StreamReader(this.GetType().Assembly.GetManifestResourceStream("Application1.foldername.template.xml"));


GetManifestResourceStream returns a stream. There is a overload for the bitmap constructor that takes a stream if its an image you are working with.

Friday, December 14, 2007

NullReferenceException raising an event in C#

I was working with events in C# and ran into this exception. System.NullReferenceException was unhandled Message="Object reference not set to an instance of an object." This exception was at the exact point in my code where I attempted to raise the event. It turns out that if there are not event handlers attached to your event, an attempt to raise it will give you this exception. To solve it, you have to check to see if its null before raising it.


public class TestEvent{
public event EventHandler MyEvent;
public void RaiseMyEvent(){
if(MyEvent != null){
MyEvent(this, null);
}
}
}


All the samples I was looking at did not check for a null value, so neither did I. Now that I had the problem, I see why I need to check.

Sunday, December 09, 2007

Running vbs from .net code

There are a few ways to run vbscript inside vb.net. If you just need the script to run, you can use the process object.


Dim oProcess as new Process
Try
oProcess.StartInfo.UseShellExecute = True
oProcess.StartInfo.FileName = "CScript c:\script.vbs //nologo"
oProcess.Start()
oProcess.WaitForExit()
Finally
oProcess.Dispose()
End Try

Process Class

If you have some VBScript that you want to intereact with variables or run on the fly. Microsoft has a ScriptControl that allows you to do just that. The script control has 3 options of running code.
  • Eval: Evaluates a text expression.
  • Run: Runs a named Sub or Function.
  • Execute: Executes a script statement.

You can find more information on the ScriptControl at Microsoft.
Q184740: How To Call Functions Using the Script Control
Q184739: INFO: Where to Obtain the Script Control


If you are looking to run vb.net code inside vbscript, see my other post:
Running VB.NET code in VBScript or other apps

Friday, December 07, 2007

Raising an event in C#

Here is the simplest way to raise an event.


public class TestEvent{
public event EventHandler MyEvent;
public void RaiseMyEvent(){
MyEvent(this, null);
}
}


This uses the default EventHandler that returns a object source and a EventArgs ex. If you want to pass back different parameters, you will need to create your own delegate. The delegate we just used looks like this:

public delegate void EventHandler (object source, EventArgs ex);



We dont have to define it because .NET already defined it for us. Here is a second example where we built a custom delegate and raise it.


public delegate void MyCustomEventHandler (string message);

public class TestEvent2{
public event MyCustomEventHandler MyEvent2;
public void RaiseMyEvent(){
MyEvent2("Message sent with event");
}
}


Now that I explained how to raise events, there is a bug in that code. I'm saving that for my next post: NullReferenceException raising an event in C#