It is occasionally necessary to do some heavy computing such as image manipulation while inside a VBScript.  Since script isn't suited to this purpose, the way I've accomplished this in the past is to build a c# COM complaint .dll file and reference it from the script.  Then the COM file can do the real processing.  The downside here is the fact that the .dll needs to be copied to and registered on every machine that might run this script.  In one instance that was not practical.

Here is an alternate solution where the VBScript calls a .NET webservice which responds with a binary file.  The VBScript then decodes that and saves it to disk.  All of this is accomplished using native Windows objects Microsoft.XMLHTTP, Microsoft.XMLDOM and Scripting.FileSystemObject.  This particular example service takes a string from the VBScript caller, creates a TIFF image with that string printed in the middle of it and returnes the completed TIFF to the VBScript.

You'll notice that the base64 encoding is automatically generated by the webservice. The return type is actually byte[], but the results from this call will be in xml 1.0. The VBScript is expecting this and selects the response node and decodes the base64 encoding. The base64 decoding functionality was lifted from this board http://www.visualbasicscript.com/m35754.aspx posted by member DiGiTAL.SkReAM. Thanks.

The VBScript code:


Dim xmlhttp: Set xmlhttp = CreateObject("Microsoft.XMLHTTP")
xmlhttp.Open "POST","http://serviceserver/service1.asmx",false
xmlhttp.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
xmlhttp.send "str=THISISMYPOSTINGDATA"

If xmlhttp.Status <> 200 Then
MsgBox "Server response error " & xmlhttp.status & ". " & xmlhttp.statusText & ") " & vbcrlf & "Response: " & xmlhttp.responseText
End If
Dim objFileSystem: Set objFileSystem = CreateObject("Scripting.FileSystemObject")
Dim objFile: Set objFile = objFileSystem.CreateTextFile("c:\testoutput.tiff", True)
Dim response: response = xmlhttp.responseText

Dim xmlDoc: Set xmlDoc = CreateObject("Microsoft.XMLDOM")
xmlDoc.loadxml(xmlhttp.responseText)
Dim responseNode: Set responseNode = xmlDoc.selectSingleNode("//base64Binary")

objFile.write fDecode(responseNode.text)

Set objFile = Nothing
Set objFileSystem = Nothing
Set xmlhttp = Nothing

'The fDecode base64 decoding functionality was lifted from this board http://www.visualbasicscript.com/m35754.aspx posted by member DiGiTAL.SkReAM. It is a concise and fairly speedy base64 decoder

Function fDecode(sStringToDecode)
'This function will decode a Base64 encoded string and returns the decoded string.
'This becomes usefull when attempting to hide passwords from prying eyes.
Const CharList = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
Dim iDataLength, sOutputString, iGroupInitialCharacter
sStringToDecode = Replace(Replace(Replace(sStringToDecode, vbCrLf, ""), vbTab, ""), " ", "")
iDataLength = Len(sStringToDecode)
If iDataLength Mod 4 <> 0 Then
fDecode = "Bad string passed to fDecode() function."
Exit Function
End If
For iGroupInitialCharacter = 1 To iDataLength Step 4
Dim iDataByteCount, iCharacterCounter, sCharacter, iData, iGroup, sPreliminaryOutString
iDataByteCount = 3
iGroup = 0
For iCharacterCounter = 0 To 3
sCharacter = Mid(sStringToDecode, iGroupInitialCharacter + iCharacterCounter, 1)
If sCharacter = "=" Then
iDataByteCount = iDataByteCount - 1
iData = 0
Else
iData = InStr(1, CharList, sCharacter, 0) - 1
If iData = -1 Then
fDecode = "Bad string passed to fDecode() function."
Exit Function
End If
End If
iGroup = 64 * iGroup + iData
Next
iGroup = Hex(iGroup)
iGroup = String(6 - Len(iGroup), "0") & iGroup
sPreliminaryOutString = Chr(CByte("&H" & Mid(iGroup, 1, 2))) & Chr(CByte("&H" & Mid(iGroup, 3, 2))) & Chr(CByte("&H" & Mid(iGroup, 5, 2)))
sOutputString = sOutputString & Left(sPreliminaryOutString, iDataByteCount)
Next
fDecode = sOutputString
End Function

The c# webservice code:

public class Service1 : System.Web.Services.WebService {
[WebMethod]
public byte[] makeBitmap(string str) {
string fontName = "Garamond";
using (Bitmap bmp = new Bitmap(1500, 2000)) {
using (Graphics gfx = Graphics.FromImage((Image)bmp)) {
gfx.SmoothingMode = SmoothingMode.AntiAlias;
Font font = new Font(fontName, 18, FontStyle.Regular, GraphicsUnit.Pixel);

gfx.FillRectangle(Brushes.White, new Rectangle(0, 0, bmp.Width, bmp.Height));

char[] separator = new char[1];
separator[0] = '~';
string[] strs = str.Split(separator);
int counter = 1;
foreach (string s in strs) {
SizeF sz = gfx.MeasureString(s, font);
Rectangle rcText = new Rectangle(0, 0, (int)sz.Width + 5, (int)sz.Height + 5);
rcText.Offset((bmp.Width - rcText.Width) / 2, ((bmp.Height - rcText.Height) / 3) + (int)(sz.Height * counter));

StringFormat strFormat = new StringFormat();
gfx.DrawString(s, font, new SolidBrush(Color.Black), rcText, strFormat);
counter++;
}

MemoryStream ms = new MemoryStream();
ImageCodecInfo myImageCodecInfo;
Encoder myEncoder;
EncoderParameter myEncoderParameter;
EncoderParameters myEncoderParameters;

myImageCodecInfo = GetEncoderInfo("image/tiff");
myEncoder = Encoder.Compression;
myEncoderParameters = new EncoderParameters(1);
myEncoderParameter = new EncoderParameter(myEncoder,(long)EncoderValue.CompressionLZW);
myEncoderParameters.Param[0] = myEncoderParameter;
bmp.Save(ms, myImageCodecInfo, myEncoderParameters);

// Save to memory using the Jpeg format

// read to end
byte[] bmpBytes = ms.GetBuffer();
bmp.Dispose();
ms.Close();
//string returnString = System.Text.ASCIIEncoding.ASCII.GetString(bmpBytes);
return bmpBytes;
}
}
}


private static ImageCodecInfo GetEncoderInfo(String mimeType) {
int j;
ImageCodecInfo[] encoders;
encoders = ImageCodecInfo.GetImageEncoders();
for (j = 0; j < encoders.Length; ++j) {
if (encoders[j].MimeType == mimeType)
return encoders[j];
}
return null;
}
}

 

The button rollovers using .hover with JQuery look great, but what about when the buttons will be created dynamically.  In this instance, the buttons are in a column in a table.  Additional table rows are created programmatically while using the form.  How can you add a .hover event to your newly created buttons?

I've found a really simple answer to this problem.

When the DOM is loaded (check this with the document.ready function) this attaches a listener to every object of class ro-button.  The listener responds to mouse movement over that element by executing a block of code which checks a variable in the data object (this will prevent us from attaching the listener twice) and then adding a hover event to the object.  The hover event takes as parameters a function to execute when that object is hovered and un-hovered.  In this case, we are applying the class ui-state-active and then removing it.

$(document).ready(function() { $('.ro-button').live("mousemove", function() { if (!$(this).data("init")) { $(this).data("init", true); jQuery(this).hover( function(){ $(this).addClass("ui-state-active"); }, function(){ $(this).removeClass("ui-state-active"); } ) } }); });

Hopefully others will find this useful as well.

 

I was working on an c#project and needed to add a lightweight deployable database to store some configuration information for the program.  My first thought was to use the SQL CE 3.5 database that I had used previously on Windows Mobile application development.

When I attempted to add the .SDF database file to the project i got the following:

vs2008error

"An error occurred while processing the local data file:  The system cannot find the file specified."

So I tried to use a local data file .MDF instead with the same results.  I tried to add it through the Server Explorer and got even more unusual results.  I tried to reinstall the Compact Edition v3.5 and even reinstalled Visual Studio 2008 again but it didn't help.

Eventually I discovered that this issue was due to a recent registry corruption.  The HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders\AppData key was missing from my system.  If you encounter this issue, check in your registry for that value, if it is not present add it as an Expandible String Value in the HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders folder.  The string value should point to your user application data directory.  This is typically something like "%userprofile%\Application Data"

Once this was added, a restart of Visual Studio wasn't even required it worked immediately.  Definitely not a helpful error message.

 

I lost a few minutes trying to add a local database (.mdf) to a Visual Studio project recently since the error message is so cryptic.  When adding a SQL Server Database to an existing project, you may see the following error:

A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: TCP Provider, error: 0 - No connection could be made because the target machine actively refused it.)

Like me, you may be thinking this is strange since a local .mdf file shouldn't have anything to do with a network connection.  This is apparently a reference to the SQL Server service instance on your machine.  Unfortunately, I have a lot to run on my development machines, so I turn off the SQL Service service when I'm not actively using it.  This service must be running in order to add an .mdf file to your project.

Once I restarted the service, I could add the file no problem.

 

I just spent the last 2 hours trying to get my Silverlight 2 application to call a simple webservice.  I included the Service Reference in my application, it was detected and the new namespace was constructed.  I coded the following simple test application:

 

public partial class Page : UserControl {
public Page() {
InitializeComponent();
}

private void Button_Click(object sender, RoutedEventArgs e) {
approverManager.ApproversSelectRecordSetSoapClient client = new ApproversSelectRecordSetSoapClient();
client.approversListRecordSetByVendorCompleted += new EventHandler<approversListRecordSetByVendorCompletedEventArgs>(client_approversListRecordSetByVendorCompleted);
client.approversListRecordSetByVendorAsync();
}

void client_approversListRecordSetByVendorCompleted(object sender, approversListRecordSetByVendorCompletedEventArgs e) {
Console.WriteLine(e.Result.ToString());
_textbox_one.Text = e.Result.ToString();
}
}

But every time this executed I got an error about "attempting to access a service in a cross-domain way without a proper cross-domain policy in place, or a policy that is unsuitable for SOAP services."

The solution for this is as simple as it is annoying.  The problem has nothing to do with your application, but rather the service call is expecting to find a file on the root of the server where your service is located called clientaccesspolicy.xml.  This is not in the root directory of the service itself, but on the root of the server.  If you can't store files on your server root, you're apparently out of luck.

The contents of the file should be something like:

 

<?xml version="1.0" encoding="utf-8"?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers="*">
<domain uri="*"/>
</allow-from>
<grant-to>
<resource path="/" include-subpaths="true"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>

That is the simplest form and will get your service up and running.  If you want to get down and dirty with access allowances and denials, you can read more at the msdn article:

http://msdn.microsoft.com/en-us/library/cc197955(VS.95).aspx

 
Code Project RSS
Contact Me
Contact me here: by email or check out my resume http://stuartmorris.emurse.com
Web Hosting By ICDSoft.com