Thursday, February 26, 2009

Develop Security Trimmed navigation Menu for SharePoint

In my previous article, I explained developing navigation menu in SharePoint using XML file and dataformwebpart. In this log, I will explain how to generate security trimmed navigation menu. To make things even more complex, there are two types of trimming:

1. Still show the menu item in the navigation, but while users click the menu, a message box should pop up and say "You are not authorized to view the page"

2. Will not show the menu item at all.

The solution is to add another SPDataSource to the DataFormWebPart in addition to the XML data source used to retrieve the XML file. (Notice, you are using AggregateSource here) The new datasource will perform a "CrossList" query to all the Pages libraries in the sitecollection. If the current log-in user does not have permission to view a page, the new datasource should not return any record for the page. So, in XSLT code, we just need to perform a filter not to generate menu item for those pages in XML datasource but not returned from the new datasource.

However, we have not solved the problem completely because, for some trimmed pages, we still need to generate menu item and hook up the java script code to display the pop up message box. The solution is to introduce a new attribute to the nodes in the XML file. For example, we can add a boolean attribute "IsGeneratingMessageIfNoPermmission" . The XSLT code will handle the property accordingly.

Once again, it demonstrates using "XML file + DataFormWebpart" to generate navigation menu for sharepoint is a very extensible approach, which fully takes advantage of the power of XSLT and dataformwebprt.

Tuesday, February 24, 2009

How to play sound in windows mobile?

Recently I created a Smart Device application called SightReader. There is a virtual piano keyboard in it and I need to play sound when the user clicks a key on keyboard. I was trying to use the WavPlayer I created before. It is easy to use, but it only support WAV file. I generated the sound MIDI file for each key and then converted them to WAV file. However I couldn’t get the wav file to be reasonable size. So the compiled executable was huge and impossible to use on a Smart Device. Finally I created another SoundPlayer which can play MIDI, MP3 and WAV file. It works fine except it has slower response time.

New update(3/3/2009): I really don't like the sound of the MIDI in my SightReader. So I searched and searched. Finally somebody mentioned that you can use "Sound Recorder" in Windows to reduce the size of a WAV file. But when I looked the Sound Recorder in Vista, I don't see any choice other than recording sound. So I went to a Windows 2000. Aha! Here we go. Now I was able to use audio format "11.025 khz, 16 Bit, Mono" to convert my once 200 KB WAV file to 22 KB. Other good things about the Sound Record is you can do some editing to the WAV file, such as increase the volume or deletion. It is a shame that Microsoft doesn't provide the same features in Vista. 

How to play WAV file?

public class WavPlayer
{
private byte[] m_soundBytes;
private string m_fileName;

private enum Flags
{
SND_SYNC = 0x0000, /* play synchronously (default) */
SND_ASYNC = 0x0001, /* play asynchronously */
SND_NODEFAULT = 0x0002, /* silence (!default) if sound not found */
SND_MEMORY = 0x0004, /* pszSound points to a memory file */
SND_LOOP = 0x0008, /* loop the sound until next sndPlaySound */
SND_NOSTOP = 0x0010, /* don't stop any currently playing sound */
SND_NOWAIT = 0x00002000, /* don't wait if the driver is busy */
SND_ALIAS = 0x00010000, /* name is a registry alias */
SND_ALIAS_ID = 0x00110000, /* alias is a predefined ID */
SND_FILENAME = 0x00020000, /* name is file name */
SND_RESOURCE = 0x00040004 /* name is resource name or atom */
}

[DllImport("CoreDll.DLL", EntryPoint = "PlaySound", SetLastError = true)]
private extern static int WCE_PlaySound(string szSound, IntPtr hMod, int flags);

[DllImport("CoreDll.DLL", EntryPoint = "PlaySound", SetLastError = true)]
private extern static int WCE_PlaySoundBytes(byte[] szSound, IntPtr hMod, int flags);

/// <summary>
/// Construct the Sound object to play sound data from the specified file.
/// </summary>
public WavPlayer(string fileName)
{
m_fileName = fileName;
}

/// <summary>
/// Construct the Sound object to play sound data from the specified stream.
/// </summary>
public WavPlayer(Stream stream)
{
// read the data from the stream
m_soundBytes = new byte[stream.Length];
stream.Read(m_soundBytes, 0, (int)stream.Length);
}

public WavPlayer(byte[] soundBytes)
{
m_soundBytes = soundBytes;
}


/// <summary>
/// Play the sound
/// </summary>
public void Play()
{
// if a file name has been registered, call WCE_PlaySound,
// otherwise call WCE_PlaySoundBytes
if (m_fileName != null)
WCE_PlaySound(m_fileName, IntPtr.Zero, (int)(Flags.SND_SYNC | Flags.SND_FILENAME));
else
WCE_PlaySoundBytes(m_soundBytes, IntPtr.Zero, (int)(Flags.SND_SYNC | Flags.SND_MEMORY));
}
}




How to play MIDI, MP3 and other sound?



This method will only work in Windows Mobile 6 and later.




public enum SoundFileType { WAV, MP3, MIDI, WMA }

public class SoundPlayer : IDisposable
{
[DllImport("aygshell.dll")]
static extern uint SndOpen(string pszSoundFile, ref IntPtr phSound);

[DllImport("aygshell.dll")]
static extern uint SndPlayAsync(IntPtr hSound, uint dwFlags);

[DllImport("aygshell.dll")]
static extern uint SndClose(IntPtr hSound);

[DllImport("aygshell.dll")]
static extern uint SndStop(int SoundScope, IntPtr hSound);

[DllImport("aygshell.dll")]
static extern uint SndPlaySync(string pszSoundFile, uint dwFlags);

const int SND_SCOPE_PROCESS = 0x1;
IntPtr sound = IntPtr.Zero;
Thread soundThread = null;

string _filePath = string.Empty;
public string FilePath
{
get { return _filePath; }
set { _filePath = value; }
}

public SoundPlayer(string filePath)
{
_filePath = filePath;
}

public SoundPlayer(byte[] soundBytes, SoundFileType fileType)
{
string fileExtension = ".wav";
switch (fileType)
{
case SoundFileType.WAV:
fileExtension = ".wav";
break;
case SoundFileType.MP3:
fileExtension = ".mp3";
break;
case SoundFileType.MIDI:
fileExtension = ".mid";
break;
default:
throw new Exception("Audio format is not supported.");
break;
}

_filePath = Path.GetTempPath() + "tempSound" + fileExtension;
FileStream fs = new FileStream(_filePath, FileMode.Create, FileAccess.ReadWrite);
fs.Write(soundBytes, 0, soundBytes.Length);
fs.Close();
}

public void Play()
{
SndPlaySync(_filePath, 0);
}

public void PlayLooping()
{
soundThread = new Thread(Playing);
soundThread.Start();
}

private void Playing()
{
while (true)
{
SndPlaySync(_filePath, 0);
}
}

public void PlayAsync()
{
SndOpen(_filePath, ref sound);
SndPlayAsync(sound, 0);
}

public void Stop()
{
if (soundThread != null)
{
SndStop(SND_SCOPE_PROCESS, IntPtr.Zero);
soundThread.Abort();
soundThread = null;
}
if (sound != IntPtr.Zero)
{
SndStop(SND_SCOPE_PROCESS, IntPtr.Zero);
SndClose(sound);
sound = IntPtr.Zero;
}
}

#region IDisposable Members

public void Dispose()
{
Stop();
}

#endregion
}

region

Wednesday, February 4, 2009

Why use SharePoint Content Pages instead of Simple ASP.NET pages for transactional page? (The elegant solution for implementing SharePoint user controls.)

A Page is transactional when the page needs to perform certain actions that require Server Side coding. If you want to implement the page in SharePoint and so End user can change the style of the Page through SharePoint designer, you have to implement the Server Side code in a Custom code behind Page class. You can place all the UI components in the SharePoint page or Page Layout in case of a publishing page. The code behind custom Page class will handle the server side logic. This approach will allow Designers to change the look/feel of the page through SharePoint designer while leaving the server side logic to developer. Allowing Designers to customize without any code change is the advantage to use SharePoint here.

The problem with this approach is that the Server Side logic is tied up with the page and so is not so reusable. What presented here is to use “Template” user controls/Custom controls to achieve the same functionality in a more reusable fashion. Basically, the all the UI components will be inside the “Template” properties of the User/Custom Controls. Therefore, they can be placed inside the SharePoint Page and End users can customize the templates through SharePoint designer.

It is not a new idea.  It is exactly what ASP.Net “template” is designed for. It allows customized UI tied up to the same Server Side Logic. A good example is ASP.NET 2.0 login control, in which you can customize the layout of all the UI components while using for the same server side logic. The same idea applies perfectly in the context of SharePoint. SharePoint allows Users to customize the UI components through SharePoint designer while allowing certain degree of Server Side Activities. So, while writing User Controls for SharePoint projects, think about exposing “Template” properties and make them customizable through SharePoint Designer.

It is not so difficult to write a “template” controls. Please follow the link to learn how to add templates to a ASP.NET user controls http://weblogs.asp.net/scottgu/archive/2006/06/04/Supporting-Templates-with-ASP.NET-User-Controls.aspx