Web Q&A

Mobile Internet Toolkit versus Smart Device Extensions, SSL Glitch Again, and More

Edited by Nancy Michell

Q I want to build a little note-taking application for mobile phones and other devices. It would be used to keep personal notes like reminders and grocery lists. I also need to update my company's Web site so it can deliver content to all the different handheld devices that are out there. I'm confused about which tool to use. I've heard about the Microsoft® Mobile Internet Toolkit (MMIT) and the Smart Device Extensions (SDE). What do they do? Which tool should I use?

Q I want to build a little note-taking application for mobile phones and other devices. It would be used to keep personal notes like reminders and grocery lists. I also need to update my company's Web site so it can deliver content to all the different handheld devices that are out there. I'm confused about which tool to use. I've heard about the Microsoft® Mobile Internet Toolkit (MMIT) and the Smart Device Extensions (SDE). What do they do? Which tool should I use?

A When you're building a standalone application, the right choice would be SDE. Both SDE and MMIT integrate into Visual Studio® .NET. SDE allows you to build GUI applications for handheld devices using the Microsoft .NET Compact Framework. For that application to run on a device, the device must have the framework libraries installed.

A When you're building a standalone application, the right choice would be SDE. Both SDE and MMIT integrate into Visual Studio® .NET. SDE allows you to build GUI applications for handheld devices using the Microsoft .NET Compact Framework. For that application to run on a device, the device must have the framework libraries installed.

MMIT, on the other hand, will solve your Web compatibility problems. It includes controls that are fine-tuned for portable devices. Like browser sniffing, an application built with MMIT will send down the right code for the device that made the Web request. This determination is made at run time, which means that you write one code base and let the toolkit send the proper code.

If you take a look at the Mobile Internet Toolkit episode of the .NET Show with Robert Hess, you'll learn about how the controls work. For instance, a calendar control is discussed. This control is rendered differently on each type of device. On phones that have tabbing mechanisms, the control is adapted for that mechanism. For devices that allow scrolling, it's a scrolling calendar, and for devices with touch screens, it's a touch calendar. All the developer does is choose a calendar control; the runtime does the rest.

For more information on MMIT, see Paul Yao and David Durant's article in this issue. To take a look at the list of devices that MMIT has been tested on, visit Tested Devices.

Q Last month you discussed a problem in which Microsoft Internet Explorer (at least since version 4.0) misreports a move to an unsecured zone when you access a Secure Sockets Layer (SSL) site and then navigate from a linkbutton that's nested inside a control tree. The problem stemmed from the fact that there were one or more colons in the NAME attribute because of nesting, and the browser has trouble when more than one colon is passed in an href attribute. Since it is not always possible to avoid nesting of controls, do you have any other workarounds?

Q Last month you discussed a problem in which Microsoft Internet Explorer (at least since version 4.0) misreports a move to an unsecured zone when you access a Secure Sockets Layer (SSL) site and then navigate from a linkbutton that's nested inside a control tree. The problem stemmed from the fact that there were one or more colons in the NAME attribute because of nesting, and the browser has trouble when more than one colon is passed in an href attribute. Since it is not always possible to avoid nesting of controls, do you have any other workarounds?

A Yes, here is another solution you can try. Fortunately, the pages (.aspx Web Forms) on the site used to develop this workaround were inherited from a single class. In other words, when the linkbuttons href is:

__doPostBack('LeftMenu:LinkButtonApplyNow','') <script language="javascript"> function PressLeftMenu_LinkButtonApplyNow() {__doPostBack('LeftMenu:LinkButtonApplyNow','')} </script> ••• href="https://javascript:PressLeftMenu_LinkButtonApplyNow() "

the workaround behavior has been generalized (to add a function that implements the linkbutton functionality and assign this to all instances of linkbuttons found on a page) using regular expression match and replace.

A Yes, here is another solution you can try. Fortunately, the pages (.aspx Web Forms) on the site used to develop this workaround were inherited from a single class. In other words, when the linkbuttons href is:

__doPostBack('LeftMenu:LinkButtonApplyNow','') <script language="javascript"> function PressLeftMenu_LinkButtonApplyNow() {__doPostBack('LeftMenu:LinkButtonApplyNow','')} </script> ••• href="https://javascript:PressLeftMenu_LinkButtonApplyNow() "

the workaround behavior has been generalized (to add a function that implements the linkbutton functionality and assign this to all instances of linkbuttons found on a page) using regular expression match and replace.

All of these Web Forms are derived from a custom implementation of a Web Form (referred to as PortalPage). The generalized workaround has been added to this Web Form, which requires changing the code in only one place. Within PortalPage you override the Render function. Then you find all instances of an href that executes doPostBack and replace them with a function name. You include this function in the page. The function calls the doPostBack function that was originally called inline (see Figure 1).

Figure 1 Web Form

override protected void Render(HtmlTextWriter textwriter ) { string userAgent = httpContext.Current.Request.UserAgent.ToUpper(); if((HttpContext.Current.Request.Path.ToUpper().IndexOf("DEFAULT.ASPX") == -1) && ((-1 != userAgent.IndexOf("MSIE")) && (-1 != userAgent.IndexOf("WIN")))) { int i; StringWriter sw = new StringWriter(); HtmlTextWriter htmltw = new HtmlTextWriter(sw); System.Text.StringBuilder sb = sw.GetStringBuilder(); for(i = 0; i < Page.Controls.Count; i++) { Page.Controls[i].RenderControl(htmltw); } string HTMLPage = sb.ToString(); Response.Write(PageParser(HTMLPage)); } else { base.Render(textwriter); } } private string PageParser(string strInput) { //if (smTrace.Switch.TraceInfo) smTrace.TraceInfo("FILTER: //Start of Filter: strInput = " + strInput); //create regular expression to find instances of href that //call doPostBack with at least one colon in the parameter string strFindHREF = @"href="https://+ '"' + @"javascript" + @":[a-z0-9A-Z\-_|{}\(\)!=':\s]*__doPostBack" + @"\('([a-z0-9A-Z- _]*:[a-z0-9A-Z-_]*)*'\,''\)[}]*"; Regex regexFindHREF = new Regex(strFindHREF); //create regular expression to find the id of the linkbutton for //which this href belongs Regex regexFindPostBack = new Regex(@"__doPostBack\('([a-z0-9A-Z- _]*:[a-z0-9A-Z-_]*)*'\,''\)",RegexOptions.IgnoreCase); string NewCommand; string NewFunction; string FullLinkButtonHREFCommand; string strID; int iHead; int iEndTag; //process each href that is found that satisfies the regular expression //pattern (contains at least one colon in its parameter) MatchCollection matches = regexFindHREF.Matches(strInput); foreach(Match match in matches) { //if (smTrace.Switch.TraceInfo) smTrace.TraceInfo("FILTER Filter //Match = " + match.Value); //find the unique id of the link button for which this href is //associated FullLinkButtonHREFCommand = match.Value; strID = regexFindPostBack.Match (FullLinkButtonHREFCommand).Value.Remove(0,14); strID = strID.Substring(0,strID.Length-5); //create a new href command that calls a function //the name of the function is the id with underscores replacing //colons and preceeded by 'Press' NewCommand = @"href="https://+ '"' + "java" + "script:Press" + strID.Replace(":","_") + '(' + ')'; //replace the doPostBack command in the href with a call to the new //function strInput = strInput.Replace(FullLinkButtonHREFCommand,NewCommand); //add a new function to the page //this has the same name as that called within the the href command //the function calls doPostBack passing the unique id of the //linkbutton as the parameter iHead = strInput.IndexOf("</script>"); NewFunction = "\n" + "<script language=javascript>function Press" + strID.Replace(":","_") + '(' + ')' + "{__doPostBack('" + strID.Replace("_",":") + "','')}</script>\n"; if(iHead != -1) { strInput = strInput.Insert(iHead+9, NewFunction); } else { //there is no <HEAD> tag (must be part of a control without a //HEAD tag) //insert the function after the first ending tag iEndTag = strInput.IndexOf("/>"); strInput = strInput.Insert(iEndTag+2, NewFunction); } } //if (smTrace.Switch.TraceInfo) smTrace.TraceInfo("FILTER End of //Filter: strInput = " + strInput); return strInput; }

If your pages have many link buttons, then you can optimize the workaround by generating just one Press function and passing the name of the link button to execute as a parameter. This workaround has an insignificant impact on performance.

Q I have three or four submit buttons on a page. In my onsubmit handler, I want to find out which button was clicked. How can I get this information?

Q I have three or four submit buttons on a page. In my onsubmit handler, I want to find out which button was clicked. How can I get this information?

I tried using the window.event.srcElement property in my onsubmit handler, but it just returns the form element, not the button that invoked the submit. My code always returns the form id, but not the button id:

<form id="test" runat="server" method="post" action="test.aspx" onsubmit="return(testSubmit());" > <input type="submit" value="click here" id="testButton1" runat="server" > <input type="submit" value="click here" id="testButton2" runat="server" > </form> function testSubmit() { alert( 'This submit was caused by ' + window.event.srcElement.id ); }

A Instead of catching the form's submit event, you can catch a simple click event on the form. In the click handler, you can then explicitly call the form's submit method. The advantage is that now you will get information about the source object (button). It works something like this:

<form id="test" runat="server" method="post" action="foo.html" onclick="testSubmit()"> <input type="submit" value="click here" id="testButton1" runat="server"> <input type="submit" value="click here" id="testButton2" runat="server"> </form> function testSubmit() { alert( 'This submit was caused by ' + window.event.srcElement.id ); test.submit(); }

A Instead of catching the form's submit event, you can catch a simple click event on the form. In the click handler, you can then explicitly call the form's submit method. The advantage is that now you will get information about the source object (button). It works something like this:

<form id="test" runat="server" method="post" action="foo.html" onclick="testSubmit()"> <input type="submit" value="click here" id="testButton1" runat="server"> <input type="submit" value="click here" id="testButton2" runat="server"> </form> function testSubmit() { alert( 'This submit was caused by ' + window.event.srcElement.id ); test.submit(); }

This works in the sense that the click event bubbles up to the form. You would be wise to check the type of srcElement to be sure it was a button, though (see Figure 2).

Figure 2 Get Submit Source

function GetSubmitButtonID(oForm) { var iLen = oForm.children.length; for(var i=0; i<iLen; i++) { if(oForm.children[i].type == "submit" && window.event.srcElement == oForm.children[i]) { alert("you clicked the " + window.event.srcElement.id + " submit button"); } } } <form id="test" runat="server" method="post" action="foo.html" onclick="GetSubmitButtonID(this);"> <input id="testButton1" type="submit" /> <input id="testButton2" type="submit" /> <input id="chk1" type="checkbox" /> <input type="button" id="btn" value="Click me" /> </form>

Q Using JScript®, I want to get a popup menu to appear on top of an ActiveX® control. However, the popup menu is appearing behind the OCX. I've set the z-index at design time and at run time, so the menu should appear on top of the OCX. Do OCXs always appear as the topmost element in the z order?

Q Using JScript®, I want to get a popup menu to appear on top of an ActiveX® control. However, the popup menu is appearing behind the OCX. I've set the z-index at design time and at run time, so the menu should appear on top of the OCX. Do OCXs always appear as the topmost element in the z order?

A Yes, ActiveX controls are always on top, as are <select> controls. You can either make the ActiveX control into a windowless control, or you can temporarily hide the control during the time that the menu is active.

A Yes, ActiveX controls are always on top, as are <select> controls. You can either make the ActiveX control into a windowless control, or you can temporarily hide the control during the time that the menu is active.

You may also want to try the popup object. In order to do so, you use the CreatePopup method, which is windowed and which should appear above your control.

You can find out more information about CreatePopup at the following pages: Using the Popup Object.

Q I am writing a VBScript file that needs to invoke code in another VBScript file. How can I do this? The scenario is as follows: I have two VBScript files, A.vbs and B.vbs. Inside A.vbs I need to do some work and then call B.vbs with some parameters.

Q I am writing a VBScript file that needs to invoke code in another VBScript file. How can I do this? The scenario is as follows: I have two VBScript files, A.vbs and B.vbs. Inside A.vbs I need to do some work and then call B.vbs with some parameters.

A Because they act as containers, as you can see at Using Windows Script Files (.wsf), you can use a .wsf file or a subroutine like the one shown in Figure 3.

A Because they act as containers, as you can see at Using Windows Script Files (.wsf), you can use a .wsf file or a subroutine like the one shown in Figure 3.

Figure 3 Calling Another Script

'//////////////////////////////////////////////////////////////////////// ' Include ' Reads and globally executes an external VBScript file ' ' objFSO FileSystem object ' strlExternalFile Path for file ' Sub Include(strlExternalFile) Dim reflExternalFile, strCode Set reflExternalFile = objFSO.OpenTextFile(strlExternalFile, ForReading) strCode = reflExternalFile.ReadAll reflExternalFile.Close ExecuteGlobal strCode End Sub '////////////////////////////////////////////////////////////////////////

Q Why are relative paths in file include directives not allowed in Microsoft Internet Information Services (IIS) 6.0? This line

<!-- #include file="../include/functions.inc" -->

produces the following error:

Active Server Pages error 'ASP 0131' Disallowed ParentPath /ipdiss/admin/DispNCOA.asp, line 4 The Include file '../include/functions.inc' cannot contain '..' to indicate the parent directory.

Is there some security issue that's being addressed here?

Q Why are relative paths in file include directives not allowed in Microsoft Internet Information Services (IIS) 6.0? This line

<!-- #include file="../include/functions.inc" -->

produces the following error:

Active Server Pages error 'ASP 0131' Disallowed ParentPath /ipdiss/admin/DispNCOA.asp, line 4 The Include file '../include/functions.inc' cannot contain '..' to indicate the parent directory.

Is there some security issue that's being addressed here?

A Yes, there is a security issue. The metabase property AspEnableParentPaths has been changed by default from TRUE to FALSE in IIS 6.0. Restricting ParentPaths reduces an attacker's ability to traverse the file system and do things like snagging the local SAM store or firing up a cmd.exe shell.

A Yes, there is a security issue. The metabase property AspEnableParentPaths has been changed by default from TRUE to FALSE in IIS 6.0. Restricting ParentPaths reduces an attacker's ability to traverse the file system and do things like snagging the local SAM store or firing up a cmd.exe shell.

Q If I turn on SSL for a page (say page.asp) in a site that is protected by SSL, do I need to change the action of the form to be https://server/site/page.asp? Currently the action is set to page.asp.

Q If I turn on SSL for a page (say page.asp) in a site that is protected by SSL, do I need to change the action of the form to be https://server/site/page.asp? Currently the action is set to page.asp.

A If you use HTTPS to browse to the page with the form, then HTTPS will be used; if you browse using HTTP, then HTTP will be used. When you navigate to page.asp, Internet Explorer will take the current folder URL and add it onto the end of that URL. You don't need to do anything special to get the form to use HTTPS, but you can use https:// if you want.

A If you use HTTPS to browse to the page with the form, then HTTPS will be used; if you browse using HTTP, then HTTP will be used. When you navigate to page.asp, Internet Explorer will take the current folder URL and add it onto the end of that URL. You don't need to do anything special to get the form to use HTTPS, but you can use https:// if you want.

Got a question? Send questions and comments to WebQA@microsoft.com.

Thanks to the following Microsoft developers for their technical expertise: Rory Clark, Ed Elliott, Ravikumar Gopinath (Aditi), Nick Hertl, William Hickman (Softsource), Paula Mills, Andy Morrison, Michael Murgolo, Mike Pope, Liming Ren, Janet Robinson, Alan Stuart, Tom Taylor (EHOME), Peter Torr, Charles Torre.