2024年10月17日 星期四

[Notepad++]前後字串加上雙引號

 有時候可能需要在字串的前後加上雙引號,我們就可以使用Notepad++來處理。

可以在尋找內容的地方輸入^(字串的後方就輸入$),並在取代的地方輸入你想替換的符號,接著在搜尋模式的地方選取規則運算式,接著再按下全部取代即可。

\r\n 換行

2023年11月15日 星期三

Excel 敏感資料遮蔽處理

參考資料:[Excel] 個資隱碼篇-例身分證G123***456

有時候Excel中有些欄位資料是很敏感的,例如姓名、身分證字號、電話、信箱等,遇到這些欄位我們就必須作敏感資料的遮蔽處理。

1-1. 身分證字號,從第幾碼之後將敏感資料用*號替代

=REPLACE(A2,D2,(LEN(A2)-D2)+1,REPT("*",(LEN(A2)-D2)+1))


1-2.信箱,從第幾碼之後將敏感資料用*號替代,但只保留@之後的資訊

=REPLACE(A5,D5,(FIND("@",A5)-D5),REPT("*",(FIND("@",A5)-D5)))


2026/09/24 姓名資料遮蔽

=LEFT(A2, 1) & REPT("*", LEN(A2) - 1)


畫面如下



2023年7月19日 星期三

MS SQL 計算字串中的全形、半形,各佔幾個字

計算字串中的全形、半形,各佔幾個字。

DECLARE @MSG nvarchar(500),@OrderNo int,@x1 int,@s1 int;

--假設@MSG為要計算的字串內容
Set @MSG=N'零壹貳參肆伍陸柒捌玖拾零壹貳參肆伍陸柒捌玖拾零壹貳參肆伍陸柒捌玖拾零壹貳參肆伍陸柒捌玖拾零壹貳參肆伍陸柒捌玖拾零壹貳參肆伍陸柒捌玖ab,cdA。';

Set @x1=LEN(@MSG);
Set @s1=1;

DECLARE @fullWidthCount INT,@halfWidthCount INT;
Set @fullWidthCount=0;
Set @halfWidthCount=0;

WHILE (@s1<=@x1)
BEGIN
IF (UNICODE(SUBSTRING(@MSG, @s1, 1)) > 255)
Begin
Set @fullWidthCount=@fullWidthCount+1;
End
ELSE
Begin
Set @halfWidthCount=@halfWidthCount+1;
End
--加1
Set @s1=@s1+1
END

print DATALENGTH(@MSG);
print LEN(@MSG);
print 'fullWidthCount='+Convert(varchar,@fullWidthCount)+';halfWidthCount='+Convert(varchar,@halfWidthCount);

2023年6月20日 星期二

Windows 修改Apache port,瀏覽器強制導回localhost

本篇記錄當我修改完Apache port後,在瀏覽器的網址列輸入localhost:8081,瀏覽器就會自動強制導回localhost。

參考資料:Apache Virtual Host 多網域網站放置在同一台主機

2023/06/20 

一般修改Apache Port只需要修改httpd.conf檔即可,檔案的位置位在apache/conf目錄底下,並找到以下兩行代碼,如下。

Listen 80
.....
ServerName localhost:80

將上方的80 Port改為你想要的Port即可,我是將80改為8081,改完後請重新啟動Apache。

重點來了,當我重啟Apache後,只要我在瀏覽器的網址列輸入localhost:8081(預設的80是我本機的IIS),瀏覽器就會自動強制導回localhost(也就是IIS),因為我公司專案是委外開發的,後來我在httpd.conf看到了這一行代碼,如下。

# Virtual hosts
Include conf/extra/httpd-vhosts.conf

原來我的專案中是有設定了Virtual hosts,其目的是為了可以在同一個伺服器架設多個網站。

於是我試著修改conf/extra/httpd-vhosts.conf檔,將原本有80的地方改為8081,如下。

<VirtualHost _default_:8081>
DocumentRoot "${WEBROOT}"
<Directory "${WEBROOT}">
Options FollowSymLinks
AllowOverride All
Require all granted
AddDefaultCharset utf-8
</Directory>
</VirtualHost>

修改完後一樣重新啟動Apache,就可以正常執行localhost:8081

2020年6月8日 星期一

ASP.NET WebForm RadioButtonList 使用JQuery取得使用者所選擇的項目

參考資料1:[jQuery] RadioButtonList 取值


<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
    <script src="js/jquery-1.11.3.js"></script>
    <script type="text/javascript">
        $(document).ready(function () {
            $('input[type="radio"][name="<%=RBL1.UniqueID %>"]').change(function () {
                var SelectVal = $(this).val();
                var SelectText = $(this).closest('td').find('label').text(); //用closest取得radio上一層的td,並取得label的text
                $('#<%=Label1.ClientID%>').text(SelectText+':');

            });
//法1.請看參考資料1
            //$('#<%=Label1.ClientID%>').text($('input:radio[name="<%=RBL1.UniqueID %>"]:checked + label').text()+':');
//法2.先取得RadioButtonList預設選取哪一個項目,並用closest取得radio上一層的td,並取得label的text
            $('#<%=Label1.ClientID%>').text($('input:radio[name="<%=RBL1.UniqueID %>"]:checked').closest('td').find('label').text()+':');
        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
        <div>
    查詢方式:
            <asp:RadioButtonList ID="RBL1" runat="server" RepeatDirection="Horizontal">
                <asp:ListItem Selected="True" Value="0">姓名</asp:ListItem>
                <asp:ListItem Value="1">學號</asp:ListItem>
            </asp:RadioButtonList>
            <br/>
            <asp:Label ID="Label1" runat="server"></asp:Label>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
        </div>
    </form>
</body>
</html>

2019年10月1日 星期二

Delphi TADOQuery 查詢資料

參考資料1:[delphi]Delphi ADOQuery連接數據庫的查詢、插入、刪除、修改
參考資料2:請問有關動態建立ADOQuery的方法

uses ...., ADODB; //要使用TADOQuery必須在uses這裡先引用ADODB

procedure TForm1.ButIfClick(Sender: TObject);
var tmp: string;
var DMODULE:TDATAMODULE;
    ADOQueryTmp1:TADOQuery;
begin

  tmp:='';
  InputQuery('查詢', '請輸入學號或姓名:', tmp);
  tmp:=trim(tmp);
  if tmp='' then
  begin
    ShowMessage('要查詢的資料不能為空白');
    Exit;
  end;

  DMODULE := TDATAMODULE.Create(Application);
  ADOQueryTmp1 := TADOQuery.Create(DMODULE);
  ADOQueryTmp1.ConnectionString :='資料庫的連線字串';
  with ADOQueryTmp1 do
  begin
      ADOQueryTmp1.Close;
      ADOQueryTmp1.SQL.Clear;
      {
      //法1 開始==========================
      //法1.用字串串字串的方式組合出SQL指令
      ADOQueryTmp1.SQL.Text:='Select StudentID,StudentName from Student where StudentID=' + quotedstr(tmp) + ' or StudentName=' + quotedstr(tmp);
      //法1 結束==========================
      }

      //法2 開始==========================
      //建議使用法2
      ADOQueryTmp1.SQL.Text:='Select StudentID,StudentName from Student where StudentID=:D1 or StudentName=:D2';
      ADOQueryTmp1.Parameters.ParamByName('D1').Value:=tmp;
      ADOQueryTmp1.Parameters.ParamByName('D2').Value:=tmp;
      //法2 結束==========================

      //ADOQuery.Open與ADOQuery.ExecSQL不同之處在於ADOQuery.Open一般用在Select查詢;而ADOQuery.ExecSQL用在insert、delete、update等。
      ADOQueryTmp1.Open;

      if ADOQueryTmp1.isempty=false then
      begin
         ShowMessage('有資料,姓名:' + ADOQueryTmp1.FieldByName('StudentName').AsString);
      end;
      ADOQueryTmp1.Close;
  end;

end;

Delphi 字串切割

我所使用的環境是Delphi 7

以下是字串切割的程式碼:

var str_data: string;a: TStringList;
str_data := '0001 王小明'; //假如這是我的資料,0001是職員編號

a := TStringList.Create;
a.Delimiter := ' '; // 指定分割字元
a.DelimitedText := str_data; // 要被分割的字串


然後只要抓取a[0]就可以取得0001

2019年3月13日 星期三

Delphi 備忘錄


Chr(13) 代表換行;有時候在程式碼中,會有些字串希望可以換行,就可以使用Chr(13);也可以在程式碼中直接加上#13#10可以換行,例如:'ABCD'+#13#10+'EFGH'。
Chr(9) 代表Tab鍵,也可以輸入#9。

如果想在一個字串中加入單引號,必須打上兩個單引號,例如:'Hello~ 我是''王小明'''。

內建函數
1. IntToStr 數字轉字串;範例:IntToStr('2019') + 'Hello~'。
2. quotedstr 在字串前後加上單引號;範例:quotedstr('Hello~')。
3. Format 字串格式化;範例:Format('Hello 我是%s,我的專長是%s',['王小明','程式設計']),輸出的結果:Hello 我是王小明,我的專長是程式設計。
4. Exit 中斷執行。

快捷鍵
Delphi 7開發環境
Shift + Ctrl + U或 I   選取程式碼在按下快捷鍵,可增減縮排。



2019/10/02
InputQuery函數的提示文字有缺字
參考資料:inputbox的提示字字數會少SHOW出來
在程式碼中使用InputQuery函數,只要提示的字數到一定的長度,中文字就會有缺字的情況發生,要解決這個問題只要在FormCreate事件中設定DefFontData.Name為新細明體即可,程式碼如下。
procedure TfrmTEST1.FormCreate(Sender: TObject);
begin
  ....
  DefFontData.Name := '新細明體';
  ....
end;

2019年1月12日 星期六

Windows Server 2008 R2 之 RPC 伺服器無法使用

  公司有支小程式是使用C#寫的,專門處理AD(Active Directory),但最近因為Server的網路流量異常,公司同仁就把一些區域連線的設定拿掉,當我再次使用小程式要去修改AD時,就造成沒辦法順利新增或修改,直到我使用逐步執行找原因時,發現程式都會停在設定AD密碼這行程式碼,我也開始在網路上找資料都無法解決,直到我想起公司同仁有去設定區域連線的設定時,我將其中一項設定打勾,再次去執行程式就可以順利執行了,以下是我C#遇到的錯誤訊息。


C#錯誤訊息
System.Reflection.TargetInvocationException: 引動過程的目標傳回例外狀況
RPC 伺服器無法使用。 (發生例外狀況於 HRESULT: 0x800706BA)


解決方法
開啟網路和共用中心→區域連線→內容→勾選「File and Printer Sharing for Microsoft Networks」

以上是我遇到的問題,不見得各位也和我一樣遇到同樣的問題,但我還是在此特別紀錄一下。

2018年12月4日 星期二

Windows CMD指令


2023/04/06
1. 切換目錄
例如:cd C:\Temp

2.  搜尋檔案
例如:dir /s C:\Temp\202303*.zip

3. 複製檔案
COPY C:\ABC\Hello.zip C:\temp
將C:\ABC\Hello.zip檔案複製到C:\temp

2018/12/05
1. 利用nslookup指令,用網址查詢IP
範例:nslookup 網址
例如:nslookup www.abc.com.tw

2018年9月19日 星期三

2018年8月31日 星期五

VB.NET 使用 DES / AES 字串加密

參考資料:[C#.NET] 字串及檔案 利用 DES / AES 演算法加解密

此篇參考上方的參考資料,並翻成VB.NET。

Imports Microsoft.VisualBasic
Imports System.Security.Cryptography '加密
Imports System.Text
Imports System.IO
Public Class EnDe
'字串長度必須為8
    Dim DesKey As String = "abc!@#df", DesIv As String = "+_)xyz*&"

    Public Sub New()
    End Sub

    '參考資料https://dotblogs.com.tw/yc421206/archive/2012/04/18/71609.aspx
'source:要加密的字串
    Function DesEncrypt(ByVal source As String) As String
        Dim des As DESCryptoServiceProvider = New DESCryptoServiceProvider()
        Dim key() As Byte = Nothing
        Dim iv() As Byte = Nothing
        Dim dataByteArray() As Byte = Nothing

        key = Encoding.ASCII.GetBytes(DesKey)
        iv = Encoding.ASCII.GetBytes(DesIv)
        dataByteArray = Encoding.UTF8.GetBytes(source)

        des.Key = key
        des.IV = iv

        Dim encrypt As String = String.Empty
        Using ms As MemoryStream = New MemoryStream()
            Try
                Using cs As CryptoStream = New CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write)
                    cs.Write(dataByteArray, 0, dataByteArray.Length)
                    cs.FlushFinalBlock()

                    Dim sb As StringBuilder = New StringBuilder()
                    For Each b As Byte In ms.ToArray()
                        sb.AppendFormat("{0:X2}", b)
                    Next
                    encrypt = sb.ToString()
                End Using
            Catch ex As Exception
                encrypt = "error"
            End Try
        End Using

        Return encrypt
    End Function

    '解密 encrypt:要解密的字串
    Function DesDecrypt(ByVal encrypt As String) As String

        Dim a1 As Integer = ((encrypt.Length) / 2)
        a1 = a1 - 1
        Dim dataByteArray(a1) As Byte

        For x1 As Integer = 0 To a1
            Dim i As Integer = Convert.ToInt32(encrypt.Substring(x1 * 2, 2), 16)
            dataByteArray(x1) = CByte(i)
        Next

        Dim des As DESCryptoServiceProvider = New DESCryptoServiceProvider()
        Dim key() As Byte = Nothing
        Dim iv() As Byte = Nothing

        key = Encoding.ASCII.GetBytes(DesKey)
        iv = Encoding.ASCII.GetBytes(DesIv)

        des.Key = key
        des.IV = iv

        Dim DesString As String = String.Empty
        Using ms As MemoryStream = New MemoryStream()
            Try
                Using cs As CryptoStream = New CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write)
                    cs.Write(dataByteArray, 0, dataByteArray.Length)
                    cs.FlushFinalBlock()
                    DesString = Encoding.UTF8.GetString(ms.ToArray())
                End Using
            Catch ex As Exception
                DesString = "error"
            End Try
        End Using
        Return DesString
    End Function

End Class

用ASP.NET WebForm來測試,畫面很簡單,兩個TextBox、兩個Button(分別是加密、解密),程式碼如下。

Partial Class _Default
    Inherits System.Web.UI.Page

    Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim str_en As String = String.Empty
        Dim ed As EnDe
        ed = New EnDe()
        str_en = ed.DesEncrypt(TextBox1.Text)
        Response.Write("[" & str_en & "]")

    End Sub
    Protected Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        Dim str_de As String = String.Empty
        Dim ed As EnDe
        ed = New EnDe()
        str_de = ed.DesDecrypt(TextBox2.Text)
        Response.Write("[" & str_de & "]")
    End Sub
End Class

執行過程,如下:


2018年3月2日 星期五

ASP.NET 使用DataTable實作分頁

參考資料:How To Copy DataRows Between DataTables by Using Visual Basic .NET

  這個作法是將資料庫的資料先存到DataTable,然後程式碼中會設定每一頁顯示幾筆資料,並算出目前從第幾筆資料到第幾筆資料,換頁之後在計算出,下一頁該從第幾筆到第幾筆資料,只是這個作法在每一次換頁的時候,都會重新和資料庫拿資料。

前端程式碼
<%@ Page Language="VB" AutoEventWireup="false" CodeFile="test_pagination.aspx.vb" Inherits="test_test_pagination" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
    <link rel="stylesheet" href="../css/bootstrap.css" />
    <script src="../js/jquery-1.11.3.js"></script>
    <script src="../js/bootstrap.js"></script>
    <!--[if lt IE 9]>
      <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
      <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->

</head>
<body>
    <form id="form1" runat="server">
    <div>
        <nav id="nav_pagehead" runat="server">
            <ul id="paging_head" runat="server" class="pagination">
            </ul>
        </nav>
        <asp:GridView ID="GridView1" runat="server">
        </asp:GridView>
        <nav>
            <ul id="paging_foot" runat="server" class="pagination">
            </ul>
        </nav>
    </div>
    </form>
</body>
</html>

後端程式碼
Imports System.Data
Imports System.Data.SqlClient

Partial Class test_test_pagination
    Inherits System.Web.UI.Page
    Dim str_sql As String = String.Empty
    Dim def_dt As DataTable = Nothing

    '=============================
    Dim prows As Integer = 20 '每一頁多少筆數(此處100筆分成一頁)
    Dim this_page As Integer = 1 '目前在第幾頁
    Dim maxpage As Integer = 10 '最多顯示頁數(不變動)
    Dim showpage As Integer = 10 '計算目前顯示頁數

    Sub Call_get_paging()
        '取得目前分頁頁數
        If (Not Request("p") Is Nothing) Then
            If Regex.IsMatch(Request("p").ToString, "^\d+$") = False Then '數字會回傳true
                '不是數字,設定回1
                this_page = 1
            Else
                this_page = CInt(Request("p").ToString)
            End If
        Else
            this_page = 1
        End If
    End Sub

    Private Sub form1_Load(sender As Object, e As EventArgs) Handles form1.Load
        If Not Page.IsPostBack Then


            def_dt = Nothing
            str_sql = "select TOP 5000 * from Student"
 '假設def_dt已經有資料了,請自行換成自己的DataTable
            def_dt = queryDataTable2(str_sql)

            Call_get_paging() '取得目前的頁數,傳到this_page變數

            Dim rows_count As Integer = 0 '資料的總筆數
            rows_count = def_dt.Rows.Count

            Dim dt1 As DataTable = CopyData_NewDataTable(def_dt, this_page, prows)
            If Not dt1 Is Nothing Then
                GridView1.DataSource = dt1
                GridView1.DataBind()
                GridView1.CssClass = "table table-bordered"
            End If
            def_dt.Clear()
            def_dt.Dispose()
            def_dt = Nothing
            'Response.Write("total_rows=" & total_rows & "<br/>")

            If rows_count > 0 Then
                's1開始頁數;tot_x1 全部的頁數
                Dim s1 As Integer = 1, tot_x1 As Integer = 0
                tot_x1 = Fix(rows_count / prows) '總筆數/每一頁多少筆數
                '總筆數 求餘數,餘數>0就加1頁
                If (CInt(rows_count) Mod prows) > 0 Then
                    tot_x1 = tot_x1 + 1
                End If
                '==========================
                '頁數變動
                If this_page >= 7 Then
                    If ((tot_x1 + 1) - ((this_page - 6) + 1)) >= maxpage Then
                        s1 = (this_page - 6) + 1
                        showpage = maxpage + (this_page - 6)
                    Else
                        s1 = ((this_page - 6) + 1) + (((tot_x1 + 1) - ((this_page - 6) + 1)) - maxpage)
                        showpage = tot_x1
                    End If
                Else
                    '預設
                    s1 = 1 '第一頁開始
                    showpage = maxpage '顯示的頁數
                End If
                '==========================
                If tot_x1 > 1 Then
                    Dim str_ago As String = String.Empty, str_back As String = String.Empty, str_num As String = String.Empty
                    Dim str_navpag As String = String.Empty, str_navpag_laquo As String = String.Empty, str_navpag_ago As String = String.Empty, str_navpag_back As String = String.Empty, str_navpag_raquo As String = String.Empty
                    For i As Integer = s1 To tot_x1
                        str_num = CStr(i)
                        If str_num.Length = 1 Then
                            str_num = "0" & str_num
                        End If
                        If i = this_page Then
                            str_navpag = str_navpag & "<li class=" & Chr(34) & "active" & Chr(34) & "><a>" & str_num & "<span class=" & Chr(34) & "sr-only" & Chr(34) & ">(current)</span></a></li>"
                            If i > 1 Then
                                str_navpag_ago = "<li><a href=" & Chr(34) & "test_pagination.aspx?p=" & (i - 1) & Chr(34) & " aria-label=" & Chr(34) & "Previous" & Chr(34) & "><span aria-hidden=" & Chr(34) & "true" & Chr(34) & ">&lt;</span></li>"
                                If i > 2 Then
                                    str_navpag_laquo = "<li><a href=" & Chr(34) & "test_pagination.aspx?p=1" & Chr(34) & " aria-label=" & Chr(34) & "Previous" & Chr(34) & "><span aria-hidden=" & Chr(34) & "true" & Chr(34) & ">&laquo;</span></li>"
                                End If
                            End If
                            If i < tot_x1 Then
                                str_navpag_back = "<li><a href=" & Chr(34) & "test_pagination.aspx?p=" & (i + 1) & Chr(34) & " aria-label=" & Chr(34) & "Next" & Chr(34) & "><span aria-hidden=" & Chr(34) & "true" & Chr(34) & ">&gt;</span></li>"
                                If (tot_x1 - i) > 2 Then
                                    str_navpag_raquo = "<li><a href=" & Chr(34) & "test_pagination.aspx?p=" & tot_x1 & Chr(34) & " aria-label=" & Chr(34) & "Next" & Chr(34) & "><span aria-hidden=" & Chr(34) & "true" & Chr(34) & ">&raquo;</span></li>"
                                End If
                            End If
                        Else
                            str_navpag = str_navpag & "<li><a href=" & Chr(34) & "test_pagination.aspx?p=" & i & Chr(34) & ">" & str_num & "</a></li>"
                        End If
                        If i = showpage Then
                            Exit For
                        End If
                    Next

                    Me.paging_head.InnerHtml = str_navpag_laquo & str_navpag_ago & str_navpag & str_navpag_back & str_navpag_raquo
                    Me.paging_foot.InnerHtml = str_navpag_laquo & str_navpag_ago & str_navpag & str_navpag_back & str_navpag_raquo
                Else
                    Me.nav_pagehead.Attributes.Add("Style", "display:none;")
                    Me.paging_head.InnerHtml = ""
                    Me.paging_foot.InnerHtml = ""
                End If
            Else
                Me.nav_pagehead.Attributes.Add("Style", "display:none;")
                Me.paging_head.InnerHtml = ""
                Me.paging_foot.InnerHtml = ""
            End If
        End If


    End Sub

    Function CopyData_NewDataTable(ByVal def_dt1 As DataTable, ByVal this_page As Integer, ByVal get_count As Integer) As DataTable
        Dim New_dt As DataTable = Nothing
        If Not def_dt1 Is Nothing Then
            '從第幾筆開始,第幾筆結束
            Dim data_Start_count As Integer = 0, data_End_count As Integer = 0
            data_Start_count = (this_page * get_count) - get_count + 1
            data_End_count = this_page * get_count

            New_dt = def_dt1.Clone() '將table的結構複製到新的DataTable
            For y1 As Integer = data_Start_count To data_End_count
                If (y1 - 1) > (def_dt1.Rows.Count - 1) Then
                    Exit For
                Else
                    New_dt.ImportRow(def_dt1.Rows(y1 - 1))
                End If
            Next
            Return New_dt
        Else
            Return Nothing
        End If

    End Function

End Class

2018年2月15日 星期四

VB.NET 連結Access下達Insert指令並取回自動編號Id

參考資料:Getting AutoNumber from Access via "SELECT @@IDENTITY" needs to be done in same connection as the INSERT.


此篇單存只是做個紀錄,目前測試是有效的,可以在下達Insert指令後,透過SELECT @@IDENTITY去取得Access資料庫中的自動編號。

    '|DataDirectory|意思是您的Access資料庫必須將它放在專案中的App_Data資料夾底下
    Public strsqlCon As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|" & WebConfigurationManager.AppSettings("acc_dbname").ToString & ";Jet OLEDB:DataBase Password=" & WebConfigurationManager.AppSettings("acc_dbpwd").ToString & ";Persist Security Info=False"
    Public sqlCon As OleDbConnection 'Connection物件建立ASP.NET程式與資料庫間的連結
    Public E_SQL As Boolean 'SQL指令執行成功或失敗
    Public sql_enq As String = Nothing
    Public Sub ODB_Open()
        '假如資料庫目前以關閉,就開啟資料庫連結
        sqlCon = New OleDbConnection(strsqlCon)
        sqlCon.Open() '開啟資料庫連結
    End Sub

    Public Function ODB_E_insert_getID1(ByVal sqlstr As String, ByVal pv As String, ByVal sqlvalue_p() As String) As String
        Dim insert_cmd As OleDbCommand = Nothing, insert_return As String = "NULL"

        Dim sql_p() As String = Nothing
        sql_p = pv.Split(",") 'sql字串中的參數
        sql_enq = Nothing

        If (sql_p.Length - 1) <> (sqlvalue_p.Length - 1) Then
            E_SQL = False
            insert_return = "err_Lv1"
        Else
            Try
                insert_cmd = sqlCon.CreateCommand()
                Dim x_end As Integer = sql_p.Length - 1
                For x As Integer = 0 To x_end
                    If insert_cmd.Parameters.Contains(sql_p(x)) Then
                        If sqlvalue_p(x) = String.Empty Then
                            insert_cmd.Parameters(sql_p(x)).Value = DBNull.Value
                        Else
                            insert_cmd.Parameters(sql_p(x)).Value = sqlvalue_p(x)
                        End If

                    Else
                        If sqlvalue_p(x) = String.Empty Then
                            insert_cmd.Parameters.AddWithValue(sql_p(x), DBNull.Value) '讓ADO.NET自行判斷型別轉換
                        Else
                            insert_cmd.Parameters.AddWithValue(sql_p(x), sqlvalue_p(x)) '讓ADO.NET自行判斷型別轉換
                        End If
                    End If
                Next

                insert_cmd.CommandText = sqlstr

                Dim insert_enq As Integer = 0
                insert_enq = insert_cmd.ExecuteNonQuery()

                If insert_enq = 1 Then
                    insert_cmd.CommandText = "SELECT @@IDENTITY"
                    insert_return = CStr(insert_cmd.ExecuteScalar())
                    E_SQL = True
                Else
                    insert_return = "err_Lv3" '新增失敗
                End If
            Catch ex As Exception
                insert_return = "err_Lv2"
            End Try
        End If

        If Not insert_cmd Is Nothing Then
            insert_cmd.Dispose()
        End If

        Return insert_return
    End Function

    Public Sub ODB_Close()

        If sqlCon.State = ConnectionState.Open Then
            sqlCon.Close() '關閉資料庫連結
            sqlCon.Dispose()
        End If
    End Sub

2018年2月9日 星期五

Access SQL

2018/03/11
Access使用Like,Access中的*在SQL Server中代表%,但是在ASP.NET中使用System.Data.OleDb還是使用%

2018/02/16
1.使用 StrComp 函數,區分大小寫;此函數如果回傳0代表等於。
SELECT * From TestUser Where StrComp(帳號欄位,'使用者輸入帳號',0)=0 and StrComp(密碼欄位,'使用者輸入密碼',0)=0

2018/02/10
1.日期時間
SELECT  Format(Now(),'yyyy/mm/dd hh:nn:ss');


2018年1月5日 星期五

VB.NET 利用登錄檔,紀錄程式使用次數

參考資料1:[VB6][VBA][C#][JAVA] 製作簡易 時間/次數 測試版 試用版
參考資料2:讀取和寫入登錄 (Visual Basic)
或者搜尋Computer.Registry

Step 1. 畫面上建立三個Button,分別是Button1、Button2、Button3,Button1屬性Name為「點我 增加使用次數」、Button2屬性Name為「刪除使用次數」、Button3屬性Name為「完整刪除」,建議先看一下參考資料2。

Code 如下

Public Class Form1

    '點我 增加使用次數
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        '開啟TEST_Company1\TestAPP01
        Dim regVersion = My.Computer.Registry.CurrentUser.OpenSubKey("TEST_Company1\TestAPP01", True)

        If regVersion Is Nothing Then
            '假如不存在,就在HKEY_CURRENT_USER底下,建立TEST_Company1\TestAPP01
            '這裡TEST_Company1\TestAPP01,有點像是電腦中的資料夾路徑的概念,程式會幫我們儲存在登錄檔的HKEY_CURRENT_USER底下,並建立TEST_Company1\TestAPP01
            regVersion = My.Computer.Registry.CurrentUser.CreateSubKey(
                         "TEST_Company1\TestAPP01") ' Key doesn't exist; create it.
        End If

        Dim int_usage_count As Integer = 0
        If regVersion IsNot Nothing Then
            int_usage_count = regVersion.GetValue("usage_count", 0)
            int_usage_count = int_usage_count + 1
            regVersion.SetValue("usage_count", int_usage_count)
            regVersion.Close()

            MsgBox("使用次數" & int_usage_count)
        End If

    End Sub

    '刪除使用次數
    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        '開啟TEST_Company1\TestAPP01
        Dim regVersion = My.Computer.Registry.CurrentUser.OpenSubKey("TEST_Company1\TestAPP01", True)

        If Not regVersion Is Nothing Then
            '假如存在
            If regVersion IsNot Nothing Then
                regVersion.DeleteValue("usage_count")
                regVersion.Close()
                MsgBox("刪除完成")
            End If
        End If

    End Sub

    '完整刪除
    Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
        '開啟TEST_Company1
        Dim regVersion = My.Computer.Registry.CurrentUser.OpenSubKey("TEST_Company1", True)

        If Not regVersion Is Nothing Then
            '假如存在,就整個刪除
            My.Computer.Registry.CurrentUser.DeleteSubKeyTree("TEST_Company1")

            '假如只要刪除TestAPP01底下的資料,可以使用以下程式碼刪除
            'My.Computer.Registry.CurrentUser.DeleteSubKey("TEST_Company1\TestAPP01")

            regVersion.Close()
            MsgBox("全部刪除完成")
        End If
    End Sub
End Class

Step 2.執行程式完後,可以開啟「登入編輯程式」(開始>搜尋程式及檔案>輸入regedit)


2017年12月29日 星期五

VB.NET 檔案是否被鎖定

  在和朋友聊到他寫的程式,有些使用者反應程式沒有正常執行(好像停擺了),和朋友討論著有哪些原因會造成程式無法正常執行,其中討論到會不會是檔案還在建立中還沒有完成,結果程式去搬移了檔案或複製檔案發生例外錯誤,導致程式無法正常運作。
  我和朋友把這個原因,納入是程式無法正常執行的原因,開始上網搜尋資料,找到以下幾篇參考資料,自己先作個陽春版的程式,實作先檢查檔案是否存在,再檢查檔案是否可以正常讀取檔案,如果不能讀取就表示檔案已被鎖定(Lock)。


參考資料1:[C#]如何偵測特定檔案是否為Lock狀態
參考資料2:can't check in file : file is open by another application
參考資料3:VB.NET Checking if a File is Open before proceeding with a Read/Write?

說明

首先拉個陽春的畫面,畫面上放上2個TextBox、1個Button,TextBox1的作用是自己填上完整的檔案路徑、TextBox2顯示執行過程訊息(其屬性設定為ScrollBars=Vertical、Multiline=True),Button1為執行按鈕。

P.S 因為是陽春測試的小程式,所以沒有防呆,在測試時路徑要填寫完整(例如:D:\test.mp4),不要填錯了。

程式碼

Imports System.IO
Imports System.Runtime.InteropServices

Public Class Form1

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Dim str_thispath As String = String.Empty '完整檔案路徑
        str_thispath = TextBox1.Text
        TextBox2.Text = ""
        If File.Exists(str_thispath) Then
            IsFileOpen(str_thispath)
        Else
            TextBox2.Text = "檔案不存在:" & Date.Now.ToString("yyyy/MM/dd HH:mm:ss.fffffff") & " 結束執行。" & vbNewLine & TextBox2.Text
        End If
        TextBox2.Text = "系統於 " & Date.Now.ToString("yyyy/MM/dd HH:mm:ss.fffffff") & " 結束執行。" & vbNewLine & TextBox2.Text
    End Sub

    Function IsFileOpen(ByVal str_thispath As String) As Boolean
        Dim stream As FileStream = Nothing
        Try
            stream = File.Open(str_thispath, FileMode.Open, FileAccess.ReadWrite, FileShare.None)
            stream.Close()
            TextBox2.Text = "檔案可開啟:" & Date.Now.ToString("yyyy/MM/dd HH:mm:ss.fffffff") & " " & vbNewLine & TextBox2.Text
        Catch ex As Exception

            If TypeOf ex Is IOException AndAlso IsFileLocked(ex) Then
                TextBox2.Text = "發生例外錯誤:原因可能檔案正在使用中已上鎖..." & Date.Now.ToString("yyyy/MM/dd HH:mm:ss.fffffff") & " " & vbNewLine & TextBox2.Text
                Return True
            End If
        End Try
        Return False
    End Function

    Function IsFileLocked(exception As Exception) As Boolean
        Dim ERROR_SHARING_VIOLATION As Integer = 32, ERROR_LOCK_VIOLATION As Integer = 33
        Dim errorCode As Integer = Marshal.GetHRForException(exception) And ((1 << 16) - 1)
        Return errorCode = ERROR_SHARING_VIOLATION OrElse errorCode = ERROR_LOCK_VIOLATION
    End Function

End Class

2017年11月11日 星期六

ASP.NET[VB語法] 初次使用NLog

初次使用NLog,來記錄專案的Log檔,方便追中問題的結果。

圖片太小看不到,請自己另存圖片。


程式碼:
Imports NLog

Partial Class Default_TEST_Nlog
    Inherits System.Web.UI.Page

    Private Sub Default_TEST_Nlog_Load(sender As Object, e As EventArgs) Handles Me.Load
        If Not Page.IsPostBack Then
            Dim logger As Logger = Nothing
            logger = NLog.LogManager.GetCurrentClassLogger()
            logger.Debug("這裡是Page_Load")
        End If
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim logger As Logger = Nothing
        logger = NLog.LogManager.GetCurrentClassLogger()
        logger.Info("Button1_Click")
        logger.Trace("我是Trace")
        logger.Debug("我是Debug")
        logger.Info("我是Info")
        logger.Warn("我是Warn")
        logger.Error("我是Error")
        logger.Fatal("我是Fatal")
    End Sub

End Class

補充:
2017/11/14
如果想要以每個月來記錄Log檔,你可以修改NLog.config這個檔案。先找到這一行,如下:
 <target xsi:type="File" name="f" fileName="${basedir}/logs/${shortdate}.log" layout="${longdate} ${uppercase:${level}} ${message}" />
將 fileName 的${shortdate}.log 改為 ${date:format=yyyy-MM}.log,這樣就會把每一天的log記錄在當月份的log檔。
改完如下:
<target xsi:type="File" name="f" fileName="${basedir}/logs/${date:format=yyyy-MM}.log" layout="${longdate} ${uppercase:${level}} ${message}" />

2017年9月17日 星期日

ASP.NET FileUpload.PostedFile.InputStream + MemoryStream儲存檔案

參考資料1:How to Save the MemoryStream as a file in c# and VB.Net

Web.config
<?xml version="1.0"?>
<configuration>
    <!--這裡自己加入appSettings標籤以及FileUpload_path1-->
    <appSettings>
      <add key="FileUpload_path1" value="~/FileUpload/File1/" />
    </appSettings>
    ....
</configuration>

Default.aspx
<%@ Page Language="VB" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        使用FileUpload.PostedFile.InputStream + MemoryStream儲存檔案<br/>
        <asp:FileUpload ID="FileUpload2" runat="server" />
        <asp:Button ID="Button2" runat="server" Text="Start Upload2" />
        <br/>
        <asp:Label ID="Label2" runat="server"></asp:Label>
    </div>
    </form>
</body>
</html>

Default.aspx.vb
Imports System.IO
Imports System.Web.Configuration

Partial Class _Default
    Inherits System.Web.UI.Page

    Function EnMD5(ByVal EnString As String, Optional ByVal substring_startIndex As Integer = 8, Optional ByVal select_length As Integer = 16) As String
        Dim str_En As String = Nothing
        If select_length = 16 Then
            str_En = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(EnString, "MD5").ToLower().Substring(substring_startIndex, select_length)
        ElseIf select_length = 32 Then
            str_En = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(EnString, "MD5").ToLower()
        Else
            str_En = "0"
        End If
        Return str_En
    End Function

    Protected Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        If Not FileUpload2.PostedFile Is Nothing Then
            Try
                If FileUpload2.HasFile And FileUpload2.PostedFile.ContentLength > 0 Then
                    Dim filetype As String = Nothing
                    Dim bool_by As Boolean = True
                    Dim str_DirPath As String = String.Empty
                    If (Not WebConfigurationManager.AppSettings("FileUpload_path1") Is Nothing) Then

                        str_DirPath = Server.MapPath(WebConfigurationManager.AppSettings("FileUpload_path1").ToString())
                        If Directory.Exists(str_DirPath) = False Then '檢查目錄存不存在
                            '不存在就建立資料夾
                            Directory.CreateDirectory(str_DirPath)
                        End If
                        '====================================
                        Dim s As Stream = FileUpload2.PostedFile.InputStream
                        Dim file_bytes(s.Length - 1) As Byte
                        s.Read(file_bytes, 0, s.Length)

                        Dim header As String = Hex(file_bytes(0)) & Hex(file_bytes(1)) & Hex(file_bytes(2)) & Hex(file_bytes(3))
                        '檢查檔案格式
                        Select Case header
                            Case "FFD8FFE0" '*.jfif *.jpe *.jpeg *.jpg
                                '假如是用小畫家製作的圖或另存的圖檔,header值會是FFD8FFE0,但如果是其他方式產生的jpg圖檔最後一碼會變動
                                filetype = "jpg"
                            Case "25504446"
                                filetype = "pdf"
                            Case "D0CF11E0"
                                filetype = "doc"
                            Case "504B34"
                                filetype = "docx"
                            Case Else
                                bool_by = False
                        End Select
                        '=====================================
                        If bool_by = True Then
                            '====================================
                            Dim myFileName As String
                            myFileName = FileUpload2.PostedFile.FileName
                            Dim c As String = String.Empty  '取得檔案及副檔名System.IO.Path.GetFileName(myFileName)
                            filetype = myFileName.Substring(myFileName.LastIndexOf(".") + 1)

                            '=========================================
                            Dim str_temp_fn As String = String.Empty
                            '用MD5來作檔案名稱
                            str_temp_fn = EnMD5("FU_PATH1_" & Date.Now.ToString("yyyyMMddHHmmssffff"), select_length:=32)
                            Dim Uploadfile As String = String.Empty
                            '重新命名
                            c = str_temp_fn & "." & filetype 'MD5命名
                            Uploadfile = str_DirPath & c
                            Dim myfilecount As Integer = 1
                            '檢查檔名是否有重複
                            While (System.IO.File.Exists(Uploadfile))
                                '有重複的檔案從2開始
                                myfilecount = myfilecount + 1
                                c = str_temp_fn & myfilecount & "." & filetype  'MD5命名 + 第幾個檔案
                                Uploadfile = str_DirPath & c '重新命名並加上副檔名
                            End While
                            '==========================================
                            Dim ms As New MemoryStream(file_bytes)
                            Dim fs2 As New FileStream(Uploadfile, FileMode.Create, FileAccess.Write)
                            ms.WriteTo(fs2)
                            fs2.Close()
                            ms.Close()
                            '==========================================
                            Label2.Text = Uploadfile
                        Else
                            Label2.Text = "檔案格式不符"
                        End If
                        s.Close()
                        s.Dispose() '釋放所有資源要在最後執行,否則即使存檔也無效

                    End If
                Else
                    Label2.Text = "請選擇檔案"
                End If
            Catch ex As Exception
                Label2.Text = ex.ToString
            End Try
        Else
            Label2.Text = "請選擇檔案"
        End If
    End Sub
End Class

2017年7月29日 星期六

ASP.NET 多檔上傳,加上移除檔案按鈕

參考資料:JAVASCRIPT - W3C DOM簡介

繼上一篇「ASP.NET 利用JavaScript達到多檔上傳」,這次我想在每個檔案上傳的地方個別再加上移除檔案的按鈕,除了第一個檔案上傳之外,當我不要這個檔案的時候,我就可以移除我不要的檔案。

執行結果

Step 1.請在另外建立一個aspx檔案,檔名為test_multi-file_fileupload2.aspx,程式碼如下:

紅色的字是我而外加上去的,橘色的底是我有修改過的地方,請先看前一篇的作法。

<%@ Page Language="VB" AutoEventWireup="false" CodeFile="test_multi-file_fileupload2.aspx.vb" Inherits="test_multi_file_fileupload2" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script type="text/javascript">

        function addFileUploadBox() {
            if (!document.getElementById || !document.createElement) {
                return false;
            };
            //取得id叫作upload-area元素
            var uploadArea = document.getElementById('upload-area');
            if (!uploadArea) {
                return false;
            };
            //建立br元素(在Html中叫作換行)
            var newLine = document.createElement('br');
            //在upload-area中加入換行
            uploadArea.appendChild(newLine);
            //建立input元素
            var newUploadBox = document.createElement('input');
            newUploadBox.type = 'file'; //input的類型為file檔案類型
            newUploadBox.size = '40';
            if (!addFileUploadBox.lastAssignedId) {
                addFileUploadBox.lastAssignedId = 1;
            };
            //設定input的id、name
            newUploadBox.setAttribute('id', 'FileF' + addFileUploadBox.lastAssignedId);
            newUploadBox.setAttribute('name', 'FileF:' + addFileUploadBox.lastAssignedId);
            uploadArea.appendChild(newUploadBox);
            //=======================
            //建立input元素-移除檔案 按鈕
            var newBRF = document.createElement('input');
            newBRF.setAttribute('type', 'button');
            newBRF.setAttribute('value', '移除檔案');
            newBRF.setAttribute('onclick', 'RemoveFile(' + addFileUploadBox.lastAssignedId + ');');
            //設定input按鈕的id、name
            newBRF.setAttribute('id', 'BRF' + addFileUploadBox.lastAssignedId);
            newBRF.setAttribute('name', 'BRF:' + addFileUploadBox.lastAssignedId);
            uploadArea.appendChild(newBRF);
            //=======================
            addFileUploadBox.lastAssignedId++;
        };
        function RemoveFile(tempid) {
            var uploadArea = document.getElementById('upload-area');
            if (!uploadArea) {
                return false;
            };
            //利用id取得file元素
            var UploadBox = document.getElementById('FileF' + tempid); 
            var preItem = prevSib(UploadBox); //尋找type=File的上一個節點,也就是br元素
            if (preItem != null) {
                //有找到就不等於null,代表有找到br
                uploadArea.removeChild(preItem);
            };
            //利用id取得button元素
            var BRF = document.getElementById('BRF' + tempid); 
            uploadArea.removeChild(UploadBox); //移除file
            uploadArea.removeChild(BRF); //移除button
        };
        //此處參考http://blog.kkbruce.net/2012/02/javascript-w3c-dom.html#.WXViWISGOUm
        function prevSib(node) {
            var tempFirst = node.parentNode.firstChild; //取得node的第一個節點
            if (node == tempFirst) { //是否為第一個節點
                return null;
            }
            var tempObj = node.previousSibling; //非第一個,可往上找上一個Node
            while (tempObj.nodeType != 1 && tempObj.previousSibling != null) //nodeType不是元素節點且不是第一個,即找到元素節點為止
                tempObj = tempObj.previousSibling; //往上找上一個
            return (tempObj.nodeType == 1) ? tempObj : null; //如果是元素節點,傳回節點本身,否則傳回null
        };
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <h1>測試多檔上傳,加上移除檔案按鈕</h1>
        附加檔案:<br/>
        <p id="upload-area">
            <input id="FileField" type="File" runat="server" size="40" />
        </p>
        <input id="ButtonAdd" type="button" value="繼續附加" onclick="addFileUploadBox();" />&nbsp;&nbsp;
        <asp:Button ID="Button1" runat="server" Text="開始上傳" /><span style=" color:red;">檔案附加不可超過10MB</span><br/>
        <asp:Label ID="Send_msg" runat="server"></asp:Label>
    </div>
    </form>
</body>
</html>

Step 2.後置程式碼一樣沒有變,請自行參考前一篇。