【VisualBasic6】デバッグモードとexeファイルで結果が異なった事例

引き継いだVB6アプリのメンテをしていたのですが、PDF帳票作成機能がIDEデバッグモードとexeファイル実行で結果が違ったというお話。
PDF作成はPrinterで作成した帳票をPDFプリンターに投げる処理なんですが、IDEデバッグモードでは正常にPDF出力できるのだけど、exeファイルではA4白紙が出力されてしまう。
通常業務もデバッグモードでしていたようです。

様々に調査検証してみると、PDFプリンターが全角文字のドキュメントタイトルを認識できていなかったというのが直接の原因でした。
IDEデバッグモードではドキュメントタイトルが「MicrosoftVisualBasic」なのに対して、exe実行ではVBのプロジェクト名(全角)になっていました。
じゃあ、exe実行時のタイトルを半角文字にすればいいとなりますが、exeファイル名や各種プロパティ名などさまざまな場所にプロジェクト名が存在します。
で、結局はvbpファイル名がexe実行時のドキュメントタイトル名だと分かりました。

今回の教訓→プロジェクト名は半角文字にしましょう

【VBA】2024年9月以降にファイルIO関連でエラーが発生するようになる

9月になったので、いつものように月次レポートを作成していたら、VBAマクロで書き込みエラーが発生する。
どうやらログファイルの読み書き時に発生。
冒頭ログは問題ないことから、Close→再Open時に失敗しているもよう。

上記のようなコードでのエラーだったので、TextStreamにCloseメソッドを追加してみると正常に動作しました。
先月までは問題なかったので、Windows または Excelのアップデートが原因のようでした。
まぁ、Closeしないでリソース開放しちゃうマクロコードも大概なんですがね・・・

Acrobatで特定のフォントの表示サイズがおかしくなる

他部署からの相談でPDFの中の特定のフォント(TimesNewRoman)のサイズがおかしくなるという相談がありました
じぶんAdobeは全然使わないんですが・・w
英語サイトを漁っていたら、どうやら最新バージョン(2024.002.21005)で発生するissueとのこと

community.adobe.com

現時点で回避するには過去バージョンをインストールすれば良いです
なかなか面倒なのでカンタンな手順を説明します(有償版)

まずはインストーラーとパッチを入手します

オフラインインストーラ
helpx.adobe.com

24.002.20991パッチリリースノート
www.adobe.com

オフラインインストーラーを解凍したフォルダの中にパッチをコピーします。

コピーしたパッチを仕向けるようにsetup.iniを修正します。

以上で、旧バージョンのインストーラーが完成しました。

現バージョンをアンインストール後に上記で作成したsetupを実行します
インストール完了後に環境設定>アップデーターの自動更新を無効にします(Pro版のみ)
手順は以上です。

プレゼントに当選しました

日本ギガバイトが運営しているファンサイトAORUS4Uで応募したプレゼントに当選しました。
Chibiちゃんが来てくれるのを期待していたけど、帽子というのも要所で目立ちそうで良いなw

Aorus mouse pad, baseball cap and Gigabyte motherboard

一緒に撮影しているのは、約10年前のギガバイト製のG1.Sniper 5というマザーボード
このころはAorusというブランドはまだ存在せず、G1-Killerシリーズを展開していました。
Z270くらいまでの時代は、フラッグシップモデルのMoboは4-way SLIをするためにx16スロットを4つ備えているのが常でした。

しかしGTX1xxxで2-wayのみのサポートとなり、RTX2xxxではSLI→劣化NV-Linkになり、
RTX4xxxではとうとうNV-Linkもサポート対象外になりました。
NV-Linkもフルスペックなら素晴らしいのですが、革ジャンCEOはAI-GPU(旧Tesla)しか興味がないのか・・・

x16をフル装備したマザーボードというのは、ゲームでいうと強化ソケットが上限の武器のようなもので、胸が躍るものがありました。
メインストリームで発売されなくなってさみしい限りです・・・
え、Xeon-WとTRがあるって??
さすがに予算3桁万円は・・・😅

【C#】端末が操作されていない時間を取得する

Windows端末がどのくらいの間AFKであるかを知りたかったので調査結果をノートします。

参考サイト
csharp.hotexamples.com

C#の場合】

internal struct LASTINPUTINFO
{
    public uint cbSize;
    public uint dwTime;
}

class Program
{
    [System.Runtime.InteropServices.DllImport("User32.dll")]
    private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);

    static void Main(string[] args)
    {
        LASTINPUTINFO lastInputInfo = new LASTINPUTINFO();
        lastInputInfo.cbSize = (uint)System.Runtime.InteropServices.Marshal.SizeOf(lastInputInfo);

        while (true)
        {
            Console.WriteLine(GetAfkSecond(lastInputInfo));

            System.Threading.Thread.Sleep(1000);
        }
    }

    /// <summary>
    /// 端末が入力されていない時間を取得する
    /// </summary>
    /// <returns>AFK秒数</returns>
    public static long GetAfkSecond(LASTINPUTINFO lastInputInfo)
    {
        GetLastInputInfo(ref lastInputInfo);
        return ((Environment.TickCount - lastInputInfo.dwTime) / 1000);
    }
}

【実行結果】
f:id:ktts:20210414002720p:plain

【VisualBasic】PrinterオブジェクトでUTF8文字を印字する

VB6のPrinterでUTF8を印字する方法を調べたのでノートします。

PrinterでUTF8文字を出力すると、通常は’?’と出力されるけど、
TextOutW関数(gdi32.dll)を利用することで出力できました。


参考サイト
stackoverflow.com

' TextOutW関数の宣言
Private Declare Function TextOutW Lib "gdi32" ( _
    ByVal hdc As Long, _
    ByVal x As Long, _
    ByVal y As Long, _
    ByVal lpStringU As Long, _
    ByVal nCount As Long) As Long  


' ScaleModeをミリメートルにする
Printer.ScaleMode = vbMillimeters

' 通常のPrintメソッドによるテキスト出力
Printer.CurrentX = 100
Printer.CurrentY = 200
Printer.Print strText

' TextOutW関数によるテキスト出力
TextOutW Printer.hdc, _
    Printer.ScaleX(100, vbMillimeters, vbPixels), _
    Printer.ScaleY(200, vbMillimeters, vbPixels), _
    StrPtr(strText), _
    Len(strText)

【C#】【VB.NET】文字列の中にList<string>が含まれるかを判定する

ある文字列の中に、ある文字列リストの一部/全部が含まれるかを判定する手法を調べたのでノートします

参考サイト
stackoverflow.com

C#の場合】

List<string> words = new List<string>() { "bar", "baz" };
string chat1 = "What is foo?";
string chat2 = "What is bar doing?";
string chat3 = "What is bar doing in baz?";

// or
Console.WriteLine("chat 1 is {0}.", words.Any(x => chat1.Contains(x)));
Console.WriteLine("chat 2 is {0}.", words.Any(x => chat2.Contains(x)));
Console.WriteLine("chat 3 is {0}.", words.Any(x => chat3.Contains(x)));

// and
Console.WriteLine("chat 1 is {0}.", words.All(x => chat1.Contains(x)));
Console.WriteLine("chat 2 is {0}.", words.All(x => chat2.Contains(x)));
Console.WriteLine("chat 3 is {0}.", words.All(x => chat3.Contains(x)));

VB.NETの場合】

Dim words As New List(Of String)(New String() {"bar", "baz"})
Dim chat1 As String = "What is foo?"
Dim chat2 As String = "What is bar doing?"
Dim chat3 As String = "What is bar doing in baz?"

' or
Console.WriteLine("chat 1 is {0}.", words.Any(Function(x) chat1.Contains(x)))
Console.WriteLine("chat 2 is {0}.", words.Any(Function(x) chat2.Contains(x)))
Console.WriteLine("chat 3 is {0}.", words.Any(Function(x) chat3.Contains(x)))

' and
Console.WriteLine("chat 1 is {0}.", words.All(Function(x) chat1.Contains(x)))
Console.WriteLine("chat 2 is {0}.", words.All(Function(x) chat2.Contains(x)))
Console.WriteLine("chat 3 is {0}.", words.All(Function(x) chat3.Contains(x)))

【結果】
f:id:ktts:20200719155951p:plain