Skip to content

Instantly share code, notes, and snippets.

@asm256
Last active September 21, 2015 14:38
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save asm256/9bfb88336a1433e2328a to your computer and use it in GitHub Desktop.
Save asm256/9bfb88336a1433e2328a to your computer and use it in GitHub Desktop.
コンソールの文字化けを直すUnityInjectorプラグイン
$build_script = 'https://gist.githubusercontent.com/asm256/9bfb88336a1433e2328a/raw/build.ps1'
$build_lib = 'https://gist.githubusercontent.com/asm256/ed75d84a9e89802821f8/raw/8015406dcf3eea94e36621cfd9ffb1e891639253/build_lib.ps1'
$web = new-object net.webclient
[Text.Encoding]::UTF8.GetString($web.DownloadData("$build_lib")) | iex
(WebDownloadString $web "$build_script")| iex
#改変再配布自由
#大抵の場合ここから
$prjName = 'ConsoleCodePage'
$base = 'https://gist.githubusercontent.com/asm256/9bfb88336a1433e2328a/raw/'
$srcs = @('CM3D2.ConsoleCodePage.Plugin.cs')
#ここまで
Init($prjName)
pushd -LiteralPath $prjDir
$web = new-object net.webclient
$web.BaseAddress = $base
Write-Host "ダウンロード"
foreach($s in $srcs){
WebDownload $web $s
}
Write-Host "レシピ作成"
$recipe = foreach( $s in $srcs){
make_recipe $s
}
Write-Host "コンパイル"
#csc /t:library /r:Assembly-CSharp-firstpass.dll CM3D2.ArchiveReplacer.Hook.cs
# これだけなら楽だったのに…
foreach($r in $recipe){
compile $r
}
Write-Host "インストール"
foreach($r in $recipe){
install $r
}
#パッチ当ては各自で
Pop-Location
//@powershell -NoProfile -ExecutionPolicy Bypass -Command "iex ((new-object net.webclient).DownloadString('https://gist.githubusercontent.com/asm256/9bfb88336a1433e2328a/raw/bootstrap.ps1'))"
/*
コンソールの文字化けを直すUnityInjectorプラグイン
必要なもの
.net Framework 3.5
ビルド方法
CM3D2_KAIZOU\UnityInjector\ 内に保存して
C:\Windows\Microsoft.NET\Framework\v3.5\csc /t:library /lib:..\CM3D2x64_Data\Managed /r:UnityEngine.dll /r:UnityInjector.dll /unsafe CM3D2.ConsoleCodePage.Plugin.cs
でビルド
*/
// @AB_addarg /lib:%managed%
// @AB_addarg /r:UnityEngine.dll
// @AB_addarg /r:UnityInjector.dll
// @AB_addarg /unsafe
// @AB_install %uinjector%
// 2015.9.3.1 初版
// 2015.9.3.2 クラス名変更
// 2015.9.3.3 I18N.dll不要化 >>783 thx!
// 2015.9.9 簡易インストール対応
using System;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
using UnityEngine;
using UnityInjector.Attributes;
namespace CM3D2.ConsoleCodePage.Plugin
{
[PluginFilter("CM3D2x64"),
PluginFilter("CM3D2x86"),
PluginFilter("CM3D2VRx64"),
PluginName("CM3D2 ConsoleCodePage"),
PluginVersion("2015.9.3.3")]
public class ConsoleCodePage : UnityInjector.PluginBase
{
// P/Invoke required:
[DllImport("kernel32.dll")]
private static extern IntPtr SetConsoleOutputCP(UInt32 codepage);
public const string Version = "2015.9.3.3";
public void Awake()
{
//一応、これでも表示はできるが…windows側のバグで酷い事になる
//SetConsoleOutputCP(65001);
//Console.OutputEncoding = Encoding.UTF8;
//表示は化けるが、7bitなので可逆に変換できる
//Console.OutputEncoding = Encoding.UTF7;
//SJISにない文字は表示できない可能性がある
SetConsoleOutputCP(932);
Console.OutputEncoding = Win32Encoding.GetEncoding(932);
Console.Write("Console コードページ(");
Console.Write(Console.OutputEncoding.ToString());
Console.WriteLine(")");
}
}
#region >>783 thx
// WIN32 APIを利用したSystem.Text.Encodingの実装
// パクり元 http://jonskeet.uk/csharp/ebcdic/
public class Win32Encoding : System.Text.Encoding
{
uint codePage;
[System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true)]
static extern int WideCharToMultiByte(uint CodePage, uint dwFlags, System.IntPtr lpWideCharStr, int cchWideChar, System.IntPtr lpMultiByteStr, int cbMultiByte, System.IntPtr lpDefaultChar, System.IntPtr lpUsedDefaultChar);
[System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true)]
static extern int MultiByteToWideChar(uint CodePage, uint dwFlags, System.IntPtr lpMultiByteStr, int cbMultiByte, System.IntPtr lpWideCharStr, int cchWideChar);
public static Win32Encoding GetEncoding(uint CodePage)
{
return new Win32Encoding(CodePage);
}
Win32Encoding(uint CodePage)
{
this.codePage = CodePage;
}
public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex)
{
int result;
unsafe
{
fixed (char* pChars = chars)
{
fixed (byte* pBytes = bytes)
{
int maxByteCount = GetMaxByteCount(charCount);
var lpChars = (System.IntPtr)(pChars + charIndex);
var lpBytes = (System.IntPtr)(pBytes + byteIndex);
result = WideCharToMultiByte(codePage, 0, lpChars, charCount, lpBytes, maxByteCount, System.IntPtr.Zero, System.IntPtr.Zero);
}
}
}
return result;
}
public override int GetByteCount(char[] chars, int index, int count)
{
int result;
unsafe
{
fixed (char* pChars = chars)
{
var lpChars = (System.IntPtr)(pChars + index);
result = WideCharToMultiByte(codePage, 0, lpChars, count, System.IntPtr.Zero, 0, System.IntPtr.Zero, System.IntPtr.Zero);
}
}
return result;
}
public override int GetMaxByteCount(int charCount)
{
return charCount * 2; // !!!
}
public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex)
{
int result;
unsafe
{
fixed (byte* pBytes = bytes)
{
fixed (char* pChars = chars)
{
int maxCharCount = GetMaxCharCount(byteCount);
var lpChars = (System.IntPtr)(pChars + charIndex);
var lpBytes = (System.IntPtr)(pBytes + byteIndex);
result = MultiByteToWideChar(codePage, 0, lpBytes, byteCount, lpChars, maxCharCount);
}
}
}
return result;
}
public override int GetCharCount(byte[] bytes, int index, int count)
{
int result;
unsafe
{
fixed (byte* pBytes = bytes)
{
var lpBytes = (System.IntPtr)(pBytes + index);
result = MultiByteToWideChar(codePage, 0, lpBytes, count, System.IntPtr.Zero, 0);
}
}
return result;
}
public override int GetMaxCharCount(int byteCount)
{
return byteCount;
}
}
#endregion
}
@neguse11
Copy link

勝手に収録させてもらいました。もし問題があれば教えてください。次回以降取り下げます

@usagirei
Copy link

This is a nice fix for the console gibberish issue, I'll try to including it on the Core DebugPlugin, as an optional configuration parameter.

@neguse11
Copy link

Hi, @usagirei
Is there any chance to use GetACP() to determine system Code Page ?

using System;
using System.Runtime.InteropServices;

class Program {
    [DllImport("kernel32.dll")]
    private static extern uint GetACP();

    static void Main(string[] args) {
        // The following line will show "GetACP() = 932" for Japanese Windows system.
        Console.WriteLine("GetACP() = {0}", GetACP());
    }
}

And you could use GetACP() in the DebugPlugin something like this :

namespace UnityInjector.Plugins
{
    ...
    public class DebugPlugin : PluginBase
    {
        [DllImport("kernel32.dll")]
        private static extern uint GetACP();

        ...
        public void Awake()
        {
            if (this.CodePage != -1)
            {
                if(this.CodePage == 0)
                {
                    this.CodePage = GetACP();
                }
                Console.OutputEncoding = ConsoleEncoding.GetEncoding(this.CodePage);
                ...
            }
        }
    }
}

@neguse11
Copy link

@asm256
UnityInjector 1.0.3.0の対応時に、ConsoleCodePage相当のコードがUnityInjector側に取り込まれたので、自動コンパイル対象から外しました。
つけたり外したりせわしなくて申し訳ない!

@usagirei
Copy link

@neguse11
Interesting, i'll have a look at GetACP, -1 = disable (since it breaks text mirroring in some cases), 0 to Automatic via GetACP, and >1 manual

EDIT: Included, thanks for the tip, check in UnityInjector 1.0.3.4, 0 should call GetACP

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment