2014/4/16

[JavaScript] Iframe Communication

最近遇到了要跟 IFrame 去做互動
使用JavaScript可以達成這樣的需求



首先來製作Parent.htm

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Parent Frame</title>
    <style type="text/css">
        #PT1
        {
            width: 129px;
        }
        #PT2
        {
            width: 168px;
        }
    </style>
</head>
<body>
    <div>
        Send to Child:
        <br />
        <input type="text" id="PT1" size="20" />
        <input type="button" value="Send" onclick="SendMsgToChild()" />
        <br />
        <br />
        Receive From Child:
        <br />
        <input type="text" id="PT2" size="20" /><br />
        <br />
        <hr />
        <iframe src="Child.htm" id="Childframe" width="250px" height="180px"></iframe>
    </div>
</body>
</html>
<script type="text/javascript">
    function SendMsgToChild() {
        document.getElementById('Childframe').contentWindow.ReceiveMsgFromParent(document.getElementById('PT1').value);
    }

    function ReceiveMsgFromChild(message) {
        document.getElementById('PT2').value = message;
    }
</script>


看到裡面有一個<IFrame>的控制項,這邊決定子視窗的路徑
id="Childframe"很重要,要給他id,之後才能找到他

按鈕的觸發事件就會傳送訊息給Child.htm,會去呼叫他的ReceiveMsgFromParent()
document.getElementById('Childframe').contentWindow.ReceiveMsgFromParent(document.getElementById('PT1').value);

ReceiveMsgFromChild()是接收來自Child.htm的訊息


接著來看 Child.htm
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Child Frame</title>
    <style type="text/css">
        #CT2
        {
            width: 129px;
        }
        #CT1
        {
            width: 168px;
        }
    </style>
</head>
<body>
    <div>
        Receive From Parent:
        <br />
        <input type="text" id="CT1" size="20" /><br />
        <br />
        Send to Parent:
        <br />
        <input type="text" id="CT2" size="20" />
        <input type="button" value="Send" onclick="SendMsgToParent()" />
        <br />
    </div>
</body>
</html>
<script type="text/javascript">
    function SendMsgToParent() {
        parent.ReceiveMsgFromChild(document.getElementById('CT2').value);
    }

    function ReceiveMsgFromParent(message) {
        document.getElementById('CT1').value = message;
    }
</script>


這邊可以看到ReceiveMsgFromParent(),這個就是給Parent呼叫的

按鈕的觸發事件會去呼叫"Parent"的Function
這邊的Parent是關鍵字,會直接導向呼叫這IFrame的那一頁
不用知道父視窗的id
 parent.ReceiveMsgFromChild(document.getElementById('CT2').value);

假設有多層的IFrame呼叫"祖父"的那一頁
只要這樣寫
parent.parent.ReceiveMsgFromChild(document.getElementById('CT2').value);


Demo:

2014/1/27

[JavaScript] RTSP streamed by VLC

最近遇到一個需求,要在網頁上呈現透過RTSP方式傳送的影音串流

我這邊是選用 VLC Player  Plug-in
主要原因是因為它可以跨瀏覽器支援
在IE、FireFox、Chrome 上都可以使用

在寫程式之前,要先測試RTSP的串流是否有正常的發送
可以先下載VLC media player來進行測試

媒體 -> 開啟網路串流
在裡面輸入要測試的RTSP串流的位址



接著來完成網頁的部分
其實這個範例只有單純的使用到HTML
但是如果要對影音串流做控制就需要JavaScript的幫忙了

<!DOCTYPE html>
<html><body>
<object
  classid="clsid:9BE31822-FDAD-461B-AD51-BE1D1C159921" 
  codebase="http://download.videolan.org/pub/videolan/vlc/last/win32/axvlc.cab"
  id="vlc"
  name="vlc"
  class="vlcPlayer"
  events="True">
    <param name="Src" value="rtsp://Your Address" />
    <param name="ShowDisplay" value="True" />
    <param name="AutoLoop" value="False" />
    <param name="AutoPlay" value="True" />
   <embed id="vlcEmb"  type="application/x-google-vlc-plugin" version="VideoLAN.VLCPlugin.2" autoplay="yes" loop="no" width="640" height="480"
     target="rtsp://Your Address" ></embed>
</OBJECT>
</html></body>

這邊嵌入的<Object>就是控制VLC player呈現的控制項
注意這邊有兩地方要輸入 RTSP的位址

給IE看的
<param name="Src" value="rtsp://Your Address" />

給FireFox、Chrome看的
 <embed id="vlcEmb"  type="application/x-google-vlc-plugin" version="VideoLAN.VLCPlugin.2" autoplay="yes" loop="no" width="640" height="480"
     target="rtsp://Your Address" ></embed>


研究過程中有看到說 HTML5 的 Video Tag可以支援RTSP
但是我怎麼試都是不成功....後來才發現有另一派的言論說HTML5不支援

如果有一天HTML5支援RTSP,就會變得很方便了


範例檔


參考資料:
http://stackoverflow.com/questions/14711438/vlc-javascript-api-on-ie

http://nerijuso.lt/how-stream-video-with-vlc-plugin-in-your-website/

http://stackoverflow.com/questions/3120027/embed-vlc-player-in-html



2013/12/18

Embed Javascript in Blogger



在Blogger 裡面加入JavaScript 的想法
找了很多的方法,終於完成了

這邊主要分成兩個部分
1.將JavaScript找一個網路空間放置
2.將 JavaScript(html) 嵌入 Blogger

第一個部分花了點時間去尋找
主因是因為不想要花錢.....

後來找到Dropbox 跟Site44的結合
就可以顯示靜態網頁(也可以放入JavaScript)

教學網址:
Site44:讓你在 Dropbox 免費雲端空間上架設網頁

設定完成之後,在Dropbox裡面就初出現以下的路徑
這邊就可以放想放的網頁了




第二個部分比較簡單
只要使用 iframe 的標籤就可以將其他的網頁嵌到Blogger裡面了

frameborder -> 邊框
height -> 高度
width -> 寬度
src -> URL 來源

<iframe frameborder="0" height="380" src="//mrj.site44.com/LeafLet/leaflet.htm" width="570"></iframe>

將上面區塊程式碼的內容貼到Blogger的HTML模式中




2013/11/1

[PowerShell] cannot be loaded because the execution of scripts is disabled on this system - Server 2008 R2

最近在研究PowerShell,在執行的時候遇到了一些問題
直接打開PowerShell執行 xxx.ps1 的Script是可以正常運作的
但是要使用C# 去呼叫寫好的 xxx.ps1就會發生問題了

xxx.ps1 檔案無法載入,因為這個系統上已停用指令碼執行。如需詳細資訊,請參閱 \"get-help about_signing\"。"}

英文版

xxx.ps1 cannot be loaded because the execution of scripts is disabled on this system.

依照他的提示打指令"get-help about_signing"看了一下 
PowerShell有些執行上的政策去限制了檔案(.ps1)的執行

有四種執行的政策

Restricted - 限制任何的.ps1的執行....這是預設值

AllSigned - 要執行的.ps1都要經過信任者的簽名發行

RemoteSigned - 這是允許存取本機電腦上.ps1,但是透過網路去存取的就不行

UnRestricted - 完全不限制.ps1的執行
指令"Get-ExecutionPolicy" 可以取得目前的政策狀況
如果是自己寫的.ps1應該是 RemoteSigned 的權限就可以執行了
指令"Set-ExecutionPolicy RemoteSigned" 可以去更改執行政策



如畫面顯示我的執行政策已經是 UnRestricted 但是還是出現一樣的錯誤

後來才發現我使用的作業系統是 Server 2008 R2
同時會存在著 X86 和 X64兩種版本
需要檢查兩個版本是否都是可以執行的權限

X86的路徑
C:\Windows\system32\cmd.exe



X86的執行政策是 UnRestricted

接下來檢查X64的設定
C:\Windows\SysWOW64\cmd.exe

就會發現X64的執行政策是 Restricted,難怪一直都不能執行!!!
只要修改X64的政策就能執行了


這個問題困擾了我一陣子,經過這一次的經驗
下次在處理Server的問題時,就會多注意到X64和X86的版本問題

從失敗中學經驗~~

參考資料:
http://stackoverflow.com/questions/4037939/powershell-execution-of-scripts-is-disabled-on-this-system

2013/10/31

[PowerShell] get-wmiobject invalid class - 模組多次Import 錯誤

最近在研究使用PowerShell 跟Hyper-V 互動
寫了一個 Script(.ps1)去建立&設定VM

Import-Module hyperv

$newvm = "JJ_VM1-3"
$vhdpath="C:\Users\Public\Documents\Hyper-V\Virtual hard disks\jj1-3.vhd"
$cpu=2
$memsize=1024
$memlimit=2048
$vmVirtualSwitch="Test2"


New-VM $newvm

Add-VMDisk -VM $newvm -Path $vhdpath 0 0

Set-VMCPUCount -VM $newvm -CPUCount $cpu 

Set-VMMemory -VM $newvm -Memory $memsize

Add-VMNic -VM $newvm -VirtualSwitch $vmVirtualSwitch

就可以成功的建立VM了

但是要再次執行時就發生了問題....
就會出現下面的錯誤訊息

Get-WmiObject : Invalid class

想說奇怪剛剛不是好好的嗎??
同樣的程式卻不能執行兩次...
重複試了很多次,還是出現相同的錯誤

最後關掉了PowerShell的視窗,重新開一個
執行Script,又成功建立VM了
但是當我要在執行第二次的時候又出現了相同的錯誤...

重複試了幾次只要是開視窗的第一次執行
都可以成功,後面就都會出現錯誤訊息了




仔細看了一下錯誤的訊息,好像是找不到模組
可是我的Script 的第一行不就 Import-Module
如果沒有Import 第一次也不會成功阿....

找很久之後終於找到了答案
原來是模組多次 Import造成這樣的問題....
以為頂多是 On 跟 Off 狀態而已

但是看看錯誤訊息跟上一篇沒有 Import模組的不一樣
一旦重複 Import之後就回不去了....只能重開視窗了

那有什麼方法可以避免重複 Import呢??

if(!(get-module hyperv))
{
   import-module hyperv
}
其實只要改成要Import前,先判斷模組是否已經存在了
如果沒有的話再Import,這樣就沒問題了


參考資料:
http://pshyperv.codeplex.com/discussions/230371

2013/10/30

[PowerShell]使用 PowerShell 來操控 Hyper-V

最近開始接觸到了Hyper-V,想著要如何去做到自動化的功能(建立VM等....)
找些網路上的文章有使用 PowerShell 和 C#
最後考量到 PowerShell 的彈性比較大,所以選用

我使用的是 Windows Server 2008 R2, 上面搭載Hyper-V 2.0 的版本
但是我手邊的參考書都是 Windows Server 2012 使用的都是 Hyper-V 3.0
書上沒有特別強調要去安裝設定 PowerShell ,我就以為 Windows Server 2008 R2也不用設定
但是在打第一句指令的時候就出錯了....

Get-VM 這個指令是取得機器上有那些VM


上網找了資料才發現原來還要替 PowerShell安裝 Hyper-V的套件才能使用

下載解壓縮之後,找到 install.cmd 用系統管理員的身分去執行


在安裝的過程會出現兩個錯誤,但是不會造成影響

接著會要確認登錄編輯程式,就按"是"



接著會跳出一個視窗就可以打 Get-VM 這個指令
就會跳出機器上的VM了

以為這樣就可以使用了,關掉視窗之後再打開就還是不行....
後來才發現使用之前 Import-Module ,但是還是出錯了...
奇怪剛剛登錄程式不是有按"是"...

後來知道要經過重開機之後才會重新登錄程式
也才找的到Hyper-V 的 Module


這時候Get-VM 這個指令就可找出VM了


這是我第一次接觸PowerShell & Hyper-V
所有的資訊都是Google來的,只是在這邊留個紀錄
我遇到了這個問題並且解決了這個問題

參考資料:

2013/10/6

[c#] 錄音程式

先前有寫到有使用WebCam錄影的功能
但是錄製的影片只有影像沒有聲音的
想要加入聲音,但是研究後發現 EmguCV無法加入聲音
而且只支援.avi格式的限制

所以就先來個寫個錄音的小程式
之後再來做整合

首先先拉畫面
有三個按鈕 "錄音"、"結束"、"播放"
接著是下面的 WindowsMediaPlayer的元件
這邊會遇到一些小問題,可能會在工具箱裡面找不到
在工具 -->選擇工具箱項目  可以設定

選擇 COM元件 ,將 Windows Media Player打勾

之後在工具箱裡就可以找到了



接著就可以開始寫程式碼了
這邊遇到一個新的東西 -- DllImport
稍微研究一下是說要使用第三方非在管理範圍中DLL的方法
還沒有完全研究完,等之後有比較清楚再進行補充

        //使用非託管(Unmanaged)的DLL
        [DllImport("winmm.dll", EntryPoint = "mciSendString", CharSet = CharSet.Auto)]
        public static extern int mciSendString(
         string lpstrCommand,
         string lpstrReturnString,
         int uReturnLength,
         int hwndCallback
        );

mciSendString 是用來播放多媒體資料的API
參考文獻

開始錄音,有一些的參數設定
可以依據需求去調整
        //開始錄音
        private void button1_Click(object sender, EventArgs e)
        {
            mciSendString("set wave bitpersample 8", "", 0, 0);
            mciSendString("set wave samplespersec 20000", "", 0, 0);
            mciSendString("set wave channels 2", "", 0, 0);
            mciSendString("set wave format tag pcm", "", 0, 0);
            mciSendString("open new type WAVEAudio alias movie", "", 0, 0);
            mciSendString("record movie", "", 0, 0);

            button1.Enabled = false;
            button2.Enabled = true;
        }

結束錄音時,將檔案存在我們定義的路徑跟檔名
//結束錄音
        private void button2_Click(object sender, EventArgs e)
        {
            //檔案存放的路徑
            fileName = string.Format("{0}{1}{2}", voiceDirectory, DateTime.Now.ToString("yyyyMMddHmmss"), ".avi");

            mciSendString("stop movie", "", 0, 0);
            mciSendString("save movie " + fileName, "", 0, 0);  
            mciSendString("close movie", "", 0, 0);

            button1.Enabled = true;
            button2.Enabled = false;
            button3.Enabled = true;
        }



之後我們可以播放一下剛剛的錄音檔
看錄製的效果如何
//播放錄音檔
        private void button3_Click(object sender, EventArgs e)
        {
            if (!playing)
            {
                playing = true;
                button3.Text = "停止";
                //播放錄製的檔案
                this.axWindowsMediaPlayer1.URL = fileName;
                axWindowsMediaPlayer1.Ctlcontrols.play();
            }
            else
            {
                axWindowsMediaPlayer1.Ctlcontrols.stop();
                playing = false;
                button3.Text = "播放";
            }  
        }

這樣就可以達成簡單的錄音程式
如果要陽春一點,這邊就可以跟之前的WebCam錄影程式整合
雖然會是影像跟音效檔分開,但是只要在程式裡面使用兩個WindowsMediaPlayer的元件
就可以同時有影像跟聲音了....

但是這使用上還是很不方便
之後再來研究有沒有更完整的方法吧

DEMO