簡単にUSBメモリーにバックアップする手順 robocopy

 バックアップは重要です。パソコンは絶対に壊れるので定期的にパソコンの外にバックアップする必要があります。もちろんバックアップ先も絶対に壊れるので同じと言えます。しかし、その2つが同時に故障する可能性は天文学的に低いです。

そう、同時にパソコンとバックアップしたUSBメモリが壊れることはほぼ無いといえます。

でも、バックアップは手順が複雑ではないでしょうか? 確かに複雑ですが、一度仕組みを作ってしまえば簡単に行うことが出来ます。

設定方法は最後に書きますが、使い方は簡単です。

  1. USBメモリやSDカードをパソコンに挿入する
  2. そのフォルダの「右クリックして「管理者として時実行する」」というファイルを右クリックする。
  3. 「管理者として実行する」をクリック。
  4. パソコンをシャットダウンして完全に終了してからメモリを抜き、安全な場所に補完する。

と簡単です。バックアップ用のUSBメモリやSDカードの作り方は以下です。分からなければ慣れている人に作ってもらってください。

  1. USBメモリやSDカードに backup というフォルダを作る。(好きな名前でも可能)
  2. 「右クリックして管理者として実行する」という名前のbatファイルを作成する。
  3. 後述するコードをbatファイルに作成する。

です。バックアップ元やバックアップ先は適宜コードを編集してください。編集のポイントとしては

robocopy C:\data ./backup  ......  の部分です。 C:\data がバックアップ元、backup がバックアップ先です。 詳しくは robocopy のドキュメントをご覧ください。

  1. @echo off
  2. net session >nul 2>&1
  3. if %ERRORLEVEL% neq 0 (
  4.     for /l %%i in (1,1,15) do echo(
  5.     echo ** エラー *****************************************
  6.     echo * 右クリックして「管理者として実行」してください。*
  7.     echo ***************************************************
  8.     pause
  9.     exit /b
  10. )
  11. cd /d %~dp0
  12. robocopy C:\data ./backup /E /ZB /J /COPY:DATOU /MIR /DCOPY:DAT /FFT /R:1 /W:10 /BYTES
  13. for /l %%i in (1,1,15) do echo(
  14. echo ** 正常終了 ***********************************************************
  15. echo * バックアップが正常に終了しました。 *
  16. echo * シャットダウンしてランプが消えたらSDカードを抜いて保管してください。*
  17. echo ***********************************************************************
  18. pause

G++ で warning: 'memcpy' reading between 4 and 9223372036854775804 bytes from a region of size 2 [-Wstringop-overread] 警告

 G++で -flto オプションでコンパイル時に 「 warning: 'memcpy' reading between 4 and 9223372036854775804 bytes from a region of size 2 [-Wstringop-overread]」 警告が出た場合の疑いとして以下があります。

std::wstring buf;
buf=L"";

とwstringをヌル文字で初期化している可能性があります。この場合

buf.clear();

と空白文字列を設定すれば問題がありません。ぜひ試してください。



イテレーターや抽象化を使った自前Classの作成

 C++をC言語の経験で使っていると陥る罠は「昔の方法でデータ管理してしまうことです」特にstring型を使わずに低レベルな操作で連結や比較をしてしまう点です。実はC++には標準で文字列を+で連結したり、文字列の比較を現代の言語のように行うことも出来ます。

更にVectorなどのコンテナも充実しています。そう、自前で配列や連結ポインタを管理する必要もありません。更に、ソートや一覧出力は「イテレーター」という標準的な繰り返し処理で可能です。 そう、組み込まれた変数以外であっても、既存のライブラリでソートや一覧が出来てしまう点です。

ただ、完全に自動ではなく、イテレーターやソート、一覧を行うには、自前のClassにそれなりの配慮も必要です。

以下のコードは自前のClassを標準関数によって最大値の取得と一覧の出力を行っています。では、それなりの配慮とは何でしょうか? それは、聞かれることを想定するということです。

最大値を取得するには「比較の手段」を提供する必要があります。そう、「何を持って大きいとするのか」です。人間でも、身長、体重、BMIなど色々な比較を検討する必要があります。

次に一覧を出力する場合、何を出力するかを明示する必要があります。

比較に関しては 演算子 < の振る舞いを指示する必要があります。今回はstring型の比較結果をそのまま返しています。

一覧出力の場合は 演算子 << の振る舞いを指示します。今回はメンバーの中から value を選んで出力しています。たまたま、今回は一つだけですが、複数のメンバーがある場合は「どれを出すのか?」「連結するのか?」をプログラマが指示する必要があります。

なにか面倒ですが、一度苦労して抽象的に処理できる概念を作っておけば、幅広く汎用的に使えるコードが出来上がるので便利になると考えます。


  1. // G++ auto.cpp -std=c++23 -o auto
  2. #include <algorithm>
  3. #include <vector>
  4. #include <string>
  5. #include <iostream>
  6. #include <iterator>
  7. void f(auto &a){
  8.     
  9.    auto it = std::max_element(std::begin(a), std::end(a));
  10.     std::cout << *it << std::endl; // 出力: orange
  11.     
  12. }
  13. class TEST{
  14.     
  15. public:
  16.     std::string value;
  17.      bool operator<(const TEST& other) const {
  18.         return value < other.value;
  19.     };
  20.     
  21.     
  22. };
  23. std::ostream& operator<<(std::ostream& os, TEST& t) {
  24.     os << t.value; // メンバ value を出力
  25.     return os; // ostream を返すことが重要
  26. }
  27. int main() {
  28. // std::vector<std::string> v = {"apple", "banana", "orange"};
  29.     std::vector<TEST> v;
  30.     
  31.     v.push_back(TEST {"apple"});
  32.     v.push_back(TEST {"banana"});
  33.     v.push_back(TEST {"orenge"});
  34.     
  35.     
  36.     f(v);
  37.  
  38. }

G++でGDI+で描画したAVIファイルを出力するC++


Windowsの描画API GDI+でAVIファイルを出力するC++サンプルです。グラフや数値表示など簡単なグラフィックをC++で作りたい場合にお勧めです。サンプルコードとして見やすいようにファイル選択、エラー処理などは極力省いています。


ファイルはUTF8で保存して以下のコマンドでコンパイル、ビルドしてください。

g++ .\avisample002.cpp -mwindows -lvfw32 -lgdiplus -lmsimg32 -municode -static -o avisample002


  1. #define _UNICODE    //ワイド文字列 (Unicode) 対応
  2. #include <windows.h>
  3. #include <gdiplus.h>
  4. #include <vfw.h>
  5. #include <sstream>
  6. #include <string>
  7. /********************************************************************
  8. GDI+対応版
  9. 実行するとカウントアップするAVI動画を作成します。以下のコマンドラインでビルドしてください。
  10. g++ .\avisample002.cpp -mwindows -lvfw32 -lgdiplus -lmsimg32 -municode -static -o avisample002
  11. *********************************************************************/
  12. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hinstPrev, LPWSTR lpszCmdLine, int nCmdShow)
  13. {
  14.     constexpr int width = 1280; //画面サイズフレームレートなどを設定
  15.     constexpr int height = 720;
  16.     constexpr int fps = 5; //フレームレート
  17.     constexpr int frames = 400;
  18.     constexpr int c_thic = 80; //円の厚さ
  19.     constexpr int div = 59; //円を分割する数
  20.     constexpr int size = width < height?width:height; //高さと幅の短い方を選ぶ
  21.     constexpr int marX = (width - size)/2;
  22.     constexpr int marY = (height - size)/2;
  23.     constexpr float step = (float)360 / div; //分割された度数
  24.     constexpr float seg = step / 2; //空白部と実部の割合(数字が大きいほど実部が減る)
  25.     
  26.     //GDI+用変数
  27.     const Gdiplus::GdiplusStartupInput gdiSI;
  28.     ULONG_PTR gdiToken;
  29.     
  30.     Gdiplus::GdiplusStartup(&gdiToken, &gdiSI, NULL); //GDI+を使うための宣言
  31.     const Gdiplus::Font font(L"Segoe UI", 160); //フォントの宣言
  32.     const Gdiplus::RectF RectBK(0,0,width,height); //背景の矩形領域の宣言
  33.     const Gdiplus::RectF RectCircleOut(marX,marY,size,size); //円の外側の矩形領域
  34.     const Gdiplus::RectF RectCircleInner(marX+c_thic,marY+c_thic,size-c_thic*2,size-c_thic*2); //円の内側の矩形領域
  35.     
  36.     Gdiplus::StringFormat format; //文字列のフォーマットの宣言
  37.     format.SetAlignment(Gdiplus::StringAlignmentCenter); // DT_CENTER
  38.     format.SetLineAlignment(Gdiplus::StringAlignmentCenter); // DT_VCENTER
  39.     const Gdiplus::SolidBrush brushFW(Gdiplus::Color(255, 255, 255, 255)); //表の色の宣言
  40.     const Gdiplus::SolidBrush brushBK(Gdiplus::Color(255, 0, 0, 0)); //背景色の宣言
  41.     
  42.     PAVIFILE pfile;
  43.     PAVISTREAM pavi;
  44.     AVISTREAMINFO si;
  45.     const LPAVISTREAMINFO lpsi = &si;
  46.     LPVOID lpBits;
  47.     BITMAPINFOHEADER bmiHeader;    
  48.     
  49.     AVIFileInit();
  50.     if (AVIFileOpen(&pfile, L"video.avi", OF_CREATE | OF_WRITE, NULL) != 0) {
  51.         MessageBox(NULL, L"Fail file open.", L"OK", MB_OK);
  52.         AVIFileExit();
  53.         return 0;}
  54.     ZeroMemory(&si, sizeof(AVISTREAMINFO));
  55.     si.fccType = streamtypeVIDEO;
  56.     si.fccHandler = comptypeDIB;
  57.     si.dwScale = 1;
  58.     si.dwRate = fps;
  59.     si.dwLength = 0;
  60.     si.dwQuality = (DWORD)-1;
  61.     SetRect(&si.rcFrame, 0, 0, width, height);
  62.     if (AVIFileCreateStream(pfile, &pavi, &si) != 0) {
  63.         MessageBox(NULL, TEXT("Fail open stream."), TEXT("OK"), MB_OK);
  64.         AVIFileRelease(pfile);
  65.         AVIFileExit();
  66.         return 0;}
  67.     ZeroMemory(&bmiHeader, sizeof(BITMAPINFOHEADER));
  68.     bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  69.     bmiHeader.biWidth = lpsi->rcFrame.right;
  70.     bmiHeader.biHeight = lpsi->rcFrame.bottom;
  71.     bmiHeader.biPlanes = 1;
  72.     bmiHeader.biBitCount = 24;
  73.     bmiHeader.biCompression = BI_RGB;
  74.     bmiHeader.biSizeImage = bmiHeader.biHeight * ((3 * bmiHeader.biWidth + 3) / 4) * 4;
  75.     AVIStreamSetFormat(pavi, 0, &bmiHeader, sizeof(BITMAPINFOHEADER));
  76.     //ここにHDCへ描画し、AVIStreamWriteを呼び出し一コマ書き出す。これを繰り返す。
  77.     const HDC hdc = CreateCompatibleDC(NULL);
  78.     const HBITMAP hbmpMem = CreateDIBSection(NULL, (LPBITMAPINFO)&bmiHeader, DIB_RGB_COLORS, &lpBits, NULL, 0);
  79.     const HBITMAP hbmpMemPrev = (HBITMAP)SelectObject(hdc, hbmpMem);
  80.     Gdiplus::Graphics hGdip(hdc); //GDI+の宣言
  81.     hGdip.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); //図形のアンチエイリアス
  82.     hGdip.SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAlias); // テキストのアンチエイリアス
  83.     
  84.     SetBkMode(hdc, TRANSPARENT);
  85.     
  86.     bool isTop = true; //裏表フラグ
  87.     for (int fCnt = 0; fCnt < frames; fCnt++) {
  88.         hGdip.FillRectangle(&brushBK,RectBK); //背景を塗りつぶす
  89.         std::wstringstream wss; //カウンターの数字を文字列に変換
  90.         wss << fCnt;
  91.         std::wstring buf = wss.str();
  92.         const int l_begin = isTop?0:fCnt%(div+1);
  93.         const int l_end = isTop?fCnt%(div+1):div;
  94.         for (int j = l_begin;j<l_end;j++){
  95.             
  96.             Gdiplus::GraphicsPath path; //描画パスを宣言する
  97.             
  98.          path.AddArc(RectCircleOut,step*j, seg); //外周をパスに追加する
  99.          path.AddArc(RectCircleInner, step*j+seg, -seg); //内周をパスに追加
  100.             path.CloseFigure(); //パスを閉じる
  101.          hGdip.FillPath(&brushFW, &path); //パスを塗りつぶす
  102.     
  103.         }
  104.         hGdip.DrawString(buf.c_str(), -1, &font, RectCircleOut, &format, &brushFW); //文字を表示する
  105.         
  106.         AVIStreamWrite(pavi, fCnt, 1, lpBits, bmiHeader.biSizeImage, AVIIF_KEYFRAME, NULL, NULL); //一コマ書き出し
  107.         
  108.         if(fCnt%(div+1) == div){
  109.             isTop = !isTop; //裏表逆転
  110.         }
  111.     }
  112.     SelectObject(hdc, hbmpMemPrev);
  113.     DeleteObject(hbmpMem);
  114.     DeleteDC(hdc);
  115.     AVIStreamRelease(pavi);
  116.     AVIFileRelease(pfile);
  117.     AVIFileExit();
  118.     Gdiplus::GdiplusShutdown(gdiToken);
  119.     MessageBox(NULL, L"Done.", L"OK", MB_OK);
  120.     return 0;
  121. }

劇遅 メモリ交換だけで古いセレロンパソコンを使えるレベルにアップグレード esprimo FH52/W 2950M SP016GLSTU160N22


ウチにある古いパソコンの富士通ESPRIMO FH52/W が酷く遅くなりました。OSの起動も遅く、アプリの起動も遅いです。さらにブラウザや事務ソフト程度の軽いソフトも突然固まります。30秒くらい待っていればまた使えるようになりますがストレスはあります。

古いパソコンはSSDに交換すると良いと言われていますが、イメージのコピーやパソコンの分解など手間が必要です。部品自体は安いですが面倒です。

一方でメモリ交換は簡単です。交換しやすい場所に取り付けられていたり、コピーなどの作業が不要だからです。 とは言ってもSSDに交換しないと意味がないとも言われています。

でも、とりあえずメモリを交換してみます。今回使ったのはシリコンパワーのメモリです。パソコンの機種名でググったらこのメモリの販売サイトが表示されました。16ギガは大げさですが、2500円と安いので買ってしまいました。今考えると8ギガでも良さそうですが、これはロマンということで。

FH52/Wのメモリ交換は裏蓋を外して、ドライバでシールドパネルを外すだけで出来ます。非常に簡単です。静電気だけには気を付けて交換してください。

その後、PCを再起動しますが、案の定、起動速度は改善していません。もちろんアプリの起動もそれほど速くなっていません。 ここだけ見ると残念ですが、大きな収穫もあります。

それは、アプリの利用が超快適になったところです。今まではアプリのメニューを開いただけで30秒くらい固まったりしていましたが、それが全く無くなりました。ネット閲覧もスムーズに画面遷移し、オフィスソフトや会計ソフトも普通に操作できるようになりました。

私の感覚では、朝起動したら立ち上げ放しの会社の事務用パソコンが遅いと感じている場合におすすめです。 ブラウザや会計ソフト、写真とか図が大量に入っていない文書程度で軽く固まる現象があれば是非、メモリを交換してみてください。


Windowsでウィンドウアプリを作成する覚書 MinGW64


 Windowsでアプリ作成というとMicrosoftのVisualStudioです。昔は有料でしたが、今では一部無料で使えるものがあります。ダウンロードして、プロジェクト作成ウィザードを実行すれば簡単なウィンドウが開けます。ただ、妙に大げさでブラックボックスなところもありますのでDIYプログラマにとっては気持ち悪いところがあります。ソフトウェア企業ならそういう開発環境などを丁寧に教えてくれることもありますが、独学だと複雑な開発環境は使いこなすのが難しいです。

そこで便利なのがMinGW64です。「ダウンロードして解凍して好きな場所にコピーしてパス通す。」これだけでビルドできます。知っていれば分かりやすいです。

ただ、パソコンを更新したりした場合にいつも悩むこともあります。それは、どのビルドをダウンロードすれば良かったのかです。もちろん、当時にダウンロードしたファイルを保管しておけば良いだけですが、いつでも手に入ると思って削除しているかもしれません。

この記事ではその覚書です。

まず、ダウンロードは有志の方々がビルドしてまとめたものが便利です。以下のURLにあります。

https://github.com/niXman/mingw-builds-binaries/releases

ここから私は

x86_64-14.2.0-release-posix-seh-ucrt-rt_v12-rev2

をダウンロードして解凍しました。7z形式なので解凍するツールは別途ダウンロードしてください。

ただ、色々ある意味がわからないと思います。ここでざっくりと意味を説明していきます。詳細は説明のリンク先から見てください。

x86_64 これがいわゆる64ビット版を示すものです。今ならこれで良いです。

posix はスレッドの形式です。windows独自形式もありパフォーマンスも高いですが、今は互換性という意味でposixを選ぶとのことです。

seh は例外処理の方法です。この方式はwindowsの本能に近い部分で処理される効率が良い処理とされています。片方は理屈で処理される処理です。

UCRT はwindows10以降であれば問題ないとのことです。今から普通な環境で実行できるアプリを作るのであれば問題無いと考えます。古いパソコンとかに対応する人は多分職業プログラマなのでこんな文章は読まないと考えます。

詳しい説明は以下のURLを見てください。
https://text.baldanders.info/remark/2018/03/mingw-w64/
https://qiita.com/syoyo/items/36935d8231c6ebd41262

ダウンロードしてパスを通し、再起動したら任意のフォルダでプロンプト画面を開き

G++ hoge.cpp

でビルドしてください。言葉足らずですが hoge.cpp にはコードを入れておいてください。

C++の関数での情報の渡し方。

 C++などC言語系では、情報がどのように渡されているか見えないことが多いです。コンピュータにある程度のメモリがあり、取り扱う情報も少なければそれほど気にはなりません。しかし、組み込みマイコンのようにメモリや演算速度が遅い場合や画像や動画、ビッグデータなどの情報が巨大な場合は処理速度に影響が出てきます。

このため、情報がどのようにやり取りされているかを意識する必要があります。繰り返しますが、これから示す効率の良いプログラミングは見た目が悪いです。つまり、可読性が悪いということです。 昔ながらのパフォーマンスが悪い記述方法は計算アルゴリズムの記述としてはシンプルなわけです。

だから、数学やアルゴリズムの研究としてプログラミングをする場合は、エラー処理や例外処理、無駄なコピーなどを気にせずにシンプルに記述すればよいわけです。全てに完璧と汎用性を求めすぎることは愚行です。

一方で業務で使われるプログラムの場合はそれ自体のシンプルさや可読性より処理速度やメモリー消費のほうが重要になります。今回はこのための考察をします。

普通な記述

int test(int arg){…};

こんな関数は普通に記述します。そして、余計なものが書かれていないのでわかりやすいです。昔から書かれている方法ですが、これは、関数を呼び出すときと、戻るときに二回コピーが発生します。ある意味無駄なわけです。でも繰り返しますがわかりやすいです。

ちなみにこの方法を現実に例えますと、「相手にファックスを送り、それに記入後、ファックスで返信」という方法です。書類なら素早いですが、大きなものでは実現不可です。

参照渡し

void test(int &arg) {…}

この方法は場所だけを関数に知らせます。そして、関数はその場所にあるデータを処理した後に、作業終了だけを伝えます。これは最も効率が良い方法だと言われますが、戻り値が無い不思議な関数でもあります。そもそも戻り値がない関数とは何なのか?と数学者に突っ込まれそうでもあります。だから、可読性が悪いわけです。

あと、この方法は実は現実的であったりします。家のトイレを修理してもらうために技術者を呼ぶという方法です。相手にはトイレの場所を言うだけです。そして、修理が終わった後はその報告だけ受けます。

移動

int test(int &&arg) {…}

この方法はデータを移動させます。これはC++の途中から生まれた考えです。例えると、壊れた電化製品を修理するためにメーカーに送り、修理後に戻してもらうというものです。これも現実世界では自然な考えです。

ただし、プログラミングではややわかりにくい moveという命令を使う必要があります。見られないコードが増えるので可読性が悪いです。

まとめ

元々のプログラミングは少ないデータを複雑なアルゴリズムで解析して、少ない計算結果を返すというものでした。 データは少ないが、計算が複雑というものです。しかし、今ではビッグデータに代表される、データが極端に大きいものが増えてきています。この場合にデータを渡すたびにコピーをしていたらそれだけで時間が食われてしまいます。だから、参照や移動を使って大きなデータをできるだけ動かさずに処理をする必要が出てきます。

数秒程度の処理であれば、コードの見やすさを重視することは重要ですが、参照や移動を使えば一週間の処理が一晩になるのであれば検討の価値はあると考えます。

ある程度プログラミングに慣れてきたら、実際のデータはどのように移動しているのか?を考える必要もあるのではないでしょうか?

  1. #include <iostream>
  2. #include <string>
  3. #include <vector>
  4. //原紙のコピーを作業者に渡す、作業者はそれに加筆する。そして作業者はコピーを取り戻す。(二回コピーされる、ファックスに近い)
  5. std::vector<std::string> fx(std::vector<std::string> arg){
  6.     
  7.     arg[0] = "xxxxx";
  8.     
  9.     return arg;
  10. }
  11. //原紙の場所を作業者に伝え、作業者はそれに加筆する。そして、作業者は作業を終わったことを通知する。(一度もコピーされないし、移動もない)
  12. void fy(std::vector<std::string> &arg){
  13.     
  14.     arg[0] = "yyyyy";
  15.     
  16. }
  17. //依頼主は原紙を渡し、作業者はそれに加筆する、そして、作業者はその原紙を返却する。
  18.     std::vector<std::string> fz(std::vector <std::string> &&arg) {
  19.         
  20.         arg[0] = "zzzzzz";
  21.         
  22.         return std::move(arg);
  23.         
  24.     }
  25. int main(){
  26.     std::vector <std::string> test;
  27.     
  28.     test.push_back("aaaa");
  29.     
  30.     test = fx(test); //移動するたびにコピーが作られる(ファックスで書類を送り、記入後、ファックスで受ける)
  31.     std::cout <<test[0]<< std::endl;
  32.     
  33.     fy(test); //移動もコピーも作られない(相手を自宅に呼び、書類に記入してもらう)
  34.     std::cout <<test[0]<< std::endl;
  35.     
  36.     test=fz(std::move(test)); //書類を郵送し、記入してもらい、また戻す
  37.     std::cout << test[0]<< std::endl;
  38.     //依頼主に渡したのにそれを受け取らずに処理した場合(やってはいけない)
  39.     fz(std::move(test)); //この時点でtestは無効な値である。
  40.     std::cout << test[0]<< std::endl;
  41.     
  42.     return 0;
  43.     
  44.     
  45. }



Garmin FITファイルをCSVに変換するツール

 Garminのフィットネスデータ(ランニングやサイクリング)のFIT形式のファイルをCSVに変換するツールを公開します。CSVに変換すれば手持ちのソフトで分析したり、動画に合成することが可能です。是非以下からダウンロードして使ってください。インストールはファイルを解凍後、好きなフォルダにコピーしてください。実行するとファイルを聞かれますので、FITファイルを選んでください。その後にCSVファイル出力先を選べばファイルが作成されます。

http://tool.toyokawa.jp/software/fitCSVW.zip


CSVは左から、タイムスタンプ、速度、高度、斜度、心拍、ケイデンス、距離、パワーと並んでいます。パワーに関してはパワーメーターを所有していないので動作確認は出来ていません。 動画にサイコン情報を重ねるなどの処理の助けになれば良いと考えています。

C++でAVIを出力する実験 60fps 簡易アニメーション

 C++でAVIを出力する実験をしています。無圧縮なので高解像度の本編では使えないですが、動画内のアクセントとなるアニメーションや特殊効果程度なら応用例があると考えます。WindowsのGDIでグラフなどを描画するスキルが有ればそれをそのまま動画制作に応用可能です。以下のソースはG++でコンパイルできます。(Windows APIを使ってるので残念ながらWindows専用です。)



  1. #define _UNICODE    //ワイド文字列 (Unicode) 対応
  2. #include <windows.h>
  3. #include <vfw.h>
  4. #include <sstream>
  5. #include <string>
  6. /********************************************************************
  7. 実行すると100までカウントアップするAVI動画を作成します。以下のコマンドラインでビルドしてください。
  8. g++ .\avisample001.cpp -mwindows -lvfw32 -municode -o avisample001
  9. *********************************************************************/
  10. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hinstPrev, LPWSTR lpszCmdLine, int nCmdShow)
  11. {
  12.     const int width = 640; //画面サイズフレームレートなどを設定
  13.     const int height = 560;
  14.     const int fps = 60;
  15.     const int frames = 1200;
  16.     
  17.     PAVIFILE pfile;
  18.     PAVISTREAM pavi;
  19.     AVISTREAMINFO si;
  20.     LPAVISTREAMINFO lpsi = &si;
  21.     LPVOID lpBits;
  22.     BITMAPINFOHEADER bmiHeader;    
  23.     
  24.     AVIFileInit();
  25.     if (AVIFileOpen(&pfile, L"video.avi", OF_CREATE | OF_WRITE, NULL) != 0) {
  26.         MessageBox(NULL, L"Fail file open.", L"OK", MB_OK);
  27.         AVIFileExit();
  28.         return 0;}
  29.     ZeroMemory(&si, sizeof(AVISTREAMINFO));
  30.     si.fccType = streamtypeVIDEO;
  31.     si.fccHandler = comptypeDIB;
  32.     si.dwScale = 1;
  33.     si.dwRate = fps;
  34.     si.dwLength = 0;
  35.     si.dwQuality = (DWORD)-1;
  36.     SetRect(&si.rcFrame, 0, 0, width, height);
  37.     if (AVIFileCreateStream(pfile, &pavi, &si) != 0) {
  38.         MessageBox(NULL, TEXT("Fail open stream."), TEXT("OK"), MB_OK);
  39.         AVIFileRelease(pfile);
  40.         AVIFileExit();
  41.         return 0;}
  42.     ZeroMemory(&bmiHeader, sizeof(BITMAPINFOHEADER));
  43.     bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  44.     bmiHeader.biWidth = lpsi->rcFrame.right;
  45.     bmiHeader.biHeight = lpsi->rcFrame.bottom;
  46.     bmiHeader.biPlanes = 1;
  47.     bmiHeader.biBitCount = 24;
  48.     bmiHeader.biCompression = BI_RGB;
  49.     bmiHeader.biSizeImage = bmiHeader.biHeight * ((3 * bmiHeader.biWidth + 3) / 4) * 4;
  50.     AVIStreamSetFormat(pavi, 0, &bmiHeader, sizeof(BITMAPINFOHEADER));
  51.     //ここにHDCへ描画し、AVIStreamWriteを呼び出し一コマ書き出す。これを繰り返す。
  52.     HDC hdc = CreateCompatibleDC(NULL);
  53.     HBITMAP hbmpMem = CreateDIBSection(NULL, (LPBITMAPINFO)&bmiHeader, DIB_RGB_COLORS, &lpBits, NULL, 0);
  54.     HBITMAP hbmpMemPrev = (HBITMAP)SelectObject(hdc, hbmpMem);
  55.     
  56.     SetTextColor(hdc, RGB(255, 255, 255));
  57.     HGDIOBJ hFont = CreateFontW(100, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS,
  58.         CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"UI Gothic");
  59.     HGDIOBJ hFontOld = SelectObject(hdc, hFont);
  60.     
  61.     HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  62.     HBRUSH hPrevBrush =(HBRUSH)SelectObject(hdc,hBrush);
  63.     
  64.     SetBkMode(hdc, TRANSPARENT);
  65.     
  66.     bool isTop = true; //裏表フラグ
  67.     for (int fCnt = 0; fCnt < frames; fCnt++) {
  68.         FillRect(hdc, &lpsi->rcFrame, (HBRUSH)GetStockObject(BLACK_BRUSH)); //背景を黒で塗る
  69.         
  70.         std::wstringstream wss;
  71.         wss << fCnt;
  72.         std::wstring buf = wss.str();
  73.         const int size = width < height?width:height; //高さと幅の短い方を選ぶ
  74.         const int c_width = size/10; //円の幅を調整
  75.         const int div = 59; //円を分割する数
  76.         const float step = (float)360 / div; //分割された度数
  77.         const float seg = step / 2; //空白部と実部の割合(数字が大きいほど実部が減る)
  78.         const int c_x = width / 2; //円の中心座標
  79.         const int c_y = height /2;
  80.         const int radius = size / 2 - size / 20; //余白
  81.         const int l_begin = isTop?0:fCnt%(div+1);
  82.         const int l_end = isTop?fCnt%(div+1):div;
  83.         for (int j = l_begin;j<l_end;j++){
  84.             BeginPath(hdc);
  85.             AngleArc(hdc,c_x,c_y,radius,step*j,0);
  86.             EndPath(hdc);    
  87.             BeginPath(hdc);
  88.             AngleArc(hdc,c_x,c_y,radius,step*j,seg);
  89.             AngleArc(hdc,c_x,c_y,radius-c_width,step*j+seg,-seg);
  90.             CloseFigure(hdc);
  91.             EndPath(hdc);    
  92.             FillPath(hdc);
  93.         }
  94.         
  95.         DrawText(hdc, buf.c_str(), -1, &lpsi->rcFrame, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  96.         AVIStreamWrite(pavi, fCnt, 1, lpBits, bmiHeader.biSizeImage, AVIIF_KEYFRAME, NULL, NULL); //一コマ書き出し
  97.         
  98.         if(fCnt%(div+1) == div){
  99.             isTop = !isTop; //裏表逆転
  100.         }
  101.     }
  102.     
  103.     
  104.     SelectObject(hdc,hPrevBrush);
  105.     DeleteObject(hBrush);
  106.     SelectObject(hdc, hFontOld);
  107.     DeleteObject(hFont);
  108.     SelectObject(hdc, hbmpMemPrev);
  109.     DeleteObject(hbmpMem);
  110.     DeleteDC(hdc);
  111.     AVIStreamRelease(pavi);
  112.     AVIFileRelease(pfile);
  113.     AVIFileExit();
  114.     MessageBox(NULL, L"Done.", L"OK", MB_OK);
  115.     return 0;
  116. }

簡易アニメをAVI出力するコード C++ でAVI出力

 C++で作成する簡易アニメをAVI出力するコードです。G++でビルドできます。WindowsのAPIを使っているのでWindows専用だと考えます。既にGDIで出力できるスキルが有れば簡単にAVI形式でアニメ(動画)を出力できます。実験結果を簡易的にCGにするなどの目的に使えそうです。 以下のコードをUTF-8で保存してコンパイルしてください。サンプルコードでは320x240ですが、ストレステストとしてFullHD(1920x1080)や4Kでの出力もテストしています。8Kも出力しましたが再生環境が無いので出力確認は出来ていません。




  1. #define _UNICODE    //ワイド文字列 (Unicode) 対応
  2. #include <windows.h>
  3. #include <vfw.h>
  4. #include <sstream>
  5. #include <string>
  6. /********************************************************************
  7. 実行すると100までカウントアップするAVI動画を作成します。以下のコマンドラインでビルドしてください。
  8. g++ .\avisample001.cpp -mwindows -lvfw32 -municode -o avisample001
  9. *********************************************************************/
  10. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hinstPrev, LPWSTR lpszCmdLine, int nCmdShow)
  11. {
  12.     const int width = 320; //画面サイズフレームレートなどを設定
  13.     const int height = 240;
  14.     const int fps = 2;
  15.     
  16.     PAVIFILE pfile;
  17.     PAVISTREAM pavi;
  18.     AVISTREAMINFO si;
  19.     LPAVISTREAMINFO lpsi = &si;
  20.     LPVOID lpBits;
  21.     BITMAPINFOHEADER bmiHeader;    
  22.     
  23.     AVIFileInit();
  24.     if (AVIFileOpen(&pfile, L"video.avi", OF_CREATE | OF_WRITE, NULL) != 0) {
  25.         MessageBox(NULL, L"Fail file open.", L"OK", MB_OK);
  26.         AVIFileExit();
  27.         return 0;}
  28.     ZeroMemory(&si, sizeof(AVISTREAMINFO));
  29.     si.fccType = streamtypeVIDEO;
  30.     si.fccHandler = comptypeDIB;
  31.     si.dwScale = 1;
  32.     si.dwRate = fps;
  33.     si.dwLength = 0;
  34.     si.dwQuality = (DWORD)-1;
  35.     SetRect(&si.rcFrame, 0, 0, width, height);
  36.     if (AVIFileCreateStream(pfile, &pavi, &si) != 0) {
  37.         MessageBox(NULL, TEXT("Fail open stream."), TEXT("OK"), MB_OK);
  38.         AVIFileRelease(pfile);
  39.         AVIFileExit();
  40.         return 0;}
  41.     ZeroMemory(&bmiHeader, sizeof(BITMAPINFOHEADER));
  42.     bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  43.     bmiHeader.biWidth = lpsi->rcFrame.right;
  44.     bmiHeader.biHeight = lpsi->rcFrame.bottom;
  45.     bmiHeader.biPlanes = 1;
  46.     bmiHeader.biBitCount = 24;
  47.     bmiHeader.biCompression = BI_RGB;
  48.     bmiHeader.biSizeImage = bmiHeader.biHeight * ((3 * bmiHeader.biWidth + 3) / 4) * 4;
  49.     AVIStreamSetFormat(pavi, 0, &bmiHeader, sizeof(BITMAPINFOHEADER));
  50.     //ここにHDCへ描画し、AVIStreamWriteを呼び出し一コマ書き出す。これを繰り返す。
  51.     HDC hdc = CreateCompatibleDC(NULL);
  52.     HBITMAP hbmpMem = CreateDIBSection(NULL, (LPBITMAPINFO)&bmiHeader, DIB_RGB_COLORS, &lpBits, NULL, 0);
  53.     HBITMAP hbmpMemPrev = (HBITMAP)SelectObject(hdc, hbmpMem);
  54.     
  55.     SetTextColor(hdc, RGB(255, 255, 255));
  56.     HGDIOBJ hFont = CreateFontW(100, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS,
  57.         CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"UI Gothic");
  58.     HGDIOBJ hFontOld = SelectObject(hdc, hFont);
  59.     
  60.     HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  61.     HBRUSH hPrevBrush =(HBRUSH)SelectObject(hdc,hBrush);
  62.     
  63.     SetBkMode(hdc, TRANSPARENT);
  64.     for (int fCnt = 0; fCnt < 100; fCnt++) {
  65.         FillRect(hdc, &lpsi->rcFrame, (HBRUSH)GetStockObject(BLACK_BRUSH)); //背景を黒で塗る
  66.         
  67.         std::wstringstream wss;
  68.         wss << fCnt;
  69.         std::wstring buf = wss.str();
  70.         const int c_width = 30;
  71.         const int div = 8;
  72.         const int step = 360 / div;
  73.         const int seg = step / 2;
  74.         BeginPath(hdc);
  75.         AngleArc(hdc,width/2,height/2,height/2-20,0,0);
  76.         EndPath(hdc);        
  77.         
  78.         for (int j = 0;j<fCnt%(div+1);j++){ //区切りの数+1がアニメのコマ数になる
  79.             BeginPath(hdc);
  80.             AngleArc(hdc,width/2,height/2,height/2-20,step*j,0);
  81.             EndPath(hdc);    
  82.             BeginPath(hdc);
  83.             AngleArc(hdc,width/2,height/2,height/2-20,step*j,seg);
  84.             AngleArc(hdc,width/2,height/2,height/2-20-c_width,step*j+seg,-seg);
  85.             CloseFigure(hdc);
  86.             EndPath(hdc);    
  87.             FillPath(hdc);
  88.         }
  89.         
  90.         DrawText(hdc, buf.c_str(), -1, &lpsi->rcFrame, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  91.         AVIStreamWrite(pavi, fCnt, 1, lpBits, bmiHeader.biSizeImage, AVIIF_KEYFRAME, NULL, NULL); //一コマ書き出し
  92.     }
  93.     
  94.     
  95.     SelectObject(hdc,hPrevBrush);
  96.     DeleteObject(hBrush);
  97.     SelectObject(hdc, hFontOld);
  98.     DeleteObject(hFont);
  99.     SelectObject(hdc, hbmpMemPrev);
  100.     DeleteObject(hbmpMem);
  101.     DeleteDC(hdc);
  102.     AVIStreamRelease(pavi);
  103.     AVIFileRelease(pfile);
  104.     AVIFileExit();
  105.     MessageBox(NULL, L"Done.", L"OK", MB_OK);
  106.     return 0;
  107. }


簡単に手持ちのC,C++の処理に進捗バーを実装する方法

 C言語やC++で何か処理を書ける人は多いですが、Windowプログラムとなると実装方法が難しいです。VisualStudioのプロジェクトの雛形にボタンを配置し、そこから手持ちのコードを起動すれば動きそうです。

しかし、その方法では「未応答」状態になったり、ウィンドウの操作すらできなくなります。もちろん処理が終われば正常に動きはしますが、見た目は悪いです。

進捗バーを表示しようと配置しても、当然それを動かすためのコードも必要です。

メッセージループを処理しながら、自前のコードを動かしたり、「状態機械」にコードを移植した後でメッセージループに組み込むなど方法はありますが、非常に可読性が悪くなります。

今回は、スレッドを一本発行することで手持ちのコードを動作させます。完全に無改造では動かないですが、手持ちの関数に2つの処理を埋め込むだけで対応できます。

1つ目は進捗バーに状態を知らせるためのグローバル変数を更新することです。処理に応じて増分させた数値を定期的に書き込んでください。

2つ目は強制終了フラグを監視し、検出したら処理ループを安全に停止させる処理を行うことです。外部からスレッドを停止させる方法は、処理中のファイルやリソースのクローズがされないので問題があります。 強制終了フラグを検知したら、区切りの良い場所まで処理して、その後クロージング処理などが出来ます。

このように簡単に手持ちのC,C++コードを今風に作り上げることが出来ます。個人的に、仕事で変換プログラムなどを持っている人はリニューアルしてみてください。

AmazonでC++関連の書籍を買います

  1. /*******************************************************
  2. G++ .\progress2.cpp -mwindows -lvfw32 -municode -o progress2 でコンパイルしてください。
  3. 手持ちのC言語やC++で作成した時間がかかる変換プログラムも簡単にウィンドウアプリに出来ます。
  4. Tiktok @pistalove 好きなことをやらない人生は最高 も御覧ください。
  5. ********************************************************/
  6. #include <windows.h>
  7. #include <commctrl.h>
  8. HWND hWnd; //メインウィンドウハンドル
  9. HWND hProgress; //進捗表示用ハンドル
  10. HWND hButton; //ボタン表示用ハンドル
  11. HWND hText; //文字表示用ハンドル
  12. int iProgress = 0; //進捗状態
  13. int bAbort = false; //強制終了フラグ
  14. /******************************************
  15. ここに時間がかかる手持ちのコードを書きます。仕様は
  16. ・bAbortがtrueになったら親ウィンドウの停止ボタンが押されています。安全に処理を終了してください。
  17. ・iProgressに進捗状況をパーセントで書き込んでください。進捗バーが動きます。
  18. ・処理が完全に終了したら SendMessageで親ウィンドウを閉じてください。
  19. ・手持ちのGUIに対応していないプログラムをコピペすれば進捗バーと停止ボタンが付いて見た目が良いです。
  20. ********************************************/
  21. DWORD WINAPI MyThreadFunction( LPVOID lpParam ){
  22.      for (int i = 0; i <= 100; ++i) {
  23.             
  24.                 if(bAbort) break; //強制終了指示が出たら終了する
  25.                 iProgress = i;
  26.                  Sleep(500); //試験的に待っています。
  27.             }
  28.  
  29.     SendMessage(hWnd, WM_DESTROY, 0, 0);
  30.     return 0;
  31. }
  32. //以下のコードは基本的にそのままで動きます。表示される文字やウィンドウの体裁だけ整えてください。
  33. //ウィンドウプロシージャ
  34. LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
  35.     switch (message) {
  36.     case WM_CREATE:
  37.         // プログレスバーの作成
  38.         hProgress = CreateWindowEx(0, PROGRESS_CLASS, NULL,WS_CHILD | WS_VISIBLE | PBS_SMOOTH,10,40,280,10,hWnd,NULL,NULL,NULL);
  39.         SendMessage(hProgress, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
  40.         SendMessage(hProgress, PBM_SETSTEP, 1, 0);
  41.         hText = CreateWindowEx(0,L"STATIC",
  42.                 L"Tiktok @pistalove", // 表示するテキスト
  43.                 WS_VISIBLE | WS_CHILD | SS_CENTER,10, 10,280, 20,hWnd,NULL,NULL,NULL);
  44.     hButton = CreateWindow(L"BUTTON",L"停止",WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,230,55,60,30,hWnd,(HMENU)1,NULL,NULL);
  45.     
  46.     SetTimer(hWnd, 1, 100, NULL);//進捗画面更新用タイマー設定100ミリ秒に一回
  47.         CreateThread(NULL, 0, MyThreadFunction, NULL, 0, NULL); //手持ちのコードの関数が実行されます。
  48.         return 0;
  49.     case WM_COMMAND:
  50.         if (LOWORD(wParam) == 1) { //ボタンクリック
  51.             bAbort = true; //停止フラグを設定
  52.         }
  53.         return 0;
  54.     case WM_TIMER:
  55.     SendMessage(hProgress, PBM_SETPOS, iProgress, 0);
  56.     
  57.     return 0;
  58.     
  59.     case WM_CLOSE:
  60.      return 0;
  61.     
  62.     case WM_DESTROY:
  63.      KillTimer(hWnd, 1);
  64.         PostQuitMessage(0);
  65.         return 0;
  66.     default:
  67.         return DefWindowProc(hWnd, message, wParam, lParam);
  68.     }
  69. }
  70. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hinstPrev, LPWSTR lpCmdLine, int nCmdShow){
  71.     WNDCLASS wc = {};
  72.     wc.lpfnWndProc = WindowProc;
  73.     wc.hInstance = hInstance;
  74.     wc.lpszClassName = L"ProgressDemo";
  75.     
  76.     RegisterClass(&wc);
  77.     
  78.     hWnd = CreateWindowEx(0, L"ProgressDemo", L"Tiktok @Pistalove",    WS_OVERLAPPEDWINDOW ^ (WS_THICKFRAME|WS_MAXIMIZEBOX) | WS_VISIBLE,CW_USEDEFAULT, CW_USEDEFAULT, 320, 200, NULL,NULL,hInstance, NULL);
  79.     
  80.     MSG msg;
  81.     while (GetMessage(&msg, NULL, 0, 0)) {
  82.         TranslateMessage(&msg);
  83.         DispatchMessage(&msg);
  84.     }
  85.     return 0;
  86. }

CSVで作成したログを動画に重ねる方法(実験結果を観察撮影動画と重ねることが出来ます。)

 


データロガーや波形測定機、サイクルコンピュータなどで取得した情報を観察した動画に重ねたいときに便利なツールを作成しました。測定器からCSVファイルに変換できれば後は変換するだけです。

使いかた

  1. csvファイルを作成します。一行目が項目名(動画の温度とか)、二行目が単位(%)などです。三行目からがデータになります。データはそのまま動画に書き込まれますので、各自フォーマット整形をお願いします。カンマを文字として使いたい場合はダブルクォーテーションで囲んでください。文字はUTF-8で出力してください。BOMは有ってもなくても良いです。大体の文字は対応できると考えます。
  2. csv2avi.exe を実行します。ファイル選択で変換するCSVファイルを選んでください。また、出力するAVIファイル名を指定してください。
  3. この動画ファイルを動画編集ソフトで希望の動画に重ねます。動画は1秒周期で出来ます。細かいサンプリングが希望なら、多めのCSVレコードを作成して、再生速度を早めれば対応可能だと考えます。
  4. アルファチャンネルが含まれますので、設定を有効にすれば背面が透けます。スッキリと合成できると考えます。
  5. 限度はありますが、CSVのフィールドを増やせば多くの項目を合成できます。
  6. 項目名、単位名で表示したくない場合は全角スペースで埋めることをおすすめします。
  7. 大体のエラーは対処方法を日本語で表示していますので対応可能だと思われます。

実行ファイルは以下からダウンロードしてください。ネットアクセスやCSVの読み込み、AVIの出力以外の処理は行っていないので安心してください。サンプルのCSVと出力されたAVIを比較すれば大体の使い方はわかると考えます。

数値表示型のダウンロード
http://tool.toyokawa.jp/software/csv2avi.zip

曲がったグラフ型のダウンロード
http://tool.toyokawa.jp/software/csv2circMult.zip

#warning MSACM.H: Defining _UNICODE because application defined UNICODE

 GPPでビルドするとエラーではないが

#warning MSACM.H: Defining _UNICODE because application defined UNICODE

という警告が出る場合があります。この場合、Unicodeを使っているがその宣言をしていないためだと考えます。この場合には

#define _UNICODE //ワイド文字列 (Unicode) 対応

の定義を行えば警告が出ません。是非試してください。プログラム初心者にはわかりにくいですが、プログラム中の文字列の格納方法は

  • Ascii文字(8ビットの英数字、昔からある形式)
  • マルチバイト文字列 (SJIS)  #define _MBCS
  • ワイド文字列 (Unicode) 対応 #define _UNICODE

があります。別に自前で全てを8ビット文字列として扱えば良いと思われますが、既存の関数を使いたい場合は、文字列の違いはこの仕組みで吸収されます。ちょっと苦しいですが覚えておくと良いと考えます。

C++でアルファチャンネル付きAVIを書き出す方法 サイコン情報書き込みに役立ちそうです


サイコン(サイクルコンピュータ)から走行情報を一秒単位のCSVファイルに変換して、それをAVIに書き込めば高価なソフト不要で走行動画に斜度や心拍情報などを表示できます。とりあえずは、文字の部分は透けずに、背景の緑の部分だけをある程度透けるようなAVIファイルを作成しています。

とりあえずはアルファチャンネル付きのAVIが出力されていますので、ある程度のプログラミングができる人であれば動画に重ねる情報を作るソフトなどを作成できそうです。

手持ちのテキスト情報を時系列に変換したり、気温データなどを動画に重ねて表示するなどの応用例が考えられます。とりあえずは単に数字をカウントアップするだけのサンプルファイルです。

  1. #include <windows.h>
  2. #include <vfw.h>
  3. #pragma comment (lib, "vfw32.lib")
  4. const int cWidth = 300;
  5. const int cHeight = 200;
  6. //実行すると100までカウントアップするアルファチャンネル付きAVI動画を作成します。複数レイヤで正確なマスクを作成します。
  7. //g++ .\outCntAviA2.cpp -mwindows -lvfw32
  8. //Bチャンネルの情報をアルファチャンネルとして独自バッファへ保存
  9. void makeAlpha(LPDWORD lpPixel,int width,int height,unsigned char *buf){
  10.     
  11.         unsigned char alphaValue;
  12.         
  13.         for(int y=0;y<height;y++){
  14.     for(int x=0;x<width;x++){
  15.     int memadr = x+y*width;
  16.                 unsigned char *data = (unsigned char *)&lpPixel[memadr];
  17.     buf[memadr] = *data;
  18.             }
  19.         }
  20. }
  21. //独自バッファへ保存されたアルファチャンネルを実際のアルファチャンネルへコピー
  22. void loadAlpha(LPDWORD lpPixel,int width,int height,unsigned char *buf){
  23.     
  24.         
  25.         unsigned char alphaValue;
  26.         
  27.         for(int y=0;y<height;y++){
  28.     for(int x=0;x<width;x++){
  29.     int memadr = x+y*width;
  30.                 unsigned char *pTest=(unsigned char *)&lpPixel[memadr];
  31.    pTest +=3; //アドレスを3つ増分(アルファチャンネルにアクセス)
  32.                 *pTest = buf[memadr]; //本物のアルファチャンネルに独自アルファチャンネルをコピー
  33.                 }
  34.         }
  35. }
  36. int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
  37. {
  38.     PAVIFILE pfile;
  39.     PAVISTREAM pavi;
  40.     AVISTREAMINFO si;
  41.     LPAVISTREAMINFO lpsi = &si;
  42.     HDC hdcMem;
  43.     HBITMAP hbmpMem, hbmpMemPrev;
  44.     DWORD i;
  45.     TCHAR szBuf[32];
  46.     LPVOID lpBits;
  47.     BITMAPV5HEADER bmiHeader;    
  48.     
  49.     
  50.     unsigned char * savealpha; //アルファチャンネル保存用
  51.     
  52.     //作業用描画領域
  53.     HDC hdcWork,hdcMask;
  54.     HBITMAP hdcWorkBitmap,hdcMaskBitmap,hdcWorkBitmapPrev,hdcMaskBitmapPrev;
  55.     
  56.     AVIFileInit();
  57.     if (AVIFileOpen(&pfile, TEXT("video.avi"), OF_CREATE | OF_WRITE, NULL) != 0) {
  58.         MessageBox(NULL, TEXT("Fail file open."), TEXT("OK"), MB_OK);
  59.         AVIFileExit();
  60.         return 0;
  61.     }
  62.     ZeroMemory(&si, sizeof(AVISTREAMINFO));
  63.     si.fccType = streamtypeVIDEO;
  64.     si.fccHandler = comptypeDIB;
  65.     si.dwScale = 1;
  66.     si.dwRate = 2;
  67.     si.dwLength = 0;
  68.     si.dwQuality = (DWORD)-1;
  69.     SetRect(&si.rcFrame, 0, 0, cWidth,cHeight);
  70.     if (AVIFileCreateStream(pfile, &pavi, &si) != 0) {
  71.         MessageBox(NULL, TEXT("Fail open stream."), TEXT("OK"), MB_OK);
  72.         AVIFileRelease(pfile);
  73.         AVIFileExit();
  74.         return 0;
  75.     }
  76.     ZeroMemory(&bmiHeader, sizeof(BITMAPINFOHEADER));
  77.     bmiHeader.bV5Size = sizeof(BITMAPINFOHEADER);
  78.     bmiHeader.bV5Width = lpsi->rcFrame.right;
  79.     bmiHeader.bV5Height = lpsi->rcFrame.bottom;
  80.     bmiHeader.bV5Planes = 1;
  81.     bmiHeader.bV5BitCount = 32;
  82.     bmiHeader.bV5Compression = BI_RGB;
  83.     bmiHeader.bV5SizeImage = bmiHeader.bV5Height * bmiHeader.bV5Width * 4;
  84.     if (AVIStreamSetFormat(pavi, 0, &bmiHeader, sizeof(BITMAPINFOHEADER)) != 0){
  85.         MessageBox(NULL, TEXT("Fail Init BMI Header."), TEXT("OK"), MB_OK);
  86.     }
  87.     savealpha = new unsigned char[cWidth*cHeight];
  88.     
  89.     hdcMem = CreateCompatibleDC(NULL);
  90.     hbmpMem = CreateDIBSection(NULL, (LPBITMAPINFO)&bmiHeader, DIB_RGB_COLORS, &lpBits, NULL, 0);
  91.     hbmpMemPrev = (HBITMAP)SelectObject(hdcMem, hbmpMem);
  92.     
  93.     //作業用領域確保
  94.     hdcWork = CreateCompatibleDC(hdcMem);
  95.     hdcWorkBitmap = CreateCompatibleBitmap(hdcMem,cWidth,cHeight);
  96.     hdcWorkBitmapPrev = (HBITMAP)SelectObject(hdcWork,hdcWorkBitmap);
  97.     
  98.     hdcMask =CreateCompatibleDC(NULL);
  99.     hdcMaskBitmap = CreateCompatibleBitmap(hdcMem,cWidth,cHeight);
  100.     hdcMaskBitmapPrev = (HBITMAP)SelectObject(hdcMask,hdcMaskBitmap);
  101.     
  102.     //バックグラウンドモードを透過に設定
  103.     SetBkMode(hdcWork, TRANSPARENT);
  104.     SetBkMode(hdcMask, TRANSPARENT);
  105.     //テキスト描画カラーを設定
  106.     SetTextColor(hdcWork, RGB(255, 0, 0));    //純粋にこの色が描画される
  107.     SetTextColor(hdcMask, RGB(0, 0, 255));    //アルファチャンネル用として描画される(青チャンネルをアルファとして利用)
  108.     
  109.     HGDIOBJ hFont = CreateFontW(100, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS,
  110.         CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"UI Gothic");
  111.     //仮領域とマスク領域にフォントを設定+初期設定されたフォントを保管
  112.     HGDIOBJ hWorkFontOld = SelectObject(hdcWork, hFont);
  113.     HGDIOBJ hMaskFontOld = SelectObject(hdcMask, hFont);
  114.     
  115.     
  116.     HBRUSH hBrush = CreateSolidBrush(RGB(30, 255, 30));    //背景色描画用
  117.     HBRUSH hBrushMask = CreateSolidBrush(RGB(0, 0, 150));//アルファチャネル用背景
  118.     for (int fCnt = 0; fCnt < 1000; fCnt++) {
  119.         wsprintf(szBuf, TEXT("%d"), fCnt);
  120.         FillRect(hdcWork, &lpsi->rcFrame, hBrush); //仮領域へ描画
  121.         FillRect(hdcMask, &lpsi->rcFrame, hBrushMask); //マスク領域へ描画
  122.         DrawText(hdcWork, szBuf, -1, &lpsi->rcFrame, DT_CENTER | DT_VCENTER | DT_SINGLELINE); //仮領域へ文字出力
  123.         DrawText(hdcMask, szBuf, -1, &lpsi->rcFrame, DT_CENTER | DT_VCENTER | DT_SINGLELINE); //マスク領域へ文字出力
  124.         
  125.         BitBlt(hdcMem,0,0,cWidth,cHeight,hdcMask,0,0,SRCCOPY); //とりあえずマスク領域をメイン領域へコピー
  126.         makeAlpha((LPDWORD)lpBits,cWidth,cHeight,savealpha); //メイン領域の描画情報を独自のアルファチャンネルへコピー
  127.         
  128.         BitBlt(hdcMem,0,0,cWidth,cHeight,hdcWork,0,0,SRCCOPY); //裏描画領域をメイン領域へコピー
  129.         loadAlpha((LPDWORD)lpBits,cWidth,cHeight,savealpha);    //独自のアルファチャンネルからメイン領域のアルファチャンネルへコピー
  130.         AVIStreamWrite(pavi, fCnt, 1, lpBits, bmiHeader.bV5SizeImage, AVIIF_KEYFRAME, NULL, NULL);    //AVIファイルに一コマ書き込み
  131.     }
  132.     
  133.     delete[] savealpha;    //アルファチャンネル保存領域を開放
  134.     
  135.     //hdcで掴んでいるフォント手放して、それぞれ元のフォントを掴む
  136.     SelectObject(hdcWork, hWorkFontOld);
  137.     SelectObject(hdcMask, hMaskFontOld);
  138.     
  139.     //フォントを削除
  140.     DeleteObject(hFont);
  141.     //ブラシの削除    
  142.     DeleteObject(hBrushMask);
  143.     DeleteObject(hBrush);
  144.     
  145.     SelectObject(hdcWork, hdcWorkBitmapPrev);
  146.     DeleteObject(hdcWorkBitmap);
  147.     DeleteDC(hdcWork);
  148.     
  149.     SelectObject(hdcMask, hdcWorkBitmapPrev);
  150.     DeleteObject(hdcMaskBitmap);
  151.     DeleteDC(hdcMask);
  152.     
  153.     SelectObject(hdcMem, hbmpMemPrev);
  154.     DeleteObject(hbmpMem);
  155.     DeleteDC(hdcMem);
  156.     AVIStreamRelease(pavi);
  157.     AVIFileRelease(pfile);
  158.     AVIFileExit();
  159.     MessageBox(NULL, TEXT("Done."), TEXT("OK"), MB_OK);
  160.     
  161.     return 0;
  162. }

簡単にUSBメモリーにバックアップする手順 robocopy

 バックアップは重要です。パソコンは絶対に壊れるので定期的にパソコンの外にバックアップする必要があります。もちろんバックアップ先も絶対に壊れるので同じと言えます。しかし、その2つが同時に故障する可能性は天文学的に低いです。 そう、同時にパソコンとバックアップしたUSBメモリが壊れ...