Google Serach

自訂搜尋

2012年2月6日星期一

做事的10個順序

今天在Plurk上看到噗友分享的『做事必須搞清的10個順序』,覺得寫的真好,這邊紀錄一下,也分享給大家。

噗友的原文在這邊

  1. 職場:先升值,再升職; 
  2. 溝通:先求同,再求異; 
  3. 執行:先完成,再完美;
  4. 學習:先記錄,再記憶; 
  5. 設計:先仿造,再創造; 
  6. 創業:先成長,再成功; 
  7. 發展:先站住,再站高;
  8. 人際:先交流,再交心;
  9. 先做好自己,再要求別人; 
  10. 先解決心情,再解決事情。

2012年1月31日星期二

SendKeys in WPF

在以往Windows Form的程式開發當中,當要送出鍵盤的相關資料時,會使用SendKeys的方式來處理,例如說要把一個字加到TextBox上這樣;用SendKeys的好處不用去處理當輸入的游標在文字中間的問題,會比像是
TextBox1.Text &= "1"
這樣的方式來的方便些。而到了WPF,沒有SendKeys可以用了,那麼應該怎麼辦呢?在網路上搜尋了一下,可以利用呼叫API的方式來做,可以參考一下下面 SendInput 的說明,所有需要的東西都在裡面了。動作原理大概是下面過程

紀錄要輸入的控制項在畫面上的位置
使用SendInput模擬滑鼠的動作,點擊要輸入的控制項(主要是要取得Focus)
使用SendInput模擬KeyDown的動作
使用 SendInput模擬KeyUp的動作

大概的過程是這樣子了;而我自己的使用方式有點偷懶,直接略過模擬滑鼠的部分,直接傳控制項的參考過去 XDD

下面是目前的程式碼,還沒詳細測試,大致就是上面列出的SendInput中的程式碼了,參考看看了;首先是宣告的部分

#Region "Const"
    Const INPUT_MOUSE As UInt32 = 0
    Const INPUT_KEYBOARD As Integer = 1
    Const INPUT_HARDWARE As Integer = 2
    Const KEYEVENTF_EXTENDEDKEY As UInt32 = &H1
    Const KEYEVENTF_KEYUP As UInt32 = &H2
    Const KEYEVENTF_UNICODE As UInt32 = &H4
    Const KEYEVENTF_SCANCODE As UInt32 = &H8
    Const XBUTTON1 As UInt32 = &H1
    Const XBUTTON2 As UInt32 = &H2
    Const MOUSEEVENTF_MOVE As UInt32 = &H1
    Const MOUSEEVENTF_LEFTDOWN As UInt32 = &H2
    Const MOUSEEVENTF_LEFTUP As UInt32 = &H4
    Const MOUSEEVENTF_RIGHTDOWN As UInt32 = &H8
    Const MOUSEEVENTF_RIGHTUP As UInt32 = &H10
    Const MOUSEEVENTF_MIDDLEDOWN As UInt32 = &H20
    Const MOUSEEVENTF_MIDDLEUP As UInt32 = &H40
    Const MOUSEEVENTF_XDOWN As UInt32 = &H80
    Const MOUSEEVENTF_XUP As UInt32 = &H100
    Const MOUSEEVENTF_WHEEL As UInt32 = &H800
    Const MOUSEEVENTF_VIRTUALDESK As UInt32 = &H4000
    Const MOUSEEVENTF_ABSOLUTE As UInt32 = &H8000
#End Region
 
#Region "Enums"
    Public Enum InputType As Integer
        Mouse = 0
        Keyboard = 1
        Hardware = 2
    End Enum
 
    <Flags()> _
    Public Enum MOUSEEVENTF As Integer
        MOVE = &H1
        LEFTDOWN = &H2
        LEFTUP = &H4
        RIGHTDOWN = &H8
        RIGHTUP = &H10
        MIDDLEDOWN = &H20
        MIDDLEUP = &H40
        XDOWN = &H80
        XUP = &H100
        VIRTUALDESK = &H400
        WHEEL = &H800
        ABSOLUTE = &H8000
    End Enum
 
    <Flags()> _
    Public Enum KEYEVENTF As Integer
        EXTENDEDKEY = 1
        KEYUP = 2
        [UNICODE] = 4
        SCANCODE = 8
    End Enum
#End Region
 
#Region "Structure"
    <StructLayout(LayoutKind.Explicit)> _
    Public Structure INPUT
        <FieldOffset(0)> Dim dwType As Integer
        <FieldOffset(4)> Dim mouseInput As MOUSEINPUT
        <FieldOffset(4)> Dim keyboardInput As KEYBDINPUT
        <FieldOffset(4)> Dim hardwareInput As HARDWAREINPUT
    End Structure
 
    <StructLayout(LayoutKind.Explicit)> _
    Public Structure KEYBDINPUT
        <FieldOffset(0)> Public wVk As Short
        <FieldOffset(2)> Public wScan As Short
        <FieldOffset(4)> Public dwFlags As Integer
        <FieldOffset(8)> Public time As Integer
        <FieldOffset(12)> Public dwExtraInfo As IntPtr
    End Structure
 
    <StructLayout(LayoutKind.Explicit)> _
    Public Structure HARDWAREINPUT
        <FieldOffset(0)> Public uMsg As Integer
        <FieldOffset(4)> Public wParamL As Short
        <FieldOffset(6)> Public wParamH As Short
    End Structure
 
    <StructLayout(LayoutKind.Explicit)> _
    Public Structure MOUSEINPUT
        <FieldOffset(0)> Public dx As Integer
        <FieldOffset(4)> Public dy As Integer
        <FieldOffset(8)> Public mouseData As Integer
        <FieldOffset(12)> Public dwFlags As Integer
        <FieldOffset(16)> Public time As Integer
        <FieldOffset(20)> Public dwExtraInfo As IntPtr
    End Structure
#End Region
 
    <DllImport("user32.dll", EntryPoint:="SendInput")>
    Public Shared Function SendInput(ByVal cInputs As IntegerByRef pInputs As INPUTByVal cbSize As IntegerAs Integer
    End Function
 
    Public Shared Sub DoKeyBoard(ByVal flags As KEYEVENTFByVal key As Char)
        Dim _input As New INPUT
        Dim ki As New KEYBDINPUT
        _input.dwType = InputType.Keyboard
 
        _input.keyboardInput = ki
        _input.keyboardInput.wVk = Convert.ToInt16(key)
        _input.keyboardInput.wScan = 0
        _input.keyboardInput.time = 0
        _input.keyboardInput.dwFlags = flags
        _input.keyboardInput.dwExtraInfo = IntPtr.Zero
        Dim cbSize As Integer = Marshal.SizeOf(GetType(INPUT))
        Dim result As Integer = SendInput(1, _input, cbSize)
        'If result = 0 Then Debug.WriteLine(Marshal.GetLastWin32Error)
        _input = Nothing
        ki = Nothing
    End Sub


而外面的UerControl多加了一個Property,使用方式大約會像是這樣子

Public Property FoucedCtl As TextBox
 
    Private Sub Button_Click(sender As System.Object, e As System.Windows.RoutedEventArgs)
        If Me.FoucedCtl Is Nothing Then
            Exit Sub
        End If
        Me.FoucedCtl.Focus()
        Win32Helper.DoKeyBoard(0, CType(sender, Button).Content.ToString.Chars(0))
        System.Threading.Thread.Sleep(5)
        Win32Helper.DoKeyBoard(Win32Helper.KEYEVENTF.KEYUP, CType(sender, Button).Content.ToString.Chars(0))
    End Sub

2011年12月28日星期三

在Windows CE中,如何修改IP設定之後立即套用新的設定呢?

在Windows CE中,通常我們會將網路卡設定一個固定IP,用來與其他的設備做溝通、通訊,那麼設定了IP之後,跟著就會有IP變更的需求了,那麼怎麼去變更IP呢?

從登錄檔中,可以看到IP的相關設定會在這個位置當中
HKEY_LOCAL_MACHINE\Comm\PCI\網卡名稱\Parms\TCPIP
其中會看到Ipaddress、defaultGetway、SubnetMask這三個就是對應到IP的設定了,要變更的地方也就是這三個了,而在compact framework 2.0對登錄檔的操作也有提供了類別可以使用,可以參考MSDN上的相關類別使用說明,下面這邊是利用p/Invoke的方式來做

p/Inove的宣告

    <DllImport("CoreDll.dll", EntryPoint:="RegDeleteKeyW")> _
    Public Function RegDeleteKey(ByVal hKey As Integer, ByVal lpSubKey As String) As Integer
    End Function

    <DllImport("CoreDll.dll", EntryPoint:="RegCreateKeyExW")> _
    Public Function RegCreateKeyEx(ByVal hkey As Integer, ByVal lpSubKey As String, _
                                   ByVal Reserved As Integer, ByVal lpClass As String, _
                                   ByVal dwOptions As Integer, ByVal samDesired As Integer, _
                                   ByVal lpSecurityAttributes As Integer, ByRef phkResult As Integer, _
                                   ByRef lpdwDisposition As Integer) As Integer
    End Function

    <DllImport("CoreDll.dll")> _
    Public Function RegSetValueEx(ByVal hKey As Integer, ByVal lpValueName As String, _
        ByVal Reserved As Integer, ByVal dwType As Integer, ByVal lpData As String, ByVal cbData As Integer) As Integer
    End Function

    <DllImport("CoreDll.dll")> _
    Public Function RegCloseKey(ByVal hKey As Integer) As Integer
    End Function

    <DllImport("CoreDll.dll", EntryPoint:="RegOpenKeyExW")> _
    Public Function RegOpenKeyEx(ByVal hKey As Integer, ByVal lpSubKey As String, ByVal dwOptions As Integer, _
        ByVal samDesired As Integer, ByRef phkResult As Integer) As Integer
    End Function

    <DllImport("CoreDll.dll")> _
    Public Function RegFlushKey(ByVal hKey As Integer) As Integer
    End Function


呼叫的時候大概會是這個樣子

Dim buf, ohKey, iTmp As Integer
Dim bolResult As Boolean = False
''R86101是我的網路卡名稱
buf = RegCreateKeyEx(RegRoots.HKEY_LOCAL_MACHINE, "Comm\PCI\R86101\Parms\TCPIP", 0, vbNullString, 0, 0, 0, ohKey, iTmp)
buf = RegSetValueEx(ohKey, "Ipaddress", 0, RegValueType.REG_MULTI_SZ, IpAddress, 30)
buf = RegFlushKey(ohKey)
buf = RegCloseKey(ohKey)
buf = RegCreateKeyEx(RegRoots.HKEY_LOCAL_MACHINE, "Comm\PCI\R86101\Parms\TCPIP", 0, vbNullString, 0, 0, 0, ohKey, iTmp)
buf = RegSetValueEx(ohKey, "DefaultGateway", 0, RegValueType.REG_MULTI_SZ, Getway, 30)
buf = RegFlushKey(ohKey)
buf = RegCloseKey(ohKey)
buf = RegCreateKeyEx(RegRoots.HKEY_LOCAL_MACHINE, "Comm\PCI\R86101\Parms\TCPIP", 0, vbNullString, 0, 0, 0, ohKey, iTmp)
buf = RegSetValueEx(ohKey, "SubnetMask", 0, RegValueType.REG_MULTI_SZ, SubMask, 30)
buf = RegFlushKey(ohKey)
buf = RegCloseKey(ohKey)


這樣子就完成了IP設定的修改了,進入網卡設定的介面中,也可看到IP有變為新的設定了;這個時候問題來了,怎麼系統沒有套用新的設定呢?
在初期還沒有找到解決方式的時候,是讓系統重新開機,重新開機之後就會使用新的IP設定了,但是重新開機會花上不少的時間,而且明明在CE的介面上,變更好IP之後按下『OK』的按鈕明明就是會立刻更新IP位置的,找了相關資料後,原來是還要對系統發出一個更新通知,這樣系統才會進行IP位置的更新,這時候又得使用p/Invoke來處理了,最終的目的是要利用DeviceIoControl來對系統發出Rebind adepater的通知

const的宣告

Public Const OPEN_EXISTING As UInt32 = 3
Public Const INVALID_HANDLE_VALUE As Int32 = -1
Public Const IOCTL_NDIS_REBIND_ADAPTER As UInt32 = &H17002E
Public Const FILE_ATTRIBUTE_NORMAL As UInt32 = &H80


API的部分

    <DllImport("coredll.dll", EntryPoint:="CreateFileW")> _
    Public Function CreateFile(ByVal lpFileName As String, ByVal dwDesiredAccess As Integer, _
                               ByVal dwShareMode As Integer, ByVal lpSecurityAttributes As Integer, _
                               ByVal dwCreationDisposition As Integer, ByVal dwFlagsAndAttributes As Integer, _
                               ByVal hTemplateFile As Integer) As Integer
    End Function

    <DllImport("CoreDll.dll", setlasterror:=True)> _
    Public Function DeviceIoControl(ByVal m_handle As Integer, ByVal dwIoControlCode As Integer, _
                                    ByVal npInBuffer As String, ByVal nInBufferSize As Integer, _
                                    ByVal lpOutBuffer As String, ByVal nOutBufferSize As Integer, _
                                    ByVal lpBytesReturned As Integer, ByVal lpOverlapped As Integer) As Boolean
    End Function

    <DllImport("CoreDll.dll")> _
   Public Function GetLastError() As Integer
    End Function

    <DllImport("coredll.dll")> _
    Public Function CloseHandle(ByVal m_handle As IntPtr) As Integer
    End Function


使用的時候會像是下面這樣

Dim _NDISAdapterName As String = mMyInfo.NDISAdapterName
Dim m_handle As Integer
      
m_handle = CreateFile("NDS0:", 0, 0, Nothing, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE)

If Not DeviceIoControl(m_handle, IOCTL_NDIS_REBIND_ADAPTER, _NDISAdapterName, _
                              _NDISAdapterName.Length * 2 + 2, Nothing, 0, 0, 0) Then
    ''intResult = GetLastError()
    bolResult = False
Else
    bolResult = True
End If

CloseHandle(m_handle)


這樣就可以馬上套用新的IP設定了,這邊做個備忘也給各位參考了。

Note:程式碼中錯誤處理的部分沒有做很仔細的錯誤處理,還請自行加上嚕

2011年12月26日星期一

關閉接收中的UdpClient

在撰寫Udp相關的應用時,呼叫Receive方法時會等候到接收了資料為止;因為這個特性,通常會使用另外一個Thread來處理Udp的動作,例如說一個接聽廣播封包的thread,專門對特定的port number等候廣播訊息,而接聽到指令之後進行特定動作,程式碼可能長的像是下面這樣

Private Sub WaitForCommand()
       
        Do
            If _bolStop Then Exit Do

            Try
                btyRecv = _client.Receive(_anyEndpoint)
                If btyRecv.Length > 0 Then
                    If ByteToStr(btyRecv) = "command" Then
                        ''do something
                    End If
                End If
            Catch ex As Exception  
                ''錯誤處理
            End Try

            Threading.Thread.Sleep(100)
        Loop
    End Sub

當執行到_client.Receive之後,就會在這一行指令等候資料接收,那麼在這個狀況之下,如果應用程式必須要關閉的話,要怎麼處理呢?Thread.Abort() ? 這個時候如果呼叫Thread的Abort方法還是無法停止Thread的運作 Orz

那麼應該怎麼做呢?搜尋了一下之後發現方法也是出乎意料的簡單,直接呼叫UdpClient的Close方法就可以了,那麼就可以用類似下面的方式來停止等候接收


Public Sub [Stop]()
        _bolStop = True
        Try
            If _client IsNot Nothing Then
                _client.Close()
            End If
        Catch ex As Exception
            ''錯誤處理
        End Try
    End Sub


其中要特別留意Exception的處理,因為呼叫了Close,在接受資料這邊是會出現錯誤狀況的;給大家參考看看了 :)

2011年12月9日星期五

你知道WP7的模擬器也有中文輸入嗎?

這篇我應該是Lag很大,不過由於有實機可以測試就一直沒去看模擬器的設定 XD
今天看了一下,模擬器中也有中文輸入的設定可以使用,下面就直接用幾張圖來看吧~



簡短的分享一下我 Lag很大的資訊 Orz

2011年12月8日星期四

自訂ValueConverter (值轉換器)

在Silverlight中,Binding(資料繫結)是一個很強大而且方便的功能;利用Binging可以將元素的屬性跟其他的元素屬性作綁定,或是綁定到我們自訂定義的類別。詳細的下次再來談,這次先來看看ValueConverter;轉換器所扮演的角色是做為一個中介,例如說我們想要將一個Checkbox的Visibility綁定到自訂的類別屬性上面去,那麼應該要怎麼做呢?下面就來看看這個部分

假設現在有一個類別叫做clsImageItem,裡面定義了一些屬性,例如
public uint ImageWidth { get; set; }
        public uint ImageHeight { get; set; }
        public int ImageIndex { get; set; }
        public bool IsEditMode 
        { 
            get
            {
                return _IsEditMode;
            }
            set
            {
                _IsEditMode = value;
                NotifyPropertyChanged("IsEditMode");
            } 
        }

而在介面的設計上,放了一個StackPanel,StackPnael中放置了一個CheckBox以及Image;希望達成的效果是在一般的情形下,CheckBox是不可見的,而進入『編輯模式』的時候,就將CheckBox給顯示出來,介面的XAML大概會像是這樣

<StackPanel Orientation="Horizontal" d:DesignWidth="290">
    <CheckBox x:Name="chkMark" VerticalAlignment="Top" Width="55"
       Visibility="{Binding IsEditMode, 
              Converter={StaticResource VisibleConverter}}"/>
    <Image Width="90" Source="{Binding TumbUrl}" 
        Stretch="UniformToFill" d:LayoutOverrides="Width" />
StackPanel>
在上面的XAML就可以看到在CheckBox的Visibility屬性直接Binding到了IsEditMode的屬性,並且賦予了一個自訂的Converter,這個Converter也是一個自訂的類別,主要是處理邏輯,比如說當IsEditMode == true的時候,要吐甚麼東西給CheckBox的Visibility屬性,程式碼大概會像是這樣
public class clsVisibleConverter : IValueConverter
    {

        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if ((bool)value)
                return Visibility.Visible;
            else
                return Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }
另外由於在XAML中利用的StaticResource去綁定,所以在頁面的資源中要再加入資源的設定,像是下面這樣

<UserControl.Resources>
    <myConverter:clsVisibleConverter x:Key="VisibleConverter" />
UserControl.Resources>

這樣就可以達到想要的效果,在一般情形下畫面會像是左側的樣子,進入了編輯模式就會像是右邊圖片顯示出來的效果了

2011年11月29日星期二

Cross-domain calls for Silverlight apps on self-hosted service

最近開始將一些新的App改用WPF來實作,而在撰寫的過程中也一起試了一下Silverlight,畢竟如果用SL可以搞定的話,Web部屬的方便性還是要比Client-Server一台一台去安裝要來的方便很多的。
而在測試Silverlight的過程中,想起在之前就有看過一些安全性的規定,在跨網域(cross-domain)的狀況下,Silverlight是會被限制存取的;而現在大部分的App後面都帶著一隻Windows Service,並且裝載了WCF Service提供呼叫,所以就優先來測試一下這個部分了。

在進入今天的正題之前,先來看一下在一般的情形下(這裡的一般指的是裝載在IIS上的Service或是網站資源等狀況),Silverlight apps如果需要跨網域去存取資源的話要怎麼做呢? 首先先說一下跨網域,跨網域的意思是什麼呢?比如說Silverlight裝載的位置是http://www.myweb.com/myApp,而開始執行App之後,假設App需要去呼叫位於http://www.othersite.com/xxxx.asmx所提供的Web Service,那麼這個時候的動作就是cross-domain了,那怎麼去處理這個問題呢?首先可以參考一下這篇資料
在上面這篇文章可以看到有兩種方式可以處理,加入『clientaccesspolicy.xml』或是『crossdomain.xml』都可以,首先要特別注意的是不論使用哪個檔案,都必須放置在服務的提供端,而不是放在Silverlight app這邊,所以如果提供服務的這端如果不是你自己可以控制的,那麼就要聯絡服務端,確認是不是可以開放呼叫的權限,要不就是要另外自行撰寫另外的Service來做中介,一邊向原始來源取得資料,另一邊提供給Silverlight app使用了。 這邊簡單的看一下clientaccesspolicy.xml的內容,檔案內容會長的像是下面這樣

<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-request-headers="SOAPAction">
        <domain uri="*">
      </domain></allow-from>
      <grant-to>
        <resource include-subpaths="true" path="/">
      </resource></grant-to>
    </policy>
  </cross-domain-access>
</access-policy>

內容還滿容易理解的,在allow-form http-request-headers="SOAPAction"這個是表示允許SOAP的操作要求,而接下來的domain uri="*"在這邊是指允許所有地方連線過來取得資源的要求,而要限定只允許某個Uri的話就會是設定成像domain uri="http://www.othersite.com"這樣的設定,詳細的說明可以參考一下上面提到的網頁內容。
檔案準備好了之後,是要擺放在服務端的根目錄中;以上面提到的例子來說,服務是位於http://www.othersite.com/xxxx.asmx,那麼檔案就必須在http://www.othersite.com/clientaccesspolicy.xml,如果位置錯誤的話,那麼Silverlight app呼叫的時候也是會跟著出現cross-domain的錯誤的,這個要特別注意一下。

好,那麼接下來就進入正題了,在Self-hosted web service(自我裝載的web服務)的情形要怎麼處理這個問題;那麼也許你心中的第一個想法跟我是一樣的,『不是就是把上面的檔案給放到網站的根目錄就行了』,結果我就這麼給他用下去,結果就..殘念,這個想法是行不通的,為什麼?
以我的應用情境來說,我是建立了一個Windows Service,在這個Windows Service中利用ServiceHost類別提供的功能,來裝載進一個Web Service給其他的用戶端呼叫使用,而通常這樣的狀況下,會定義出一個服務的名稱(Uri)以及使用的連接埠號碼,例如說http://192.168.1.1:1234/myService這樣的服務位置,看過上面的說明,很直覺的就想要把設定檔案放到http://192.168.1.1/clientaccesspolicy.xml這個位置,但是由於服務並非裝載在IIS上,因此Silverlight app發出要求的時候是會到http://192.168.1.1:1234/clientaccesspolicy.xml這個地方來確認是不是有相關的存取權限的,因為找不到檔案,所以Silverlight也無法順利取得資源。那麼解決方式也就出來了,就是要想辦法搞出http://192.168.1.1:1234/clientaccesspolicy.xml這個東西出來,來讓Silverlight app可以順利的取得存取的權限,那就搞定了,那麼接下來就是要修改一下Service這邊的程式碼了。

首先,下面先列出參考來源,我也是依照下面這些資源的方式下去修改程式碼、測試的
接下來看一下要修改的部分,首先在Widnwos Service的架構中,通常會有下面這些檔案(以Visual Basic為例,檔案名稱為示範用途不會一致)
  • myWindwosService.vb
  • 這是Widnwos Service主要程式碼的檔案
  • ImyWebService.vb
  • 這個檔案是定義服務提供的方法、資料型別/內容的介面(interface)檔案
  • myWebServiceHost.vb
  • 這個檔案是實作介面的類別,介面的細節都會在這個程式碼中加以實作
接下來,由於要實作產生cross-domain時的xml檔案動作,先新增一個介面(interface)檔案,這邊名稱就取做IPolicyRetriever.vb,內容會像是下面這樣


Imports System.IO
Imports System.ServiceModel
Imports System.ServiceModel.Web

<servicemodel.servicecontract()>
Public Interface IPolicyRetriever
    <operationcontract(), webget(uritemplate:="/clientaccesspolicy.xml" )="">
    Function GetSilverlightPolicy() As Stream
End Interface


很簡單的一個檔案;其中這個GetSilverlightPolicy的方法就是要實作當Silverlight app對http://192.168.1.1:1234/clientaccesspolicy.xml發出要求的時候,需要處理的動作了。接下來在myWebServiceHost.vb這個原本實作Web Service提拱的功能的檔案中,再實作一個剛剛定義出來的介面(IPolicyRetriever),實作的程式碼節錄出來大致會像是下面這邊


Public Class AcsServiceHost
    Implements ImyWebService
    Implements IPolicyRetriever

    Public Function GetSilverlightPolicy() As System.IO.Stream Implements IPolicyRetriever.GetSilverlightPolicy
        ServiceModel.Web.WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml"
        Return New IO.MemoryStream(Encoding.UTF8.GetBytes(PolicyXML))
    End Function

    Private Const PolicyXML As String =
        "" &
        "" &
            "" &
                "" &
                  "" *="">" &
                      "" *="">" &
                  "" &
                  "" &
                      "" &
                  "" &
                "" &
            "" &
        ""
End Class


這邊我是有點偷懶,直接宣告了一個字串,裡面就是xml檔案內容,存取權限的部分也沒有做任何的限制,這個部分可以依照實際的需求再去調整。
實作完介面的方法之後,接下來就是要設定一下ServiceHost的部分了;在myWindowsService.vb這個檔案中,應該會看到原本設定ServiceHost的程式碼區域,以我的使用情況來說,會像是下面這樣


Dim basic As New BasicHttpBinding()
        basic.MaxBufferSize = 8192000
        basic.MaxBufferPoolSize = 8192000
        basic.MaxReceivedMessageSize = 8192000
        basic.MessageEncoding = WSMessageEncoding.Text

        Host = New ServiceHost(GetType(AcsServiceHost), New Uri("http://192.168.1.1:1234/myWindowsService"))
        Host.AddServiceEndpoint(GetType(IAcsService), basic, "http://192.168.1.1:1234/myWindowsService")

        Host.AddServiceEndpoint(GetType(IPolicyRetriever), New WebHttpBinding, "http://192.168.1.1:1234").Behaviors.Add(New Description.WebHttpBehavior)
        Dim smb As Description.ServiceMetadataBehavior = New Description.ServiceMetadataBehavior
        smb.HttpGetEnabled = True
        Host.Description.Behaviors.Add(smb)

        Host.Open()


其中可以看到對於Host(也就是ServiceHost類別的執行個體)加入了兩個Endpoint,第一個是原先使用中的,是屬於basicHttpbinding的類型,而第二個Endpoint是WebHttpBinding,第二個加入的這個主要就是當要求cross-domain需要的xml檔案時,要連接到的網址用的;而往下一點的程式碼也可以看到,必須要把httpGetEnable給設定為True才可以正常動作喔。
這樣就完成了整個動作,如果想要測試看看是不是能順利的讓Silverlight app呼叫的話,在直接測試app之前,可以先用IE連線到http://192.168.1.1:1234/clientaccesspolicy.xml來看看是不是有正常的產生出xml資料,有的話Silverlight app就可以正常運作了。
那麼就趕緊動手測試看看吧~