新聞速報

        

2018年7月31日 星期二

讓 VB6 的程式 自動適應簡體OS準備事項



:
2015/05/20 發現有一個 GHOSTXP 安裝的OS,執行WINPOS 必死
死亡點 .Font.Name = '細明體'。以往這一行是沒問題,我將 細明體字型mingliu.ttc COPY安裝。問題就解決


1.    VB6 程式碼 皆是以 ANSI規格存檔,繁體VB6 是以 BIG5存檔,簡體VB6是以 GBK存檔。所以直接把程式碼放至對方的OS下開啟,均會看到一堆中文的亂碼。
2.    VB6 IDE 開啟程式碼,若是可以看到中文繁體字/簡體字。
有一些注意事項:
A. 程式原始碼要跨越不同語系的作業系統,必須要事先轉碼,將 ANSI BIG5 ßà ANSI GBK (在各個OS下,才不會看到亂碼)
B. 簡體OS + VB6 只認識ANSI GBK的原始碼、繁體OS + VB6 只認識ANSI BIG5的原始碼。
C. VB6 IDE 讀入 ANSI 的程式碼,會以 UniCode方式在畫面上呈現,但是原始碼檔案仍然是以 ANSI規格存檔。
D. 簡體OS + VB6 IDE 可以看到中文繁體字/簡體字,因為簡體OS  UniCode GBK字集 同時支援繁體字/簡體字。讀入 ANSI GBK編碼(內含繁/簡字碼),會自動對應至 IDE UniCodeGBK字集方式在畫面上呈現。 PS: GBK之繁體字碼 BIG5繁體字碼完全不相容。
E. 繁體OS + VB6 IDEBIG5 只支援繁體字集,所以原始碼檔案根本無法存入簡體字碼
若要在 IDE textbox輸入框 label 內看到簡體字,必須安裝 Unicode補完計畫
F. 共同點: 繁體OS UniCode 簡體OS UniCode,中文繁體/簡體編碼是相同的
?ASCW(“”) = 21326     繁體OS 簡體OS 解出來的 UniCode碼是相同。
?ASCW("") = -31761 = 0xFFFF83EF = U+83EF 繁體OS 簡體OS 解出來的 UniCode碼是相同。
ASCW相對 CHRW

上述字串轉成 ANSI 的陣列時:
'UniCode BIG5 ANSI B5(181)  D8(216)
'UniCode GBK  ANSI 繁體字   C8(200)    41(65)
'UniCode BIG5 ANSI 85(133)   4F(79)    '可能是有安裝 UniCode裝補計畫,才可以得到 BIG5 之簡體編碼
'UniCode GBK  ANSI 繁體字   BB(187)   AA(170)

AA() = StrConv("", vbFromUnicode, &H404)    'UNICODE 轉為 台灣之 ANSI--> BIG5
BB() = StrConv("", vbFromUnicode, &H804)    'UNICODE 轉為 大陸之 ANSI--> GBK
CC() = StrConv("", vbFromUnicode, &H404)    'UNICODE 轉為 台灣之 ANSI--> BIG5
DD() = StrConv("", vbFromUnicode, &H804)    'UNICODE 轉為 大陸之 ANSI--> GBK


3.    程式碼補強: (以繁體 OS + VB6 為開發基礎)
必須引用下列 API 函式:
Private Declare Function GetSystemDefaultLangID Lib "kernel32" () As Integer
' LangID   2052 簡體    1028 繁體

Private Declare Function LCMapString Lib "kernel32" Alias "LCMapStringA" _
                         (ByVal Locale As Long, ByVal dwMapFlags As Long, _
                          ByVal lpSrcStr As String, ByVal cchSrc As Long, _
                          ByVal lpDestStr As String, ByVal cchDest As Long) As Long
                        
Private Declare Function lstrlen Lib "kernel32" Alias "lstrlenA" (ByVal lpString As String) As Long

依照 OS 語系,動態變更 程式元件語系
Public Sub FormCharset_Change(x_FORM As Form)
On Error Resume Next

Dim LangID          As Integer
Dim T_CONTROL       As Control


    LangID = GetSystemDefaultLangID   '2052 簡體    1028 繁體

    With x_FORM
        If LangID = 2052 Then       '2052 簡體
       
            If .Font.Charset = 136 Then
                .Font.Charset = 134
            End If

            .Caption = Big5_2_SimplifiedChinese(.Caption)
        End If
    End With

    For Each T_CONTROL In x_FORM.Controls
   
        With T_CONTROL
       
            If LangID = 2052 Then       '2052 簡體
           
                If .Font.Charset = 136 Then
                    .Font.Charset = 134
                End If
                               
                                
                '無效,以下在執行階段,簡體OS 找不到"細明體" 這三個字,會自動以 宋體取代。所以以下程式碼永遠執行不到
                'If .Font.Name = "細明體" Then
                '    .Font.Name = "宋体"
                'End If
               
                'If .Font.Name = "新細明體" Then
                '    .Font.Name = "新宋体"
                'End If

               
                If (TypeOf T_CONTROL Is SSTab) Then
                    ' 簡體OS 發現,開發階段 TAB有焦點存檔,該 TAB的字體會轉換錯誤
                    'TAB 元件已經自行 將內容轉過一次碼 ,我們 Big5_2_SimplifiedChinese() 再轉一次就會 亂掉  (但是元件編碼 還是得自己修改)
                    ' 事後 手動設定 元件內容
                    .Caption = UniCode_GBK繁體_to_GBK簡體(.Caption)
                Else
                    .Caption = Big5_2_SimplifiedChinese(.Caption)
                    .text = Big5_2_SimplifiedChinese(.text)
                End If
               
            End If
        End With
    Next

End Sub

繁體 简体  (執行階段 應該在 簡體OS 下,LCMapString &H804 才會正常)
'1. GB字集 裡含有 繁體字型 簡體字型
'2. GB裡的 繁體字型部份 轉為 Unicode , 便與 Big5 轉為 Unicode後的值 是一樣的
'3. 使用 LCMapString函數 , 可將 GB裡的 繁與簡 字體 做內碼映射轉換

'Big5 to GB 方法為:
'Big5 -> Unicode (使用MultiByteToWideChar) -> GB繁字集(GBK) -> GB簡字集(GB2312) (使用LCMapString)

'?Big5_2_SimplifiedChinese("租賃項目")
'租賃項目 --> 租赁项目  (繁體OS+VB6 DEBUG 視窗看的到,  UNICODE 簡體 )
'租賃項目 --> 租赁项目  (繁體OS+VB6 DEBUG 視窗看到是亂碼,  ANSI 簡體 適合傳入 VB6 程式碼動態文字[因為VB6 內部程式流程是用 ANSI] )

Function Big5_2_SimplifiedChinese(x_text As String) As String

Const LCMAP_SIMPLIFIED_CHINESE = &H2000000
Const LCMAP_TRADITIONAL_CHINESE = &H4000000

‘0x0404   Chinese     Taiwan   950   CHT
‘0x0804   Chinese     PRC      936   CHS

Dim STf     As String
Dim STlen   As Integer
Dim STj     As String


Debug.Print "---------------------------------------------------------"

Dim ST  As String
Dim Te  As String

        Te = x_text

        ST = Te
        ST = StrConv(ST, vbFromUnicode, &H804)      '再將 Unicode 轉換為 ANSI( GBK編碼)    0x0804   Chinese     PRC      936   CHS
        'Te = StrConv(ST, vbUnicode)                '簡體 ANSI --> 簡體 UNICODE (DEFBAULT 本地-台灣 404 ) ,如果沒有特別指定&H404,相同程式碼在簡體OS會認定以&H804DEFAUL
        Te = StrConv(ST, vbUnicode, &H404)          '上一行程式碼因為要跨平台,所以要強烈指定 原始碼之區域編碼

    Debug.Print "STEP 1: " & Te         '在繁體作業系統 看到會是亂碼  (在簡體作業系統上,可以看到 GB字集 繁體字)


        '可能是因為 LCMapString() 只會針對執行程式時,所得到的本地語系 作動
        '由於當執行下列程式流程時,一定是在簡體 OS下,所以 LCMapString &H804 會有反應
        '反而在繁體 OS 指定 LCMapString &H804 看不出結果


        '//轉換 Gb碼繁體 Gb碼簡體,使用API函數 LCMapString
        STf = Te
        STlen = lstrlen(STf)
        STj = Space(STlen)

        LCMapString &H804, LCMAP_SIMPLIFIED_CHINESE, STf, STlen, STj, STlen

    Debug.Print "STEP 2: " & STj            '在繁體作業系統 看到會是亂碼 (在簡體作業系統上,可以看到 GB字集 簡體字)



'    '?form1.Big5_2_SimplifiedChinese("租賃項目")
'    'STEP 1: 逤揎?       <------  傳入 簡體 VB6 程式碼流程可以正常使用,可以看到 GB字集 繁體字
'    'STEP 2: 逤醣?       <------  傳入 簡體 VB6 程式碼流程可以正常使用,可以看到 GB字集 簡體字

   
     Big5_2_SimplifiedChinese = Te  '可以看到 GB字集 繁體字, 因為我的程式碼有很多 直接指明 字串內容
    
     'Big5_2_SimplifiedChinese = STj    'GB字集 簡體字 (僅適用 元件上的靜態文字,變為簡體)
                                        '由於VB6 程式碼的訊息文字,幾乎是繁體字,就算動態設定至元件,仍是繁體字
                                        '既然無法全面一致,建議用  GB字集 繁體字模式
    
End Function

4.    關於LCMapString() 只會針對執行程式時,所得到的本地語系 作動,若是在執行階段是在繁體OS下,參數一 只有 &H804 (台灣)才能正常作用。若是在執行階段是在簡體OS下,參數一 只有 &H404 (大陸)才能正常作用。
5.    關於LCMapString() 當參數三 傳入是 UniCode,參數五 回傳就是 UniCode
當參數三 傳入是 ANSI,參數五 回傳就是 ANSI
'以下範例 Test1() / Test2() 必須在 繁體OS 才能看出結果
'嚴格來說應該是說: UniCode 簡體 UniCode 繁體,因為 VB 程式碼內的中文字串是 UniCode
Sub Test1()    'UniCode 簡體 UniCode 繁體(for 台灣語系 404)

    Const LCMAP_SIMPLIFIED_CHINESE = &H2000000
    Const LCMAP_TRADITIONAL_CHINESE = &H4000000

    STj = "中华人民共和国"
    STlen = lstrlen(STj)
    STf = Space(STlen)
   
    LCMapString &H404, &H4000000, STj, STlen, STf, STlen        '0x0404   Chinese     Taiwan   950   CHT
   
    Debug.Print "Test1:" & STj & " ----> " & STf
End Sub


'以下範例 Test1() / Test2() 必須在 繁體OS 才能看出結果
Sub Test2()    'UniCode 繁體 UniCode 簡體(for 台灣語系 404)

    Const LCMAP_SIMPLIFIED_CHINESE = &H2000000
    Const LCMAP_TRADITIONAL_CHINESE = &H4000000
   
    STf = "中華人民共和國"
    STlen = lstrlen(STf)
    STj = Space(STlen)
   
    LCMapString &H404, &H2000000, STf, STlen, STj, STlen        '0x0404   Chinese     Taiwan   950   CHT
   
    Debug.Print "Test2:" & STf & " ----> " & STj
End Sub



'以下範例 Test5() / Test6() 必須在 簡體OS 才能看出結果 ( 繁體OS 會無變化)
'可能是因為 LCMapString 只會針對執行程式時,所得到的本地語系 作動
'嚴格來說應該是說: UniCode 簡體 UniCode 繁體,因為 VB 程式碼內的中文字串是 UniCode
Sub Test5()    ''UniCode 簡體 UniCode 繁體(for 大陸語系 804)

    Const LCMAP_SIMPLIFIED_CHINESE = &H2000000
    Const LCMAP_TRADITIONAL_CHINESE = &H4000000
   
    STj = "中华人民共和国"
    STlen = lstrlen(STj)
    STf = Space(STlen)
   
    LCMapString &H804, &H4000000, STj, STlen, STf, STlen        '0x0804   Chinese     PRC      936   CHS
   
    Debug.Print "Test5:" & STj & " ----> " & STf
End Sub


'以下範例 Test5() / Test6() 必須在 簡體OS 才能看出結果 ( 繁體OS 會無變化)
'可能是因為 LCMapString 只會針對執行程式時,所得到的本地語系系 作動
Sub Test6()    'UniCode 繁體 UniCode 簡體(for 大陸語系 804)

    Const LCMAP_SIMPLIFIED_CHINESE = &H2000000
    Const LCMAP_TRADITIONAL_CHINESE = &H4000000
   
    STf = "中華人民共和國"
    STlen = lstrlen(STf)
    STj = Space(STlen)
   
    LCMapString &H804, &H2000000, STf, STlen, STj, STlen        '0x0804   Chinese     PRC      936   CHS
   
    Debug.Print "Test6:" & STf & " ----> " & STj
End Sub


沒有留言:

張貼留言