Code Repo    |     RSS
MD's Technical Sharing



Monday, September 29, 2008

Scrolling WebBrowser Control

This shows some ways to scroll a WebBrowser control pixel by pixel

Method 1 - Use JavaScript:

Me.WebBrowser1.Navigate(New Uri("javascript:window.scroll(100,100);"))

Where (100, 100) is the coordinate to scroll to.

This will work in a Windows Form application and probably in a .NET CF application if the device browser supports JavaScript.

Method 2 - By posting WM_HSCROLL/WM_VSCROLL message:

We must first find the webbrowser window handle. WebBrowser1.Handle alone is not sufficent as the control is an ActiveX object. The sequence of calls to FindWindowEx and the required parameters can be figured out by using Spy++:

Dim wbHandle As IntPtr = FindWindowEx(Me.WebBrowser1.Handle, IntPtr.Zero, "Shell Embedding", Nothing)
wbHandle = FindWindowEx(wbHandle, IntPtr.Zero, "Shell DocObject View", Nothing)
wbHandle = FindWindowEx(wbHandle, IntPtr.Zero, "Internet Explorer_Server", Nothing)

The following is necessary if the web browser does not have focus when the function is called.

Me.WebBrowser1.Document.Body.Focus()

Finally, send the message to scroll to the right.

SendMessage(wbHandle, WM_HSCROLL, SB_LINERIGHT, 0)

To scroll more precisely, e.g. pixelwise, use:

SendMessage(wbHandle, WM_VSCROLL, SB_THUMBPOSITION + &H10000 * nPos, Nothing)

Where nPos is the position to scroll to. Notice that SB_THUMBPOSITION + &H10000 * nPos creates an integer having nPos as the high WORD and SB_THUMBPOSITION as the low WORD.

Method 3 - By using GetScrollInfo and SetScrollInfo

SCROLLINFO si;
ZeroMemory(&si, sizeof(si));
si.cbSize = sizeof(si);
si.fMask = SIF_ALL;
::GetScrollInfo(this->webviewHandle, SB_VERT, &si);
si.nPos += 10;
::SetScrollInfo(this->webviewHandle, SB_VERT, &si, true);

This will scroll down 10 pixels. This works on other control but somehow does not work on the WebBrowser control as its scroll-bar is custom painted.

Reference:

http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=2727441&SiteID=1&pageid=0
http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=3951060&SiteID=1
http://www.tech-archive.net/Archive/InetSDK/microsoft.public.inetsdk.programming.webbrowser_ctl/2005-08/msg00092.html
Read More »

Monday, September 22, 2008

P2P audio Streaming between computer & device

This project attempts to develop a simple program, which can run on the Pocket PC device as well as the personal computers with Windows installed, that allows 2 people to talk to each other via a simple P2P streaming system.

The software runs on Pocket devices with Windows Mobile 5.0 and 6.0 having .NET Compact Framework 2.0 installed. Interestingly, since the .NET Compact Framework is compatible with the .NET framework which can run on Windows XP, our program can also run on the personal computer with Windows XP installed without any major code changes.

Regardless of the platform on which the program is running, the user needs to configure the address of the destination which he intends to talk to. This consists of the IP address of the target device/computer as well as the port to which the outgoing audio data (recorded from the microphone, referred to as outgoing audio) is sent to. He also needs to configure the port on which the program receives audio data (which will be played back, referred to as incoming audio). On both ends, the settings of IP address and ports must match in order for the program to work:
  • Local IP: the IP address and the port at which the program receives audio data for playback. The local IP field is read-only; user can select one of the listed values.
  • Remote IP: the IP address and the port to which the recorded audio data is sent.
Given this information, it is obvious that user should swap the values of Remote IP and Local IP on both ends for the program to work. This would mean, the values for Local IP on one end should be used as Remote IP on the other end, and vice versa.

Technical details

As mentioned, the program is written using .NET Compact Framework 2.0, with the help of Visual Studio 2005. Two important features are demonstrated in the program

1. Audio capturing and playing back. This is done via the Waveform Application Programming Interface (API), which comes with the SDK. This allows the programmer to capture real-time audio data from the microphone and transmit to the remote destination, as well as to receive audio data from the remote destination and play back locally. This creates an effect of real-time voice conversation.

2. Socket programming. Audio is transmitted and received via UDP (User Datagram Protocol) socket, which is handy as the .NET compact framework has built-in support for UDP. Since UDP requires that data must be sent via a single data port, this explains why the port must be specified in the user interface. Obviously, further development can automatically guess the port in the background and there would be no need for the user to manually specify the port.

Download 

Source Code
Binary (Windows Mobile and PC) 

References

1. The Waveform API

Useful information about how to record and play back audio on a Pocket PC is found on this website

2. Full-duplex audio player in .NET

This is an example of how to use the Waveform API. It records audio and playback locally.

3. Sockets Programming in .NET

This gives information about how to transmit and receive data via UDP sockets
Read More »

Sunday, September 21, 2008

WebException on HTTPWebRequest with SSL connection: "Unable to read data from the transport connection"

Behaviour:


For SSL URLs (e.g. https://login.yahoo.com/), HttpWebRequest.GetRequestStream() and HttpWebRequest.GetResponse() fails with WebException. Exception status is 'ReceiveFailure' and message is 'Unable to read data from the transport connection'.


Cause:


The server sends an empty encryption packet to the NetCF client. The trouble with NetCF's SSL stack is when the server encrypts a buffer of zero length and sends it to the client. Although the original data had a length of zero, the encrypted version of it actually has a non-zero length. When this packet is sent to a NetCF client, current versions of NetCF decrypt the packet and return a zero length buffer to the caller. The semantics of a network Read method is traditionally that it blocks until some data is received, and if a zero length buffer is returned it is the sign that the socket was closed. Because NetCF will return an empty buffer after decrypting an "empty" encryption packet, the caller may misinterpret this as a sign of a disconnected socket and terminate the connection. In fact this is exactly what happens in NetCF's web services code when calling services over SSL that respond with empty encryption packets. As a result the connection fails before the response is fully received and an exception is thrown.


Solution/Workarounds:


None. But a detector for this problem is available at http://code.msdn.microsoft.com/emptysslpackets


References:

1. Unable to read data from the transport connection" error with SSL connection
2. Why .NET Compact Framework fails to call some HTTPS web servers
3. Empty SSL packet detector source code
Read More »

Thursday, September 18, 2008

VS IDE check if Design Mode is active

Useful when desining user controls - in order to make certain functionalities available in design mode but not in runtime and vice versa.

public bool IsInDesignMode()
{
bool returnFlag = false;

#if DEBUG
if (System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime)
{
returnFlag = true;
}
else if (Process.GetCurrentProcess().ProcessName.ToUpper().Equals("DEVENV"))
{
returnFlag = true;
}
#endif

Debug.WriteLine("IsInDesignMode returns " + returnFlag.ToString());
return returnFlag;
}


Reference: http://devlicio.us/blogs/derik_whittaker/archive/2006/09/25/Determining-if-the-.Net-IDE-is-in-Design-Mode.aspx
Read More »

Tuesday, September 16, 2008

OneNote API Error Codes

Error

HRESULT

hrMalformedXML

0x80042000

hrInvalidXML

0x80042001

hrCreatingSection

0x80042002

hrOpeningSection

0x80042003

hrSectionDoesNotExist

0x80042004

hrPageDoesNotExist

0x80042005

hrFileDoesNotExist

0x80042006

hrInsertingImage

0x80042007

hrInsertingInk

0x80042008

hrInsertingHtml

0x80042009

hrNavigatingToPage

0x8004200a

hrSectionReadOnly

0x8004200b

hrPageReadOnly

0x8004200c

hrInsertingOutlineText

0x8004200d

hrPageObjectDoesNotExist

0x8004200e

hrBinaryObjectDoesNotExist

0x8004200f

hrLastModifiedDateDidNotMatch

0x80042010

hrGroupDoesNotExist

0x80042011

hrPageDoesNotExistInGroup

0x80042012

hrNoActiveSelection

0x80042013

hrObjectDoesNotExist

0x80042014

hrNotebookDoesNotExist

0x80042015

hrInsertingFile

0x80042016

hrInvalidName

0x80042017

hrFolderDoesNotExist

0x80042018

hrInvalidQuery

0x80042019

hrFileAlreadyExists

0x8004201a

hrSectionEncryptedAndLocked

0x8004201b

hrDisabledByPolicy

0x8004201c

hrNotYetSynchronized

0x8004201d

hrLegacySection

0x8004201e

Read More »

Saturday, September 13, 2008

Using System.Windows.Forms.WebBrowser.ActiveXInstance

Expanding the WebBrowser control functionalities by using its ActiveXInstance property.


The WebBrowser control has a property called ActiveXInstance which is its run-time ActiveX instance and exposes many other methods/properties not available in the main control.

However, since ActiveXInstance is Object and requires late-binding to access all its methods and properties, Option Strict needs to be turned off in order to use it.

To use the WebBrowser extra functionalities: call WebBrowser.ActiveXInstance.ExecBB()

Define enums for use with ExecBB:

Private Enum Exec
OLECMDID_OPTICAL_ZOOM = 63
OLECMDID_SELECTALL = 17
OLECMDID_COPY = 12
OLECMDID_CLEARSELECTION = 18
End Enum

Private Enum ExecOpt
OLECMDEXECOPT_DODEFAULT = 0
OLECMDEXECOPT_PROMPTUSER = 1
OLECMDEXECOPT_DONTPROMPTUSER = 2
OLECMDEXECOPT_SHOWHELP = 3
End Enum

Copy selected text to clipboard:

Me.WebSMSView.ActiveXInstance.ExecWB(Exec.OLECMDID_COPY, ExecOpt.OLECMDEXECOPT_DODEFAULT)

Select all text:

Me.WebSMSView.ActiveXInstance.ExecWB(Exec.OLECMDID_SELECTALL, ExecOpt.OLECMDEXECOPT_DODEFAULT)

Zoom to 75%:

Me.WebSMSView.ActiveXInstance.ExecWB(Exec.OLECMDID_OPTICAL_ZOOM, ExecOpt.OLECMDEXECOPT_DODEFAULT, 75, 0)

To use a custom context menu in the WebBrowser control, the default context menu needs to be disabled by setting WebBrowser.IsWebBrowserContextMenuEnabled to false.


Reference:


  • Copy the contents of the WebBrowser control to the Clipboard
  • Using ExecWB with the native .NET 2.0 WebBrowser control
  • Allow only Copy/Paste Context Menu in System.Windows.Forms.WebBrowser Control
  • ExecWB Method
  • Read More »

    Wednesday, September 10, 2008

    Read WMA and MP3 ID3 Tag

    The attached project shows how to read/write and change the ID3 tag of a MP3 or WM3 file.


    Download source code


    References:

  • Reading ID3 tags from a WMA file (MP3 as well), http://www.codeproject.com/KB/files/tagreader.aspx

  • Read MP3 header information and read/write the ID3v1 tag, http://www.codeproject.com/KB/recipes/vbmp3header.aspx

  • Read More »

    Thursday, September 4, 2008

    Change ComboBox.Text property in SelectedIndexChanged event

    It seems that you can't change the Text property of a combobox inside SelectedIndexChanged event. The .Text will still contain the old value after the change due to cross-threading issues:

    Workaround: Use delegation to do this, this will change the text right after the SelectedIndexChanged event:


    this.comboBox1.SelectedIndexChanged += new EventHandler(comboBox1_SelectedIndexChanged);
    void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
    {
    this.BeginInvoke(new ChangeTextDelegete(ChangeText));
    }

    private delegate void ChangeTextDelegete();
    public void ChangeText()
    {
    this.comboBox1.Text = "Changed";
    }


    Problem: With this approach, sometimes "Exception has been thrown by the target of an invocation" fires randomly.


    Reference:

    How to change combobox text property after SelectedIndexChanged event?

    Read More »