├── .gitignore ├── AsyncSocket.cpp ├── AsyncSocket.h ├── ChangeLog.txt ├── CommentPrinter.cpp ├── CommentPrinter.h ├── CommentWindow.cpp ├── CommentWindow.h ├── Direct2DRenderer.cpp ├── Direct2DRenderer.h ├── Exports.def ├── JKIDNameTable.h ├── NetworkServiceIDTable.h ├── NicoJK.cpp ├── NicoJK.h ├── NicoJK.ini ├── NicoJK.rc ├── NicoJK.sln ├── NicoJK.vcxproj ├── NicoJK.vcxproj.filters ├── NicoJK.vcxproj.user ├── OsdCompositor.cpp ├── OsdCompositor.h ├── Readme.txt ├── TVTestPlugin.h ├── TextFileReader.cpp ├── TextFileReader.h ├── Util.cpp ├── Util.h ├── jkch.sh.txt ├── resource.h ├── stdafx.cpp └── stdafx.h /.gitignore: -------------------------------------------------------------------------------- 1 | Debug/ 2 | Release/ 3 | ipch/ 4 | *.opensdf 5 | *.sdf 6 | *.suo -------------------------------------------------------------------------------- /AsyncSocket.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "AsyncSocket.h" 3 | 4 | CAsyncSocket::CAsyncSocket() 5 | : hGethost_(NULL) 6 | , soc_(INVALID_SOCKET) 7 | , bReady_(false) 8 | , bShutdown_(false) 9 | , hwnd_(NULL) 10 | , msg_(0) 11 | , name_(NULL) 12 | , port_(0) 13 | , bKeepSession_(false) 14 | , bDoHalfClose_(false) 15 | { 16 | } 17 | 18 | CAsyncSocket::~CAsyncSocket() 19 | { 20 | Close(); 21 | delete [] name_; 22 | } 23 | 24 | // 非同期通信を開始する 25 | // すでに開始しているときは失敗するが、name==NULLのときは開いているソケットに送信データを追加する 26 | bool CAsyncSocket::Send(HWND hwnd, UINT msg, const char *name, unsigned short port, const char *buf, int len, bool bKeepSession) 27 | { 28 | if (len < 0) { 29 | len = lstrlenA(buf); 30 | } 31 | if (len > 0) { 32 | // 前のデータを送信済みのときだけ送信データを追加できる 33 | if (IsPending() && !name && bKeepSession_ && sendBuf_.empty()) { 34 | sendBuf_.assign(&buf[0], &buf[len]); 35 | bKeepSession_ = bKeepSession; 36 | PostMessage(hwnd_, msg_, (WPARAM)soc_, WSAMAKESELECTREPLY(FD_WRITE, 0)); 37 | return true; 38 | } else if (!IsPending() && name) { 39 | sendBuf_.assign(&buf[0], &buf[len]); 40 | hwnd_ = hwnd; 41 | msg_ = msg; 42 | delete [] name_; 43 | name_ = new char[lstrlenA(name) + 1]; 44 | lstrcpyA(name_, name); 45 | port_ = port; 46 | bKeepSession_ = bKeepSession; 47 | // キューにたまっているかもしれないメッセージを流すため待機 48 | bReady_ = true; 49 | PostMessage(hwnd, msg, 0, 0); 50 | return true; 51 | } 52 | } 53 | return false; 54 | } 55 | 56 | // ウィンドウメッセージを処理してデータを受信する 57 | // 受信データはrecvBufに追記される 58 | // 戻り値: 負値=切断した(-2=正常,-1=中断), 0=正常に処理した 59 | int CAsyncSocket::ProcessRecv(WPARAM wParam, LPARAM lParam, std::vector *recvBuf) 60 | { 61 | UINT imAddr = INADDR_NONE; 62 | 63 | if (bReady_) { 64 | // 待機中 65 | if (wParam || lParam) { 66 | return 0; 67 | } 68 | bReady_ = false; 69 | if (bShutdown_) { 70 | bShutdown_ = false; 71 | return -1; 72 | } 73 | if ((imAddr = inet_addr(name_)) == INADDR_NONE) { 74 | hGethost_ = WSAAsyncGetHostByName(hwnd_, msg_, name_, hostBuf_, sizeof(hostBuf_)); 75 | return hGethost_ ? 0 : -1; 76 | } 77 | // IPアドレス即値(名前解決を省略) 78 | 79 | } else if (hGethost_) { 80 | // 名前解決中 81 | bool bValid = wParam == (WPARAM)hGethost_ && WSAGETASYNCERROR(lParam) == 0; 82 | hGethost_ = NULL; 83 | if (bShutdown_) { 84 | bShutdown_ = false; 85 | return -1; 86 | } 87 | if (!bValid || (imAddr = *(UINT*)((HOSTENT*)hostBuf_)->h_addr) == INADDR_NONE) { 88 | return -1; 89 | } 90 | } 91 | 92 | if (imAddr != INADDR_NONE) { 93 | // 接続 94 | if ((soc_ = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { 95 | return -1; 96 | } 97 | WSAAsyncSelect(soc_, hwnd_, msg_, FD_WRITE | FD_READ | FD_CLOSE); 98 | struct sockaddr_in addr = {0}; 99 | addr.sin_family = AF_INET; 100 | addr.sin_addr.s_addr = imAddr; 101 | addr.sin_port = htons(port_); 102 | if (connect(soc_, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) { 103 | closesocket(soc_); 104 | soc_ = INVALID_SOCKET; 105 | return -1; 106 | } 107 | return 0; 108 | } 109 | 110 | if (soc_ != INVALID_SOCKET) { 111 | // 送受信中 112 | if (wParam == (WPARAM)soc_) { 113 | switch(WSAGETSELECTEVENT(lParam)) { 114 | case FD_WRITE: 115 | if (!bShutdown_) { 116 | while (!sendBuf_.empty()) { 117 | int wrote = send(soc_, &sendBuf_.front(), (int)sendBuf_.size(), 0); 118 | if (wrote == SOCKET_ERROR) { 119 | // WSAEWOULDBLOCK時はつぎのFD_WRITEに先送り 120 | if (WSAGetLastError() != WSAEWOULDBLOCK) { 121 | Shutdown(); 122 | } 123 | break; 124 | } 125 | sendBuf_.erase(sendBuf_.begin(), sendBuf_.begin() + wrote); 126 | } 127 | if (sendBuf_.empty() && !bKeepSession_ && bDoHalfClose_) { 128 | // ハーフクローズ 129 | // Bitdefender環境で受信が中断する不具合を確認(2013-10-28) 130 | shutdown(soc_, SD_SEND); 131 | } 132 | } 133 | return 0; 134 | case FD_READ: 135 | for (;;) { 136 | char buf[2048]; 137 | int read = recv(soc_, buf, sizeof(buf), 0); 138 | if (read == SOCKET_ERROR || read <= 0) { 139 | // FD_CLOSEで拾うので無視 140 | return 0; 141 | } 142 | recvBuf->insert(recvBuf->end(), &buf[0], &buf[read]); 143 | } 144 | break; 145 | case FD_CLOSE: 146 | if (WSAGETSELECTERROR(lParam) != 0) { 147 | Close(); 148 | return -1; 149 | } 150 | for (;;) { 151 | char buf[2048]; 152 | int read = recv(soc_, buf, sizeof(buf), 0); 153 | if (read == SOCKET_ERROR || read <= 0) { 154 | Close(); 155 | return read == 0 ? -2 : -1; 156 | } 157 | recvBuf->insert(recvBuf->end(), &buf[0], &buf[read]); 158 | } 159 | break; 160 | } 161 | } 162 | return 0; 163 | } 164 | return -1; 165 | } 166 | 167 | // 送受信停止を要求する 168 | // 呼び出し後ProcessRecv()が負値を返すと完了(ソケットも閉じられる) 169 | bool CAsyncSocket::Shutdown() 170 | { 171 | if (IsPending() && !bShutdown_) { 172 | if (soc_ != INVALID_SOCKET) { 173 | shutdown(soc_, SD_BOTH); 174 | } 175 | bShutdown_ = true; 176 | } 177 | return bShutdown_; 178 | } 179 | 180 | // ソケットを強制的に閉じる 181 | // ポストされたメッセージが残る可能性があるのでなるべくShutdown()を使う 182 | void CAsyncSocket::Close() 183 | { 184 | if (hGethost_) { 185 | WSACancelAsyncRequest(hGethost_); 186 | hGethost_ = NULL; 187 | } 188 | if (soc_ != INVALID_SOCKET) { 189 | closesocket(soc_); 190 | soc_ = INVALID_SOCKET; 191 | } 192 | bReady_ = false; 193 | bShutdown_ = false; 194 | } 195 | -------------------------------------------------------------------------------- /AsyncSocket.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // おもにGETリクエストを想定した非同期TCPクライアント 4 | class CAsyncSocket 5 | { 6 | public: 7 | CAsyncSocket(); 8 | ~CAsyncSocket(); 9 | bool Send(HWND hwnd, UINT msg, const char *name, unsigned short port, const char *buf, int len = -1, bool bKeepSession = false); 10 | int ProcessRecv(WPARAM wParam, LPARAM lParam, std::vector *recvBuf); 11 | bool Shutdown(); 12 | void Close(); 13 | bool IsPending() const { return bReady_ || hGethost_ || soc_ != INVALID_SOCKET; } 14 | void SetDoHalfClose(bool bDoHalfClose) { bDoHalfClose_ = bDoHalfClose; } 15 | private: 16 | HANDLE hGethost_; 17 | SOCKET soc_; 18 | bool bReady_; 19 | bool bShutdown_; 20 | HWND hwnd_; 21 | UINT msg_; 22 | char *name_; 23 | unsigned short port_; 24 | bool bKeepSession_; 25 | bool bDoHalfClose_; 26 | std::vector sendBuf_; 27 | char hostBuf_[MAXGETHOSTSTRUCT]; 28 | }; 29 | -------------------------------------------------------------------------------- /ChangeLog.txt: -------------------------------------------------------------------------------- 1 | rev.16(2014-03-11) 2 | 過去ログ再生時の初期ディレイ設定(defaultPlaybackDelay)追加 (thanks xt氏) 3 | コメントの描画行数設定(commentDrawLineCount)追加 (thanks NicoJK関連小物置場さん) 4 | rev.15(2014-03-09) 5 | Chromeのクッキー暗号化に対応 (thanks xt氏) 6 | 過去ログ再生時のシーク後のコメント出るまでの時間を短縮 7 | rev.14(2014-03-05) 8 | マージしてReadmeとか修正した 9 | 修正21(2014-01-06) 10 | 修正19でリストの描画が少し重くなったのをさらに修正 11 | 修正20(2014-01-03) 12 | http://www1.axfc.net/u/3134333 13 | 修正19でリストの描画がちらつくようになったのを修正 14 | リストの背景色をいじれるようにした 15 | 修正19(2013-12-29) 16 | http://www1.axfc.net/u/3128931 17 | 原作にマージできるかもしれないので機能のすり合わせ 18 | 勢い窓からのチャンネル変更を復活(設定で無効にできる) 19 | NicoJK.iniのコメントを整理 20 | 勢い窓のリストのフォントを指定できるようにした 21 | 勢い窓のリストをOwnerDrawするようにした 22 | 色々できるがとりあえずログの文字位置揃えと色変更してみた 23 | 修正18(2013-10-29) 24 | http://www1.axfc.net/u/3072916 25 | TCPハーフクローズしないようにした 26 | 一部ウィルス対策ソフトの環境で通信が中断されるため 27 | ついでに通信回りのコードをすこし整頓 28 | 修正17(2013-10-26) 29 | http://www1.axfc.net/u/3069154 30 | 勢い窓にラジオのチャンネルを表示できるようにした(設定キーshowRadio) 31 | スレッド生成について微調整 32 | 修正16(2013-10-02) 33 | http://www1.axfc.net/uploader/so/3048093 34 | 複数行コメントのフォントを指定できるようにした 35 | マージン大きめのフォントが下寄りにならないようにした 36 | ウィンドウが小さいときにテクスチャキャッシュを小さくしすぎないようにした 37 | Vista以降について、下コメの無駄な更新処理をさらに削減 38 | デバッグ表示機能を追加(ローカルコマンド@debug) ※個人都合のテキトーな機能 39 | 修正15(2013-09-04) 40 | http://www1.axfc.net/uploader/so/3018213 41 | ログファイルをシークするときの負荷を軽減 42 | 非チューナー系BonDriver(UDPとか)で視聴中のチャンネル変更を検知できるようにした 43 | 勢い窓を手前に表示中に音量変更などでメインウィンドウの後ろに隠れるのを防止 44 | NG登録ダイアログにコメ番も表示 45 | ログファイルをメインウィンドウにもD&Dできる機能を追加 46 | 勢い窓の透過レベルを指定できるようにした(ローカルコマンド@fopa) 47 | コメント投稿欄が空のとき、Ctrl+Vで複数行のペーストができるようにした 48 | 修正14(2013-07-31) 49 | http://www1.axfc.net/uploader/so/2980886 50 | コメント投稿欄のプルダウンリストの装飾例をカスタマイズできるようにした 51 | メインスレッドの仕事を減らすためにコメント描画処理の大部分をスレッドに移した 52 | 勢いリストの更新負荷をさらに軽減 53 | オフライン時はログフォルダにある実況チャンネルを勢い窓に表示するようにした 54 | 修正13(2013-05-29) 55 | http://www1.axfc.net/uploader/Sc/so/459765 56 | 透過率スライドバーを追加 57 | Vista以降について、下コメの無駄な更新処理を削減 58 | 勢い窓の位置復元処理を微修正 59 | timerIntervalのデフォルトを-5000に変更 60 | コメント投稿欄に"ローカルコマンド"機能を追加(実験的) 61 | 修正12(2013-05-20) 62 | http://www1.axfc.net/uploader/Sc/so/457294 63 | コメント投稿の上限はどうやら75文字のようなので緩和 64 | 投稿文字数の上限を超えたときにログリストに警告を出すようにした 65 | コメント投稿欄でカーソルキー上下を押した時の挙動を修正 66 | RS文字も改行文字と解釈するようにした 67 | 勢いリストの更新負荷を軽減 68 | ログファイルの先頭数秒分のコメントが表示されない場合があるのを修正 69 | 4時リセット耐性をさらに向上 70 | 3系統のコード(NicoJK_src/+OsdCompositor/+OsdCompositor+Texture)の平行更新が面 71 | 倒になってきたので1系統に収束 72 | 修正11(2013-04-21) 73 | http://www1.axfc.net/uploader/Sc/so/448492 74 | 暗色コメントは白い影をつけるようにした 75 | 自分のコメント(yourpost="1")を目立つデザインで表示するようにした 76 | 同じコメントの連続投稿をErrorにするようにした 77 | 投稿後に空になったコメント入力欄をCtrl+Zで元に戻せるようにした 78 | 投稿失敗した時にちょっとだけ便利 79 | ポストキー取得処理を微修正 80 | 修正10(2013-04-06) 81 | http://www1.axfc.net/uploader/Sc/so/444348 82 | コメント投稿機能を追加 83 | HTTP-GETリクエストを公式サイトにより近い形に調整(パケット解析の副産物) 84 | 修正9(2013-03-11) 85 | http://www1.axfc.net/uploader/Sc/so/435324 86 | コメントの表示期間を設定可能にした 87 | ue/shitaコメントを左右端に表示する属性(align="left|right")を追加 88 | ue/shitaコメントを時系列順に表示する属性(insert_at="last")を追加 89 | 修正7を一部差し戻して4時リセット耐性を向上 90 | Vista以降について、閑散とした実況での無駄な更新処理を削減 91 | 修正8(2013-02-25) 92 | http://www1.axfc.net/uploader/Sc/so/431952 93 | スレ>>283報告起動時にパネル部分でも実況が流れてしまう問題を修正 94 | 描画の同期ずれ(カクつき)を軽減 95 | 大画面表示中にコメントの描画処理を半減できるようにした 96 | ini読み込みを高速化 97 | 修正7(2013-02-20) 98 | http://www1.axfc.net/uploader/Sc/so/428936 99 | スレ>>293報告Windows7でU+2588(FULL BLOCK)の上端が残る現象がみられたため対応 100 | commentLineMarginを100付近にしたときに下コメが1行だけ上に表示されるのを修正 101 | プラグイン有効時の表示ができるようにした 102 | smallコマンドに対応(文字サイズ75%で表示) 103 | Relチェックボックスのチェック状態を記憶するようにした 104 | 4時リセット耐性を少し上げた 105 | chatタグに稀に'>'を含んだmail属性が来るっぽいので対応+正規表現を最適化 106 | 修正6(2013-02-13) 107 | http://www1.axfc.net/uploader/Sc/so/426325 108 | フルスクリーン切替でコメントクリアしないようにした 109 | スレ>>248のマルチモニタ問題を解決できたかもしれない 110 | ログ再生ドライバ→非再生ドライバ変更後に指定ファイル再生できなくなるのを修正 111 | ユーザーNG機能をつけた(勢い窓のログリストをダブルクリック) 112 | コメントの置換機能をつけた 113 | 軽量化のため非表示中のリストボックスの更新作業を省略 114 | 安定性向上のためPCR/TOT取得部分をメッセージから排他制御に変更 115 | 修正5(2013-02-07) 116 | http://www1.axfc.net/uploader/Sc/so/424388 117 | 指定ファイル再生機能をつけた(勢い窓のFile/Relチェックボックス) 118 | # 読み込めるファイルは下記ソフトの.jkl、.xml、およびNicoJKログの.txt 119 | # ・「JikkyoRec」http://d.hatena.ne.jp/modalblue/20130119/1358617042 120 | # ・「ニコニコ実況コメントビューア」http://air.fem.jp/jkcommentviewer/ 121 | # ファイルに含まれる実況番号は無視します。Relチェックボックスはログの開始時刻 122 | # を現在の動画位置に合わせるかどうかです。ファイルを開くとPluginsフォルダに一 123 | # 時ファイル"NicoJK_{プロセスID}.tmp"が作成されます。 124 | commentFontOutlineキーに対応 125 | ログ記録に外部ツールのみ使う場合を考慮してlogfileModeキーの定義をすこし変更 126 | コメントシフト機能搭載 127 | バックバッファの初期化処理を軽量化 128 | 修正4(2013-02-02) 129 | http://www1.axfc.net/uploader/Sc/so/422213 130 | Vista以降でDWMのリフレッシュに同期して描画できるようにした 131 | デフォルトにはしないがなるべく設定することをお勧め(NicoJK.ini参照) 132 | # 先発の同種ソフトに同様の機能があったのでやり方をググってたらできた 133 | # http://d.hatena.ne.jp/c299792458/20100418 の記事が参考になりました 134 | 複数行コメントのアライメントを間違えていたのを修正 135 | 中央揃えだと勘違いしてた 136 | 修正3(2013-01-31) 137 | http://www1.axfc.net/uploader/Sc/so/421563 138 | ※本家の動きを待ちつつじわじわ追加パッチを上げる感じで行きます 139 | テクスチャキャッシュで負荷軽減 140 | 古典的だけど結構効果があるよう(GDI実装が微妙なVista等でどうでるかは不明) 141 | ソースは"NicoJK_src.zip"→"+OsdCompositor.zip"→"+OsdCompositor+Texture.zip" 142 | の順に中身を上書き 143 | コメントは(公式には)75文字が最長らしいのでこれに合わせてバッファを少し削減 144 | 修正2(2013-01-26) 145 | http://www1.axfc.net/uploader/Sc/so/420106 146 | ※基本が揃った雰囲気なのでこの辺で改造版への機能追加を止めます(バグ修正はある 147 | かも)。機能追加するときはこれをベースにパッチする予定 148 | 正規表現にミスがあったのを修正 149 | (?:^|&)ms=(\d+.\d+.\d+.\d+)(?:&|$) → (?:^|&)ms=(\d+\.\d+\.\d+\.\d+)(?:&|$) 150 | 修正前のでも動作やセキュリティの問題はないだろうけど一応 151 | 映像へのコメント合成機能をつけた 152 | 非Aero環境でパフォーマンスが改善するかもしれない 153 | NicoJK+OsdCompositor_src.zipの中身をNicoJK_src.zipの中身に上書きする 154 | コードはTVCaptionMod2から引っ張ってきた(自由に利用してください) 155 | 修正1(2013-01-21) 156 | http://www1.axfc.net/uploader/Sc/so/418416 157 | コメント受信状態で勢い窓やコメントを表示切替できるようキー割り当てを2つ追加 158 | hideForceWindowキーを拡張 159 | 複数行の実況コメントに対応 160 | 初期受信時に実況コメントを1つだけ取りこぼす場合があるのを修正 161 | コメントが10秒間流れなければコメント描画用ウィンドウを隠すようにした 162 | 動画に重ねているだけでもそれなりにCPU・GPUの負担になるため 163 | コンパイルオプション見直し 164 | 改造初版(2013-01-12) 165 | http://www1.axfc.net/uploader/Sc/so/415460 166 | rev.13 167 | コメント設定をini設定可能にする変更をマージ 168 | 勢い一覧を取得するAPIを変更。BSも表示するようにした。 169 | DirectWriteをデフォルトでは使用しないようにした(iniで設定可) 170 | 勢いウィンドウを表示しない設定を追加(hideForceWindow)。 171 | 勢いウィンドウから同チャンネルの別サービスに切り替えできなかったのを修正。 172 | 大きなディスプレイの場合にコメントが切れる/表示できないのを修正(したはず)。 173 | rev.12 174 | DirectWriteが使える環境では使ってみた 175 | 新BSチャンネルを追加した 176 | rev.11 177 | コメントの表示タイミングを改善した(行が溢れない限り重ならなくなった) 178 | shitaコメントの表示が切れてたのを修正した 179 | rev.10 180 | コメントを描画するウィンドウの制御方法を変更した 181 | 画面サイズに応じてフォントサイズを自動で変えるようにした 182 | 勢い窓のフォントをちょっと大きくした 183 | コメントの描画がされない環境があったのを修正した・・・はず 184 | rev.9 185 | コメントログを追加した 186 | ついでに文字をちっさくし、ウィンドウをリサイズできるようにした 187 | 透過色を変えてみた 188 | TVTestの「常に前面に表示」が効かないのを直した・・・はず 189 | rev.8 190 | 独自実装によるコメント取得・描画をデフォルトで有効にした 191 | 色とshitaコマンドには対応した。 192 | 勢い取得も独自になった。BSは提供されてないので表示できません。 193 | useSDK=1とすると、以前のようにSDKを使って表示します。 194 | TVTestをアクティブにすると、勢い窓も見えるようにした 195 | 勢い窓で現在見てるチャンネルを選択状態にした 196 | 独自実装で半角の><&"が表示されないのを修正 197 | rev.7 198 | 独自実装でBSの実況も見れるようになった 199 | useSDK=0とすると、地デジでも独自実装で見れるようになった 200 | 勢い窓の位置を保存するようにした 201 | rev.6 202 | コメントの位置調整方法を変えた(わりと決め打ちに) 203 | rev.5 204 | コメントの勢いを見れるウィンドウを実装 205 | rev.4 206 | プラグインを切っても起動時やチャンネル切替時にコメントが表示されたのを修正 207 | ドライバ切替時にはすぐコメントを消すようにした 208 | rev.3 209 | 難視聴のチャンネル名、通常のサービス名をNicoJK.iniに追加 210 | TVTestへの追尾方法を変更(全画面表示・最前面表示だとまだ微妙におかしいけど) 211 | サービス切替時にコメントが変更されないのを修正 212 | 実況のないチャンネルに切替してもコメントが消えなかったのを修正 213 | rev.2 214 | チャンネル設定対応 215 | 全画面対応 216 | rev.1 217 | 初期リリース -------------------------------------------------------------------------------- /CommentPrinter.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutice/NicoJK/c96aeaafd5e9158792c36a01b47df372ab0e893f/CommentPrinter.cpp -------------------------------------------------------------------------------- /CommentPrinter.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | class Chat; 5 | 6 | interface Printer { 7 | virtual ~Printer(){ }; 8 | virtual const TCHAR *GetPrinterName() = 0; 9 | virtual void SetParams(HWND hWnd, int fontSize) = 0; 10 | virtual SIZE GetTextSize(const wchar_t *text, int len) = 0; 11 | virtual void Begin(RECT rcWnd, int yPitch) = 0; 12 | virtual void End() = 0; 13 | virtual void DrawShita(const Chat &chat) = 0; 14 | virtual void DrawNormal(const Chat &chat, int vpos) = 0; 15 | }; 16 | 17 | Printer *CreatePrinter(bool disableDW); 18 | -------------------------------------------------------------------------------- /CommentWindow.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutice/NicoJK/c96aeaafd5e9158792c36a01b47df372ab0e893f/CommentWindow.cpp -------------------------------------------------------------------------------- /CommentWindow.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutice/NicoJK/c96aeaafd5e9158792c36a01b47df372ab0e893f/CommentWindow.h -------------------------------------------------------------------------------- /Direct2DRenderer.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************ 2 | * 3 | * File: CustomTextRenderer.cpp 4 | * 5 | * Description: 6 | * 7 | * 8 | * This file is part of the Microsoft Windows SDK Code Samples. 9 | * 10 | * Copyright (C) Microsoft Corporation. All rights reserved. 11 | * 12 | * This source code is intended only as a supplement to Microsoft 13 | * Development Tools and/or on-line documentation. See these other 14 | * materials for detailed information regarding Microsoft code samples. 15 | * 16 | * THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY 17 | * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 19 | * PARTICULAR PURPOSE. 20 | * 21 | ************************************************************************/ 22 | 23 | #include "stdafx.h" 24 | #include 25 | #include 26 | #include "Direct2DRenderer.h" 27 | #include "NicoJKSettings.h" 28 | 29 | /****************************************************************** 30 | * * 31 | * CustomTextRenderer::CustomTextRenderer * 32 | * * 33 | * The constructor stores the Direct2D factory, the render * 34 | * target, and the outline and fill brushes used for drawing the * 35 | * glyphs, underlines, and strikethroughs. * 36 | * * 37 | ******************************************************************/ 38 | 39 | CustomTextRenderer::CustomTextRenderer( 40 | ID2D1Factory* pD2DFactory, 41 | ID2D1RenderTarget* pRT, 42 | ID2D1SolidColorBrush* pOutlineBrush 43 | ) 44 | : 45 | cRefCount_(0), 46 | pD2DFactory_(pD2DFactory), 47 | pRT_(pRT), 48 | pOutlineBrush_(pOutlineBrush), 49 | pFillBrush_(NULL) 50 | { 51 | pD2DFactory_->AddRef(); 52 | pRT_->AddRef(); 53 | pOutlineBrush_->AddRef(); 54 | //pFillBrush_->AddRef(); 55 | } 56 | 57 | /****************************************************************** 58 | * * 59 | * CustomTextRenderer::~CustomTextRenderer * 60 | * * 61 | * The destructor releases the member variables * 62 | * * 63 | ******************************************************************/ 64 | 65 | CustomTextRenderer::~CustomTextRenderer() 66 | { 67 | SafeRelease(&pD2DFactory_); 68 | SafeRelease(&pRT_); 69 | SafeRelease(&pOutlineBrush_); 70 | SafeRelease(&pFillBrush_); 71 | } 72 | 73 | /****************************************************************** 74 | * * 75 | * CustomTextRenderer::DrawGlyphRun * 76 | * * 77 | * Gets GlyphRun outlines via IDWriteFontFace::GetGlyphRunOutline * 78 | * and then draws and fills them using Direct2D path geometries * 79 | * * 80 | ******************************************************************/ 81 | 82 | IFACEMETHODIMP CustomTextRenderer::DrawGlyphRun( 83 | __maybenull void* clientDrawingContext, 84 | FLOAT baselineOriginX, 85 | FLOAT baselineOriginY, 86 | DWRITE_MEASURING_MODE measuringMode, 87 | __in DWRITE_GLYPH_RUN const* glyphRun, 88 | __in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription, 89 | IUnknown* clientDrawingEffect 90 | ) 91 | { 92 | HRESULT hr = S_OK; 93 | 94 | // Create the path geometry. 95 | ID2D1PathGeometry* pPathGeometry = NULL; 96 | hr = pD2DFactory_->CreatePathGeometry( 97 | &pPathGeometry 98 | ); 99 | 100 | // Write to the path geometry using the geometry sink. 101 | ID2D1GeometrySink* pSink = NULL; 102 | if (SUCCEEDED(hr)) 103 | { 104 | hr = pPathGeometry->Open( 105 | &pSink 106 | ); 107 | } 108 | 109 | // Get the glyph run outline geometries back from DirectWrite and place them within the 110 | // geometry sink. 111 | if (SUCCEEDED(hr)) 112 | { 113 | hr = glyphRun->fontFace->GetGlyphRunOutline( 114 | glyphRun->fontEmSize, 115 | glyphRun->glyphIndices, 116 | glyphRun->glyphAdvances, 117 | glyphRun->glyphOffsets, 118 | glyphRun->glyphCount, 119 | glyphRun->isSideways, 120 | glyphRun->bidiLevel%2, 121 | pSink 122 | ); 123 | } 124 | 125 | // Close the geometry sink 126 | if (SUCCEEDED(hr)) 127 | { 128 | hr = pSink->Close(); 129 | } 130 | 131 | // Initialize a matrix to translate the origin of the glyph run. 132 | D2D1::Matrix3x2F const matrix = D2D1::Matrix3x2F( 133 | 1.0f, 0.0f, 134 | 0.0f, 1.0f, 135 | baselineOriginX, baselineOriginY 136 | ); 137 | 138 | // Create the transformed geometry 139 | ID2D1TransformedGeometry* pTransformedGeometry = NULL; 140 | if (SUCCEEDED(hr)) 141 | { 142 | hr = pD2DFactory_->CreateTransformedGeometry( 143 | pPathGeometry, 144 | &matrix, 145 | &pTransformedGeometry 146 | ); 147 | } 148 | 149 | // Draw the outline of the glyph run 150 | pRT_->DrawGeometry( 151 | pTransformedGeometry, 152 | pOutlineBrush_, 153 | CNJIni::GetSettings()->commentFontOutline 154 | ); 155 | 156 | // Fill in the glyph run 157 | pRT_->FillGeometry( 158 | pTransformedGeometry, 159 | pFillBrush_ 160 | ); 161 | 162 | SafeRelease(&pPathGeometry); 163 | SafeRelease(&pSink); 164 | SafeRelease(&pTransformedGeometry); 165 | 166 | return hr; 167 | } 168 | 169 | /****************************************************************** 170 | * * 171 | * CustomTextRenderer::DrawUnderline * 172 | * * 173 | * Draws underlines below the text using a Direct2D recatangle * 174 | * geometry * 175 | * * 176 | ******************************************************************/ 177 | 178 | IFACEMETHODIMP CustomTextRenderer::DrawUnderline( 179 | __maybenull void* clientDrawingContext, 180 | FLOAT baselineOriginX, 181 | FLOAT baselineOriginY, 182 | __in DWRITE_UNDERLINE const* underline, 183 | IUnknown* clientDrawingEffect 184 | ) 185 | { 186 | // Not implemented 187 | return E_NOTIMPL; 188 | } 189 | 190 | /****************************************************************** 191 | * * 192 | * CustomTextRenderer::DrawStrikethrough * 193 | * * 194 | * Draws strikethroughs below the text using a Direct2D * 195 | * recatangle geometry * 196 | * * 197 | ******************************************************************/ 198 | 199 | IFACEMETHODIMP CustomTextRenderer::DrawStrikethrough( 200 | __maybenull void* clientDrawingContext, 201 | FLOAT baselineOriginX, 202 | FLOAT baselineOriginY, 203 | __in DWRITE_STRIKETHROUGH const* strikethrough, 204 | IUnknown* clientDrawingEffect 205 | ) 206 | { 207 | // Not implemented 208 | return E_NOTIMPL; 209 | } 210 | 211 | /****************************************************************** 212 | * * 213 | * CustomTextRenderer::DrawInlineObject * 214 | * * 215 | * This function is not implemented for the purposes of this * 216 | * sample. * 217 | * * 218 | ******************************************************************/ 219 | 220 | IFACEMETHODIMP CustomTextRenderer::DrawInlineObject( 221 | __maybenull void* clientDrawingContext, 222 | FLOAT originX, 223 | FLOAT originY, 224 | IDWriteInlineObject* inlineObject, 225 | BOOL isSideways, 226 | BOOL isRightToLeft, 227 | IUnknown* clientDrawingEffect 228 | ) 229 | { 230 | // Not implemented 231 | return E_NOTIMPL; 232 | } 233 | 234 | /****************************************************************** 235 | * * 236 | * CustomTextRenderer::AddRef * 237 | * * 238 | * Increments the ref count * 239 | * * 240 | ******************************************************************/ 241 | 242 | IFACEMETHODIMP_(unsigned long) CustomTextRenderer::AddRef() 243 | { 244 | return InterlockedIncrement(&cRefCount_); 245 | } 246 | 247 | /****************************************************************** 248 | * * 249 | * CustomTextRenderer::Release * 250 | * * 251 | * Decrements the ref count and deletes the instance if the ref * 252 | * count becomes 0 * 253 | * * 254 | ******************************************************************/ 255 | 256 | IFACEMETHODIMP_(unsigned long) CustomTextRenderer::Release() 257 | { 258 | unsigned long newCount = InterlockedDecrement(&cRefCount_); 259 | if (newCount == 0) 260 | { 261 | delete this; 262 | return 0; 263 | } 264 | 265 | return newCount; 266 | } 267 | 268 | /****************************************************************** 269 | * * 270 | * CustomTextRenderer::IsPixelSnappingDisabled * 271 | * * 272 | * Determines whether pixel snapping is disabled. The recommended * 273 | * default is FALSE, unless doing animation that requires * 274 | * subpixel vertical placement. * 275 | * * 276 | ******************************************************************/ 277 | 278 | IFACEMETHODIMP CustomTextRenderer::IsPixelSnappingDisabled( 279 | __maybenull void* clientDrawingContext, 280 | __out BOOL* isDisabled 281 | ) 282 | { 283 | *isDisabled = FALSE; 284 | return S_OK; 285 | } 286 | 287 | /****************************************************************** 288 | * * 289 | * CustomTextRenderer::GetCurrentTransform * 290 | * * 291 | * Returns the current transform applied to the render target.. * 292 | * * 293 | ******************************************************************/ 294 | 295 | IFACEMETHODIMP CustomTextRenderer::GetCurrentTransform( 296 | __maybenull void* clientDrawingContext, 297 | __out DWRITE_MATRIX* transform 298 | ) 299 | { 300 | //forward the render target's transform 301 | pRT_->GetTransform(reinterpret_cast(transform)); 302 | return S_OK; 303 | } 304 | 305 | /****************************************************************** 306 | * * 307 | * CustomTextRenderer::GetPixelsPerDip * 308 | * * 309 | * This returns the number of pixels per DIP. * 310 | * * 311 | ******************************************************************/ 312 | 313 | IFACEMETHODIMP CustomTextRenderer::GetPixelsPerDip( 314 | __maybenull void* clientDrawingContext, 315 | __out FLOAT* pixelsPerDip 316 | ) 317 | { 318 | float x, yUnused; 319 | 320 | pRT_->GetDpi(&x, &yUnused); 321 | *pixelsPerDip = x / 96; 322 | 323 | return S_OK; 324 | } 325 | 326 | /****************************************************************** 327 | * * 328 | * CustomTextRenderer::QueryInterface * 329 | * * 330 | * Query interface implementation * 331 | * * 332 | ******************************************************************/ 333 | 334 | IFACEMETHODIMP CustomTextRenderer::QueryInterface( 335 | IID const& riid, 336 | void** ppvObject 337 | ) 338 | { 339 | if (__uuidof(IDWriteTextRenderer) == riid) 340 | { 341 | *ppvObject = this; 342 | } 343 | else if (__uuidof(IDWritePixelSnapping) == riid) 344 | { 345 | *ppvObject = this; 346 | } 347 | else if (__uuidof(IUnknown) == riid) 348 | { 349 | *ppvObject = this; 350 | } 351 | else 352 | { 353 | *ppvObject = NULL; 354 | return E_FAIL; 355 | } 356 | 357 | this->AddRef(); 358 | 359 | return S_OK; 360 | } 361 | 362 | -------------------------------------------------------------------------------- /Direct2DRenderer.h: -------------------------------------------------------------------------------- 1 | /************************************************************************ 2 | * 3 | * File: CustomTextRenderer.h 4 | * 5 | * Description: 6 | * 7 | * 8 | * This file is part of the Microsoft Windows SDK Code Samples. 9 | * 10 | * Copyright (C) Microsoft Corporation. All rights reserved. 11 | * 12 | * This source code is intended only as a supplement to Microsoft 13 | * Development Tools and/or on-line documentation. See these other 14 | * materials for detailed information regarding Microsoft code samples. 15 | * 16 | * THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY 17 | * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 19 | * PARTICULAR PURPOSE. 20 | * 21 | ************************************************************************/ 22 | 23 | #pragma once 24 | 25 | template void SafeRelease(T **ppT) 26 | { 27 | if (*ppT) 28 | { 29 | (*ppT)->Release(); 30 | *ppT = NULL; 31 | } 32 | } 33 | 34 | /****************************************************************** 35 | * * 36 | * CustomTextRenderer * 37 | * * 38 | * The IDWriteTextRenderer interface is an input parameter to * 39 | * IDWriteTextLayout::Draw. This interfaces defines a number of * 40 | * callback functions that the client application implements for * 41 | * custom text rendering. This sample renderer implementation * 42 | * renders text using text outlines and Direct2D. * 43 | * A more sophisticated client would also support bitmap * 44 | * renderings. * 45 | * * 46 | ******************************************************************/ 47 | 48 | class CustomTextRenderer : public IDWriteTextRenderer 49 | { 50 | public: 51 | CustomTextRenderer( 52 | ID2D1Factory* pD2DFactory, 53 | ID2D1RenderTarget* pRT, 54 | ID2D1SolidColorBrush* pOutlineBrush 55 | ); 56 | 57 | ~CustomTextRenderer(); 58 | 59 | IFACEMETHOD(IsPixelSnappingDisabled)( 60 | __maybenull void* clientDrawingContext, 61 | __out BOOL* isDisabled 62 | ); 63 | 64 | IFACEMETHOD(GetCurrentTransform)( 65 | __maybenull void* clientDrawingContext, 66 | __out DWRITE_MATRIX* transform 67 | ); 68 | 69 | IFACEMETHOD(GetPixelsPerDip)( 70 | __maybenull void* clientDrawingContext, 71 | __out FLOAT* pixelsPerDip 72 | ); 73 | 74 | IFACEMETHOD(DrawGlyphRun)( 75 | __maybenull void* clientDrawingContext, 76 | FLOAT baselineOriginX, 77 | FLOAT baselineOriginY, 78 | DWRITE_MEASURING_MODE measuringMode, 79 | __in DWRITE_GLYPH_RUN const* glyphRun, 80 | __in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription, 81 | IUnknown* clientDrawingEffect 82 | ); 83 | 84 | IFACEMETHOD(DrawUnderline)( 85 | __maybenull void* clientDrawingContext, 86 | FLOAT baselineOriginX, 87 | FLOAT baselineOriginY, 88 | __in DWRITE_UNDERLINE const* underline, 89 | IUnknown* clientDrawingEffect 90 | ); 91 | 92 | IFACEMETHOD(DrawStrikethrough)( 93 | __maybenull void* clientDrawingContext, 94 | FLOAT baselineOriginX, 95 | FLOAT baselineOriginY, 96 | __in DWRITE_STRIKETHROUGH const* strikethrough, 97 | IUnknown* clientDrawingEffect 98 | ); 99 | 100 | IFACEMETHOD(DrawInlineObject)( 101 | __maybenull void* clientDrawingContext, 102 | FLOAT originX, 103 | FLOAT originY, 104 | IDWriteInlineObject* inlineObject, 105 | BOOL isSideways, 106 | BOOL isRightToLeft, 107 | IUnknown* clientDrawingEffect 108 | ); 109 | 110 | public: 111 | IFACEMETHOD_(unsigned long, AddRef) (); 112 | IFACEMETHOD_(unsigned long, Release) (); 113 | IFACEMETHOD(QueryInterface) ( 114 | IID const& riid, 115 | void** ppvObject 116 | ); 117 | 118 | public: 119 | void SetColorBrush(ID2D1SolidColorBrush* pBrush) { 120 | SafeRelease(&pFillBrush_); 121 | pFillBrush_ = pBrush; 122 | pFillBrush_->AddRef(); 123 | } 124 | 125 | private: 126 | unsigned long cRefCount_; 127 | ID2D1Factory* pD2DFactory_; 128 | ID2D1RenderTarget* pRT_; 129 | ID2D1SolidColorBrush* pOutlineBrush_; 130 | ID2D1SolidColorBrush* pFillBrush_; 131 | }; 132 | -------------------------------------------------------------------------------- /Exports.def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | TVTGetVersion 3 | TVTGetPluginInfo 4 | TVTInitialize 5 | TVTFinalize 6 | -------------------------------------------------------------------------------- /JKIDNameTable.h: -------------------------------------------------------------------------------- 1 | struct JKID_NAME_ELEM { 2 | int jkID; 3 | LPCTSTR name; 4 | struct COMPARE { 5 | bool operator()(const JKID_NAME_ELEM &l, const JKID_NAME_ELEM &r) { return l.jkID < r.jkID; } 6 | }; 7 | }; 8 | 9 | static const JKID_NAME_ELEM DEFAULT_JKID_NAME_TABLE[] = { 10 | // ニコニコ実況チャンネルリスト(2013-01-02時点)(jkIDでソート必須) 11 | { 1, TEXT("NHK 総合") }, 12 | { 2, TEXT("Eテレ") }, 13 | { 4, TEXT("日本テレビ") }, 14 | { 5, TEXT("テレビ朝日") }, 15 | { 6, TEXT("TBS テレビ") }, 16 | { 7, TEXT("テレビ東京") }, 17 | { 8, TEXT("フジテレビ") }, 18 | { 9, TEXT("TOKYO MX") }, 19 | { 10, TEXT("テレ玉") }, 20 | { 11, TEXT("tvk") }, 21 | { 12, TEXT("チバテレビ") }, 22 | { 101, TEXT("NHKBS-1") }, 23 | { 103, TEXT("NHK BSプレミアム") }, 24 | { 141, TEXT("BS 日テレ") }, 25 | { 151, TEXT("BS 朝日") }, 26 | { 161, TEXT("BS-TBS") }, 27 | { 171, TEXT("BSジャパン") }, 28 | { 181, TEXT("BSフジ") }, 29 | { 191, TEXT("WOWOWプライム") }, 30 | { 192, TEXT("WOWOWライブ") }, 31 | { 193, TEXT("WOWOWシネマ") }, 32 | { 200, TEXT("スターチャンネル1") }, 33 | { 201, TEXT("スターチャンネル2") }, 34 | { 202, TEXT("スターチャンネル3") }, 35 | { 211, TEXT("BSイレブン") }, 36 | { 222, TEXT("TwellV") }, 37 | { 231, TEXT("放送大学") }, 38 | { 234, TEXT("BSグリーンチャンネル") }, 39 | { 236, TEXT("BSアニマックス") }, 40 | { 238, TEXT("FOX bs 238") }, 41 | { 241, TEXT("BSスカパー!") }, 42 | { 242, TEXT("J Sports 1") }, 43 | { 243, TEXT("J Sports 2") }, 44 | { 244, TEXT("J Sports 3") }, 45 | { 245, TEXT("J Sports 4") }, 46 | { 251, TEXT("BS釣りビジョン") }, 47 | { 252, TEXT("IMAGICA BS") }, 48 | { 255, TEXT("BS日本映画専門チャンネル") }, 49 | { 256, TEXT("ディズニー・チャンネル") }, 50 | { 258, TEXT("Dlife") }, 51 | { 910, TEXT("SOLiVE24") }, 52 | }; 53 | -------------------------------------------------------------------------------- /NetworkServiceIDTable.h: -------------------------------------------------------------------------------- 1 | struct NETWORK_SERVICE_ID_ELEM { 2 | // 優先度の高い対応であることを表すjkIDのマスク 3 | static const int JKID_PRIOR = 0x40000000; 4 | // ネットワークID(下位16bit、ただし地上波は0x000F)とサービスID(上位16bit)とをパックした値、0は無効値を表す 5 | DWORD ntsID; 6 | // ntsIDに対応する実況ID、負値は対応無しを表す 7 | int jkID; 8 | struct COMPARE { 9 | bool operator()(const NETWORK_SERVICE_ID_ELEM &l, const NETWORK_SERVICE_ID_ELEM &r) { return l.ntsID < r.ntsID; } 10 | }; 11 | }; 12 | 13 | // 別にここまでケチる必要もないけど 14 | #define PACK_NTSID(ntsID,jkID) ((ntsID)|(jkID)<<4) 15 | 16 | static const DWORD DEFAULT_NTSID_TABLE[] = { 17 | // 以下は"jkch.sh.txt"による自動生成(ntsIDでソート必須) 18 | PACK_NTSID(0x00650004, 101), 19 | PACK_NTSID(0x00660004, 101), 20 | PACK_NTSID(0x00670004, 103), 21 | PACK_NTSID(0x00680004, 103), 22 | PACK_NTSID(0x008D0004, 141), 23 | PACK_NTSID(0x008E0004, 141), 24 | PACK_NTSID(0x008F0004, 141), 25 | PACK_NTSID(0x00970004, 151), 26 | PACK_NTSID(0x00980004, 151), 27 | PACK_NTSID(0x00990004, 151), 28 | PACK_NTSID(0x00A10004, 161), 29 | PACK_NTSID(0x00A20004, 161), 30 | PACK_NTSID(0x00A30004, 161), 31 | PACK_NTSID(0x00AB0004, 171), 32 | PACK_NTSID(0x00AC0004, 171), 33 | PACK_NTSID(0x00AD0004, 171), 34 | PACK_NTSID(0x00B50004, 181), 35 | PACK_NTSID(0x00B60004, 181), 36 | PACK_NTSID(0x00B70004, 181), 37 | PACK_NTSID(0x00BF0004, 191), 38 | PACK_NTSID(0x00C00004, 192), 39 | PACK_NTSID(0x00C10004, 193), 40 | PACK_NTSID(0x00C80004, 200), 41 | PACK_NTSID(0x00C90004, 201), 42 | PACK_NTSID(0x00CA0004, 202), 43 | PACK_NTSID(0x00D30004, 211), 44 | PACK_NTSID(0x00DE0004, 222), 45 | PACK_NTSID(0x00E70004, 231), 46 | PACK_NTSID(0x00E80004, 231), 47 | PACK_NTSID(0x00E90004, 231), 48 | PACK_NTSID(0x00EA0004, 234), 49 | PACK_NTSID(0x00EC0004, 236), 50 | PACK_NTSID(0x00EE0004, 238), 51 | PACK_NTSID(0x00F10004, 241), 52 | PACK_NTSID(0x00F20004, 242), 53 | PACK_NTSID(0x00F30004, 243), 54 | PACK_NTSID(0x00F40004, 244), 55 | PACK_NTSID(0x00F50004, 245), 56 | PACK_NTSID(0x00FB0004, 251), 57 | PACK_NTSID(0x00FC0004, 252), 58 | PACK_NTSID(0x00FF0004, 255), 59 | PACK_NTSID(0x01000004, 256), 60 | PACK_NTSID(0x01020004, 258), 61 | PACK_NTSID(0x038E0004, 910), 62 | PACK_NTSID(0x0400000F, 1), 63 | PACK_NTSID(0x0408000F, 2), 64 | PACK_NTSID(0x0410000F, 4), 65 | PACK_NTSID(0x0418000F, 6), 66 | PACK_NTSID(0x0420000F, 8), 67 | PACK_NTSID(0x0428000F, 5), 68 | PACK_NTSID(0x0430000F, 7), 69 | PACK_NTSID(0x0440000F, 231), 70 | PACK_NTSID(0x0808000F, 2), 71 | PACK_NTSID(0x0810000F, 6), 72 | PACK_NTSID(0x0818000F, 5), 73 | PACK_NTSID(0x0820000F, 8), 74 | PACK_NTSID(0x0828000F, 4), 75 | PACK_NTSID(0x0C08000F, 2), 76 | PACK_NTSID(0x0C10000F, 8), 77 | PACK_NTSID(0x0C18000F, 6), 78 | PACK_NTSID(0x0C20000F, 5), 79 | PACK_NTSID(0x0C28000F, 4), 80 | PACK_NTSID(0x1010000F, 6), 81 | PACK_NTSID(0x1018000F, 4), 82 | PACK_NTSID(0x1020000F, 5), 83 | PACK_NTSID(0x1028000F, 8), 84 | PACK_NTSID(0x1030000F, 7), 85 | PACK_NTSID(0x1410000F, 4), 86 | PACK_NTSID(0x1418000F, 5), 87 | PACK_NTSID(0x1420000F, 6), 88 | PACK_NTSID(0x1428000F, 7), 89 | PACK_NTSID(0x1430000F, 8), 90 | PACK_NTSID(0x1810000F, 8), 91 | PACK_NTSID(0x1818000F, 6), 92 | PACK_NTSID(0x1820000F, 4), 93 | PACK_NTSID(0x2800000F, 1), 94 | PACK_NTSID(0x2808000F, 2), 95 | PACK_NTSID(0x2810000F, 6), 96 | PACK_NTSID(0x2818000F, 4), 97 | PACK_NTSID(0x2820000F, 5), 98 | PACK_NTSID(0x2828000F, 8), 99 | PACK_NTSID(0x2830000F, 7), 100 | PACK_NTSID(0x2C00000F, 1), 101 | PACK_NTSID(0x2C08000F, 2), 102 | PACK_NTSID(0x2C10000F, 6), 103 | PACK_NTSID(0x2C18000F, 4), 104 | PACK_NTSID(0x2C20000F, 5), 105 | PACK_NTSID(0x2C28000F, 8), 106 | PACK_NTSID(0x2C30000F, 7), 107 | PACK_NTSID(0x3000000F, 1), 108 | PACK_NTSID(0x3008000F, 2), 109 | PACK_NTSID(0x3010000F, 6), 110 | PACK_NTSID(0x3018000F, 4), 111 | PACK_NTSID(0x3020000F, 5), 112 | PACK_NTSID(0x3028000F, 8), 113 | PACK_NTSID(0x3030000F, 7), 114 | PACK_NTSID(0x3400000F, 1), 115 | PACK_NTSID(0x3408000F, 2), 116 | PACK_NTSID(0x3410000F, 6), 117 | PACK_NTSID(0x3418000F, 4), 118 | PACK_NTSID(0x3420000F, 5), 119 | PACK_NTSID(0x3428000F, 8), 120 | PACK_NTSID(0x3430000F, 7), 121 | PACK_NTSID(0x3800000F, 1), 122 | PACK_NTSID(0x3808000F, 2), 123 | PACK_NTSID(0x3810000F, 6), 124 | PACK_NTSID(0x3818000F, 4), 125 | PACK_NTSID(0x3820000F, 5), 126 | PACK_NTSID(0x3828000F, 8), 127 | PACK_NTSID(0x3830000F, 7), 128 | PACK_NTSID(0x3C00000F, 1), 129 | PACK_NTSID(0x3C08000F, 2), 130 | PACK_NTSID(0x3C10000F, 6), 131 | PACK_NTSID(0x3C18000F, 4), 132 | PACK_NTSID(0x3C20000F, 5), 133 | PACK_NTSID(0x3C28000F, 8), 134 | PACK_NTSID(0x3C30000F, 7), 135 | PACK_NTSID(0x4000000F, 1), 136 | PACK_NTSID(0x4008000F, 2), 137 | PACK_NTSID(0x4010000F, 6), 138 | PACK_NTSID(0x4018000F, 4), 139 | PACK_NTSID(0x4020000F, 5), 140 | PACK_NTSID(0x4028000F, 8), 141 | PACK_NTSID(0x4030000F, 7), 142 | PACK_NTSID(0x4400000F, 1), 143 | PACK_NTSID(0x4408000F, 2), 144 | PACK_NTSID(0x4410000F, 6), 145 | PACK_NTSID(0x4418000F, 8), 146 | PACK_NTSID(0x4420000F, 4), 147 | PACK_NTSID(0x4428000F, 5), 148 | PACK_NTSID(0x4800000F, 1), 149 | PACK_NTSID(0x4808000F, 2), 150 | PACK_NTSID(0x4810000F, 4), 151 | PACK_NTSID(0x4818000F, 8), 152 | PACK_NTSID(0x4820000F, 5), 153 | PACK_NTSID(0x4C00000F, 1), 154 | PACK_NTSID(0x4C08000F, 2), 155 | PACK_NTSID(0x4C10000F, 4), 156 | PACK_NTSID(0x4C18000F, 5), 157 | PACK_NTSID(0x4C20000F, 6), 158 | PACK_NTSID(0x4C28000F, 8), 159 | PACK_NTSID(0x5000000F, 1), 160 | PACK_NTSID(0x5008000F, 2), 161 | PACK_NTSID(0x5010000F, 6), 162 | PACK_NTSID(0x5018000F, 4), 163 | PACK_NTSID(0x5020000F, 8), 164 | PACK_NTSID(0x5028000F, 5), 165 | PACK_NTSID(0x5400000F, 1), 166 | PACK_NTSID(0x5408000F, 2), 167 | PACK_NTSID(0x5410000F, 8), 168 | PACK_NTSID(0x5418000F, 4), 169 | PACK_NTSID(0x5420000F, 5), 170 | PACK_NTSID(0x5428000F, 6), 171 | PACK_NTSID(0x5800000F, 1), 172 | PACK_NTSID(0x5808000F, 2), 173 | PACK_NTSID(0x5810000F, 4), 174 | PACK_NTSID(0x5818000F, 6), 175 | PACK_NTSID(0x5820000F, 5), 176 | PACK_NTSID(0x5C38000F, 9), 177 | PACK_NTSID(0x6038000F, 11), 178 | PACK_NTSID(0x6400000F, 1), 179 | PACK_NTSID(0x6800000F, 1), 180 | PACK_NTSID(0x6C38000F, 12), 181 | PACK_NTSID(0x7000000F, 1), 182 | PACK_NTSID(0x7438000F, 10), 183 | PACK_NTSID(0x7800000F, 1), 184 | PACK_NTSID(0x7808000F, 2), 185 | PACK_NTSID(0x7810000F, 4), 186 | PACK_NTSID(0x7818000F, 5), 187 | PACK_NTSID(0x7820000F, 6), 188 | PACK_NTSID(0x7828000F, 8), 189 | PACK_NTSID(0x7C00000F, 1), 190 | PACK_NTSID(0x7C08000F, 2), 191 | PACK_NTSID(0x7C10000F, 6), 192 | PACK_NTSID(0x7C18000F, 8), 193 | PACK_NTSID(0x7C20000F, 4), 194 | PACK_NTSID(0x7C28000F, 5), 195 | PACK_NTSID(0x8000000F, 1), 196 | PACK_NTSID(0x8008000F, 2), 197 | PACK_NTSID(0x8010000F, 4), 198 | PACK_NTSID(0x8018000F, 6), 199 | PACK_NTSID(0x8400000F, 1), 200 | PACK_NTSID(0x8430000F, 7), 201 | PACK_NTSID(0x8800000F, 1), 202 | PACK_NTSID(0x8808000F, 2), 203 | PACK_NTSID(0x8810000F, 4), 204 | PACK_NTSID(0x8818000F, 5), 205 | PACK_NTSID(0x8820000F, 6), 206 | PACK_NTSID(0x8828000F, 8), 207 | PACK_NTSID(0x8C00000F, 1), 208 | PACK_NTSID(0x8C08000F, 2), 209 | PACK_NTSID(0x8C10000F, 6), 210 | PACK_NTSID(0x8C18000F, 8), 211 | PACK_NTSID(0x8C20000F, 4), 212 | PACK_NTSID(0x8C28000F, 5), 213 | PACK_NTSID(0x9000000F, 1), 214 | PACK_NTSID(0x9008000F, 2), 215 | PACK_NTSID(0x9010000F, 4), 216 | PACK_NTSID(0x9018000F, 8), 217 | PACK_NTSID(0x9400000F, 1), 218 | PACK_NTSID(0x9408000F, 2), 219 | PACK_NTSID(0x9410000F, 4), 220 | PACK_NTSID(0x9418000F, 8), 221 | PACK_NTSID(0x9420000F, 6), 222 | PACK_NTSID(0x9800000F, 1), 223 | PACK_NTSID(0x9C00000F, 1), 224 | PACK_NTSID(0xA000000F, 1), 225 | PACK_NTSID(0xA030000F, 7), 226 | PACK_NTSID(0xA400000F, 1), 227 | PACK_NTSID(0xA800000F, 1), 228 | PACK_NTSID(0xAC00000F, 1), 229 | PACK_NTSID(0xB000000F, 1), 230 | PACK_NTSID(0xB400000F, 1), 231 | PACK_NTSID(0xB800000F, 1), 232 | PACK_NTSID(0xB808000F, 2), 233 | PACK_NTSID(0xB810000F, 6), 234 | PACK_NTSID(0xB818000F, 4), 235 | PACK_NTSID(0xB820000F, 5), 236 | PACK_NTSID(0xB828000F, 8), 237 | PACK_NTSID(0xBC00000F, 1), 238 | PACK_NTSID(0xBC08000F, 2), 239 | PACK_NTSID(0xC000000F, 1), 240 | PACK_NTSID(0xC008000F, 2), 241 | PACK_NTSID(0xC400000F, 1), 242 | PACK_NTSID(0xC408000F, 2), 243 | PACK_NTSID(0xC800000F, 1), 244 | PACK_NTSID(0xC808000F, 2), 245 | PACK_NTSID(0xC810000F, 4), 246 | PACK_NTSID(0xC818000F, 6), 247 | PACK_NTSID(0xC820000F, 5), 248 | PACK_NTSID(0xCC00000F, 1), 249 | PACK_NTSID(0xCC08000F, 2), 250 | PACK_NTSID(0xCC10000F, 4), 251 | PACK_NTSID(0xCC18000F, 5), 252 | PACK_NTSID(0xCC20000F, 6), 253 | PACK_NTSID(0xCC28000F, 8), 254 | PACK_NTSID(0xD000000F, 1), 255 | PACK_NTSID(0xD008000F, 2), 256 | PACK_NTSID(0xD400000F, 1), 257 | PACK_NTSID(0xD408000F, 2), 258 | PACK_NTSID(0xD410000F, 4), 259 | PACK_NTSID(0xD800000F, 1), 260 | PACK_NTSID(0xD808000F, 2), 261 | PACK_NTSID(0xD810000F, 4), 262 | PACK_NTSID(0xD818000F, 6), 263 | PACK_NTSID(0xD820000F, 8), 264 | PACK_NTSID(0xDC00000F, 1), 265 | PACK_NTSID(0xDC08000F, 2), 266 | PACK_NTSID(0xDC10000F, 5), 267 | PACK_NTSID(0xDC18000F, 6), 268 | PACK_NTSID(0xDC20000F, 4), 269 | PACK_NTSID(0xDC28000F, 7), 270 | PACK_NTSID(0xDC30000F, 8), 271 | PACK_NTSID(0xDE00000F, 1), 272 | PACK_NTSID(0xDE08000F, 2), 273 | PACK_NTSID(0xE000000F, 1), 274 | PACK_NTSID(0xE008000F, 2), 275 | PACK_NTSID(0xE010000F, 6), 276 | PACK_NTSID(0xE018000F, 8), 277 | PACK_NTSID(0xE020000F, 4), 278 | PACK_NTSID(0xE028000F, 5), 279 | PACK_NTSID(0xE400000F, 1), 280 | PACK_NTSID(0xE408000F, 2), 281 | PACK_NTSID(0xE410000F, 6), 282 | PACK_NTSID(0xE418000F, 8), 283 | PACK_NTSID(0xE420000F, 5), 284 | PACK_NTSID(0xE428000F, 4), 285 | PACK_NTSID(0xE800000F, 1), 286 | PACK_NTSID(0xE808000F, 2), 287 | PACK_NTSID(0xE810000F, 6), 288 | PACK_NTSID(0xE818000F, 8), 289 | PACK_NTSID(0xE820000F, 5), 290 | PACK_NTSID(0xE828000F, 4), 291 | PACK_NTSID(0xEC00000F, 1), 292 | PACK_NTSID(0xEC08000F, 2), 293 | PACK_NTSID(0xEC10000F, 6), 294 | PACK_NTSID(0xEC18000F, 8), 295 | PACK_NTSID(0xF000000F, 1), 296 | PACK_NTSID(0xF008000F, 2), 297 | PACK_NTSID(0xF010000F, 6), 298 | PACK_NTSID(0xF018000F, 4), 299 | PACK_NTSID(0xF020000F, 5), 300 | PACK_NTSID(0xF400000F, 1), 301 | PACK_NTSID(0xF408000F, 2), 302 | PACK_NTSID(0xF410000F, 8), 303 | PACK_NTSID(0xF800000F, 1), 304 | PACK_NTSID(0xF808000F, 2), 305 | PACK_NTSID(0xF810000F, 6), 306 | PACK_NTSID(0xF820000F, 5), 307 | PACK_NTSID(0xF838000F, 8), 308 | }; 309 | -------------------------------------------------------------------------------- /NicoJK.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // プラグインクラス 4 | class CNicoJK : public TVTest::CTVTestPlugin 5 | { 6 | public: 7 | // リストボックスのログ表示の最大数 8 | static const int COMMENT_TRIMEND = 1000; 9 | // リストボックスのログ表示の最小描画間隔 10 | static const int COMMENT_REDRAW_INTERVAL = 250; 11 | // 処理できるchatタグの最大文字数 12 | static const int CHAT_TAG_MAX = 2048; 13 | // 勢いリストを更新する間隔(あんまり短くしちゃダメ!) 14 | static const int UPDATE_FORCE_INTERVAL = 20000; 15 | // コメントサーバ切断をチェックして再接続する間隔(あんまり短くしちゃダメ!) 16 | static const int JK_WATCHDOG_INTERVAL = 20000; 17 | // ログファイルフォルダの更新をチェックする間隔 18 | static const int READ_LOG_FOLDER_INTERVAL = 3000; 19 | // チャンネル変更などの後に適当な実況IDのチェックを行うまでの猶予 20 | static const int SETUP_CURJK_DELAY = 3000; 21 | // 投稿できる最大コメント文字数(たぶん安易に変更しないほうがいい) 22 | static const int POST_COMMENT_MAX = 76; 23 | // 連投制限(短いと規制されるとのウワサ) 24 | static const int POST_COMMENT_INTERVAL = 3000; 25 | // CTVTestPlugin 26 | CNicoJK(); 27 | bool GetPluginInfo(TVTest::PluginInfo *pInfo); 28 | bool Initialize(); 29 | bool Finalize(); 30 | private: 31 | struct SETTINGS { 32 | // memset()するためフィールドはすべてPOD型でなければならない 33 | int hideForceWindow; 34 | int forceFontSize; 35 | TCHAR forceFontName[LF_FACESIZE]; 36 | int timerInterval; 37 | int halfSkipThreshold; 38 | int commentLineMargin; 39 | int commentFontOutline; 40 | int commentSize; 41 | int commentSizeMin; 42 | int commentSizeMax; 43 | TCHAR commentFontName[LF_FACESIZE]; 44 | TCHAR commentFontNameMulti[LF_FACESIZE]; 45 | bool bCommentFontBold; 46 | bool bCommentFontAntiAlias; 47 | int commentDuration; 48 | int commentDrawLineCount; 49 | int logfileMode; 50 | TCHAR logfileDrivers[512]; 51 | TCHAR nonTunerDrivers[512]; 52 | TCHAR logfileFolder[MAX_PATH]; 53 | TCHAR execGetCookie[1024]; 54 | TCHAR mailDecorations[1024]; 55 | bool bAnonymity; 56 | bool bUseOsdCompositor; 57 | bool bUseTexture; 58 | bool bUseDrawingThread; 59 | bool bSetChannel; 60 | bool bShowRadio; 61 | bool bDoHalfClose; 62 | int maxAutoReplace; 63 | TCHAR abone[CCommentWindow::CHAT_TEXT_MAX]; 64 | int dropLogfileMode; 65 | int defaultPlaybackDelay; 66 | int forwardList[26]; 67 | RECT rcForce; 68 | int forceOpacity; 69 | int commentOpacity; 70 | bool bSetRelative; 71 | }; 72 | struct FORCE_ELEM { 73 | int jkID; 74 | int force; 75 | TCHAR name[64]; 76 | FORCE_ELEM() {} 77 | }; 78 | struct LOG_ELEM { 79 | SYSTEMTIME st; 80 | int no; 81 | COLORREF cr; 82 | TCHAR marker[28]; 83 | TCHAR text[CCommentWindow::CHAT_TEXT_MAX]; 84 | LOG_ELEM() {} 85 | }; 86 | struct RPL_ELEM { 87 | int key; 88 | TCHAR section[32]; 89 | TCHAR comment[32]; 90 | TCHAR pattern[512]; 91 | std::regex re; 92 | std::string fmt; 93 | RPL_ELEM() : key(0) { 94 | section[0] = comment[0] = pattern[0] = TEXT('\0'); 95 | } 96 | bool IsEnabled() const { return IsCharUpper(pattern[0]) == FALSE; } 97 | void SetEnabled(bool b) { pattern[0] = b ? (TCHAR)CharLower((LPTSTR)pattern[0]) : (TCHAR)CharUpper((LPTSTR)pattern[0]); } 98 | bool AssignFromPattern(); 99 | struct COMPARE { 100 | bool operator()(const RPL_ELEM &l, const RPL_ELEM &r) { return l.key < r.key; } 101 | }; 102 | }; 103 | bool TogglePlugin(bool bEnabled); 104 | static LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam); 105 | void ToggleStreamCallback(bool bSet); 106 | static unsigned int __stdcall SyncThread(void *pParam); 107 | void LoadFromIni(); 108 | void SaveToIni(); 109 | void LoadRplListFromIni(LPCTSTR section, std::vector *pRplList); 110 | void SaveRplListToIni(LPCTSTR section, const std::vector &rplList, bool bClearSection = true); 111 | HWND GetFullscreenWindow(); 112 | HWND FindVideoContainer(); 113 | DWORD GetCurrentNetworkServiceID(); 114 | bool GetChannelNetworkServiceID(int tuningSpace, int channelIndex, DWORD *pNtsID); 115 | bool GetCurrentTot(FILETIME *pft); 116 | bool IsMatchDriverName(LPCTSTR drivers); 117 | void WriteToLogfile(int jkID, const char *text = NULL); 118 | bool ReadFromLogfile(int jkID, char *text = NULL, int len = 0, unsigned int tmToRead = 0); 119 | static LRESULT CALLBACK EventCallback(UINT Event, LPARAM lParam1, LPARAM lParam2, void *pClientData); 120 | static BOOL CALLBACK WindowMsgCallback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pResult, void *pUserData); 121 | bool ProcessChatTag(const char *tag, bool bShow = true, int showDelay = 0); 122 | void OutputMessageLog(LPCTSTR text); 123 | void GetPostComboBoxText(LPTSTR comm, int commSize, LPTSTR mail = NULL, int mailSize = 0); 124 | void ProcessLocalPost(LPCTSTR comm); 125 | static INT_PTR CALLBACK ForceDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 126 | INT_PTR ForceDialogProcMain(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 127 | static BOOL CALLBACK StreamCallback(BYTE *pData, void *pClientData); 128 | 129 | // 設定ファイルの名前(Shlwapi使うのでMAX_PATHより大きくしても意味がない) 130 | TCHAR szIniFileName_[MAX_PATH]; 131 | SETTINGS s_; 132 | std::vector ntsIDList_; 133 | std::vector rplList_; 134 | char cookie_[2048]; 135 | bool bDragAcceptFiles_; 136 | 137 | // 勢い窓 138 | HWND hForce_; 139 | HFONT hForceFont_; 140 | HHOOK hKeyboardHook_; 141 | bool bDisplayLogList_; 142 | std::vector forceList_; 143 | std::list logList_; 144 | size_t logListDisplayedSize_; 145 | bool bPendingTimerUpdateList_; 146 | DWORD lastUpdateListTick_; 147 | TCHAR lastCalcText_[64]; 148 | int lastCalcWidth_; 149 | 150 | // コメント描画ウィンドウ 151 | CCommentWindow commentWindow_; 152 | DWORD forwardTick_; 153 | HANDLE hSyncThread_; 154 | bool bQuitSyncThread_; 155 | bool bPendingTimerForward_; 156 | bool bHalfSkip_; 157 | bool bFlipFlop_; 158 | int forwardOffset_; 159 | int forwardOffsetDelta_; 160 | 161 | // 通信用 162 | CAsyncSocket channelSocket_; 163 | CAsyncSocket jkSocket_; 164 | CAsyncSocket postSocket_; 165 | std::vector channelBuf_; 166 | std::vector jkBuf_; 167 | std::vector postBuf_; 168 | int currentJKToGet_; 169 | int currentJK_; 170 | char jkLeaveThreadID_[16]; 171 | int jkLeaveThreadCheck_; 172 | bool bConnectedToCommentServer_; 173 | char commentServerResponse_[CHAT_TAG_MAX]; 174 | DWORD commentServerResponseTick_; 175 | char getflvUserID_[16]; 176 | bool bGetflvIsPremium_; 177 | int lastChatNo_; 178 | DWORD lastPostTick_; 179 | TCHAR lastPostComm_[POST_COMMENT_MAX]; 180 | 181 | // 過去ログ関係 182 | bool bRecording_; 183 | bool bUsingLogfileDriver_; 184 | bool bSetStreamCallback_; 185 | bool bResyncComment_; 186 | int currentLogfileJK_; 187 | HANDLE hLogfile_; 188 | HANDLE hLogfileLock_; 189 | int currentReadLogfileJK_; 190 | CTextFileReader readLogfile_; 191 | char readLogText_[CHAT_TAG_MAX]; 192 | unsigned int tmReadLogText_; 193 | DWORD readLogfileTick_; 194 | FILETIME ftTot_[2]; 195 | DWORD totTick_[2]; 196 | DWORD pcr_; 197 | DWORD pcrTick_; 198 | int pcrPid_; 199 | int pcrPids_[8]; 200 | int pcrPidCounts_[8]; 201 | CCriticalLock streamLock_; 202 | 203 | // 指定ファイル再生 204 | bool bSpecFile_; 205 | TCHAR tmpSpecFileName_[MAX_PATH]; 206 | TCHAR dropFileName_[MAX_PATH]; 207 | int dropFileTimeout_; 208 | }; 209 | -------------------------------------------------------------------------------- /NicoJK.ini: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutice/NicoJK/c96aeaafd5e9158792c36a01b47df372ab0e893f/NicoJK.ini -------------------------------------------------------------------------------- /NicoJK.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rutice/NicoJK/c96aeaafd5e9158792c36a01b47df372ab0e893f/NicoJK.rc -------------------------------------------------------------------------------- /NicoJK.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual C++ Express 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NicoJK", "NicoJK.vcxproj", "{F941C1D5-1DE1-4AEB-9410-4DEC982367EE}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Debug|x64 = Debug|x64 10 | Release|Win32 = Release|Win32 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {F941C1D5-1DE1-4AEB-9410-4DEC982367EE}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {F941C1D5-1DE1-4AEB-9410-4DEC982367EE}.Debug|Win32.Build.0 = Debug|Win32 16 | {F941C1D5-1DE1-4AEB-9410-4DEC982367EE}.Debug|x64.ActiveCfg = Debug|x64 17 | {F941C1D5-1DE1-4AEB-9410-4DEC982367EE}.Debug|x64.Build.0 = Debug|x64 18 | {F941C1D5-1DE1-4AEB-9410-4DEC982367EE}.Release|Win32.ActiveCfg = Release|Win32 19 | {F941C1D5-1DE1-4AEB-9410-4DEC982367EE}.Release|Win32.Build.0 = Release|Win32 20 | {F941C1D5-1DE1-4AEB-9410-4DEC982367EE}.Release|x64.ActiveCfg = Release|x64 21 | {F941C1D5-1DE1-4AEB-9410-4DEC982367EE}.Release|x64.Build.0 = Release|x64 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | EndGlobal 27 | -------------------------------------------------------------------------------- /NicoJK.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {F941C1D5-1DE1-4AEB-9410-4DEC982367EE} 23 | Win32Proj 24 | NicoJK 25 | 26 | 27 | 28 | DynamicLibrary 29 | true 30 | Unicode 31 | 32 | 33 | DynamicLibrary 34 | true 35 | Unicode 36 | Windows7.1SDK 37 | 38 | 39 | DynamicLibrary 40 | false 41 | true 42 | Unicode 43 | 44 | 45 | DynamicLibrary 46 | false 47 | true 48 | Unicode 49 | Windows7.1SDK 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | true 69 | .tvtp 70 | 71 | 72 | true 73 | .tvtp 74 | 75 | 76 | false 77 | .tvtp 78 | 79 | 80 | false 81 | .tvtp 82 | 83 | 84 | 85 | Use 86 | Level4 87 | Disabled 88 | WIN32;_DEBUG;_WINDOWS;_USRDLL;NICOJK_EXPORTS;%(PreprocessorDefinitions) 89 | 90 | 91 | Windows 92 | true 93 | Exports.def 94 | dwmapi.dll;%(DelayLoadDLLs) 95 | 96 | 97 | 98 | 99 | Use 100 | Level4 101 | Disabled 102 | WIN32;_DEBUG;_WINDOWS;_USRDLL;NICOJK_EXPORTS;%(PreprocessorDefinitions) 103 | 104 | 105 | Windows 106 | true 107 | dwmapi.dll;%(DelayLoadDLLs) 108 | 109 | 110 | 111 | 112 | Level4 113 | Use 114 | true 115 | true 116 | WIN32;NDEBUG;_WINDOWS;_USRDLL;NICOJK_EXPORTS;%(PreprocessorDefinitions) 117 | MinSpace 118 | 119 | 120 | Windows 121 | true 122 | true 123 | true 124 | Exports.def 125 | /PDBALTPATH:%_PDB% %(AdditionalOptions) 126 | dwmapi.dll;%(DelayLoadDLLs) 127 | 128 | 129 | 130 | 131 | Level4 132 | Use 133 | true 134 | true 135 | WIN32;NDEBUG;_WINDOWS;_USRDLL;NICOJK_EXPORTS;%(PreprocessorDefinitions) 136 | MinSpace 137 | 138 | 139 | Windows 140 | true 141 | true 142 | true 143 | /PDBALTPATH:%_PDB% %(AdditionalOptions) 144 | dwmapi.dll;%(DelayLoadDLLs) 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | MaxSpeed 167 | MaxSpeed 168 | NotUsing 169 | NotUsing 170 | 171 | 172 | 173 | MaxSpeed 174 | MaxSpeed 175 | NotUsing 176 | NotUsing 177 | 178 | 179 | Create 180 | Create 181 | Create 182 | Create 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | -------------------------------------------------------------------------------- /NicoJK.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ヘッダー ファイル 23 | 24 | 25 | ヘッダー ファイル 26 | 27 | 28 | ヘッダー ファイル 29 | 30 | 31 | ヘッダー ファイル 32 | 33 | 34 | ヘッダー ファイル 35 | 36 | 37 | ヘッダー ファイル 38 | 39 | 40 | ヘッダー ファイル 41 | 42 | 43 | ヘッダー ファイル 44 | 45 | 46 | ヘッダー ファイル 47 | 48 | 49 | ヘッダー ファイル 50 | 51 | 52 | ヘッダー ファイル 53 | 54 | 55 | 56 | 57 | ソース ファイル 58 | 59 | 60 | ソース ファイル 61 | 62 | 63 | ソース ファイル 64 | 65 | 66 | ソース ファイル 67 | 68 | 69 | ソース ファイル 70 | 71 | 72 | ソース ファイル 73 | 74 | 75 | ソース ファイル 76 | 77 | 78 | 79 | 80 | リソース ファイル 81 | 82 | 83 | -------------------------------------------------------------------------------- /NicoJK.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | C:\app\PT2\TVTest32\TVTest.exe 5 | 6 | 7 | C:\app\PT2\TVTest32\ 8 | 9 | 10 | WindowsLocalDebugger 11 | 12 | -------------------------------------------------------------------------------- /OsdCompositor.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include 3 | #include "OsdCompositor.h" 4 | #include 5 | #include 6 | 7 | #pragma comment(lib, "dbghelp.lib") 8 | #pragma comment(lib, "strmiids.lib") 9 | #pragma comment(lib, "mfuuid.lib") 10 | 11 | #if 0 12 | static int GetRefCount(IUnknown *pUnk) 13 | { 14 | if (!pUnk) return 0; 15 | pUnk->AddRef(); 16 | return pUnk->Release(); 17 | } 18 | #endif 19 | 20 | #define WM_SET_CONTAINER_WINDOW (WM_APP + 0) 21 | #define WM_ADD_TEXTURE (WM_APP + 1) 22 | #define WM_DELETE_TEXTURE (WM_APP + 2) 23 | #define WM_GET_TEXTURE_INFO (WM_APP + 3) 24 | #define WM_SET_TEXTURE_INFO (WM_APP + 4) 25 | #define WM_GET_SURFACE_RECT (WM_APP + 5) 26 | #define WM_UPDATE_SURFACE (WM_APP + 6) 27 | #if OSD_COMPOSITOR_VERSION >= 1 28 | #define WM_SET_UPDATE_CALLBACK (WM_APP + 7) 29 | #define WM_GET_VERSION (WM_APP + 8) 30 | #endif 31 | 32 | static const LPCTSTR OSD_COMPOSITOR_WINDOW_CLASS = TEXT("TVTest Plugin OsdCompositor"); 33 | static const CLSID CLSID_madVR = {0xe1a8b82a, 0x32ce, 0x4b0d, {0xbe, 0x0d, 0xaa, 0x68, 0xc7, 0x72, 0xe4, 0x23}}; 34 | 35 | COsdCompositor::COsdCompositor() 36 | : m_hwnd(NULL) 37 | , m_hwndContainer(NULL) 38 | , m_hOle32(NULL) 39 | , m_pfnCoCreateInstance(NULL) 40 | , m_pRenderer(NULL) 41 | , m_RendererType(RT_VMR9) 42 | , m_hD3D9(NULL) 43 | , m_pD3D9(NULL) 44 | , m_pD3DD9(NULL) 45 | , m_pD3DS9(NULL) 46 | , m_TxListLen(0) 47 | , m_TxCount(0) 48 | , m_GroupListLen(0) 49 | #if OSD_COMPOSITOR_VERSION >= 1 50 | , m_CallbackListLen(0) 51 | , m_LocCallback(NULL) 52 | #endif 53 | { 54 | } 55 | 56 | COsdCompositor::~COsdCompositor() 57 | { 58 | Uninitialize(); 59 | } 60 | 61 | HWND COsdCompositor::FindHandle() 62 | { 63 | HWND hwnd = NULL; 64 | while ((hwnd = ::FindWindowEx(HWND_MESSAGE, hwnd, OSD_COMPOSITOR_WINDOW_CLASS, NULL)) != NULL) { 65 | DWORD pid; 66 | ::GetWindowThreadProcessId(hwnd, &pid); 67 | if (pid == ::GetCurrentProcessId()) break; 68 | } 69 | return hwnd; 70 | } 71 | 72 | LRESULT COsdCompositor::SendMessageToHandle(UINT Msg, WPARAM wParam, LPARAM lParam) const 73 | { 74 | // 自分でウィンドウを作成した場合は探さなくていい 75 | HWND hwnd = m_hwnd ? m_hwnd : FindHandle(); 76 | if (hwnd) { 77 | return ::SendMessage(hwnd, Msg, wParam, lParam); 78 | } 79 | return FALSE; 80 | } 81 | 82 | // TVTestの"Video Container"ウィンドウのハンドルを設定する 83 | // このウィンドウは起動中に変化しないようなので、オブジェクトを利用する初回に1度だけ呼べばいい 84 | bool COsdCompositor::SetContainerWindow(HWND hwndContainer) 85 | { 86 | return SendMessageToHandle(WM_SET_CONTAINER_WINDOW, 0, reinterpret_cast(hwndContainer)) != FALSE; 87 | } 88 | 89 | // OSDのテクスチャを追加する 90 | // Groupに0以外の値を入れておくとDeleteTexture()でまとめて削除できる 91 | // テクスチャのID、または0(失敗)を返す 92 | int COsdCompositor::AddTexture(HBITMAP hbm, int Left, int Top, bool fShow, int Group) 93 | { 94 | if (m_GroupListLen < _countof(m_GroupList)) { 95 | TEXTURE_PARAM txp = {0}; 96 | txp.nSize = sizeof(TEXTURE_PARAM); 97 | txp.Left = !fShow ? Left - 200000 : Left; 98 | txp.Top = Top; 99 | txp.hbm = hbm; 100 | int ID = static_cast(SendMessageToHandle(WM_ADD_TEXTURE, 0, reinterpret_cast(&txp))); 101 | if (ID != 0) { 102 | m_GroupList[m_GroupListLen].ID = ID; 103 | m_GroupList[m_GroupListLen++].Group = Group; 104 | } 105 | return ID; 106 | } 107 | return 0; 108 | } 109 | 110 | // OSDのテクスチャを削除する 111 | // (ID,Group) = (0,0):すべて削除, (0,!0):グループのテクスチャを削除, (!0,any):IDのテクスチャを削除 112 | // 1つ以上の削除が行われればtrueを返す 113 | bool COsdCompositor::DeleteTexture(int ID, int Group) 114 | { 115 | bool fDeleted = false; 116 | for (int i = 0; i < m_GroupListLen; ++i) { 117 | if (!ID && !Group || !ID && m_GroupList[i].Group == Group || m_GroupList[i].ID == ID) { 118 | if (SendMessageToHandle(WM_DELETE_TEXTURE, 0, m_GroupList[i].ID) != FALSE) { 119 | fDeleted = true; 120 | } 121 | ::memmove(&m_GroupList[i], &m_GroupList[i + 1], (m_GroupListLen - (i + 1)) * sizeof(m_GroupList[0])); 122 | --m_GroupListLen; 123 | --i; 124 | } 125 | } 126 | return fDeleted; 127 | } 128 | 129 | // テクスチャの表示/非表示を設定する 130 | bool COsdCompositor::ShowTexture(bool fShow, int ID, int Group) 131 | { 132 | bool fModified = false; 133 | for (int i = 0; i < m_GroupListLen; ++i) { 134 | if (!ID && !Group || !ID && m_GroupList[i].Group == Group || m_GroupList[i].ID == ID) { 135 | TEXTURE_PARAM txp = {0}; 136 | txp.nSize = sizeof(TEXTURE_PARAM); 137 | txp.ID = m_GroupList[i].ID; 138 | if (SendMessageToHandle(WM_GET_TEXTURE_INFO, 0, reinterpret_cast(&txp)) != FALSE) { 139 | TEXTURE_PARAM txq = {0}; 140 | txq.nSize = sizeof(TEXTURE_PARAM); 141 | txq.ID = txp.ID; 142 | txq.Left = !fShow && txp.Left >= -100000 ? txp.Left - 200000 : 143 | fShow && txp.Left < -100000 ? txp.Left + 200000 : txp.Left; 144 | txq.Top = txp.Top; 145 | if (txq.Left != txp.Left) { 146 | if (SendMessageToHandle(WM_SET_TEXTURE_INFO, 0, reinterpret_cast(&txq)) != FALSE) { 147 | fModified = true; 148 | } 149 | } 150 | } 151 | } 152 | } 153 | return fModified; 154 | } 155 | 156 | // 描画領域の矩形を得る 157 | bool COsdCompositor::GetSurfaceRect(RECT *pRect) 158 | { 159 | return SendMessageToHandle(WM_GET_SURFACE_RECT, 0, reinterpret_cast(pRect)) != FALSE; 160 | } 161 | 162 | // テクスチャを合成して描画領域を更新する 163 | // AddTexture()/DeleteTexture()が成功したら呼ぶ 164 | bool COsdCompositor::UpdateSurface() 165 | { 166 | return SendMessageToHandle(WM_UPDATE_SURFACE, 0, 0) != FALSE; 167 | } 168 | 169 | #if OSD_COMPOSITOR_VERSION >= 1 170 | // サーフェイス合成時(UpdateSurface()を呼んだとき)のコールバックを設定する 171 | // AddTexture()より低コストだけど自力で再描画が必要 172 | bool COsdCompositor::SetUpdateCallback(UpdateCallbackFunc Callback, void *pClientData, bool fTop) 173 | { 174 | // 自オブジェクトが設定したコールバックがあれば解除 175 | if (m_LocCallback) { 176 | SET_UPDATE_CALLBACK_PARAM ucp = {0}; 177 | ucp.nSize = sizeof(ucp); 178 | ucp.Flags = 0; 179 | ucp.Callback = m_LocCallback; 180 | SendMessageToHandle(WM_SET_UPDATE_CALLBACK, 0, reinterpret_cast(&ucp)); 181 | m_LocCallback = NULL; 182 | } 183 | if (Callback) { 184 | SET_UPDATE_CALLBACK_PARAM ucp = {0}; 185 | ucp.nSize = sizeof(ucp); 186 | ucp.Flags = fTop ? 3 : 1; 187 | ucp.Callback = Callback; 188 | ucp.pClientData = pClientData; 189 | if (!SendMessageToHandle(WM_SET_UPDATE_CALLBACK, 0, reinterpret_cast(&ucp))) { 190 | return false; 191 | } 192 | m_LocCallback = Callback; 193 | } 194 | return true; 195 | } 196 | 197 | // 生成されたOsdCompositorウィンドウのバージョンを取得する 198 | // 失敗または無印版の場合は0を返す 199 | int COsdCompositor::GetVersion() 200 | { 201 | return static_cast(SendMessageToHandle(WM_GET_VERSION, 0, 0)); 202 | } 203 | #endif 204 | 205 | // 初期化する 206 | // 先行プラグインが既にウィンドウを作成していた場合にもfalseを返すので、 207 | // 実際にオブジェクトを利用できるかどうかはFindHandle()がNULLを返すかどうかで判断する 208 | bool COsdCompositor::Initialize() 209 | { 210 | if (m_hwnd) return true; 211 | 212 | // ウィンドウクラス登録(プロセス内でただ1つに限定) 213 | HMODULE hBase = ::GetModuleHandle(NULL); 214 | WNDCLASS wc = {0}; 215 | wc.lpfnWndProc = WndProc; 216 | wc.hInstance = hBase; 217 | wc.lpszClassName = OSD_COMPOSITOR_WINDOW_CLASS; 218 | if (::RegisterClass(&wc)) { 219 | // ウィンドウ作成 220 | m_hwnd = ::CreateWindow(OSD_COMPOSITOR_WINDOW_CLASS, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, hBase, this); 221 | if (m_hwnd) { 222 | // CoCreateInstanceをフック 223 | m_hOle32 = ::LoadLibrary(TEXT("ole32.dll")); 224 | if (m_hOle32) { 225 | m_pfnCoCreateInstance = (CoCreateInstanceFunc*)::GetProcAddress(m_hOle32, "CoCreateInstance"); 226 | if (m_pfnCoCreateInstance) { 227 | if (Hook(CoCreateInstanceHook, m_pfnCoCreateInstance)) { 228 | return true; 229 | } 230 | m_pfnCoCreateInstance = NULL; 231 | } 232 | ::FreeLibrary(m_hOle32); 233 | m_hOle32 = NULL; 234 | } 235 | ::DestroyWindow(m_hwnd); 236 | m_hwnd = NULL; 237 | } 238 | ::UnregisterClass(OSD_COMPOSITOR_WINDOW_CLASS, hBase); 239 | } 240 | return false; 241 | } 242 | 243 | // 破棄する 244 | // Initialize()の戻り値に関わらず呼ぶ 245 | void COsdCompositor::Uninitialize() 246 | { 247 | #if OSD_COMPOSITOR_VERSION >= 1 248 | SetUpdateCallback(NULL); 249 | #endif 250 | 251 | if (m_pfnCoCreateInstance) { 252 | Hook(m_pfnCoCreateInstance, CoCreateInstanceHook); 253 | m_pfnCoCreateInstance = NULL; 254 | } 255 | if (m_pRenderer) { 256 | m_pRenderer->Release(); 257 | m_pRenderer = NULL; 258 | } 259 | if (m_hOle32) { 260 | ::FreeLibrary(m_hOle32); 261 | m_hOle32 = NULL; 262 | } 263 | if (m_hwnd) { 264 | ::DestroyWindow(m_hwnd); 265 | ::UnregisterClass(OSD_COMPOSITOR_WINDOW_CLASS, ::GetModuleHandle(NULL)); 266 | m_hwnd = NULL; 267 | } 268 | } 269 | 270 | bool COsdCompositor::Hook(CoCreateInstanceFunc *pfnNew, CoCreateInstanceFunc *pfnOld) 271 | { 272 | HMODULE hBase = ::GetModuleHandle(NULL); 273 | ULONG ulSize; 274 | PIMAGE_IMPORT_DESCRIPTOR pIID = 275 | (PIMAGE_IMPORT_DESCRIPTOR)::ImageDirectoryEntryToData(hBase, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize); 276 | if (pIID) { 277 | for (; pIID->Name && ::lstrcmpiA("ole32.dll", (char*)hBase + pIID->Name); ++pIID); 278 | if (pIID->Name) { 279 | PIMAGE_THUNK_DATA pITD = (PIMAGE_THUNK_DATA)((BYTE*)hBase + pIID->FirstThunk); 280 | for (; pITD->u1.Function && (DWORD_PTR)pITD->u1.Function != (DWORD_PTR)pfnOld; ++pITD); 281 | if (pITD->u1.Function) { 282 | DWORD dwOldProtect; 283 | if (::VirtualProtect(&pITD->u1.Function, sizeof(DWORD_PTR), PAGE_EXECUTE_READWRITE, &dwOldProtect)) { 284 | DWORD_PTR dwpBuf = (DWORD_PTR)pfnNew; 285 | ::WriteProcessMemory(::GetCurrentProcess(), &pITD->u1.Function, &dwpBuf, sizeof(DWORD_PTR), NULL); 286 | ::VirtualProtect(&pITD->u1.Function, sizeof(DWORD_PTR), dwOldProtect, &dwOldProtect); 287 | return true; 288 | } 289 | } 290 | } 291 | } 292 | return false; 293 | } 294 | 295 | LRESULT CALLBACK COsdCompositor::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 296 | { 297 | COsdCompositor *pThis = reinterpret_cast(::GetWindowLongPtr(hwnd, GWLP_USERDATA)); 298 | 299 | switch (uMsg) { 300 | case WM_CREATE: 301 | { 302 | LPCREATESTRUCT pcs = reinterpret_cast(lParam); 303 | pThis = reinterpret_cast(pcs->lpCreateParams); 304 | ::SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast(pThis)); 305 | } 306 | return 0; 307 | case WM_DESTROY: 308 | pThis->ReleaseDevice(); 309 | while (pThis->m_TxListLen > 0) { 310 | _aligned_free(pThis->m_TxList[--pThis->m_TxListLen].pBits); 311 | } 312 | #if OSD_COMPOSITOR_VERSION >= 1 313 | pThis->m_CallbackListLen = 0; 314 | #endif 315 | return 0; 316 | case WM_SET_CONTAINER_WINDOW: 317 | { 318 | HWND hwnd = reinterpret_cast(lParam); 319 | if (pThis->m_hwndContainer != hwnd) { 320 | pThis->m_hwndContainer = hwnd; 321 | pThis->ReleaseDevice(); 322 | } 323 | } 324 | return TRUE; 325 | case WM_ADD_TEXTURE: 326 | if (pThis->m_TxListLen < _countof(pThis->m_TxList)) { 327 | TEXTURE_PARAM *pTxp = reinterpret_cast(lParam); 328 | BITMAP bm; 329 | if (::GetObject(pTxp->hbm, sizeof(BITMAP), &bm) && 330 | bm.bmType == 0 && 331 | bm.bmPlanes == 1 && 332 | bm.bmBitsPixel == 32 && 333 | bm.bmWidth > 0 && 334 | bm.bmHeight > 0) 335 | { 336 | // 32bit(アルファ値つき)ビットマップのみ受け入れる 337 | TEXTURE tx; 338 | tx.pBits = _aligned_malloc(bm.bmWidth * bm.bmHeight * 4, 16); 339 | if (tx.pBits) { 340 | // 登録 341 | tx.ID = ++pThis->m_TxCount; 342 | tx.Left = pTxp->Left; 343 | tx.Top = pTxp->Top; 344 | ::memcpy(tx.pBits, bm.bmBits, bm.bmWidth * bm.bmHeight * 4); 345 | tx.Width = bm.bmWidth; 346 | tx.Height = bm.bmHeight; 347 | pThis->m_TxList[pThis->m_TxListLen++] = tx; 348 | return tx.ID; 349 | } 350 | } 351 | } 352 | return 0; 353 | case WM_DELETE_TEXTURE: 354 | { 355 | int ID = static_cast(lParam); 356 | for (int i = 0; i < pThis->m_TxListLen; ++i) { 357 | if (pThis->m_TxList[i].ID == ID) { 358 | // 登録抹消 359 | _aligned_free(pThis->m_TxList[i].pBits); 360 | ::memmove(&pThis->m_TxList[i], &pThis->m_TxList[i + 1], (pThis->m_TxListLen - (i + 1)) * sizeof(TEXTURE)); 361 | --pThis->m_TxListLen; 362 | return TRUE; 363 | } 364 | } 365 | } 366 | return FALSE; 367 | case WM_GET_TEXTURE_INFO: 368 | case WM_SET_TEXTURE_INFO: 369 | { 370 | TEXTURE_PARAM *pTxp = reinterpret_cast(lParam); 371 | for (int i = 0; i < pThis->m_TxListLen; ++i) { 372 | TEXTURE *p = &pThis->m_TxList[i]; 373 | if (p->ID == pTxp->ID) { 374 | if (uMsg == WM_GET_TEXTURE_INFO) { 375 | pTxp->nSize = sizeof(TEXTURE_PARAM); 376 | pTxp->Left = p->Left; 377 | pTxp->Top = p->Top; 378 | } 379 | else { 380 | if (pTxp->Left != INT_MAX) p->Left = pTxp->Left; 381 | if (pTxp->Top != INT_MAX) p->Top = pTxp->Top; 382 | } 383 | return TRUE; 384 | } 385 | } 386 | } 387 | return FALSE; 388 | case WM_GET_SURFACE_RECT: 389 | if (pThis->m_pRenderer) { 390 | if (GetVideoPosition(reinterpret_cast(lParam), pThis->m_pRenderer, pThis->m_RendererType)) { 391 | return TRUE; 392 | } 393 | } 394 | return FALSE; 395 | case WM_UPDATE_SURFACE: 396 | if (pThis->m_pRenderer) { 397 | RECT rc; 398 | if (pThis->CreateDevice() && GetVideoPosition(&rc, pThis->m_pRenderer, pThis->m_RendererType)) { 399 | int vw = rc.right - rc.left; 400 | int vh = rc.bottom - rc.top; 401 | RECT rcSurface; 402 | if (vw > 0 && vh > 0 && pThis->SetupSurface(vw, vh, &rcSurface)) { 403 | NORMALIZEDRECT nrc; 404 | nrc.left = (float)rcSurface.left / vw; 405 | nrc.top = (float)rcSurface.top / vh; 406 | nrc.right = (float)rcSurface.right / vw; 407 | nrc.bottom = (float)rcSurface.bottom / vh; 408 | SetAlphaBitmap(pThis->m_pRenderer, pThis->m_RendererType, pThis->m_pD3DS9, &nrc); 409 | } 410 | else { 411 | SetAlphaBitmap(pThis->m_pRenderer, pThis->m_RendererType, NULL, NULL); 412 | } 413 | } 414 | } 415 | return TRUE; 416 | #if OSD_COMPOSITOR_VERSION >= 1 417 | case WM_SET_UPDATE_CALLBACK: 418 | { 419 | SET_UPDATE_CALLBACK_PARAM *pUcp = reinterpret_cast(lParam); 420 | if (pUcp->Flags & 1) { 421 | if (pThis->m_CallbackListLen < _countof(pThis->m_CallbackList)) { 422 | // 登録 423 | pThis->m_CallbackList[pThis->m_CallbackListLen].pClientData = pUcp->pClientData; 424 | pThis->m_CallbackList[pThis->m_CallbackListLen].fTop = (pUcp->Flags & 2) != 0; 425 | pThis->m_CallbackList[pThis->m_CallbackListLen++].Callback = pUcp->Callback; 426 | return TRUE; 427 | } 428 | } 429 | else { 430 | for (int i = 0; i < pThis->m_CallbackListLen; ++i) { 431 | if (pThis->m_CallbackList[i].Callback == pUcp->Callback) { 432 | // 登録抹消 433 | ::memmove(&pThis->m_CallbackList[i], &pThis->m_CallbackList[i + 1], 434 | (pThis->m_CallbackListLen - (i + 1)) * sizeof(pThis->m_CallbackList[0])); 435 | --pThis->m_CallbackListLen; 436 | return TRUE; 437 | } 438 | } 439 | } 440 | } 441 | return FALSE; 442 | case WM_GET_VERSION: 443 | return OSD_COMPOSITOR_VERSION; 444 | #endif 445 | } 446 | return ::DefWindowProc(hwnd, uMsg, wParam, lParam); 447 | } 448 | 449 | // ビットイメージをアルファ合成する 450 | // 同時にbottom-up→top-down変換する 451 | void COsdCompositor::ComposeAlpha(DWORD* __restrict pBitsDest, int PitchDest, int WidthDest, int HeightDest, 452 | const DWORD* __restrict pBits, int Pitch, int Width, int Height, int Left, int Top) 453 | { 454 | int ySrc = min(Height - 1 + Top, Height - 1); 455 | int yDest = max(Top, 0); 456 | int yRange = max(Top + Height - HeightDest, 0); 457 | for (; ySrc >= yRange; --ySrc, ++yDest) { 458 | int i = ySrc * Pitch + max(-Left, 0); 459 | int j = yDest * PitchDest + max(Left, 0); 460 | int r = ySrc * Pitch + min(WidthDest - Left, Width); 461 | for (;; ++i, ++j) { 462 | // ほとんど重ならないことを想定 463 | for (; i < r && !(pBitsDest[j] & 0xFF000000); ++i, ++j) { 464 | pBitsDest[j] = pBits[i]; 465 | } 466 | if (i >= r) break; 467 | 468 | // 重なりがある場合 469 | DWORD v = pBits[i]; 470 | DWORD w = pBitsDest[j]; 471 | BYTE va = v>>24; 472 | BYTE wa = w>>24; 473 | BYTE outa = va + ((wa*(255-va)+255)>>8); 474 | if (outa) { 475 | BYTE outr = ((v>>16&0xFF)*va + (((w>>16&0xFF)*wa*(255-va)+255)>>8)) / outa; 476 | BYTE outg = ((v>>8&0xFF)*va + (((w>>8&0xFF)*wa*(255-va)+255)>>8)) / outa; 477 | BYTE outb = ((v&0xFF)*va + (((w&0xFF)*wa*(255-va)+255)>>8)) / outa; 478 | pBitsDest[j] = outa<<24 | outr<<16 | outg<<8 | outb; 479 | } 480 | else { 481 | pBitsDest[j] = 0; 482 | } 483 | } 484 | } 485 | } 486 | 487 | bool COsdCompositor::GetVideoPosition(RECT *pRect, IBaseFilter *pRenderer, RENDERER_TYPE RendererType) 488 | { 489 | bool fRet = false; 490 | if (RendererType == RT_VMR9) { 491 | IVMRFilterConfig9 *pVMRFC9; 492 | HRESULT hr = pRenderer->QueryInterface(IID_IVMRFilterConfig9, (void**)&pVMRFC9); 493 | if (SUCCEEDED(hr)) { 494 | DWORD dwMode; 495 | hr = pVMRFC9->GetRenderingMode(&dwMode); 496 | if (SUCCEEDED(hr) && dwMode == VMR9Mode_Windowless) { 497 | IVMRWindowlessControl9 *pVMRWC9; 498 | hr = pRenderer->QueryInterface(IID_IVMRWindowlessControl9, (void**)&pVMRWC9); 499 | if (SUCCEEDED(hr)) { 500 | RECT rcSrc; 501 | hr = pVMRWC9->GetVideoPosition(&rcSrc, pRect); 502 | if (SUCCEEDED(hr)) { 503 | fRet = true; 504 | } 505 | pVMRWC9->Release(); 506 | } 507 | } 508 | pVMRFC9->Release(); 509 | } 510 | } 511 | else if (RendererType == RT_EVR) { 512 | IMFGetService *pMFGS; 513 | HRESULT hr = pRenderer->QueryInterface(IID_IMFGetService, (void**)&pMFGS); 514 | if (SUCCEEDED(hr)) { 515 | IMFVideoDisplayControl *pIMFVDC; 516 | hr = pMFGS->GetService(MR_VIDEO_RENDER_SERVICE, IID_IMFVideoDisplayControl, (void**)&pIMFVDC); 517 | if (SUCCEEDED(hr)) { 518 | MFVideoNormalizedRect nrcSrc; 519 | hr = pIMFVDC->GetVideoPosition(&nrcSrc, pRect); 520 | if (SUCCEEDED(hr)) { 521 | fRet = true; 522 | } 523 | pIMFVDC->Release(); 524 | } 525 | pMFGS->Release(); 526 | } 527 | } 528 | return fRet; 529 | } 530 | 531 | bool COsdCompositor::SetAlphaBitmap(IBaseFilter *pRenderer, RENDERER_TYPE RendererType, IDirect3DSurface9 *pD3DS9, const NORMALIZEDRECT *pNrc) 532 | { 533 | bool fRet = false; 534 | if (RendererType == RT_VMR9) { 535 | IVMRMixerBitmap9 *pVMRMB9; 536 | HRESULT hr = pRenderer->QueryInterface(IID_IVMRMixerBitmap9, (void**)&pVMRMB9); 537 | if (SUCCEEDED(hr)) { 538 | VMR9AlphaBitmap ab; 539 | ab.dwFlags = pD3DS9 ? VMR9AlphaBitmap_EntireDDS | VMR9AlphaBitmap_FilterMode : VMR9AlphaBitmap_Disable; 540 | ab.hdc = NULL; 541 | ab.pDDS = pD3DS9; 542 | ab.rDest.left = pNrc ? pNrc->left : 0.0f; 543 | ab.rDest.top = pNrc ? pNrc->top : 0.0f; 544 | ab.rDest.right = pNrc ? pNrc->right : 1.0f; 545 | ab.rDest.bottom = pNrc ? pNrc->bottom : 1.0f; 546 | ab.fAlpha = 1.0f; 547 | ab.dwFilterMode = MixerPref_PointFiltering; 548 | hr = pVMRMB9->SetAlphaBitmap(&ab); 549 | if (SUCCEEDED(hr)) { 550 | fRet = true; 551 | } 552 | pVMRMB9->Release(); 553 | } 554 | } 555 | else if (RendererType == RT_EVR) { 556 | IMFGetService *pMFGS; 557 | HRESULT hr = pRenderer->QueryInterface(IID_IMFGetService, (void**)&pMFGS); 558 | if (SUCCEEDED(hr)) { 559 | IMFVideoMixerBitmap *pMFVMB; 560 | hr = pMFGS->GetService(MR_VIDEO_MIXER_SERVICE, IID_IMFVideoMixerBitmap, (void**)&pMFVMB); 561 | if (SUCCEEDED(hr)) { 562 | if (pD3DS9) { 563 | MFVideoAlphaBitmap ab; 564 | ab.GetBitmapFromDC = FALSE; 565 | ab.bitmap.pDDS = pD3DS9; 566 | ab.params.dwFlags = MFVideoAlphaBitmap_EntireDDS | MFVideoAlphaBitmap_FilterMode; 567 | if (pNrc) { 568 | ab.params.dwFlags |= MFVideoAlphaBitmap_DestRect; 569 | ab.params.nrcDest.left = pNrc->left; 570 | ab.params.nrcDest.top = pNrc->top; 571 | ab.params.nrcDest.right = pNrc->right; 572 | ab.params.nrcDest.bottom = pNrc->bottom; 573 | } 574 | // MSDNによるとMFVideoAlphaBitmap_FilterModeのデフォルトのはずだが実際には違うみたい 575 | ab.params.dwFilterMode = D3DTEXF_POINT; 576 | hr = pMFVMB->SetAlphaBitmap(&ab); 577 | if (SUCCEEDED(hr)) { 578 | fRet = true; 579 | } 580 | } 581 | else { 582 | hr = pMFVMB->ClearAlphaBitmap(); 583 | if (SUCCEEDED(hr)) { 584 | fRet = true; 585 | } 586 | } 587 | pMFVMB->Release(); 588 | } 589 | pMFGS->Release(); 590 | } 591 | } 592 | return fRet; 593 | } 594 | 595 | bool COsdCompositor::CreateDevice() 596 | { 597 | if (m_hD3D9) return true; 598 | if (!m_hwndContainer) return false; 599 | 600 | m_hD3D9 = ::LoadLibrary(TEXT("d3d9.dll")); 601 | if (m_hD3D9) { 602 | Direct3DCreate9Func *pfnDirect3DCreate9 = (Direct3DCreate9Func*)::GetProcAddress(m_hD3D9, "Direct3DCreate9"); 603 | if (pfnDirect3DCreate9) { 604 | m_pD3D9 = pfnDirect3DCreate9(D3D_SDK_VERSION); 605 | if (m_pD3D9) { 606 | D3DDISPLAYMODE dm; 607 | HRESULT hr = m_pD3D9->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &dm); 608 | if (SUCCEEDED(hr)) { 609 | D3DPRESENT_PARAMETERS pp = {0}; 610 | pp.BackBufferFormat = dm.Format; 611 | pp.MultiSampleType = D3DMULTISAMPLE_NONE; 612 | pp.SwapEffect = D3DSWAPEFFECT_DISCARD; 613 | pp.Windowed = TRUE; 614 | pp.hDeviceWindow = m_hwndContainer; 615 | hr = m_pD3D9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, NULL, 616 | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &pp, &m_pD3DD9); 617 | if (SUCCEEDED(hr)) { 618 | return true; 619 | } 620 | m_pD3DD9 = NULL; 621 | } 622 | m_pD3D9->Release(); 623 | m_pD3D9 = NULL; 624 | } 625 | } 626 | ::FreeLibrary(m_hD3D9); 627 | m_hD3D9 = NULL; 628 | } 629 | return false; 630 | } 631 | 632 | void COsdCompositor::ReleaseDevice() 633 | { 634 | if (m_pD3DS9) { 635 | m_pD3DS9->Release(); 636 | m_pD3DS9 = NULL; 637 | } 638 | if (m_pD3DD9) { 639 | m_pD3DD9->Release(); 640 | m_pD3DD9 = NULL; 641 | } 642 | if (m_pD3D9) { 643 | m_pD3D9->Release(); 644 | m_pD3D9 = NULL; 645 | } 646 | if (m_hD3D9) { 647 | ::FreeLibrary(m_hD3D9); 648 | m_hD3D9 = NULL; 649 | } 650 | } 651 | 652 | bool COsdCompositor::SetupSurface(int VideoWidth, int VideoHeight, RECT *pSurfaceRect) 653 | { 654 | // テクスチャを映像領域に配置するために必要な最小矩形をもとめる 655 | RECT rcVideo = { 0, 0, VideoWidth, VideoHeight }; 656 | RECT rcSurface = {0}; 657 | for (int i = 0; i < m_TxListLen; ++i) { 658 | RECT rc = { m_TxList[i].Left, m_TxList[i].Top, 659 | m_TxList[i].Left + m_TxList[i].Width, 660 | m_TxList[i].Top + m_TxList[i].Height }; 661 | RECT rcInter; 662 | if (::IntersectRect(&rcInter, &rcVideo, &rc)) { 663 | // テクスチャは映像領域内にある 664 | RECT rcUnion; 665 | ::UnionRect(&rcUnion, &rcSurface, &rcInter); 666 | rcSurface = rcUnion; 667 | } 668 | } 669 | // サーフェイスをつくる 670 | HRESULT hr; 671 | if (m_pD3DS9) { 672 | D3DSURFACE_DESC desc; 673 | hr = m_pD3DS9->GetDesc(&desc); 674 | if (FAILED(hr) || ::IsRectEmpty(&rcSurface) || 675 | (int)desc.Width != rcSurface.right - rcSurface.left || 676 | (int)desc.Height != rcSurface.bottom - rcSurface.top) 677 | { 678 | m_pD3DS9->Release(); 679 | m_pD3DS9 = NULL; 680 | } 681 | } 682 | if (!m_pD3DS9 && m_pD3DD9 && !::IsRectEmpty(&rcSurface)) { 683 | hr = m_pD3DD9->CreateOffscreenPlainSurface(rcSurface.right - rcSurface.left, rcSurface.bottom - rcSurface.top, 684 | D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &m_pD3DS9, NULL); 685 | if (FAILED(hr)) { 686 | m_pD3DS9 = NULL; 687 | } 688 | } 689 | // テクスチャをサーフェイスに合成 690 | if (m_pD3DS9) { 691 | D3DLOCKED_RECT lr; 692 | HRESULT hr = m_pD3DS9->LockRect(&lr, NULL, 0); 693 | if (SUCCEEDED(hr)) { 694 | //::memset(lr.pBits, 0x60, lr.Pitch * (rcSurface.bottom - rcSurface.top)); // DEBUG 695 | ::memset(lr.pBits, 0, lr.Pitch * (rcSurface.bottom - rcSurface.top)); 696 | #if OSD_COMPOSITOR_VERSION >= 1 697 | for (int i = 0; i < m_CallbackListLen; ++i) { 698 | if (!m_CallbackList[i].fTop) { 699 | m_CallbackList[i].Callback(lr.pBits, &rcSurface, lr.Pitch, m_CallbackList[i].pClientData); 700 | } 701 | } 702 | #endif 703 | for (int i = 0; i < m_TxListLen; ++i) { 704 | ComposeAlpha((DWORD*)lr.pBits, lr.Pitch / 4, 705 | rcSurface.right - rcSurface.left, rcSurface.bottom - rcSurface.top, 706 | (DWORD*)m_TxList[i].pBits, m_TxList[i].Width, m_TxList[i].Width, m_TxList[i].Height, 707 | m_TxList[i].Left - rcSurface.left, m_TxList[i].Top - rcSurface.top); 708 | } 709 | #if OSD_COMPOSITOR_VERSION >= 1 710 | for (int i = 0; i < m_CallbackListLen; ++i) { 711 | if (m_CallbackList[i].fTop) { 712 | m_CallbackList[i].Callback(lr.pBits, &rcSurface, lr.Pitch, m_CallbackList[i].pClientData); 713 | } 714 | } 715 | #endif 716 | m_pD3DS9->UnlockRect(); 717 | } 718 | } 719 | *pSurfaceRect = rcSurface; 720 | return m_pD3DS9 != NULL; 721 | } 722 | 723 | HRESULT WINAPI COsdCompositor::CoCreateInstanceHook(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID FAR* ppv) 724 | { 725 | HRESULT hr = E_FAIL; 726 | HWND hwnd = FindHandle(); 727 | if (hwnd) { 728 | COsdCompositor *pThis = reinterpret_cast(::GetWindowLongPtr(hwnd, GWLP_USERDATA)); 729 | if (pThis) { 730 | // 他のレンダラが生成されるとき解放 731 | if (pThis->m_pRenderer && 732 | (IsEqualCLSID(CLSID_VideoMixingRenderer, rclsid) || 733 | IsEqualCLSID(CLSID_VideoMixingRenderer9, rclsid) || 734 | IsEqualCLSID(CLSID_EnhancedVideoRenderer, rclsid) || 735 | IsEqualCLSID(CLSID_OverlayMixer, rclsid) || 736 | IsEqualCLSID(CLSID_madVR, rclsid))) 737 | { 738 | pThis->m_pRenderer->Release(); 739 | pThis->m_pRenderer = NULL; 740 | } 741 | hr = pThis->m_pfnCoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv); 742 | // レンダラの生成を監視(TVTestのVideoRenderer.cpp参照) 743 | // 必ずメインスレッドで呼ばれることを仮定している 744 | if (SUCCEEDED(hr)) { 745 | if (IsEqualCLSID(CLSID_VideoMixingRenderer9, rclsid)) { 746 | pThis->m_pRenderer = static_cast(*ppv); 747 | pThis->m_pRenderer->AddRef(); 748 | pThis->m_RendererType = RT_VMR9; 749 | } 750 | else if (IsEqualCLSID(CLSID_EnhancedVideoRenderer, rclsid)) { 751 | pThis->m_pRenderer = static_cast(*ppv); 752 | pThis->m_pRenderer->AddRef(); 753 | pThis->m_RendererType = RT_EVR; 754 | } 755 | } 756 | } 757 | } 758 | return hr; 759 | } 760 | -------------------------------------------------------------------------------- /OsdCompositor.h: -------------------------------------------------------------------------------- 1 | // TVTestのVMR9/EVRレンダラに対するOSD合成管理クラス ver.1 (2013-01-24) 2 | // 改変流用自由(ただしプラグイン間の互換をなるべく維持してください) 3 | #ifndef INCLUDE_OSD_COMPOSITOR_H 4 | #define INCLUDE_OSD_COMPOSITOR_H 5 | 6 | #include 7 | #include 8 | 9 | #ifndef OSD_COMPOSITOR_VERSION 10 | #define OSD_COMPOSITOR_VERSION 1 11 | #endif 12 | 13 | class COsdCompositor 14 | { 15 | public: 16 | COsdCompositor(); 17 | ~COsdCompositor(); 18 | static HWND FindHandle(); 19 | bool SetContainerWindow(HWND hwndContainer); 20 | int AddTexture(HBITMAP hbm, int Left, int Top, bool fShow, int Group); 21 | bool DeleteTexture(int ID, int Group); 22 | bool ShowTexture(bool fShow, int ID, int Group); 23 | bool GetSurfaceRect(RECT *pRect); 24 | bool UpdateSurface(); 25 | #if OSD_COMPOSITOR_VERSION >= 1 26 | typedef BOOL (CALLBACK *UpdateCallbackFunc)(void *pBits, const RECT *pSurfaceRect, int Pitch, void *pClientData); 27 | bool SetUpdateCallback(UpdateCallbackFunc Callback, void *pClientData = NULL, bool fTop = false); 28 | int GetVersion(); 29 | #endif 30 | bool Initialize(); 31 | void Uninitialize(); 32 | private: 33 | struct TEXTURE_PARAM { 34 | int nSize; 35 | int ID; 36 | int Left; 37 | int Top; 38 | HBITMAP hbm; 39 | }; 40 | struct TEXTURE { 41 | int ID; 42 | int Left; 43 | int Top; 44 | void *pBits; 45 | int Width; 46 | int Height; 47 | }; 48 | #if OSD_COMPOSITOR_VERSION >= 1 49 | struct SET_UPDATE_CALLBACK_PARAM { 50 | int nSize; 51 | int Flags; 52 | UpdateCallbackFunc Callback; 53 | void *pClientData; 54 | }; 55 | #endif 56 | enum RENDERER_TYPE { RT_VMR9, RT_EVR, }; 57 | typedef HRESULT (WINAPI CoCreateInstanceFunc)(REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID FAR*); 58 | typedef IDirect3D9 *(WINAPI Direct3DCreate9Func)(UINT); 59 | 60 | LRESULT SendMessageToHandle(UINT Msg, WPARAM wParam, LPARAM lParam) const; 61 | static bool Hook(CoCreateInstanceFunc *pfnNew, CoCreateInstanceFunc *pfnOld); 62 | static LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 63 | static void ComposeAlpha(DWORD* __restrict pBitsDest, int PitchDest, int WidthDest, int HeightDest, 64 | const DWORD* __restrict pBits, int Pitch, int Width, int Height, int Left, int Top); 65 | static bool GetVideoPosition(RECT *pRect, IBaseFilter *pRenderer, RENDERER_TYPE RendererType); 66 | static bool SetAlphaBitmap(IBaseFilter *pRenderer, RENDERER_TYPE RendererType, IDirect3DSurface9 *pD3DS9, const NORMALIZEDRECT *pNrc); 67 | bool CreateDevice(); 68 | void ReleaseDevice(); 69 | bool SetupSurface(int VideoWidth, int VideoHeight, RECT *pSurfaceRect); 70 | static HRESULT WINAPI CoCreateInstanceHook( 71 | REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID FAR* ppv); 72 | 73 | HWND m_hwnd; 74 | HWND m_hwndContainer; 75 | HMODULE m_hOle32; 76 | CoCreateInstanceFunc *m_pfnCoCreateInstance; 77 | IBaseFilter *m_pRenderer; 78 | RENDERER_TYPE m_RendererType; 79 | HMODULE m_hD3D9; 80 | IDirect3D9 *m_pD3D9; 81 | IDirect3DDevice9 *m_pD3DD9; 82 | IDirect3DSurface9 *m_pD3DS9; 83 | TEXTURE m_TxList[256]; 84 | int m_TxListLen; 85 | int m_TxCount; 86 | struct { int ID, Group; } m_GroupList[256]; 87 | int m_GroupListLen; 88 | #if OSD_COMPOSITOR_VERSION >= 1 89 | struct { UpdateCallbackFunc Callback; void *pClientData; bool fTop; } m_CallbackList[64]; 90 | int m_CallbackListLen; 91 | UpdateCallbackFunc m_LocCallback; 92 | #endif 93 | }; 94 | 95 | #endif // INCLUDE_OSD_COMPOSITOR_H 96 | -------------------------------------------------------------------------------- /Readme.txt: -------------------------------------------------------------------------------- 1 | /* 2 | NicoJK 3 | TVTest ニコニコ実況プラグイン 4 | */ 5 | 6 | ■なにこれ? 7 | ニコニコ実況を表示するTVTest用のプラグインです。 8 | 9 | # このプラグインはニコニコ実況サーバ(jk.nicovideo.jp)と通信します。サーバに高負 10 | # 荷を与えるような利用や改変をしないでください。 11 | 12 | 13 | ■使い方 14 | NicoJK.tvtpおよびNicoJK.iniをTVTestのPluginフォルダに入れてください。 15 | 16 | ログファイルへの記録機能は、NicoJK.iniのlogfileModeを1か2にして、Pluginsフォルダ 17 | の中に"NicoJK"というフォルダを作っておくと有効になります。ログは"NicoJK"フォルダ 18 | に保存されていきます。録画中に受信した実況コメントがファイル再生プラグイン(何で 19 | もいい)で再生中に表示されればOKです。 20 | 21 | 些末なことですが勢い窓のフォントは「Meiryo UI」なので、XPやVista環境では入れてお 22 | く(PowerPointViewerとかについてくる)とちょっとだけいい感じです。 23 | Vista以降のAero環境で性能に余裕があればNicoJK.iniのtimerIntervalを-10000にすると 24 | 描画がスムーズになります。 25 | 26 | ■設定 27 | NicoJK.iniを確認してください。 28 | 29 | ■コメント投稿について 30 | コメント投稿機能を有効にする場合は以下の作業を行ってください: 31 | 1."sqlite3.exe"を用意 32 | http://www.sqlite.org/download.html の「Precompiled Binaries for Windows」から 33 | "sqlite-shell-win32-x86-{数字}.zip"をダウンロードして、中身の"sqlite3.exe"を 34 | TVTest.exeのある場所かパスの通った場所(C:\windows あたりがオススメ)に配置 35 | 2.ブラウザでニコニコ実況にログイン 36 | FirefoxまたはGoogleChromeで http://jk.nicovideo.jp/ にアクセスして各自のアカウ 37 | ントでログイン 38 | 3.NicoJK.iniのexecGetCookieにブラウザのプロファイルフォルダを設定 39 | プロファイルフォルダの場所については「firefox cookies.sqlite」や「chrome 40 | cookie 保存場所」などのキーワードでググって見つけてください。正しく設定すれば 41 | プラグイン有効時にこのコマンドが実行され、勢い窓にコメント投稿欄が現れます 42 | 43 | コメント投稿欄の仕様は以下のとおりです: 44 | ・Enterキー押下で投稿 45 | ・行頭に@があればローカルコマンドとして処理(詳しくは投稿欄に半角で"@help"と入力) 46 | ・行頭に[]で囲われた部分があれば公式サイトのコマンド欄と同等 47 | ・投稿欄が空のとき、Ctrl+Vで複数行のペーストができる 48 | ・TabまたはRS(レコードセパレータ)文字は改行文字と解釈する 49 | ・RSは右クリ→「Unicode制御文字の挿入」で入力可能。IMEに辞書登録すると便利 50 | ・最長75文字。最短投稿間隔は3秒 51 | 52 | 専用のアカウントを使う場合は、ログイン用のユーザプロファイルをブラウザに作成する 53 | と便利です。Firefoxの手順: 54 | 1.-no-remote -p sub(←プロファイル名、何でもOK)というオプション付きでfirefox.exe 55 | へのショートカットを作成して起動 56 | 2.「ユーザプロファイルの選択」というウィンドウが出るので"sub"という名前の新しい 57 | プロファイルを作成 58 | 3.リストボックスは"default"プロファイルを選択して終了ボタンを押す。以降はショー 59 | トカットから起動したときに"sub"プロファイルが使われる 60 | 61 | ■制限 62 | 今のところbigコマンドは解釈しません。 63 | 64 | ■テスト環境 65 | Win7 sp1 + PT2/PT3 + ptTimer + BonDriver_ptmr.dll + TVTest 0.7.19(x86) 66 | 67 | ■配布 68 | http://www.rutice.net/ 69 | 古いやつは↓ 70 | https://github.com/rutice/NicoJK/downloads 71 | リンクする場合は、配布ページか、ソースコードのページへお願いします。 72 | 73 | ■ソースコード 74 | https://github.com/rutice/NicoJK 75 | 76 | ■ログの仕様(開発者むけ) 77 | ルートフォルダに"jk{実況番号}"というフォルダ(jkフォルダ)を作成する。jkフォルダに 78 | は"{10桁のunix時間(=ログの最初のchatタグのdate属性値)}.txt"というログファイルを 79 | 作成する。ログファイル追記中は"lockfile"というファイルをjkフォルダに排他モードで 80 | 開いておく。ルートフォルダには(jkフォルダと被らなければ)任意のフォルダやファイル 81 | を置くことができるが、jkフォルダにはログ以外の.txtファイルは置くべきでない。 82 | 83 | ログファイルは実況サーバから取得したUTF-8のchatタグを改行CRLFで羅列したもの。 84 | chatタグの要素に改行を含むときはLF= 、CR= の数値文字参照に置きかえる。 85 | chatタグの左右に空白その他の文字を加えてはいけない(BOMも特別扱いしないので先頭行 86 | にはコメントなど入れておくと安全かも)。chat以外のタグを含んでも構わないが、最終 87 | 行はchatタグでなければならない(最終行のdate属性値からログの範囲を求めるため)。 88 | 89 | ■感謝 90 | 過去ログ再生機能、コメント機能を実装していただいたxtne6f氏に感謝いたします。 91 | 92 | ■更新履歴 93 | ChangeLog.txtを参照 94 | -------------------------------------------------------------------------------- /TVTestPlugin.h: -------------------------------------------------------------------------------- 1 | /* 2 | TVTest プラグインヘッダ ver.0.0.13 3 | 4 | このファイルは再配布・改変など自由に行って構いません。 5 | ただし、改変した場合はオリジナルと違う旨を記載して頂けると、混乱がなくてい 6 | いと思います。 7 | 8 | 特にコンパイラに依存する記述はないはずなので、Borland などでも大丈夫です。 9 | また、ヘッダを移植すれば C++ 以外の言語でプラグインを作成することも可能な 10 | はずです(凄く面倒なので誰もやらないと思いますが)。 11 | 12 | 実際にプラグインを作成する場合、このヘッダだけを見ても恐らく意味不明だと思 13 | いますので、サンプルを参考にしてください。 14 | */ 15 | 16 | 17 | /* 18 | TVTest プラグインの概要 19 | 20 | プラグインは32/64ビット DLL の形式です。拡張子は .tvtp とします。 21 | プラグインでは、以下の関数をエクスポートします。 22 | 23 | DWORD WINAPI TVTGetVersion() 24 | BOOL WINAPI TVTGetPluginInfo(PluginInfo *pInfo) 25 | BOOL WINAPI TVTInitialize(PluginParam *pParam) 26 | BOOL WINAPI TVTFinalize() 27 | 28 | 各関数については、このヘッダの最後の方にあるプラグインクラスでのエクスポート 29 | 関数の実装(#ifdef TVTEST_PLUGIN_CLASS_IMPLEMENT の部分)を参照してください。 30 | 31 | プラグインからは、コールバック関数を通じてメッセージを送信することにより、 32 | TVTest の機能を利用することができます。 33 | このような方法になっているのは、将来的な拡張が容易であるためです。 34 | 35 | また、イベントコールバック関数を登録することにより、TVTest からイベントが通 36 | 知されます。 37 | 38 | メッセージの送信はスレッドセーフではありませんので、別スレッドからメッセー 39 | ジコールバック関数を呼び出さないでください。 40 | 41 | TVTEST_PLUGIN_CLASS_IMPLEMENT シンボルが #define されていると、エクスポート 42 | 関数を直接記述しなくても、クラスとしてプラグインを記述することができます。 43 | その場合、TVTestPlugin クラスからプラグインクラスを派生させます。 44 | 45 | 以下は最低限の実装を行ったサンプルです。 46 | 47 | #include 48 | #define TVTEST_PLUGIN_CLASS_IMPLEMENT // プラグインをクラスとして実装 49 | #include "TVTestPlugin.h" 50 | 51 | // プラグインクラス。CTVTestPlugin から派生させる 52 | class CMyPlugin : public TVTest::CTVTestPlugin 53 | { 54 | public: 55 | bool GetPluginInfo(TVTest::PluginInfo *pInfo) { 56 | // プラグインの情報を返す 57 | pInfo->Type = TVTest::PLUGIN_TYPE_NORMAL; 58 | pInfo->Flags = 0; 59 | pInfo->pszPluginName = L"サンプル"; 60 | pInfo->pszCopyright = L"Copyright(c) 2010 Taro Yamada"; 61 | pInfo->pszDescription = L"何もしないプラグイン"; 62 | return true; // false を返すとプラグインのロードが失敗になる 63 | } 64 | bool Initialize() { 65 | // ここで初期化を行う 66 | // 何もしないのであればオーバーライドしなくても良い 67 | return true; // false を返すとプラグインのロードが失敗になる 68 | } 69 | bool Finalize() { 70 | // ここでクリーンアップを行う 71 | // 何もしないのであればオーバーライドしなくても良い 72 | return true; 73 | } 74 | }; 75 | 76 | // CreatePluginClass 関数で、プラグインクラスのインスタンスを生成して返す 77 | TVTest::CTVTestPlugin *CreatePluginClass() 78 | { 79 | return new CMyPlugin; 80 | } 81 | */ 82 | 83 | 84 | /* 85 | 更新履歴 86 | 87 | ver.0.0.13 (TVTest ver.0.7.16 or later) 88 | ・以下のメッセージを追加した 89 | ・MESSAGE_ENABLEPROGRAMGUIDEEVENT 90 | ・MESSAGE_REGISTERPROGRAMGUIDECOMMAND 91 | ・以下のイベントを追加した 92 | ・EVENT_STARTUPDONE 93 | ・EVENT_PROGRAMGUIDE_INITIALIZE 94 | ・EVENT_PROGRAMGUIDE_FINALIZE 95 | ・EVENT_PROGRAMGUIDE_COMMAND 96 | ・EVENT_PROGRAMGUIDE_INITIALIZEMENU 97 | ・EVENT_PROGRAMGUIDE_MENUSELECTED 98 | ・EVENT_PROGRAMGUIDE_PROGRAM_DRAWBACKGROUND 99 | ・EVENT_PROGRAMGUIDE_PROGRAM_INITIALIZEMENU 100 | ・EVENT_PROGRAMGUIDE_PROGRAM_MENUSELECTED 101 | 102 | ver.0.0.12 (TVTest ver.0.7.14 or later) 103 | ・以下のメッセージを追加した 104 | ・MESSAGE_GETEPGEVENTINFO 105 | ・MESSAGE_FREEEPGEVENTINFO 106 | ・MESSAGE_GETEPGEVENTLIST 107 | ・MESSAGE_FREEEPGEVENTLIST 108 | ・MESSAGE_ENUMDRIVER 109 | ・MESSAGE_GETDRIVERTUNINGSPACELIST 110 | ・MESSAGE_FREEDRIVERTUNINGSPACELIST 111 | ・ChannelInfo 構造体に Flags メンバを追加した 112 | 113 | ver.0.0.11 (TVTest ver.0.7.6 or later) 114 | ・以下のメッセージを追加した 115 | ・MESSAGE_SETWINDOWMESSAGECALLBACK 116 | ・MESSAGE_REGISTERCONTROLLER 117 | ・MESSAGE_ONCOTROLLERBUTTONDOWN 118 | ・MESSAGE_GETCONTROLLERSETTINGS 119 | ・EVENT_CONTROLLERFOCUS を追加した 120 | ・プラグインのフラグに PLUGIN_FLAG_NOUNLOAD を追加した 121 | 122 | ver.0.0.10 (TVTest ver.0.7.0 or later) 123 | ・以下のメッセージを追加した 124 | ・MESSAGE_GETLOGO 125 | ・MESSAGE_GETAVAILABLELOGOTYPE 126 | ・MESSAGE_RELAYRECORD 127 | ・MESSAGE_SILENTMODE 128 | ・以下のイベントを追加した 129 | ・EVENT_CLOSE 130 | ・EVENT_STARTRECORD 131 | ・EVENT_RELAYRECORD 132 | ・プラグインのフラグに PLUGIN_FLAG_DISABLEONSTART を追加した 133 | ・RecordStatusInfo 構造体に pszFileName と MaxFileName メンバを追加した 134 | 135 | ver.0.0.9.1 136 | ・64ビットで警告が出ないようにした 137 | 138 | ver.0.0.9 (TVTest ver.0.6.2 or later) 139 | ・MESSAGE_GETSETTING と MESSAGE_GETDRIVERFULLPATHNAME を追加した 140 | ・EVENT_SETTINGSCHANGE を追加した 141 | ・MESSAGE_RESET にパラメータを追加した 142 | 143 | ver.0.0.8 (TVTest ver.0.6.0 or later) 144 | ・以下のメッセージを追加した 145 | ・MESSAGE_GETBCASINFO 146 | ・MESSAGE_SENDBCASCOMMAND 147 | ・MESSAGE_GETHOSTINFO 148 | ・MESSAGE_SETCHANNEL のパラメータにサービスIDを追加した 149 | 150 | ver.0.0.7 (TVTest ver.0.5.45 or later) 151 | ・MESSAGE_DOCOMMAND を追加した 152 | 153 | ver.0.0.6 (TVTest ver.0.5.42 or later) 154 | ・MESSAGE_SETAUDIOCALLBACK を追加した 155 | ・EVENT_DSHOWINITIALIZED を追加した 156 | 157 | ver.0.0.5 (TVTest ver.0.5.41 or later) 158 | ・以下のイベントを追加した 159 | ・EVENT_RESET 160 | ・EVENT_STATUSRESET 161 | ・EVENT_AUDIOSTREAMCHANGE 162 | ・MESSAGE_RESETSTATUS を追加した 163 | 164 | ver.0.0.4 (TVTest ver.0.5.33 or later) 165 | ・EVENT_EXECUTE を追加した 166 | 167 | ver.0.0.3 (TVTest ver.0.5.27 or later) 168 | ・以下のメッセージを追加した 169 | ・MESSAGE_ISPLUGINENABLED 170 | ・MESSAGE_REGISTERCOMMAND 171 | ・MESSAGE_ADDLOG 172 | ・EVENT_STANDBY と EVENT_COMMAND を追加した 173 | 174 | ver.0.0.2 175 | ・MESSAGE_GETAUDIOSTREAM と MESSAGE_SETAUDIOSTREAM を追加した 176 | ・ServiceInfo 構造体に AudioComponentType と SubtitlePID メンバを追加した 177 | ・StatusInfo 構造体に DropPacketCount と BcasCardStatus メンバを追加した 178 | 179 | ver.0.0.1 180 | ・以下のメッセージを追加した 181 | ・MESSAGE_QUERYEVENT 182 | ・MESSAGE_GETTUNINGSPACE 183 | ・MESSAGE_GETTUNINGSPACEINFO 184 | ・MESSAGE_SETNEXTCHANNEL 185 | ・ChannelInfo 構造体にいくつかメンバを追加した 186 | 187 | ver.0.0.0 188 | ・最初のバージョン 189 | */ 190 | 191 | 192 | #ifndef TVTEST_PLUGIN_H 193 | #define TVTEST_PLUGIN_H 194 | 195 | 196 | #include 197 | 198 | 199 | namespace TVTest { 200 | 201 | 202 | // プラグインのバージョン 203 | #define TVTEST_PLUGIN_VERSION_(major,minor,rev) \ 204 | (((major)<<24) | ((minor)<<12) | (rev)) 205 | #ifndef TVTEST_PLUGIN_VERSION 206 | #define TVTEST_PLUGIN_VERSION TVTEST_PLUGIN_VERSION_(0,0,13) 207 | #endif 208 | 209 | // エクスポート関数定義用 210 | #define TVTEST_EXPORT(type) extern "C" __declspec(dllexport) type WINAPI 211 | 212 | // offsetof 213 | #define TVTEST_OFFSETOF(type,member) \ 214 | ((size_t)((BYTE*)&((type*)0)->member-(BYTE*)(type*)0)) 215 | 216 | // プラグインの種類 217 | enum { 218 | PLUGIN_TYPE_NORMAL // 普通 219 | }; 220 | 221 | // プラグインのフラグ 222 | enum { 223 | PLUGIN_FLAG_HASSETTINGS =0x00000001UL, // 設定ダイアログがある 224 | PLUGIN_FLAG_ENABLEDEFAULT =0x00000002UL // デフォルトで有効 225 | // 特別な理由が無い限り使わない 226 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,10) 227 | ,PLUGIN_FLAG_DISABLEONSTART =0x00000004UL // 起動時は必ず無効 228 | #endif 229 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,11) 230 | ,PLUGIN_FLAG_NOUNLOAD =0x00000008UL // 終了時以外アンロード不可 231 | #endif 232 | }; 233 | 234 | // プラグインの情報 235 | struct PluginInfo { 236 | DWORD Type; // 種類(PLUGIN_TYPE_???) 237 | DWORD Flags; // フラグ(PLUGIN_FLAG_???) 238 | LPCWSTR pszPluginName; // プラグイン名 239 | LPCWSTR pszCopyright; // 著作権情報 240 | LPCWSTR pszDescription; // 説明文 241 | }; 242 | 243 | // メッセージ送信用コールバック関数 244 | typedef LRESULT (CALLBACK *MessageCallbackFunc)(struct PluginParam *pParam,UINT Message,LPARAM lParam1,LPARAM lParam2); 245 | 246 | // プラグインパラメータ 247 | struct PluginParam { 248 | MessageCallbackFunc Callback; // コールバック関数 249 | HWND hwndApp; // メインウィンドウのハンドル 250 | void *pClientData; // プラグイン側で好きに使えるデータ 251 | void *pInternalData; // TVTest側で使用するデータ。アクセス禁止 252 | }; 253 | 254 | // エクスポート関数 255 | typedef DWORD (WINAPI *GetVersionFunc)(); 256 | typedef BOOL (WINAPI *GetPluginInfoFunc)(PluginInfo *pInfo); 257 | typedef BOOL (WINAPI *InitializeFunc)(PluginParam *pParam); 258 | typedef BOOL (WINAPI *FinalizeFunc)(); 259 | 260 | // メッセージ 261 | enum { 262 | MESSAGE_GETVERSION, // プログラムのバージョンを取得 263 | MESSAGE_QUERYMESSAGE, // メッセージに対応しているか問い合わせる 264 | MESSAGE_MEMORYALLOC, // メモリ確保 265 | MESSAGE_SETEVENTCALLBACK, // イベントハンドル用コールバックの設定 266 | MESSAGE_GETCURRENTCHANNELINFO, // 現在のチャンネルの情報を取得 267 | MESSAGE_SETCHANNEL, // チャンネルを設定 268 | MESSAGE_GETSERVICE, // サービスを取得 269 | MESSAGE_SETSERVICE, // サービスを設定 270 | MESSAGE_GETTUNINGSPACENAME, // チューニング空間名を取得 271 | MESSAGE_GETCHANNELINFO, // チャンネルの情報を取得 272 | MESSAGE_GETSERVICEINFO, // サービスの情報を取得 273 | MESSAGE_GETDRIVERNAME, // BonDriverのファイル名を取得 274 | MESSAGE_SETDRIVERNAME, // BonDriverを設定 275 | MESSAGE_STARTRECORD, // 録画の開始 276 | MESSAGE_STOPRECORD, // 録画の停止 277 | MESSAGE_PAUSERECORD, // 録画の一時停止/再開 278 | MESSAGE_GETRECORD, // 録画設定の取得 279 | MESSAGE_MODIFYRECORD, // 録画設定の変更 280 | MESSAGE_GETZOOM, // 表示倍率の取得 281 | MESSAGE_SETZOOM, // 表示倍率の設定 282 | MESSAGE_GETPANSCAN, // パンスキャンの設定を取得 283 | MESSAGE_SETPANSCAN, // パンスキャンを設定 284 | MESSAGE_GETSTATUS, // ステータスを取得 285 | MESSAGE_GETRECORDSTATUS, // 録画ステータスを取得 286 | MESSAGE_GETVIDEOINFO, // 映像の情報を取得 287 | MESSAGE_GETVOLUME, // 音量を取得 288 | MESSAGE_SETVOLUME, // 音量を設定 289 | MESSAGE_GETSTEREOMODE, // ステレオモードを取得 290 | MESSAGE_SETSTEREOMODE, // ステレオモードを設定 291 | MESSAGE_GETFULLSCREEN, // 全画面表示の状態を取得 292 | MESSAGE_SETFULLSCREEN, // 全画面表示の状態を設定 293 | MESSAGE_GETPREVIEW, // 再生が有効か取得 294 | MESSAGE_SETPREVIEW, // 再生の有効状態を設定 295 | MESSAGE_GETSTANDBY, // 待機状態であるか取得 296 | MESSAGE_SETSTANDBY, // 待機状態を設定 297 | MESSAGE_GETALWAYSONTOP, // 常に最前面表示であるか取得 298 | MESSAGE_SETALWAYSONTOP, // 常に最前面表示を設定 299 | MESSAGE_CAPTUREIMAGE, // 画像をキャプチャする 300 | MESSAGE_SAVEIMAGE, // 画像を保存する 301 | MESSAGE_RESET, // リセットを行う 302 | MESSAGE_CLOSE, // ウィンドウを閉じる 303 | MESSAGE_SETSTREAMCALLBACK, // ストリームコールバックを設定 304 | MESSAGE_ENABLEPLUGIN, // プラグインの有効状態を設定 305 | MESSAGE_GETCOLOR, // 色の設定を取得 306 | MESSAGE_DECODEARIBSTRING, // ARIB文字列のデコード 307 | MESSAGE_GETCURRENTPROGRAMINFO, // 現在の番組の情報を取得 308 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,1) 309 | MESSAGE_QUERYEVENT, // イベントに対応しているか取得 310 | MESSAGE_GETTUNINGSPACE, // 現在のチューニング空間を取得 311 | MESSAGE_GETTUNINGSPACEINFO, // チューニング空間の情報を取得 312 | MESSAGE_SETNEXTCHANNEL, // チャンネルを次に設定する 313 | #endif 314 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,2) 315 | MESSAGE_GETAUDIOSTREAM, // 音声ストリームを取得 316 | MESSAGE_SETAUDIOSTREAM, // 音声ストリームを設定 317 | #endif 318 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,3) 319 | MESSAGE_ISPLUGINENABLED, // プラグインの有効状態を取得 320 | MESSAGE_REGISTERCOMMAND, // コマンドの登録 321 | MESSAGE_ADDLOG, // ログを記録 322 | #endif 323 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,5) 324 | MESSAGE_RESETSTATUS, // ステータスを初期化 325 | #endif 326 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,6) 327 | MESSAGE_SETAUDIOCALLBACK, // 音声のコールバック関数を設定 328 | #endif 329 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,7) 330 | MESSAGE_DOCOMMAND, // コマンドの実行 331 | #endif 332 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,8) 333 | MESSAGE_GETBCASINFO, // B-CAS カードの情報を取得 334 | MESSAGE_SENDBCASCOMMAND, // B-CAS カードにコマンドを送信 335 | MESSAGE_GETHOSTINFO, // ホストプログラムの情報を取得 336 | #endif 337 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,9) 338 | MESSAGE_GETSETTING, // 設定の取得 339 | MESSAGE_GETDRIVERFULLPATHNAME, // BonDriverのフルパスを取得 340 | #endif 341 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,10) 342 | MESSAGE_GETLOGO, // ロゴの取得 343 | MESSAGE_GETAVAILABLELOGOTYPE, // 利用可能なロゴの取得 344 | MESSAGE_RELAYRECORD, // 録画ファイルの切り替え 345 | MESSAGE_SILENTMODE, // サイレントモードの取得/設定 346 | #endif 347 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,11) 348 | MESSAGE_SETWINDOWMESSAGECALLBACK, // ウィンドウメッセージコールバックの設定 349 | MESSAGE_REGISTERCONTROLLER, // コントローラの登録 350 | MESSAGE_ONCONTROLLERBUTTONDOWN, // コントローラのボタンが押されたのを通知 351 | MESSAGE_GETCONTROLLERSETTINGS, // コントローラの設定を取得 352 | #endif 353 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,12) 354 | MESSAGE_GETEPGEVENTINFO, // 番組情報を取得 355 | MESSAGE_FREEEPGEVENTINFO, // 番組情報を解放 356 | MESSAGE_GETEPGEVENTLIST, // 番組のリストを取得 357 | MESSAGE_FREEEPGEVENTLIST, // 番組のリストを解放 358 | MESSAGE_ENUMDRIVER, // BonDriverの列挙 359 | MESSAGE_GETDRIVERTUNINGSPACELIST, // BonDriverのチューニング空間のリストの取得 360 | MESSAGE_FREEDRIVERTUNINGSPACELIST, // BonDriverのチューニング空間のリストの解放 361 | #endif 362 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,13) 363 | MESSAGE_ENABLEPROGRAMGUIDEEVENT, // 番組表のイベントの有効/無効を設定する 364 | MESSAGE_REGISTERPROGRAMGUIDECOMMAND, // 番組表のコマンドを登録 365 | #endif 366 | MESSAGE_TRAILER 367 | }; 368 | 369 | // イベント用コールバック関数 370 | typedef LRESULT (CALLBACK *EventCallbackFunc)(UINT Event,LPARAM lParam1,LPARAM lParam2,void *pClientData); 371 | 372 | // イベント 373 | // 各イベント発生時のパラメータは CTVTestEventHadler を参照してください。 374 | enum { 375 | EVENT_PLUGINENABLE, // 有効状態が変化した 376 | EVENT_PLUGINSETTINGS, // 設定を行う 377 | EVENT_CHANNELCHANGE, // チャンネルが変更された 378 | EVENT_SERVICECHANGE, // サービスが変更された 379 | EVENT_DRIVERCHANGE, // ドライバが変更された 380 | EVENT_SERVICEUPDATE, // サービスの構成が変化した 381 | EVENT_RECORDSTATUSCHANGE, // 録画状態が変化した 382 | EVENT_FULLSCREENCHANGE, // 全画面表示状態が変化した 383 | EVENT_PREVIEWCHANGE, // プレビュー表示状態が変化した 384 | EVENT_VOLUMECHANGE, // 音量が変化した 385 | EVENT_STEREOMODECHANGE, // ステレオモードが変化した 386 | EVENT_COLORCHANGE, // 色の設定が変化した 387 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,3) 388 | EVENT_STANDBY, // 待機状態が変化した 389 | EVENT_COMMAND, // コマンドが選択された 390 | #endif 391 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,4) 392 | EVENT_EXECUTE, // 複数起動禁止時に複数起動された 393 | #endif 394 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,5) 395 | EVENT_RESET, // リセットされた 396 | EVENT_STATUSRESET, // ステータスがリセットされた 397 | EVENT_AUDIOSTREAMCHANGE, // 音声ストリームが変更された 398 | #endif 399 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,9) 400 | EVENT_SETTINGSCHANGE, // 設定が変更された 401 | #endif 402 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,10) 403 | EVENT_CLOSE, // TVTestのウィンドウが閉じられる 404 | EVENT_STARTRECORD, // 録画が開始される 405 | EVENT_RELAYRECORD, // 録画ファイルが切り替えられた 406 | #endif 407 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,11) 408 | EVENT_CONTROLLERFOCUS, // コントローラの対象を設定 409 | #endif 410 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,13) 411 | EVENT_STARTUPDONE, // 起動時の処理が終わった 412 | // 番組表関係のイベントは、MESSAGE_ENABLEPROGRAMGUIDEEVENT を呼んで有効にしないと通知されません 413 | EVENT_PROGRAMGUIDE_INITIALIZE, // 番組表の初期化 414 | EVENT_PROGRAMGUIDE_FINALIZE, // 番組表の終了 415 | EVENT_PROGRAMGUIDE_COMMAND, // 番組表のコマンド実行 416 | EVENT_PROGRAMGUIDE_INITIALIZEMENU, // 番組表のメニューの設定 417 | EVENT_PROGRAMGUIDE_MENUSELECTED, // 番組表のメニューが選択された 418 | EVENT_PROGRAMGUIDE_PROGRAM_DRAWBACKGROUND, // 番組表の番組の背景を描画 419 | EVENT_PROGRAMGUIDE_PROGRAM_INITIALIZEMENU, // 番組表の番組のメニューの設定 420 | EVENT_PROGRAMGUIDE_PROGRAM_MENUSELECTED, // 番組表の番組のメニューが選択された 421 | #endif 422 | EVENT_TRAILER 423 | }; 424 | 425 | inline DWORD MakeVersion(BYTE Major,WORD Minor,WORD Build) { 426 | return ((DWORD)Major<<24) | ((DWORD)Minor<<12) | Build; 427 | } 428 | inline DWORD GetMajorVersion(DWORD Version) { return Version>>24; } 429 | inline DWORD GetMinorVersion(DWORD Version) { return (Version&0x00FFF000UL)>>12; } 430 | inline DWORD GetBuildVersion(DWORD Version) { return Version&0x00000FFFUL; } 431 | 432 | // プログラム(TVTest)のバージョンを取得する 433 | // 上位8ビットがメジャーバージョン、次の12ビットがマイナーバージョン、 434 | // 下位12ビットがビルドナンバー 435 | // GetMajorVersion/GetMinorVersion/GetBuildVersionを使って取得できる 436 | inline DWORD MsgGetVersion(PluginParam *pParam) { 437 | return (DWORD)(*pParam->Callback)(pParam,MESSAGE_GETVERSION,0,0); 438 | } 439 | 440 | // 指定されたメッセージに対応しているか問い合わせる 441 | inline bool MsgQueryMessage(PluginParam *pParam,UINT Message) { 442 | return (*pParam->Callback)(pParam,MESSAGE_QUERYMESSAGE,Message,0)!=0; 443 | } 444 | 445 | // メモリ再確保 446 | // 仕様はreallocと同じ 447 | inline void *MsgMemoryReAlloc(PluginParam *pParam,void *pData,DWORD Size) { 448 | return (void*)(*pParam->Callback)(pParam,MESSAGE_MEMORYALLOC,(LPARAM)pData,Size); 449 | } 450 | 451 | // メモリ確保 452 | // 仕様はrealloc(NULL,Size)と同じ 453 | inline void *MsgMemoryAlloc(PluginParam *pParam,DWORD Size) { 454 | return (void*)(*pParam->Callback)(pParam,MESSAGE_MEMORYALLOC,(LPARAM)(void*)NULL,Size); 455 | } 456 | 457 | // メモリ開放 458 | // 仕様はrealloc(pData,0)と同じ 459 | // (実際にreallocでメモリ開放しているコードは見たこと無いけど...) 460 | inline void MsgMemoryFree(PluginParam *pParam,void *pData) { 461 | (*pParam->Callback)(pParam,MESSAGE_MEMORYALLOC,(LPARAM)pData,0); 462 | } 463 | 464 | // イベントハンドル用コールバックの設定 465 | // pClientData はコールバックの呼び出し時に渡されます。 466 | // 一つのプラグインで設定できるコールバック関数は一つだけです。 467 | // Callback に NULL を渡すと設定が解除されます。 468 | inline bool MsgSetEventCallback(PluginParam *pParam,EventCallbackFunc Callback,void *pClientData=NULL) { 469 | return (*pParam->Callback)(pParam,MESSAGE_SETEVENTCALLBACK,(LPARAM)Callback,(LPARAM)pClientData)!=0; 470 | } 471 | 472 | // チャンネルの情報 473 | struct ChannelInfo { 474 | DWORD Size; // 構造体のサイズ 475 | int Space; // チューニング空間(BonDriverのインデックス) 476 | int Channel; // チャンネル(BonDriverのインデックス) 477 | int RemoteControlKeyID; // リモコンID 478 | WORD NetworkID; // ネットワークID 479 | WORD TransportStreamID; // トランスポートストリームID 480 | WCHAR szNetworkName[32]; // ネットワーク名 481 | WCHAR szTransportStreamName[32]; // トランスポートストリーム名 482 | WCHAR szChannelName[64]; // チャンネル名 483 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,1) 484 | int PhysicalChannel; // 物理チャンネル番号(あまり信用できない) 485 | // 不明の場合は0 486 | WORD ServiceIndex; // サービスのインデックス 487 | // (現在は意味を無くしているので使わない) 488 | WORD ServiceID; // サービスID 489 | // サービスはチャンネルファイルで設定されているものが取得される 490 | // サービスはユーザーが切り替えられるので、実際に視聴中のサービスがこれであるとは限らない 491 | // 実際に視聴中のサービスは MESSAGE_GETSERVICE で取得できる 492 | #endif 493 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,12) 494 | DWORD Flags; // 各種フラグ(CHANNEL_FLAG_*) 495 | #endif 496 | }; 497 | 498 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,12) 499 | // チャンネルの情報のフラグ 500 | enum { 501 | CHANNEL_FLAG_DISABLED =0x00000001UL // 無効にされている 502 | }; 503 | #endif 504 | 505 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,1) 506 | enum { 507 | CHANNELINFO_SIZE_V1=TVTEST_OFFSETOF(ChannelInfo,PhysicalChannel) 508 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,12) 509 | , CHANNELINFO_SIZE_V2=TVTEST_OFFSETOF(ChannelInfo,Flags) 510 | #endif 511 | }; 512 | #endif 513 | 514 | // 現在のチャンネルの情報を取得する 515 | // 事前に ChannelInfo の Size メンバを設定しておきます。 516 | inline bool MsgGetCurrentChannelInfo(PluginParam *pParam,ChannelInfo *pInfo) { 517 | return (*pParam->Callback)(pParam,MESSAGE_GETCURRENTCHANNELINFO,(LPARAM)pInfo,0)!=0; 518 | } 519 | 520 | // チャンネルを設定する 521 | #if TVTEST_PLUGIN_VERSIONCallback)(pParam,MESSAGE_SETCHANNEL,Space,Channel)!=0; 524 | } 525 | #else 526 | inline bool MsgSetChannel(PluginParam *pParam,int Space,int Channel,WORD ServiceID=0) { 527 | return (*pParam->Callback)(pParam,MESSAGE_SETCHANNEL,Space,MAKELPARAM((SHORT)Channel,ServiceID))!=0; 528 | } 529 | #endif 530 | 531 | // 現在のサービス及びサービス数を取得する 532 | // サービスのインデックスが返る。エラー時は-1が返ります。 533 | // pNumServices が NULL でない場合は、サービスの数が返されます。 534 | inline int MsgGetService(PluginParam *pParam,int *pNumServices=NULL) { 535 | return (int)(*pParam->Callback)(pParam,MESSAGE_GETSERVICE,(LPARAM)pNumServices,0); 536 | } 537 | 538 | // サービスを設定する 539 | // fByID=false の場合はインデックス、fByID=trueの場合はサービスID 540 | inline bool MsgSetService(PluginParam *pParam,int Service,bool fByID=false) { 541 | return (*pParam->Callback)(pParam,MESSAGE_SETSERVICE,Service,fByID)!=0; 542 | } 543 | 544 | // チューニング空間名を取得する 545 | // チューニング空間名の長さが返ります。Indexが範囲外の場合は0が返ります。 546 | // pszName を NULL で呼べば長さだけを取得できます。 547 | // MaxLength には pszName の先に格納できる最大の要素数(終端の空文字を含む)を指定します。 548 | inline int MsgGetTuningSpaceName(PluginParam *pParam,int Index,LPWSTR pszName,int MaxLength) { 549 | return (int)(*pParam->Callback)(pParam,MESSAGE_GETTUNINGSPACENAME,(LPARAM)pszName,MAKELPARAM(Index,min(MaxLength,0xFFFF))); 550 | } 551 | 552 | // チャンネルの情報を取得する 553 | // 事前に ChannelInfo の Size メンバを設定しておきます。 554 | // szNetworkName,szTransportStreamName は MESSAGE_GETCURRENTCHANNEL でしか取得できません。 555 | // NetworkID,TransportStreamID はチャンネルスキャンしていないと取得できません。 556 | // 取得できなかった場合は0になります。 557 | inline bool MsgGetChannelInfo(PluginParam *pParam,int Space,int Index,ChannelInfo *pInfo) { 558 | return (*pParam->Callback)(pParam,MESSAGE_GETCHANNELINFO,(LPARAM)pInfo,MAKELPARAM(Space,Index))!=0; 559 | } 560 | 561 | // サービスの情報 562 | struct ServiceInfo { 563 | DWORD Size; // 構造体のサイズ 564 | WORD ServiceID; // サービスID 565 | WORD VideoPID; // ビデオストリームのPID 566 | int NumAudioPIDs; // 音声PIDの数 567 | WORD AudioPID[4]; // 音声ストリームのPID 568 | WCHAR szServiceName[32]; // サービス名 569 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,2) 570 | BYTE AudioComponentType[4]; // 音声コンポーネントタイプ 571 | WORD SubtitlePID; // 字幕ストリームのPID(無い場合は0) 572 | WORD Reserved; // 予約 573 | #endif 574 | }; 575 | 576 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,2) 577 | enum { SERVICEINFO_SIZE_V1=TVTEST_OFFSETOF(ServiceInfo,AudioComponentType) }; 578 | #endif 579 | 580 | // サービスの情報を取得する 581 | // 現在のチャンネルのサービスの情報を取得します。 582 | // 事前に ServiceInfo の Size メンバを設定しておきます。 583 | inline bool MsgGetServiceInfo(PluginParam *pParam,int Index,ServiceInfo *pInfo) { 584 | return (*pParam->Callback)(pParam,MESSAGE_GETSERVICEINFO,Index,(LPARAM)pInfo)!=0; 585 | } 586 | 587 | // BonDriverのファイル名を取得する 588 | // 戻り値はファイル名の長さ(終端のNullを除く)が返ります。 589 | // pszName を NULL で呼べば長さだけを取得できます。 590 | // 取得されるのは、ディレクトリを含まないファイル名のみか、相対パスの場合もあります。 591 | // フルパスを取得したい場合は MsgGetDriverFullPathName を使用してください。 592 | inline int MsgGetDriverName(PluginParam *pParam,LPWSTR pszName,int MaxLength) { 593 | return (int)(*pParam->Callback)(pParam,MESSAGE_GETDRIVERNAME,(LPARAM)pszName,MaxLength); 594 | } 595 | 596 | // BonDriverを設定する 597 | // ファイル名のみか相対パスを指定すると、BonDriver 検索フォルダの設定が使用されます。 598 | inline bool MsgSetDriverName(PluginParam *pParam,LPCWSTR pszName) { 599 | return (*pParam->Callback)(pParam,MESSAGE_SETDRIVERNAME,(LPARAM)pszName,0)!=0; 600 | } 601 | 602 | // 録画情報のマスク 603 | enum { 604 | RECORD_MASK_FLAGS =0x00000001UL, // Flags が有効 605 | RECORD_MASK_FILENAME =0x00000002UL, // pszFileName が有効 606 | RECORD_MASK_STARTTIME =0x00000004UL, // StartTime が有効 607 | RECORD_MASK_STOPTIME =0x00000008UL // StopTime が有効 608 | }; 609 | 610 | // 録画フラグ 611 | enum { 612 | RECORD_FLAG_CANCEL =0x10000000UL // キャンセル 613 | }; 614 | 615 | // 録画開始時間の指定方法 616 | enum { 617 | RECORD_START_NOTSPECIFIED, // 未指定 618 | RECORD_START_TIME, // 時刻指定 619 | RECORD_START_DELAY // 長さ指定 620 | }; 621 | 622 | // 録画停止時間の指定方法 623 | enum { 624 | RECORD_STOP_NOTSPECIFIED, // 未指定 625 | RECORD_STOP_TIME, // 時刻指定 626 | RECORD_STOP_DURATION // 長さ指定 627 | }; 628 | 629 | // 録画情報 630 | struct RecordInfo { 631 | DWORD Size; // 構造体のサイズ 632 | DWORD Mask; // マスク(RECORD_MASK_???) 633 | DWORD Flags; // フラグ(RECORD_FLAG_???) 634 | LPWSTR pszFileName; // ファイル名(NULLでデフォルト) 635 | // %~% で囲まれた置換キーワードを使用できます 636 | int MaxFileName; // ファイル名の最大長(MESSAGE_GETRECORDのみで使用) 637 | FILETIME ReserveTime; // 録画予約された時刻(MESSAGE_GETRECORDのみで使用) 638 | DWORD StartTimeSpec; // 録画開始時間の指定方法(RECORD_START_???) 639 | union { 640 | FILETIME Time; // 録画開始時刻(StartTimeSpec==RECORD_START_TIME) 641 | // ローカル時刻 642 | ULONGLONG Delay; // 録画開始時間(StartTimeSpec==RECORD_START_DELAY) 643 | // 録画を開始するまでの時間(ms) 644 | } StartTime; 645 | DWORD StopTimeSpec; // 録画停止時間の指定方法(RECORD_STOP_???) 646 | union { 647 | FILETIME Time; // 録画停止時刻(StopTimeSpec==RECORD_STOP_TIME) 648 | // ローカル時刻 649 | ULONGLONG Duration; // 録画停止時間(StopTimeSpec==RECORD_STOP_DURATION) 650 | // 開始時間からのミリ秒 651 | } StopTime; 652 | }; 653 | 654 | // 録画を開始する 655 | // pInfo が NULL で即時録画開始します。 656 | inline bool MsgStartRecord(PluginParam *pParam,const RecordInfo *pInfo=NULL) { 657 | return (*pParam->Callback)(pParam,MESSAGE_STARTRECORD,(LPARAM)pInfo,0)!=0; 658 | } 659 | 660 | // 録画を停止する 661 | inline bool MsgStopRecord(PluginParam *pParam) { 662 | return (*pParam->Callback)(pParam,MESSAGE_STOPRECORD,0,0)!=0; 663 | } 664 | 665 | // 録画を一時停止/再開する 666 | inline bool MsgPauseRecord(PluginParam *pParam,bool fPause=true) { 667 | return (*pParam->Callback)(pParam,MESSAGE_PAUSERECORD,fPause,0)!=0; 668 | } 669 | 670 | // 録画設定を取得する 671 | // 事前に RecordInfo の Size メンバを設定しておきます。 672 | inline bool MsgGetRecord(PluginParam *pParam,RecordInfo *pInfo) { 673 | return (*pParam->Callback)(pParam,MESSAGE_GETRECORD,(LPARAM)pInfo,0)!=0; 674 | } 675 | 676 | // 録画設定を変更する 677 | // 既に録画中である場合は、ファイル名と開始時間の指定は無視されます。 678 | inline bool MsgModifyRecord(PluginParam *pParam,const RecordInfo *pInfo) { 679 | return (*pParam->Callback)(pParam,MESSAGE_MODIFYRECORD,(LPARAM)pInfo,0)!=0; 680 | } 681 | 682 | // 表示倍率を取得する(%単位) 683 | inline int MsgGetZoom(PluginParam *pParam) { 684 | return (int)(*pParam->Callback)(pParam,MESSAGE_GETZOOM,0,0); 685 | } 686 | 687 | // 表示倍率を設定する 688 | // %単位だけではなく、Num=1/Denom=3などとして割り切れない倍率を設定することもできます。 689 | inline bool MsgSetZoom(PluginParam *pParam,int Num,int Denom=100) { 690 | return (*pParam->Callback)(pParam,MESSAGE_SETZOOM,Num,Denom)!=0; 691 | } 692 | 693 | // パンスキャンの種類 694 | enum { 695 | PANSCAN_NONE, // なし 696 | PANSCAN_LETTERBOX, // レターボックス 697 | PANSCAN_SIDECUT, // サイドカット 698 | PANSCAN_SUPERFRAME // 超額縁 699 | }; 700 | 701 | // パンスキャンの情報 702 | struct PanScanInfo { 703 | DWORD Size; // 構造体のサイズ 704 | int Type; // 種類(PANSCAN_???) 705 | int XAspect; // 水平アスペクト比 706 | int YAspect; // 垂直アスペクト比 707 | }; 708 | 709 | // パンスキャンの設定を取得する 710 | inline bool MsgGetPanScan(PluginParam *pParam,PanScanInfo *pInfo) { 711 | return (*pParam->Callback)(pParam,MESSAGE_GETPANSCAN,(LPARAM)pInfo,0)!=0; 712 | } 713 | 714 | // パンスキャンを設定する 715 | inline bool MsgSetPanScan(PluginParam *pParam,const PanScanInfo *pInfo) { 716 | return (*pParam->Callback)(pParam,MESSAGE_SETPANSCAN,(LPARAM)pInfo,0)!=0; 717 | } 718 | 719 | // B-CAS カードの状態 720 | enum { 721 | BCAS_STATUS_OK, // エラーなし 722 | BCAS_STATUS_NOTOPEN, // 開かれていない(スクランブル解除なし) 723 | BCAS_STATUS_NOCARDREADER, // カードリーダが無い 724 | BCAS_STATUS_NOCARD, // カードがない 725 | BCAS_STATUS_OPENERROR, // オープンエラー 726 | BCAS_STATUS_TRANSMITERROR, // 通信エラー 727 | BCAS_STATUS_ESTABLISHERROR // コンテキスト確立失敗 728 | }; 729 | 730 | // ステータス情報 731 | struct StatusInfo { 732 | DWORD Size; // 構造体のサイズ 733 | float SignalLevel; // 信号レベル(dB) 734 | DWORD BitRate; // ビットレート(Bits/Sec) 735 | DWORD ErrorPacketCount; // エラーパケット数 736 | // DropPacketCount も含まれる 737 | DWORD ScramblePacketCount; // 復号漏れパケット数 738 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,2) 739 | DWORD DropPacketCount; // ドロップパケット数 740 | DWORD BcasCardStatus; // B-CAS カードの状態(BCAS_STATUS_???) 741 | #endif 742 | }; 743 | 744 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,2) 745 | enum { STATUSINFO_SIZE_V1=TVTEST_OFFSETOF(StatusInfo,DropPacketCount) }; 746 | #endif 747 | 748 | // ステータスを取得する 749 | // 事前にStatusInfoのSizeメンバを設定しておきます。 750 | inline bool MsgGetStatus(PluginParam *pParam,StatusInfo *pInfo) { 751 | return (*pParam->Callback)(pParam,MESSAGE_GETSTATUS,(LPARAM)pInfo,0)!=0; 752 | } 753 | 754 | // 録画の状態 755 | enum { 756 | RECORD_STATUS_NOTRECORDING, // 録画していない 757 | RECORD_STATUS_RECORDING, // 録画中 758 | RECORD_STATUS_PAUSED // 録画一時停止中 759 | }; 760 | 761 | // 録画ステータス情報 762 | struct RecordStatusInfo { 763 | DWORD Size; // 構造体のサイズ 764 | DWORD Status; // 状態(RECORD_STATUS_???) 765 | FILETIME StartTime; // 録画開始時刻(ローカル時刻) 766 | DWORD RecordTime; // 録画時間(ms) 一時停止中を含まない 767 | DWORD PauseTime; // 一時停止時間(ms) 768 | DWORD StopTimeSpec; // 録画停止時間の指定方法(RECORD_STOP_???) 769 | union { 770 | FILETIME Time; // 録画停止予定時刻(StopTimeSpec==RECORD_STOP_TIME) 771 | // (ローカル時刻) 772 | ULONGLONG Duration; // 録画停止までの時間(StopTimeSpec==RECORD_STOP_DURATION) 773 | // 開始時刻(StartTime)からミリ秒単位 774 | } StopTime; 775 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,10) 776 | LPWSTR pszFileName; // ファイルパス 777 | int MaxFileName; // ファイルパスの最大長 778 | RecordStatusInfo() : pszFileName(NULL), MaxFileName(0) {} 779 | #endif 780 | }; 781 | 782 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,10) 783 | enum { RECORDSTATUSINFO_SIZE_V1=TVTEST_OFFSETOF(RecordStatusInfo,pszFileName) }; 784 | #endif 785 | 786 | // 録画ステータスを取得する 787 | // 事前に RecordStatusInfo の Size メンバを設定しておきます。 788 | // ファイル名を取得する場合は pszFileName と MaxFileName メンバを設定しておきます。 789 | inline bool MsgGetRecordStatus(PluginParam *pParam,RecordStatusInfo *pInfo) { 790 | return (*pParam->Callback)(pParam,MESSAGE_GETRECORDSTATUS,(LPARAM)pInfo,0)!=0; 791 | } 792 | 793 | // 映像の情報 794 | struct VideoInfo { 795 | DWORD Size; // 構造体のサイズ 796 | int Width; // 幅(ピクセル単位) 797 | int Height; // 高さ(ピクセル単位) 798 | int XAspect; // 水平アスペクト比 799 | int YAspect; // 垂直アスペクト比 800 | RECT SourceRect; // ソースの表示範囲 801 | }; 802 | 803 | // 映像の情報を取得する 804 | // 事前にVideoInfoのSizeメンバを設定しておきます。 805 | inline bool MsgGetVideoInfo(PluginParam *pParam,VideoInfo *pInfo) { 806 | return (*pParam->Callback)(pParam,MESSAGE_GETVIDEOINFO,(LPARAM)pInfo,0)!=0; 807 | } 808 | 809 | // 音量を取得する(0-100) 810 | inline int MsgGetVolume(PluginParam *pParam) { 811 | return LOWORD((*pParam->Callback)(pParam,MESSAGE_GETVOLUME,0,0)); 812 | } 813 | 814 | // 音量を設定する(0-100) 815 | inline bool MsgSetVolume(PluginParam *pParam,int Volume) { 816 | return (*pParam->Callback)(pParam,MESSAGE_SETVOLUME,Volume,0)!=0; 817 | } 818 | 819 | // 消音状態であるか取得する 820 | inline bool MsgGetMute(PluginParam *pParam) { 821 | return HIWORD((*pParam->Callback)(pParam,MESSAGE_GETVOLUME,0,0))!=0; 822 | } 823 | 824 | // 消音状態を設定する 825 | inline bool MsgSetMute(PluginParam *pParam,bool fMute) { 826 | return (*pParam->Callback)(pParam,MESSAGE_SETVOLUME,-1,fMute)!=0; 827 | } 828 | 829 | // ステレオモード 830 | enum { 831 | STEREOMODE_STEREO, // ステレオ 832 | STEREOMODE_LEFT, // 左(主音声) 833 | STEREOMODE_RIGHT // 右(副音声) 834 | }; 835 | 836 | // ステレオモードを取得する 837 | inline int MsgGetStereoMode(PluginParam *pParam) { 838 | return (int)(*pParam->Callback)(pParam,MESSAGE_GETSTEREOMODE,0,0); 839 | } 840 | 841 | // ステレオモードを設定する 842 | inline bool MsgSetStereoMode(PluginParam *pParam,int StereoMode) { 843 | return (*pParam->Callback)(pParam,MESSAGE_SETSTEREOMODE,StereoMode,0)!=0; 844 | } 845 | 846 | // 全画面表示の状態を取得する 847 | inline bool MsgGetFullscreen(PluginParam *pParam) { 848 | return (*pParam->Callback)(pParam,MESSAGE_GETFULLSCREEN,0,0)!=0; 849 | } 850 | 851 | // 全画面表示の状態を設定する 852 | inline bool MsgSetFullscreen(PluginParam *pParam,bool fFullscreen) { 853 | return (*pParam->Callback)(pParam,MESSAGE_SETFULLSCREEN,fFullscreen,0)!=0; 854 | } 855 | 856 | // 再生が有効であるか取得する 857 | inline bool MsgGetPreview(PluginParam *pParam) { 858 | return (*pParam->Callback)(pParam,MESSAGE_GETPREVIEW,0,0)!=0; 859 | } 860 | 861 | // 再生の有効状態を設定する 862 | inline bool MsgSetPreview(PluginParam *pParam,bool fPreview) { 863 | return (*pParam->Callback)(pParam,MESSAGE_SETPREVIEW,fPreview,0)!=0; 864 | } 865 | 866 | // 待機状態であるか取得する 867 | inline bool MsgGetStandby(PluginParam *pParam) { 868 | return (*pParam->Callback)(pParam,MESSAGE_GETSTANDBY,0,0)!=0; 869 | } 870 | 871 | // 待機状態を設定する 872 | inline bool MsgSetStandby(PluginParam *pParam,bool fStandby) { 873 | return (*pParam->Callback)(pParam,MESSAGE_SETSTANDBY,fStandby,0)!=0; 874 | } 875 | 876 | // 常に最前面表示の状態を取得する 877 | inline bool MsgGetAlwaysOnTop(PluginParam *pParam) { 878 | return (*pParam->Callback)(pParam,MESSAGE_GETALWAYSONTOP,0,0)!=0; 879 | } 880 | 881 | // 常に最前面表示の状態を設定する 882 | inline bool MsgSetAlwaysOnTop(PluginParam *pParam,bool fAlwaysOnTop) { 883 | return (*pParam->Callback)(pParam,MESSAGE_SETALWAYSONTOP,fAlwaysOnTop,0)!=0; 884 | } 885 | 886 | // 画像をキャプチャする 887 | // 戻り値はパックDIBデータ(BITMAPINFOHEADER + ピクセルデータ)へのポインタです。 888 | // 不要になった場合はMsgMemoryFreeで開放します。 889 | // キャプチャできなかった場合はNULLが返ります。 890 | inline void *MsgCaptureImage(PluginParam *pParam,DWORD Flags=0) { 891 | return (void*)(*pParam->Callback)(pParam,MESSAGE_CAPTUREIMAGE,Flags,0); 892 | } 893 | 894 | // 画像を保存する 895 | inline bool MsgSaveImage(PluginParam *pParam) { 896 | return (*pParam->Callback)(pParam,MESSAGE_SAVEIMAGE,0,0)!=0; 897 | } 898 | 899 | // リセットを行う 900 | #if TVTEST_PLUGIN_VERSIONCallback)(pParam,MESSAGE_RESET,0,0)!=0; 903 | } 904 | #else 905 | // リセットのフラグ 906 | enum { 907 | RESET_ALL = 0x00000000UL, // 全て 908 | RESET_VIEWER = 0x00000001UL // ビューアのみ 909 | }; 910 | 911 | inline bool MsgReset(PluginParam *pParam,DWORD Flags=RESET_ALL) { 912 | return (*pParam->Callback)(pParam,MESSAGE_RESET,Flags,0)!=0; 913 | } 914 | #endif 915 | 916 | // ウィンドウクローズのフラグ 917 | enum { 918 | CLOSE_EXIT =0x00000001UL // 必ず終了させる 919 | }; 920 | 921 | // ウィンドウを閉じる 922 | inline bool MsgClose(PluginParam *pParam,DWORD Flags=0) { 923 | return (*pParam->Callback)(pParam,MESSAGE_CLOSE,Flags,0)!=0; 924 | } 925 | 926 | // ストリームコールバック関数 927 | // pData は 188 バイトの TS パケットが渡されます。 928 | // FALSE を返すとパケットが破棄されます。 929 | typedef BOOL (CALLBACK *StreamCallbackFunc)(BYTE *pData,void *pClientData); 930 | 931 | // ストリームコールバックフラグ 932 | enum { 933 | STREAM_CALLBACK_REMOVE =0x00000001UL // コールバックの削除 934 | }; 935 | 936 | // ストリームコールバックの情報 937 | struct StreamCallbackInfo { 938 | DWORD Size; // 構造体のサイズ 939 | DWORD Flags; // フラグ(STREAM_CALLBACK_???) 940 | StreamCallbackFunc Callback; // コールバック関数 941 | void *pClientData; // コールバック関数に渡されるデータ 942 | }; 943 | 944 | // ストリームコールバックを設定する 945 | // ストリームコールバックを登録すると、TS データを受け取ることができます。 946 | // コールバック関数は一つのプラグインで複数設定できます。 947 | // ストリームコールバック関数で処理が遅延すると全体が遅延するので、 948 | // 時間が掛かる処理は別スレッドで行うなどしてください。 949 | inline bool MsgSetStreamCallback(PluginParam *pParam,DWORD Flags, 950 | StreamCallbackFunc Callback,void *pClientData=NULL) { 951 | StreamCallbackInfo Info; 952 | Info.Size=sizeof(StreamCallbackInfo); 953 | Info.Flags=Flags; 954 | Info.Callback=Callback; 955 | Info.pClientData=pClientData; 956 | return (*pParam->Callback)(pParam,MESSAGE_SETSTREAMCALLBACK,(LPARAM)&Info,0)!=0; 957 | } 958 | 959 | // プラグインの有効状態を設定する 960 | inline bool MsgEnablePlugin(PluginParam *pParam,bool fEnable) { 961 | return (*pParam->Callback)(pParam,MESSAGE_ENABLEPLUGIN,fEnable,0)!=0; 962 | } 963 | 964 | // 色の設定を取得する 965 | // pszColor に取得したい色の名前を指定します。 966 | // 名前は配色設定ファイル(*.httheme)の項目名("StatusBack" など)と同じです。 967 | inline COLORREF MsgGetColor(PluginParam *pParam,LPCWSTR pszColor) { 968 | return (COLORREF)(*pParam->Callback)(pParam,MESSAGE_GETCOLOR,(LPARAM)pszColor,0); 969 | } 970 | 971 | // ARIB文字列のデコード情報 972 | struct ARIBStringDecodeInfo { 973 | DWORD Size; // 構造体のサイズ 974 | DWORD Flags; // フラグ(現在は常に0) 975 | const void *pSrcData; // 変換元データ 976 | DWORD SrcLength; // 変換元サイズ(バイト単位) 977 | LPWSTR pszDest; // 変換先バッファ 978 | DWORD DestLength; // 変換先バッファのサイズ(文字単位) 979 | }; 980 | 981 | // ARIB文字列をデコードする 982 | inline bool MsgDecodeARIBString(PluginParam *pParam,const void *pSrcData, 983 | DWORD SrcLength,LPWSTR pszDest,DWORD DestLength) { 984 | ARIBStringDecodeInfo Info; 985 | Info.Size=sizeof(ARIBStringDecodeInfo); 986 | Info.Flags=0; 987 | Info.pSrcData=pSrcData; 988 | Info.SrcLength=SrcLength; 989 | Info.pszDest=pszDest; 990 | Info.DestLength=DestLength; 991 | return (*pParam->Callback)(pParam,MESSAGE_DECODEARIBSTRING,(LPARAM)&Info,0)!=0; 992 | } 993 | 994 | // 番組の情報 995 | struct ProgramInfo { 996 | DWORD Size; // 構造体のサイズ 997 | WORD ServiceID; // サービスID 998 | WORD EventID; // イベントID 999 | LPWSTR pszEventName; // イベント名 1000 | int MaxEventName; // イベント名の最大長 1001 | LPWSTR pszEventText; // イベントテキスト 1002 | int MaxEventText; // イベントテキストの最大長 1003 | LPWSTR pszEventExtText; // 追加イベントテキスト 1004 | int MaxEventExtText; // 追加イベントテキストの最大長 1005 | SYSTEMTIME StartTime; // 開始日時(JST) 1006 | DWORD Duration; // 長さ(秒単位) 1007 | }; 1008 | 1009 | // 現在の番組の情報を取得する 1010 | // 事前に Size メンバに構造体のサイズを設定します。 1011 | // また、pszEventName / pszEventText / pszEventExtText メンバに取得先のバッファへのポインタを、 1012 | // MaxEventName / MaxEventText / MaxEventExtText メンバにバッファの長さ(要素数)を設定します。 1013 | // 必要のない情報は、ポインタを NULL にすると取得されません。 1014 | // MsgGetEpgEventInfo で、より詳しい番組情報を取得することもできます。 1015 | inline bool MsgGetCurrentProgramInfo(PluginParam *pParam,ProgramInfo *pInfo,bool fNext=false) { 1016 | return (*pParam->Callback)(pParam,MESSAGE_GETCURRENTPROGRAMINFO,(LPARAM)pInfo,fNext)!=0; 1017 | } 1018 | 1019 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,1) 1020 | 1021 | // 指定されたイベントの通知に対応しているか取得する 1022 | inline bool MsgQueryEvent(PluginParam *pParam,UINT Event) { 1023 | return (*pParam->Callback)(pParam,MESSAGE_QUERYEVENT,Event,0)!=0; 1024 | } 1025 | 1026 | // 現在のチューニング空間及びチューニング空間数を取得する 1027 | inline int MsgGetTuningSpace(PluginParam *pParam,int *pNumSpaces=NULL) { 1028 | return (int)(*pParam->Callback)(pParam,MESSAGE_GETTUNINGSPACE,(LPARAM)pNumSpaces,0); 1029 | } 1030 | 1031 | // チューニング空間の種類 1032 | enum { 1033 | TUNINGSPACE_UNKNOWN, // 不明 1034 | TUNINGSPACE_TERRESTRIAL, // 地上デジタル 1035 | TUNINGSPACE_BS, // BS 1036 | TUNINGSPACE_110CS // 110度CS 1037 | }; 1038 | 1039 | // チューニング空間の情報 1040 | struct TuningSpaceInfo { 1041 | DWORD Size; // 構造体のサイズ 1042 | int Space; // チューニング空間の種類(TUNINGSPACE_???) 1043 | // 場合によっては信用できない 1044 | WCHAR szName[64]; // チューニング空間名 1045 | }; 1046 | 1047 | // チューニング空間の情報を取得する 1048 | // 事前に TuningSpaceInfo の Size メンバを設定しておきます。 1049 | inline bool MsgGetTuningSpaceInfo(PluginParam *pParam,int Index,TuningSpaceInfo *pInfo) { 1050 | return (*pParam->Callback)(pParam,MESSAGE_GETTUNINGSPACEINFO,Index,(LPARAM)pInfo)!=0; 1051 | } 1052 | 1053 | // チャンネルを次に設定する 1054 | inline bool MsgSetNextChannel(PluginParam *pParam,bool fNext=true) 1055 | { 1056 | return (*pParam->Callback)(pParam,MESSAGE_SETNEXTCHANNEL,fNext,0)!=0; 1057 | } 1058 | 1059 | #endif // TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,1) 1060 | 1061 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,2) 1062 | 1063 | // 現在の音声ストリームを取得する 1064 | // 音声ストリームの数は MESSAGE_GETSERVICEINFO で取得できます。 1065 | inline int MsgGetAudioStream(PluginParam *pParam) 1066 | { 1067 | return (int)(*pParam->Callback)(pParam,MESSAGE_GETAUDIOSTREAM,0,0); 1068 | } 1069 | 1070 | // 音声ストリームを設定する 1071 | inline bool MsgSetAudioStream(PluginParam *pParam,int Index) 1072 | { 1073 | return (*pParam->Callback)(pParam,MESSAGE_SETAUDIOSTREAM,Index,0)!=0; 1074 | } 1075 | 1076 | #endif // TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,2) 1077 | 1078 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,3) 1079 | 1080 | // プラグインの有効状態を取得する 1081 | inline bool MsgIsPluginEnabled(PluginParam *pParam) 1082 | { 1083 | return (*pParam->Callback)(pParam,MESSAGE_ISPLUGINENABLED,0,0)!=0; 1084 | } 1085 | 1086 | // コマンドの情報 1087 | struct CommandInfo { 1088 | int ID; // 識別子 1089 | LPCWSTR pszText; // コマンドの文字列 1090 | LPCWSTR pszName; // コマンドの名前 1091 | }; 1092 | 1093 | // コマンドを登録する 1094 | // TVTInitialize 内で呼びます。 1095 | // コマンドを登録すると、ショートカットキーやリモコンに機能を割り当てられるようになります。 1096 | // 以下のように使用します。 1097 | // MsgRegisterCommand(pParam, ID_MYCOMMAND, L"MyCommand", L"私のコマンド"); 1098 | // コマンドが実行されると EVENT_COMMAND イベントが送られます。 1099 | // その際、パラメータとして識別子が渡されます。 1100 | inline bool MsgRegisterCommand(PluginParam *pParam,int ID,LPCWSTR pszText,LPCWSTR pszName) 1101 | { 1102 | CommandInfo Info; 1103 | Info.ID=ID; 1104 | Info.pszText=pszText; 1105 | Info.pszName=pszName; 1106 | return (*pParam->Callback)(pParam,MESSAGE_REGISTERCOMMAND,(LPARAM)&Info,1)!=0; 1107 | } 1108 | 1109 | // コマンドを登録する 1110 | // TVTInitialize 内で呼びます。 1111 | inline bool MsgRegisterCommand(PluginParam *pParam,const CommandInfo *pCommandList,int NumCommands) 1112 | { 1113 | return (*pParam->Callback)(pParam,MESSAGE_REGISTERCOMMAND,(LPARAM)pCommandList,NumCommands)!=0; 1114 | } 1115 | 1116 | // ログを記録する 1117 | // 設定のログの項目に表示されます。 1118 | inline bool MsgAddLog(PluginParam *pParam,LPCWSTR pszText) 1119 | { 1120 | return (*pParam->Callback)(pParam,MESSAGE_ADDLOG,(LPARAM)pszText,0)!=0; 1121 | } 1122 | 1123 | #endif // TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,3) 1124 | 1125 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,5) 1126 | 1127 | // ステータス(MESSAGE_GETSTATUS で取得できる内容)をリセットする 1128 | // リセットが行われると EVENT_STATUSRESET が送られます。 1129 | inline bool MsgResetStatus(PluginParam *pParam) 1130 | { 1131 | return (*pParam->Callback)(pParam,MESSAGE_RESETSTATUS,0,0)!=0; 1132 | } 1133 | 1134 | #endif // TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,5) 1135 | 1136 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,6) 1137 | 1138 | // 音声サンプルのコールバック関数 1139 | // 渡されるサンプルは 48kHz / 16ビット固定です。 1140 | // pData の先には Samples * Channels 分のデータが入っています。 1141 | // 今のところ、5.1chをダウンミックスする設定になっている場合 1142 | // ダウンミックスされたデータが渡されますが、そのうち仕様を変えるかも知れません。 1143 | // 戻り値は今のところ常に0を返します。 1144 | typedef LRESULT (CALLBACK *AudioCallbackFunc)(short *pData,DWORD Samples,int Channels,void *pClientData); 1145 | 1146 | // 音声のサンプルを取得するコールバック関数を設定する 1147 | // 一つのプラグインで設定できるコールバック関数は一つだけです。 1148 | // pClinetData はコールバック関数に渡されます。 1149 | // pCallback に NULL を指定すると、設定が解除されます。 1150 | inline bool MsgSetAudioCallback(PluginParam *pParam,AudioCallbackFunc pCallback,void *pClientData=NULL) 1151 | { 1152 | return (*pParam->Callback)(pParam,MESSAGE_SETAUDIOCALLBACK,(LPARAM)pCallback,(LPARAM)pClientData)!=0; 1153 | } 1154 | 1155 | #endif // TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,6) 1156 | 1157 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,7) 1158 | 1159 | // コマンドを実行する 1160 | // 文字列を指定してコマンドを実行します。 1161 | // コマンドは TVTest.ini の [Accelerator] セクションの Accel*_Command の文字列と同じです。 1162 | // 一覧は TVTest のソースの Command.cpp にあります。 1163 | inline bool MsgDoCommand(PluginParam *pParam,LPCWSTR pszCommand) 1164 | { 1165 | return (*pParam->Callback)(pParam,MESSAGE_DOCOMMAND,(LPARAM)pszCommand,0)!=0; 1166 | } 1167 | 1168 | #endif // TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,7) 1169 | 1170 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,8) 1171 | 1172 | // B-CAS の情報 1173 | struct BCasInfo { 1174 | DWORD Size; // 構造体のサイズ 1175 | WORD CASystemID; // CA_system_id 1176 | BYTE CardID[6]; // カードID 1177 | BYTE CardType; // カード種別 1178 | BYTE MessagePartitionLength; // メッセージ分割長 1179 | BYTE SystemKey[32]; // システム鍵 1180 | BYTE InitialCBC[8]; // CBC初期値 1181 | BYTE CardManufacturerID; // メーカ識別 1182 | BYTE CardVersion; // バージョン 1183 | WORD CheckCode; // チェックコード 1184 | char szFormatCardID[25]; // 可読形式のカードID (4桁の数字x5) 1185 | }; 1186 | 1187 | // B-CAS カードの情報を取得する 1188 | // カードが開かれていない場合は false が返ります。 1189 | inline bool MsgGetBCasInfo(PluginParam *pParam,BCasInfo *pInfo) 1190 | { 1191 | return (*pParam->Callback)(pParam,MESSAGE_GETBCASINFO,(LPARAM)pInfo,0)!=0; 1192 | } 1193 | 1194 | // B-CAS コマンドの情報 1195 | struct BCasCommandInfo { 1196 | const BYTE *pSendData; // 送信データ 1197 | DWORD SendSize; // 送信サイズ (バイト単位) 1198 | BYTE *pReceiveData; // 受信データ 1199 | DWORD ReceiveSize; // 受信サイズ (バイト単位) 1200 | }; 1201 | 1202 | // B-CAS カードにコマンドを送信する 1203 | // BCasCommandInfo の pSendData に送信データへのポインタを指定して、 1204 | // SendSize に送信データのバイト数を設定します。 1205 | // また、pReceiveData に受信データを格納するバッファへのポインタを指定して、 1206 | // ReceiveSize にバッファに格納できる最大サイズを設定します。 1207 | // 送信が成功すると、ReceiveSize に受信したデータのサイズが返されます。 1208 | inline bool MsgSendBCasCommand(PluginParam *pParam,BCasCommandInfo *pInfo) 1209 | { 1210 | return (*pParam->Callback)(pParam,MESSAGE_SENDBCASCOMMAND,(LPARAM)pInfo,0)!=0; 1211 | } 1212 | 1213 | // B-CAS カードにコマンドを送信する 1214 | inline bool MsgSendBCasCommand(PluginParam *pParam,const BYTE *pSendData,DWORD SendSize,BYTE *pReceiveData,DWORD *pReceiveSize) 1215 | { 1216 | BCasCommandInfo Info; 1217 | Info.pSendData=pSendData; 1218 | Info.SendSize=SendSize; 1219 | Info.pReceiveData=pReceiveData; 1220 | Info.ReceiveSize=*pReceiveSize; 1221 | if (!MsgSendBCasCommand(pParam,&Info)) 1222 | return false; 1223 | *pReceiveSize=Info.ReceiveSize; 1224 | return true; 1225 | } 1226 | 1227 | // ホストプログラムの情報 1228 | struct HostInfo { 1229 | DWORD Size; // 構造体のサイズ 1230 | LPCWSTR pszAppName; // プログラム名 ("TVTest"、"TVH264" など) 1231 | struct { 1232 | int Major; // メジャーバージョン 1233 | int Minor; // マイナーバージョン 1234 | int Build; // ビルドナンバー 1235 | } Version; 1236 | LPCWSTR pszVersionText; // バージョン文字列 ("1.2.0" など) 1237 | DWORD SupportedPluginVersion; // 対応しているプラグインのバージョン 1238 | // TVTEST_PLUGIN_VERSION_(?,?,?) 1239 | }; 1240 | 1241 | // ホストプログラムの情報を取得する 1242 | // 事前に HostInfo の Size メンバに構造体のサイズを設定して呼び出します。 1243 | inline bool MsgGetHostInfo(PluginParam *pParam,HostInfo *pInfo) 1244 | { 1245 | return (*pParam->Callback)(pParam,MESSAGE_GETHOSTINFO,(LPARAM)pInfo,0)!=0; 1246 | } 1247 | 1248 | #endif // TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,8) 1249 | 1250 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,9) 1251 | 1252 | // 設定の情報 1253 | struct SettingInfo { 1254 | LPCWSTR pszName; // 設定名 1255 | DWORD Type; // 値の型 (SETTING_TYPE_???) 1256 | union { 1257 | int Int; // int 1258 | unsigned int UInt; // unsigned int 1259 | LPWSTR pszString; // 文字列 1260 | void *pData; // データ 1261 | } Value; 1262 | DWORD ValueSize; // 値のサイズ (バイト単位) 1263 | }; 1264 | 1265 | // 設定の値の型 1266 | enum SettingType { 1267 | SETTING_TYPE_UNDEFINED, // 未定義 1268 | SETTING_TYPE_INT, // int 1269 | SETTING_TYPE_UINT, // unsigned int 1270 | SETTING_TYPE_STRING, // 文字列 1271 | SETTING_TYPE_DATA // データ 1272 | }; 1273 | 1274 | /* 1275 | 今のところ以下の設定が取得できます。 1276 | 設定名の大文字と小文字は区別されません。 1277 | 1278 | 設定名 内容 型 1279 | DriverDirectory BonDriver の検索ディレクトリ 文字列 1280 | IniFilePath Ini ファイルのパス 文字列 1281 | RecordFolder 録画時の保存先フォルダ 文字列 1282 | */ 1283 | 1284 | // 設定を取得する 1285 | // 呼び出す前に SettingInfo のメンバを設定しておきます。 1286 | // 文字列とデータの場合、ValueSize に設定の格納に必要なバイト数が返されます。 1287 | // 通常は下にある型ごとにオーバーロードされた関数を使用した方が便利です。 1288 | inline bool MsgGetSetting(PluginParam *pParam,SettingInfo *pInfo) 1289 | { 1290 | return (*pParam->Callback)(pParam,MESSAGE_GETSETTING,(LPARAM)pInfo,0)!=0; 1291 | } 1292 | 1293 | // intの設定を取得する 1294 | inline bool MsgGetSetting(PluginParam *pParam,LPCWSTR pszName,int *pValue) 1295 | { 1296 | SettingInfo Info; 1297 | Info.pszName=pszName; 1298 | Info.Type=SETTING_TYPE_INT; 1299 | Info.ValueSize=sizeof(int); 1300 | if (!(*pParam->Callback)(pParam,MESSAGE_GETSETTING,(LPARAM)&Info,0)) 1301 | return false; 1302 | *pValue=Info.Value.Int; 1303 | return true; 1304 | } 1305 | 1306 | // unsigned intの設定を取得する 1307 | inline bool MsgGetSetting(PluginParam *pParam,LPCWSTR pszName,unsigned int *pValue) 1308 | { 1309 | SettingInfo Info; 1310 | Info.pszName=pszName; 1311 | Info.Type=SETTING_TYPE_UINT; 1312 | Info.ValueSize=sizeof(unsigned int); 1313 | if (!(*pParam->Callback)(pParam,MESSAGE_GETSETTING,(LPARAM)&Info,0)) 1314 | return false; 1315 | *pValue=Info.Value.UInt; 1316 | return true; 1317 | } 1318 | 1319 | // 文字列の設定を取得する 1320 | // 戻り値は取得した文字列の長さ(終端のNullを含む)です。 1321 | // pszString を NULL にすると、必要なバッファの長さ(終端のNullを含む)が返ります。 1322 | // 設定が取得できなかった場合は 0 が返ります。 1323 | /* 1324 | // 例 1325 | WCHAR szIniPath[MAX_PATH]; 1326 | if (MsgGetSetting(pParam, L"IniFilePath", szIniPath, MAX_PATH) > 0) { 1327 | // 呼び出しが成功した場合は、szIniPath に Ini ファイルのパスが格納されています 1328 | } 1329 | */ 1330 | inline DWORD MsgGetSetting(PluginParam *pParam,LPCWSTR pszName,LPWSTR pszString,DWORD MaxLength) 1331 | { 1332 | SettingInfo Info; 1333 | Info.pszName=pszName; 1334 | Info.Type=SETTING_TYPE_STRING; 1335 | Info.Value.pszString=pszString; 1336 | Info.ValueSize=MaxLength*sizeof(WCHAR); 1337 | if (!(*pParam->Callback)(pParam,MESSAGE_GETSETTING,(LPARAM)&Info,0)) 1338 | return 0; 1339 | return Info.ValueSize/sizeof(WCHAR); 1340 | } 1341 | 1342 | // BonDriverのフルパス名を取得する 1343 | // 戻り値はパスの長さ(終端のNullを除く)が返ります。 1344 | // pszPahtをNULLで呼べば長さだけを取得できます。 1345 | inline int MsgGetDriverFullPathName(PluginParam *pParam,LPWSTR pszPath,int MaxLength) 1346 | { 1347 | return (int)(*pParam->Callback)(pParam,MESSAGE_GETDRIVERFULLPATHNAME,(LPARAM)pszPath,MaxLength); 1348 | } 1349 | 1350 | #endif // TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,9) 1351 | 1352 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,10) 1353 | 1354 | // ロゴの画像を取得する 1355 | // LogoTypeは0から5までで指定します。以下のサイズのロゴが取得されます。 1356 | // 0 = 48x24 / 1 = 36x24 / 2 = 48x27 / 3 = 72x36 / 4 = 54x36 / 5 = 64x36 1357 | // いずれのロゴも16:9で表示すると本来の比率になります。 1358 | // 画像が取得できた場合はビットマップ(DIBセクション)のハンドルが返ります。 1359 | // 画像が取得できない場合はNULLが返ります。 1360 | // ビットマップは不要になった時にDeleteObject()で破棄してください。 1361 | inline HBITMAP MsgGetLogo(PluginParam *pParam,WORD NetworkID,WORD ServiceID,BYTE LogoType) 1362 | { 1363 | return (HBITMAP)(*pParam->Callback)(pParam,MESSAGE_GETLOGO,MAKELONG(NetworkID,ServiceID),LogoType); 1364 | } 1365 | 1366 | // 利用可能なロゴの種類を取得する 1367 | // 利用可能なロゴを表すフラグが返ります。 1368 | // 下位から1ビットごとにLogoTypeの0から5までを表し、ビットが1であればその種類のロゴが利用できます。 1369 | /* 1370 | // 例 1371 | if (MsgGetAvailableLogoType(pParam, NetworkID, ServiceID) & 1) { 1372 | // タイプ0のロゴが利用できる 1373 | } 1374 | */ 1375 | inline UINT MsgGetAvailableLogoType(PluginParam *pParam,WORD NetworkID,WORD ServiceID) 1376 | { 1377 | return (UINT)(*pParam->Callback)(pParam,MESSAGE_GETAVAILABLELOGOTYPE,MAKELONG(NetworkID,ServiceID),0); 1378 | } 1379 | 1380 | // 録画ファイルを切り替える 1381 | // 現在録画中のファイルを閉じて、指定されたパスにファイルを作成して続きを録画するようにします。 1382 | // 新しいファイルが開けなかった場合は、今までのファイルで録画が継続されます。 1383 | inline bool MsgRelayRecord(PluginParam *pParam,LPCWSTR pszFileName) 1384 | { 1385 | return (*pParam->Callback)(pParam,MESSAGE_RELAYRECORD,(LPARAM)pszFileName,0)!=0; 1386 | } 1387 | 1388 | // サイレントモードのパラメータ 1389 | enum { 1390 | SILENTMODE_GET, // 取得 1391 | SILENTMODE_SET // 設定 1392 | }; 1393 | 1394 | // サイレントモードの取得 1395 | // サイレントモードであるか取得します。 1396 | // サイレントモードではエラー時などにダイアログが出なくなります。 1397 | // コマンドラインで /silent を指定するか、MsgSetSilentMode で設定すればサイレントモードになります。 1398 | inline bool MsgGetSilentMode(PluginParam *pParam) 1399 | { 1400 | return (*pParam->Callback)(pParam,MESSAGE_SILENTMODE,SILENTMODE_GET,0)!=0; 1401 | } 1402 | 1403 | // サイレントモードの設定 1404 | // サイレントモードの有効/無効を設定します。 1405 | inline bool MsgSetSilentMode(PluginParam *pParam,bool fSilent) 1406 | { 1407 | return (*pParam->Callback)(pParam,MESSAGE_SILENTMODE,SILENTMODE_SET,(LPARAM)fSilent)!=0; 1408 | } 1409 | 1410 | // 録画のクライアント 1411 | enum { 1412 | RECORD_CLIENT_USER, // ユーザーの操作 1413 | RECORD_CLIENT_COMMANDLINE, // コマンドラインでの指定 1414 | RECORD_CLIENT_PLUGIN // プラグインからの指定 1415 | }; 1416 | 1417 | // 録画開始情報で変更した項目 1418 | enum { 1419 | STARTRECORD_MODIFIED_FILENAME =0x00000001UL // ファイル名 1420 | }; 1421 | 1422 | // 録画開始情報 1423 | struct StartRecordInfo { 1424 | DWORD Size; // 構造体のサイズ 1425 | DWORD Flags; // フラグ(現在未使用) 1426 | DWORD Modified; // 変更した項目(STARTRECORD_MODIFIED_???) 1427 | DWORD Client; // 録画のクライアント(RECORD_CLIENT_???) 1428 | LPWSTR pszFileName; // ファイル名 1429 | int MaxFileName; // ファイル名の最大長 1430 | DWORD StartTimeSpec; // 開始時間の指定方法(RECORD_START_???) 1431 | FILETIME StartTime; // 指定された開始時刻(ローカル時刻) 1432 | // StartTimeSpec!=RECORD_START_NOTSPECIFIED の場合のみ有効 1433 | DWORD StopTimeSpec; // 停止時間の指定方法(RECORD_STOP_???) 1434 | union { 1435 | FILETIME Time; // 停止時刻(StopTimeSpec==RECORD_STOP_TIME) 1436 | // ローカル時刻 1437 | ULONGLONG Duration; // 録画停止までの時間(StopTimeSpec==RECORD_STOP_DURATION) 1438 | // 開始時刻からのミリ秒 1439 | } StopTime; 1440 | }; 1441 | 1442 | #endif // TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,10) 1443 | 1444 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,11) 1445 | 1446 | /* 1447 | メッセージコールバック関数を登録すると、TVTest のメインウィンドウにメッセージが 1448 | 送られた時に呼び出されます。 1449 | コールバック関数では、TVTest にメッセージの処理をさせない時は TRUE を返します。 1450 | その際、pResult に書き込んだ値が返されます。 1451 | */ 1452 | 1453 | // ウィンドウメッセージコールバック関数 1454 | typedef BOOL (CALLBACK *WindowMessageCallbackFunc)(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam,LRESULT *pResult,void *pUserData); 1455 | 1456 | // ウィンドウメッセージコールバックの設定 1457 | // pClientData はコールバックの呼び出し時に渡されます。 1458 | // 一つのプラグインで設定できるコールバック関数は一つだけです。 1459 | // Callback に NULL を渡すと設定が解除されます。 1460 | inline bool MsgSetWindowMessageCallback(PluginParam *pParam,WindowMessageCallbackFunc Callback,void *pClientData=NULL) { 1461 | return (*pParam->Callback)(pParam,MESSAGE_SETWINDOWMESSAGECALLBACK,(LPARAM)Callback,(LPARAM)pClientData)!=0; 1462 | } 1463 | 1464 | /* 1465 | コントローラの登録を行うと、設定ダイアログのリモコンのページで割り当てが設定できるようになります。 1466 | コントローラの画像を用意すると、設定の右側に表示されます。 1467 | ボタンが押された時に MsgOnControllerButtonDown を呼び出して通知すると、 1468 | 割り当ての設定に従って機能が実行されます。 1469 | */ 1470 | 1471 | // コントローラのボタンの情報 1472 | struct ControllerButtonInfo { 1473 | LPCWSTR pszName; // ボタンの名称("音声切替" など) 1474 | LPCWSTR pszDefaultCommand; // デフォルトのコマンド(MsgDoCommand と同じもの) 1475 | // 指定しない場合はNULL 1476 | struct { 1477 | WORD Left,Top,Width,Height; // 画像のボタンの位置(画像が無い場合は無視される) 1478 | } ButtonRect; 1479 | struct { 1480 | WORD Left,Top; // 画像の選択ボタンの位置(画像が無い場合は無視される) 1481 | } SelButtonPos; 1482 | DWORD Reserved; // 予約領域(0にしてください) 1483 | }; 1484 | 1485 | // コントローラの情報 1486 | struct ControllerInfo { 1487 | DWORD Size; // 構造体のサイズ 1488 | DWORD Flags; // 各種フラグ(CONTROLLER_FLAG_???) 1489 | LPCWSTR pszName; // コントローラ識別名 1490 | LPCWSTR pszText; // コントローラの名称("HDUSリモコン" など) 1491 | int NumButtons; // ボタンの数 1492 | const ControllerButtonInfo *pButtonList; // ボタンのリスト 1493 | LPCWSTR pszIniFileName; // 設定ファイル名(NULL にすると TVTest の Ini ファイル) 1494 | LPCWSTR pszSectionName; // 設定のセクション名 1495 | UINT ControllerImageID; // コントローラの画像の識別子(無い場合は0) 1496 | UINT SelButtonsImageID; // 選択ボタン画像の識別子(無い場合は0) 1497 | typedef BOOL (CALLBACK *TranslateMessageCallback)(HWND hwnd,MSG *pMessage,void *pClientData); 1498 | TranslateMessageCallback pTranslateMessage; // メッセージの変換コールバック(必要無ければ NULL) 1499 | void *pClientData; // コールバックに渡すパラメータ 1500 | }; 1501 | 1502 | // コントローラのフラグ 1503 | enum { 1504 | CONTROLLER_FLAG_ACTIVEONLY =0x00000001UL // アクティブ時のみ使用できる 1505 | }; 1506 | 1507 | // コントローラを登録する 1508 | inline bool MsgRegisterController(PluginParam *pParam,const ControllerInfo *pInfo) 1509 | { 1510 | return (*pParam->Callback)(pParam,MESSAGE_REGISTERCONTROLLER,(LPARAM)pInfo,0)!=0; 1511 | } 1512 | 1513 | // コントローラのボタンが押されたことを通知する 1514 | inline bool MsgOnControllerButtonDown(PluginParam *pParam,LPCWSTR pszName,int Button) 1515 | { 1516 | return (*pParam->Callback)(pParam,MESSAGE_ONCONTROLLERBUTTONDOWN,(LPARAM)pszName,Button)!=0; 1517 | } 1518 | 1519 | // コントローラの設定 1520 | struct ControllerSettings { 1521 | DWORD Mask; // 取得する項目(CONTROLLER_SETTINGS_MASK_*) 1522 | DWORD Flags; // 各種フラグ(CONTROLLER_SETTINGS_FLAG_*) 1523 | }; 1524 | 1525 | // コントローラの設定マスク 1526 | enum { 1527 | CONTROLLER_SETTINGS_MASK_FLAGS =0x00000001UL // Flags が有効 1528 | }; 1529 | 1530 | // コントローラの設定フラグ 1531 | enum { 1532 | CONTROLLER_SETTINGS_FLAG_ACTIVEONLY =0x00000001UL // アクティブ時のみ 1533 | }; 1534 | 1535 | // コントローラの設定を取得する 1536 | inline bool MsgGetControllerSettings(PluginParam *pParam,LPCWSTR pszName,ControllerSettings *pSettings) 1537 | { 1538 | return (*pParam->Callback)(pParam,MESSAGE_GETCONTROLLERSETTINGS,(LPARAM)pszName,(LPARAM)pSettings)!=0; 1539 | } 1540 | 1541 | // コントローラがアクティブ時のみに設定されているか取得する 1542 | inline bool MsgIsControllerActiveOnly(PluginParam *pParam,LPCWSTR pszName) 1543 | { 1544 | ControllerSettings Settings; 1545 | Settings.Mask=CONTROLLER_SETTINGS_MASK_FLAGS; 1546 | if (!MsgGetControllerSettings(pParam,pszName,&Settings)) 1547 | return false; 1548 | return (Settings.Flags&CONTROLLER_SETTINGS_FLAG_ACTIVEONLY)!=0; 1549 | } 1550 | 1551 | #endif // TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,11) 1552 | 1553 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,12) 1554 | 1555 | // イベントの取得方法 1556 | enum { 1557 | EPG_EVENT_QUERY_EVENTID, // イベントID 1558 | EPG_EVENT_QUERY_TIME // 日時 1559 | }; 1560 | 1561 | // イベントの取得のための情報 1562 | struct EpgEventQueryInfo { 1563 | WORD NetworkID; // ネットワークID 1564 | WORD TransportStreamID; // ストリームID 1565 | WORD ServiceID; // サービスID 1566 | BYTE Type; // 取得方法(EPG_EVENT_QUERY_*) 1567 | BYTE Flags; // フラグ(現在は常に0) 1568 | union { 1569 | WORD EventID; // イベントID 1570 | FILETIME Time; // 日時(UTC) 1571 | }; 1572 | }; 1573 | 1574 | // 映像の情報 1575 | struct EpgEventVideoInfo { 1576 | BYTE StreamContent; // stream_content 1577 | BYTE ComponentType; // component_type 1578 | // (0x01 = 480i[4:3] / 0x03 = 480i[16:9] / 0xB1 = 1080i[4:3] / 0xB3 = 1080i[16:9]) 1579 | BYTE ComponentTag; // component_tag 1580 | BYTE Reserved; // 予約 1581 | DWORD LanguageCode; // 言語コード 1582 | LPCWSTR pszText; // テキスト(無い場合はNULL) 1583 | }; 1584 | 1585 | // 音声の情報 1586 | struct EpgEventAudioInfo { 1587 | BYTE Flags; // フラグ(EPG_EVENT_AUDIO_FLAG_*) 1588 | BYTE StreamContent; // stream_content 1589 | BYTE ComponentType; // component_type (1 = Mono / 2 = Dual Mono / 3 = Stereo / 9 = 5.1ch) 1590 | BYTE ComponentTag; // component_tag 1591 | BYTE SimulcastGroupTag; // simulcast_group_tag 1592 | BYTE QualityIndicator; // quality_indicator 1593 | BYTE SamplingRate; // サンプリング周波数の種類 1594 | BYTE Reserved; // 予約 1595 | DWORD LanguageCode; // 言語コード(主音声) 1596 | DWORD LanguageCode2; // 言語コード(副音声) 1597 | LPCWSTR pszText; // テキスト(無い場合はNULL) 1598 | }; 1599 | 1600 | // 音声のフラグ 1601 | enum { 1602 | EPG_EVENT_AUDIO_FLAG_MULTILINGUAL =0x01, // 二ヶ国語 1603 | EPG_EVENT_AUDIO_FLAG_MAINCOMPONENT =0x02 // 主音声 1604 | }; 1605 | 1606 | // ジャンルの情報 1607 | // (意味は STD-B10 第2部 付録H 等参照) 1608 | struct EpgEventContentInfo { 1609 | BYTE ContentNibbleLevel1; // 大分類 1610 | BYTE ContentNibbleLevel2; // 中分類 1611 | BYTE UserNibble1; 1612 | BYTE UserNibble2; 1613 | }; 1614 | 1615 | // イベントグループのイベントの情報 1616 | struct EpgGroupEventInfo { 1617 | WORD NetworkID; // ネットワークID 1618 | WORD TransportStreamID; // ストリームID 1619 | WORD ServiceID; // サービスID 1620 | WORD EventID; // イベントID 1621 | }; 1622 | 1623 | // イベントグループの情報 1624 | struct EpgEventGroupInfo { 1625 | BYTE GroupType; // 種類 1626 | BYTE EventListLength; // イベントのリストの要素数 1627 | BYTE Reserved[6]; // 予約 1628 | EpgGroupEventInfo *EventList; // イベントのリスト 1629 | }; 1630 | 1631 | // イベントの情報 1632 | struct EpgEventInfo { 1633 | WORD EventID; // イベントID 1634 | BYTE RunningStatus; // running_status 1635 | BYTE FreeCaMode; // free_CA_mode 1636 | DWORD Reserved; // 予約 1637 | SYSTEMTIME StartTime; // 開始日時(ローカル時刻) 1638 | DWORD Duration; // 長さ(秒単位) 1639 | BYTE VideoListLength; // 映像の情報の数 1640 | BYTE AudioListLength; // 音声の情報の数 1641 | BYTE ContentListLength; // ジャンルの情報の数 1642 | BYTE EventGroupListLength; // イベントグループの情報の数 1643 | LPCWSTR pszEventName; // イベント名(無い場合はNULL) 1644 | LPCWSTR pszEventText; // テキスト(無い場合はNULL) 1645 | LPCWSTR pszEventExtendedText; // 拡張テキスト(無い場合はNULL) 1646 | EpgEventVideoInfo **VideoList; // 映像の情報のリスト(無い場合はNULL) 1647 | EpgEventAudioInfo **AudioList; // 音声の情報のリスト(無い場合はNULL) 1648 | EpgEventContentInfo *ContentList; // ジャンルの情報(無い場合はNULL) 1649 | EpgEventGroupInfo **EventGroupList; // イベントグループ情報(無い場合はNULL) 1650 | }; 1651 | 1652 | // イベントのリスト 1653 | struct EpgEventList { 1654 | WORD NetworkID; // ネットワークID 1655 | WORD TransportStreamID; // ストリームID 1656 | WORD ServiceID; // サービスID 1657 | WORD NumEvents; // イベントの数 1658 | EpgEventInfo **EventList; // リスト 1659 | }; 1660 | 1661 | // イベントの情報の取得 1662 | // EpgEventQueryInfo で、取得したいイベントを指定します。 1663 | // 取得した情報が不要になった場合、MsgFreeEventInfo で解放します。 1664 | // 情報が取得できなかった場合は NULL が返ります。 1665 | /* 1666 | // 現在のチャンネルの現在の番組を取得する例 1667 | ChannelInfo ChInfo; 1668 | ChInfo.Size = sizeof(ChInfo); 1669 | if (MsgGetCurrentChannelInfo(pParam, &ChInfo)) { 1670 | EpgEventQueryInfo QueryInfo; 1671 | QueryInfo.NetworkID = ChInfo.NetworkID; 1672 | QueryInfo.TransportStreamID = ChInfo.TransportStreamID; 1673 | QueryInfo.ServiceID = ChInfo.ServiceID; 1674 | QueryInfo.Type = EPG_EVENT_QUERY_TIME; 1675 | QueryInfo.Flags = 0; 1676 | GetSystemTimeAsFileTime(&QueryInfo.Time); 1677 | EpgEventInfo *pEvent = MsgGetEpgEventInfo(pParam, &QueryInfo); 1678 | if (pEvent != NULL) { 1679 | ... 1680 | MsgFreeEpgEventInfo(pParam, pEvent); 1681 | } 1682 | } 1683 | */ 1684 | inline EpgEventInfo *MsgGetEpgEventInfo(PluginParam *pParam,const EpgEventQueryInfo *pInfo) 1685 | { 1686 | return (EpgEventInfo*)(*pParam->Callback)(pParam,MESSAGE_GETEPGEVENTINFO,(LPARAM)pInfo,0); 1687 | } 1688 | 1689 | // イベントの情報の解放 1690 | // MsgGetEpgEventInfo で取得した情報のメモリを解放します。 1691 | inline void MsgFreeEpgEventInfo(PluginParam *pParam,EpgEventInfo *pEventInfo) 1692 | { 1693 | (*pParam->Callback)(pParam,MESSAGE_FREEEPGEVENTINFO,(LPARAM)pEventInfo,0); 1694 | } 1695 | 1696 | // イベントのリストの取得 1697 | // EpgEventList の NetworkID / TransportStreamID / ServiceID を設定して呼び出します。 1698 | // 取得された番組は開始日時順にソートされています。 1699 | // リストが不要になった場合、MsgFreeEpgEventList で解放します。 1700 | /* 1701 | // 現在のチャンネルの番組表を取得する例 1702 | ChannelInfo ChInfo; 1703 | ChInfo.Size = sizeof(ChInfo); 1704 | if (MsgGetCurrentChannelInfo(pParam, &ChInfo)) { 1705 | EpgEventList EventList; 1706 | EventList.NetworkID = ChInfo.NetworkID; 1707 | EventList.TransportStreamID = ChInfo.TransportStreamID; 1708 | EventList.ServiceID = ChInfo.ServiceID; 1709 | if (MsgGetEpgEventList(pParam, &EventList)) { 1710 | ... 1711 | MsgFreeEpgEventList(pParam, &EventList); 1712 | } 1713 | } 1714 | */ 1715 | inline bool MsgGetEpgEventList(PluginParam *pParam,EpgEventList *pList) 1716 | { 1717 | return (*pParam->Callback)(pParam,MESSAGE_GETEPGEVENTLIST,(LPARAM)pList,0)!=0; 1718 | } 1719 | 1720 | // イベントのリストの解放 1721 | // MsgGetEpgEventList で取得したリストのメモリを解放します。 1722 | inline void MsgFreeEpgEventList(PluginParam *pParam,EpgEventList *pList) 1723 | { 1724 | (*pParam->Callback)(pParam,MESSAGE_FREEEPGEVENTLIST,(LPARAM)pList,0); 1725 | } 1726 | 1727 | // BonDriver を列挙する 1728 | // BonDriver のフォルダとして設定されているフォルダ内の BonDriver を列挙します。 1729 | // 戻り値としてファイル名の長さが返ります。Index が範囲外の場合は0が返ります。 1730 | inline int MsgEnumDriver(PluginParam *pParam,int Index,LPWSTR pszFileName,int MaxLength) 1731 | { 1732 | return (int)(*pParam->Callback)(pParam,MESSAGE_ENUMDRIVER,(LPARAM)pszFileName,MAKELPARAM(Index,min(MaxLength,0xFFFF))); 1733 | } 1734 | 1735 | // チューニング空間の情報 1736 | struct DriverTuningSpaceInfo { 1737 | DWORD Flags; // フラグ(現在は常に0) 1738 | DWORD NumChannels; // チャンネル数 1739 | TuningSpaceInfo *pInfo; // チューニング空間の情報 1740 | ChannelInfo **ChannelList; // チャンネルのリスト 1741 | }; 1742 | 1743 | // チューニング空間のリスト 1744 | struct DriverTuningSpaceList { 1745 | DWORD Flags; // フラグ(現在は常に0) 1746 | DWORD NumSpaces; // チューニング空間の数 1747 | DriverTuningSpaceInfo **SpaceList; // チューニング空間のリスト 1748 | }; 1749 | 1750 | // BonDriver のチャンネルのリストを取得する 1751 | // DriverTuningSpaceList の Flags を設定して呼び出します。 1752 | // リストが不要になった場合、MsgFreeDriverTuningSpaceList で解放します。 1753 | inline bool MsgGetDriverTuningSpaceList(PluginParam *pParam,LPCWSTR pszDriverName,DriverTuningSpaceList *pList) 1754 | { 1755 | return (*pParam->Callback)(pParam,MESSAGE_GETDRIVERTUNINGSPACELIST,(LPARAM)pszDriverName,(LPARAM)pList)!=0; 1756 | } 1757 | 1758 | // BonDriver のチャンネルのリストを解放する 1759 | inline void MsgFreeDriverTuningSpaceList(PluginParam *pParam,DriverTuningSpaceList *pList) 1760 | { 1761 | (*pParam->Callback)(pParam,MESSAGE_FREEDRIVERTUNINGSPACELIST,(LPARAM)pList,0); 1762 | } 1763 | 1764 | #endif // TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,12) 1765 | 1766 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,13) 1767 | 1768 | // 番組表の番組の情報 1769 | struct ProgramGuideProgramInfo { 1770 | WORD NetworkID; // ネットワークID 1771 | WORD TransportStreamID; // ストリームID 1772 | WORD ServiceID; // サービスID 1773 | WORD EventID; // イベントID 1774 | SYSTEMTIME StartTime; // 開始日時 1775 | DWORD Duration; // 長さ(秒単位) 1776 | }; 1777 | 1778 | // 番組表の番組の背景描画の情報 1779 | struct ProgramGuideProgramDrawBackgroundInfo { 1780 | HDC hdc; // 描画先DCハンドル 1781 | RECT ItemRect; // 項目全体の位置 1782 | RECT TitleRect; // タイトルの位置 1783 | RECT ContentRect; // 番組内容の位置 1784 | COLORREF BackgroundColor; // 背景色 1785 | }; 1786 | 1787 | // 番組表のメニューの情報 1788 | struct ProgramGuideInitializeMenuInfo { 1789 | HMENU hmenu; // メニューのハンドル 1790 | UINT Command; // 項目のID 1791 | UINT Reserved; // 予約 1792 | }; 1793 | 1794 | // 番組表の番組のメニューの情報 1795 | struct ProgramGuideProgramInitializeMenuInfo { 1796 | HMENU hmenu; // メニューのハンドル 1797 | UINT Command; // 項目のID 1798 | UINT Reserved; // 予約 1799 | POINT CursorPos; // カーソル位置 1800 | RECT ItemRect; // 番組の位置 1801 | }; 1802 | 1803 | // 番組表のイベントのフラグ 1804 | enum { 1805 | PROGRAMGUIDE_EVENT_GENERAL =0x0001, // 全体のイベント(EVENT_PROGRAMGUIDE_*) 1806 | PROGRAMGUIDE_EVENT_PROGRAM =0x0002 // 各番組のイベント(EVENT_PROGRAMGUIDE_PROGRAM_*) 1807 | }; 1808 | 1809 | // 番組表のイベントの有効/無効を設定する 1810 | // 番組表のイベント(EVENT_PROGRAMGUIDE_*)の通知が必要な場合、通知を有効に設定します。 1811 | // EventFlags で指定されたイベント(PROGRAMGUIDE_EVENT_*)の通知が有効になります。 1812 | inline bool MsgEnableProgramGuideEvent(PluginParam *pParam,UINT EventFlags) 1813 | { 1814 | return (*pParam->Callback)(pParam,MESSAGE_ENABLEPROGRAMGUIDEEVENT,EventFlags,0)!=0; 1815 | } 1816 | 1817 | // 番組表のコマンドの情報 1818 | struct ProgramGuideCommandInfo { 1819 | WORD Type; // 種類(PROGRAMGUiDE_COMMAND_TYPE_*) 1820 | WORD Flags; // 各種フラグ(現在は常に0) 1821 | UINT ID; // 識別子 1822 | LPCWSTR pszText; // コマンドの文字列 1823 | LPCWSTR pszName; // コマンドの名前 1824 | }; 1825 | 1826 | // 番組表のコマンドの種類 1827 | enum { 1828 | PROGRAMGUIDE_COMMAND_TYPE_PROGRAM =1 // 各番組 1829 | }; 1830 | 1831 | // 番組表のコマンド実行時の情報 1832 | struct ProgramGuideCommandParam { 1833 | UINT ID; // 識別子 1834 | UINT Action; // 操作の種類(PROGRAMGUIDE_COMMAND_ACTION_*) 1835 | ProgramGuideProgramInfo Program; // 番組の情報 1836 | POINT CursorPos; // カーソル位置 1837 | RECT ItemRect; // 項目の位置 1838 | }; 1839 | 1840 | // 番組表のコマンド実行の操作の種類 1841 | enum { 1842 | PROGRAMGUIDE_COMMAND_ACTION_MOUSE, // マウスなど 1843 | PROGRAMGUIDE_COMMAND_ACTION_KEY // キーボード 1844 | }; 1845 | 1846 | // 番組表のコマンドを登録する 1847 | // コマンドを登録すると、番組表のダブルクリックなどに機能を割り当てることができるようになります。 1848 | // コマンドが実行されると EVENT_PROGRAMGUIDE_COMMAND イベントが送られます。 1849 | inline bool MsgRegisterProgramGuideCommand(PluginParam *pParam, 1850 | const ProgramGuideCommandInfo *pCommandList,int NumCommands=1) 1851 | { 1852 | return (*pParam->Callback)(pParam,MESSAGE_REGISTERPROGRAMGUIDECOMMAND,(LPARAM)pCommandList,NumCommands)!=0; 1853 | } 1854 | 1855 | #endif // TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,13) 1856 | 1857 | 1858 | /* 1859 | TVTest アプリケーションクラス 1860 | 1861 | TVTest の各種機能を呼び出すためのクラスです。 1862 | ただのラッパーなので使わなくてもいいです。 1863 | TVTInitialize 関数が呼ばれた時に、引数の PluginParam 構造体へのポインタを 1864 | コンストラクタに渡してインスタンスを生成します。 1865 | */ 1866 | class CTVTestApp 1867 | { 1868 | protected: 1869 | PluginParam *m_pParam; 1870 | public: 1871 | CTVTestApp(PluginParam *pParam) : m_pParam(pParam) {} 1872 | virtual ~CTVTestApp() {} 1873 | HWND GetAppWindow() { 1874 | return m_pParam->hwndApp; 1875 | } 1876 | DWORD GetVersion() { 1877 | return MsgGetVersion(m_pParam); 1878 | } 1879 | bool QueryMessage(UINT Message) { 1880 | return MsgQueryMessage(m_pParam,Message); 1881 | } 1882 | void *MemoryReAlloc(void *pData,DWORD Size) { 1883 | return MsgMemoryReAlloc(m_pParam,pData,Size); 1884 | } 1885 | void *MemoryAlloc(DWORD Size) { 1886 | return MsgMemoryAlloc(m_pParam,Size); 1887 | } 1888 | void MemoryFree(void *pData) { 1889 | MsgMemoryFree(m_pParam,pData); 1890 | } 1891 | bool SetEventCallback(EventCallbackFunc Callback,void *pClientData=NULL) { 1892 | return MsgSetEventCallback(m_pParam,Callback,pClientData); 1893 | } 1894 | bool GetCurrentChannelInfo(ChannelInfo *pInfo) { 1895 | pInfo->Size=sizeof(ChannelInfo); 1896 | return MsgGetCurrentChannelInfo(m_pParam,pInfo); 1897 | } 1898 | #if TVTEST_PLUGIN_VERSIONSize=sizeof(ChannelInfo); 1918 | return MsgGetChannelInfo(m_pParam,Space,Index,pInfo); 1919 | } 1920 | bool GetServiceInfo(int Index,ServiceInfo *pInfo) { 1921 | pInfo->Size=sizeof(ServiceInfo); 1922 | return MsgGetServiceInfo(m_pParam,Index,pInfo); 1923 | } 1924 | int GetDriverName(LPWSTR pszName,int MaxLength) { 1925 | return MsgGetDriverName(m_pParam,pszName,MaxLength); 1926 | } 1927 | bool SetDriverName(LPCWSTR pszName) { 1928 | return MsgSetDriverName(m_pParam,pszName); 1929 | } 1930 | bool StartRecord(RecordInfo *pInfo=NULL) { 1931 | if (pInfo!=NULL) 1932 | pInfo->Size=sizeof(RecordInfo); 1933 | return MsgStartRecord(m_pParam,pInfo); 1934 | } 1935 | bool StopRecord() { 1936 | return MsgStopRecord(m_pParam); 1937 | } 1938 | bool PauseRecord(bool fPause=true) { 1939 | return MsgPauseRecord(m_pParam,fPause); 1940 | } 1941 | bool GetRecord(RecordInfo *pInfo) { 1942 | pInfo->Size=sizeof(RecordInfo); 1943 | return MsgGetRecord(m_pParam,pInfo); 1944 | } 1945 | bool ModifyRecord(RecordInfo *pInfo) { 1946 | pInfo->Size=sizeof(RecordInfo); 1947 | return MsgModifyRecord(m_pParam,pInfo); 1948 | } 1949 | int GetZoom() { 1950 | return MsgGetZoom(m_pParam); 1951 | } 1952 | int SetZoom(int Num,int Denom=100) { 1953 | return MsgSetZoom(m_pParam,Num,Denom); 1954 | } 1955 | bool GetPanScan(PanScanInfo *pInfo) { 1956 | pInfo->Size=sizeof(PanScanInfo); 1957 | return MsgGetPanScan(m_pParam,pInfo); 1958 | } 1959 | bool SetPanScan(PanScanInfo *pInfo) { 1960 | pInfo->Size=sizeof(PanScanInfo); 1961 | return MsgSetPanScan(m_pParam,pInfo); 1962 | } 1963 | bool GetStatus(StatusInfo *pInfo) { 1964 | pInfo->Size=sizeof(StatusInfo); 1965 | return MsgGetStatus(m_pParam,pInfo); 1966 | } 1967 | bool GetRecordStatus(RecordStatusInfo *pInfo) { 1968 | #if TVTEST_PLUGIN_VERSIONSize=sizeof(RecordStatusInfo); 1970 | #else 1971 | if (pInfo->pszFileName!=NULL) 1972 | pInfo->Size=sizeof(RecordStatusInfo); 1973 | else 1974 | pInfo->Size=RECORDSTATUSINFO_SIZE_V1; 1975 | #endif 1976 | return MsgGetRecordStatus(m_pParam,pInfo); 1977 | } 1978 | bool GetVideoInfo(VideoInfo *pInfo) { 1979 | pInfo->Size=sizeof(VideoInfo); 1980 | return MsgGetVideoInfo(m_pParam,pInfo); 1981 | } 1982 | int GetVolume() { 1983 | return MsgGetVolume(m_pParam); 1984 | } 1985 | bool SetVolume(int Volume) { 1986 | return MsgSetVolume(m_pParam,Volume); 1987 | } 1988 | bool GetMute() { 1989 | return MsgGetMute(m_pParam); 1990 | } 1991 | bool SetMute(bool fMute) { 1992 | return MsgSetMute(m_pParam,fMute); 1993 | } 1994 | int GetStereoMode() { 1995 | return MsgGetStereoMode(m_pParam); 1996 | } 1997 | bool SetStereoMode(int StereoMode) { 1998 | return MsgSetStereoMode(m_pParam,StereoMode); 1999 | } 2000 | bool GetFullscreen() { 2001 | return MsgGetFullscreen(m_pParam); 2002 | } 2003 | bool SetFullscreen(bool fFullscreen) { 2004 | return MsgSetFullscreen(m_pParam,fFullscreen); 2005 | } 2006 | bool GetPreview() { 2007 | return MsgGetPreview(m_pParam); 2008 | } 2009 | bool SetPreview(bool fPreview) { 2010 | return MsgSetPreview(m_pParam,fPreview); 2011 | } 2012 | bool GetStandby() { 2013 | return MsgGetStandby(m_pParam); 2014 | } 2015 | bool SetStandby(bool fStandby) { 2016 | return MsgSetStandby(m_pParam,fStandby); 2017 | } 2018 | bool GetAlwaysOnTop() { 2019 | return MsgGetAlwaysOnTop(m_pParam); 2020 | } 2021 | bool SetAlwaysOnTop(bool fAlwaysOnTop) { 2022 | return MsgSetAlwaysOnTop(m_pParam,fAlwaysOnTop); 2023 | } 2024 | void *CaptureImage(DWORD Flags=0) { 2025 | return MsgCaptureImage(m_pParam,Flags); 2026 | } 2027 | bool SaveImage() { 2028 | return MsgSaveImage(m_pParam); 2029 | } 2030 | #if TVTEST_PLUGIN_VERSIONSize=sizeof(ProgramInfo); 2057 | return MsgGetCurrentProgramInfo(m_pParam,pInfo,fNext); 2058 | } 2059 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,1) 2060 | bool QueryEvent(UINT Event) { 2061 | return MsgQueryEvent(m_pParam,Event); 2062 | } 2063 | int GetTuningSpace(int *pNumSpaces=NULL) { 2064 | return MsgGetTuningSpace(m_pParam,pNumSpaces); 2065 | } 2066 | bool GetTuningSpaceInfo(int Index,TuningSpaceInfo *pInfo) { 2067 | pInfo->Size=sizeof(TuningSpaceInfo); 2068 | return MsgGetTuningSpaceInfo(m_pParam,Index,pInfo); 2069 | } 2070 | bool SetNextChannel(bool fNext=true) { 2071 | return MsgSetNextChannel(m_pParam,fNext); 2072 | } 2073 | #endif 2074 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,2) 2075 | int GetAudioStream() { 2076 | return MsgGetAudioStream(m_pParam); 2077 | } 2078 | bool SetAudioStream(int Index) { 2079 | return MsgSetAudioStream(m_pParam,Index); 2080 | } 2081 | #endif 2082 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,3) 2083 | bool IsPluginEnabled() { 2084 | return MsgIsPluginEnabled(m_pParam); 2085 | } 2086 | bool RegisterCommand(int ID,LPCWSTR pszText,LPCWSTR pszName) { 2087 | return MsgRegisterCommand(m_pParam,ID,pszText,pszName); 2088 | } 2089 | bool RegisterCommand(const CommandInfo *pCommandList,int NumCommands) { 2090 | return MsgRegisterCommand(m_pParam,pCommandList,NumCommands); 2091 | } 2092 | bool AddLog(LPCWSTR pszText) { 2093 | return MsgAddLog(m_pParam,pszText); 2094 | } 2095 | #endif 2096 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,5) 2097 | bool ResetStatus() { 2098 | return MsgResetStatus(m_pParam); 2099 | } 2100 | #endif 2101 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,6) 2102 | bool SetAudioCallback(AudioCallbackFunc pCallback,void *pClientData=NULL) { 2103 | return MsgSetAudioCallback(m_pParam,pCallback,pClientData); 2104 | } 2105 | #endif 2106 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,7) 2107 | bool DoCommand(LPCWSTR pszCommand) { 2108 | return MsgDoCommand(m_pParam,pszCommand); 2109 | } 2110 | #endif 2111 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,8) 2112 | bool GetBCasInfo(BCasInfo *pInfo) { 2113 | pInfo->Size=sizeof(BCasInfo); 2114 | return MsgGetBCasInfo(m_pParam,pInfo); 2115 | } 2116 | bool SendBCasCommand(BCasCommandInfo *pInfo) { 2117 | return MsgSendBCasCommand(m_pParam,pInfo); 2118 | } 2119 | bool SendBCasCommand(const BYTE *pSendData,DWORD SendSize,BYTE *pReceiveData,DWORD *pReceiveSize) { 2120 | return MsgSendBCasCommand(m_pParam,pSendData,SendSize,pReceiveData,pReceiveSize); 2121 | } 2122 | bool GetHostInfo(HostInfo *pInfo) { 2123 | pInfo->Size=sizeof(HostInfo); 2124 | return MsgGetHostInfo(m_pParam,pInfo); 2125 | } 2126 | #endif 2127 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,9) 2128 | bool GetSetting(SettingInfo *pInfo) { 2129 | return MsgGetSetting(m_pParam,pInfo); 2130 | } 2131 | bool GetSetting(LPCWSTR pszName,int *pValue) { 2132 | return MsgGetSetting(m_pParam,pszName,pValue); 2133 | } 2134 | bool GetSetting(LPCWSTR pszName,unsigned int *pValue) { 2135 | return MsgGetSetting(m_pParam,pszName,pValue); 2136 | } 2137 | DWORD GetSetting(LPCWSTR pszName,LPWSTR pszString,DWORD MaxLength) { 2138 | return MsgGetSetting(m_pParam,pszName,pszString,MaxLength); 2139 | } 2140 | int GetDriverFullPathName(LPWSTR pszPath,int MaxLength) { 2141 | return MsgGetDriverFullPathName(m_pParam,pszPath,MaxLength); 2142 | } 2143 | #endif 2144 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,10) 2145 | HBITMAP GetLogo(WORD NetworkID,WORD ServiceID,BYTE LogoType) { 2146 | return MsgGetLogo(m_pParam,NetworkID,ServiceID,LogoType); 2147 | } 2148 | UINT GetAvailableLogoType(WORD NetworkID,WORD ServiceID) { 2149 | return MsgGetAvailableLogoType(m_pParam,NetworkID,ServiceID); 2150 | } 2151 | bool RelayRecord(LPCWSTR pszFileName) { 2152 | return MsgRelayRecord(m_pParam,pszFileName); 2153 | } 2154 | bool GetSilentMode() { 2155 | return MsgGetSilentMode(m_pParam); 2156 | } 2157 | bool SetSilentMode(bool fSilent) { 2158 | return MsgSetSilentMode(m_pParam,fSilent); 2159 | } 2160 | #endif 2161 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,11) 2162 | bool SetWindowMessageCallback(WindowMessageCallbackFunc Callback,void *pClientData=NULL) { 2163 | return MsgSetWindowMessageCallback(m_pParam,Callback,pClientData); 2164 | } 2165 | bool RegisterController(ControllerInfo *pInfo) { 2166 | pInfo->Size=sizeof(ControllerInfo); 2167 | return MsgRegisterController(m_pParam,pInfo); 2168 | } 2169 | bool OnControllerButtonDown(LPCWSTR pszName,int Button) { 2170 | return MsgOnControllerButtonDown(m_pParam,pszName,Button); 2171 | } 2172 | bool GetControllerSettings(LPCWSTR pszName,ControllerSettings *pSettings) { 2173 | return MsgGetControllerSettings(m_pParam,pszName,pSettings); 2174 | } 2175 | bool IsControllerActiveOnly(LPCWSTR pszName) { 2176 | return MsgIsControllerActiveOnly(m_pParam,pszName); 2177 | } 2178 | #endif 2179 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,12) 2180 | EpgEventInfo *GetEpgEventInfo(const EpgEventQueryInfo *pInfo) { 2181 | return MsgGetEpgEventInfo(m_pParam,pInfo); 2182 | } 2183 | void FreeEpgEventInfo(EpgEventInfo *pEventInfo) { 2184 | MsgFreeEpgEventInfo(m_pParam,pEventInfo); 2185 | } 2186 | bool GetEpgEventList(EpgEventList *pList) { 2187 | return MsgGetEpgEventList(m_pParam,pList); 2188 | } 2189 | void FreeEpgEventList(EpgEventList *pList) { 2190 | MsgFreeEpgEventList(m_pParam,pList); 2191 | } 2192 | int EnumDriver(int Index,LPWSTR pszFileName,int MaxLength) { 2193 | return MsgEnumDriver(m_pParam,Index,pszFileName,MaxLength); 2194 | } 2195 | bool GetDriverTuningSpaceList(LPCWSTR pszDriverName,DriverTuningSpaceList *pList) { 2196 | return MsgGetDriverTuningSpaceList(m_pParam,pszDriverName,pList); 2197 | } 2198 | void FreeDriverTuningSpaceList(DriverTuningSpaceList *pList) { 2199 | MsgFreeDriverTuningSpaceList(m_pParam,pList); 2200 | } 2201 | #endif 2202 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,13) 2203 | bool EnableProgramGuideEvent(UINT EventFlags) { 2204 | return MsgEnableProgramGuideEvent(m_pParam,EventFlags); 2205 | } 2206 | bool RegisterProgramGuideCommand(const ProgramGuideCommandInfo *pCommandList,int NumCommands=1) { 2207 | return MsgRegisterProgramGuideCommand(m_pParam,pCommandList,NumCommands); 2208 | } 2209 | #endif 2210 | }; 2211 | 2212 | /* 2213 | TVTest プラグインクラス 2214 | 2215 | プラグインをクラスとして記述するための抽象クラスです。 2216 | このクラスを各プラグインで派生させて、プラグインの内容を記述します。 2217 | このクラスを使わずに直接エクスポート関数を書いてもいいです。 2218 | */ 2219 | class CTVTestPlugin 2220 | { 2221 | protected: 2222 | PluginParam *m_pPluginParam; 2223 | CTVTestApp *m_pApp; 2224 | public: 2225 | CTVTestPlugin() : m_pPluginParam(NULL),m_pApp(NULL) {} 2226 | void SetPluginParam(PluginParam *pParam) { 2227 | m_pPluginParam=pParam; 2228 | m_pApp=new CTVTestApp(pParam); 2229 | } 2230 | virtual ~CTVTestPlugin() { delete m_pApp; } 2231 | virtual DWORD GetVersion() { return TVTEST_PLUGIN_VERSION; } 2232 | virtual bool GetPluginInfo(PluginInfo *pInfo)=0; 2233 | virtual bool Initialize() { return true; } 2234 | virtual bool Finalize() { return true; } 2235 | }; 2236 | 2237 | /* 2238 | イベントハンドルクラス 2239 | 2240 | イベント処理用クラスです。 2241 | このクラスを派生させてイベント処理を行うことができます。 2242 | イベントコールバック関数として登録した関数内で HandleEvent を呼びます。 2243 | もちろん使わなくてもいいです。 2244 | 2245 | 以下は実装例です。 2246 | 2247 | class CMyEventHandler : public TVTest::CTVTestEventHandler 2248 | { 2249 | public: 2250 | virtual bool OnPluginEnable(bool fEnable) { 2251 | if (fEnable) { 2252 | if (MessageBox(NULL, TEXT("有効にするよ"), TEXT("イベント"), 2253 | MB_OKCANCEL) != IDOK) { 2254 | return false; 2255 | } 2256 | } 2257 | return true; 2258 | } 2259 | }; 2260 | 2261 | CMyEventHandler Handler; 2262 | 2263 | // この関数がイベントコールバック関数として登録されているものとします 2264 | LRESULT CALLBACK EventCallback(UINT Event,LPARAM lParam1,LPARAM lParam2,void *pClientData) 2265 | { 2266 | return Handler.HandleEvent(Event,lParam1,lParam2,pClientData); 2267 | } 2268 | */ 2269 | class CTVTestEventHandler 2270 | { 2271 | protected: 2272 | void *m_pClientData; 2273 | 2274 | // イベントハンドラは、特に記述の無いものは何か処理したら true を返します 2275 | 2276 | // 有効状態が変化した 2277 | // 変化を拒否する場合 false を返します 2278 | virtual bool OnPluginEnable(bool fEnable) { return false; } 2279 | // 設定を行う 2280 | // プラグインのフラグに PLUGIN_FLAG_HASSETTINGS が設定されている場合に呼ばれます 2281 | // 設定が OK されたら true を返します 2282 | virtual bool OnPluginSettings(HWND hwndOwner) { return false; } 2283 | // チャンネルが変更された 2284 | virtual bool OnChannelChange() { return false; } 2285 | // サービスが変更された 2286 | virtual bool OnServiceChange() { return false; } 2287 | // ドライバが変更された 2288 | virtual bool OnDriverChange() { return false; } 2289 | // サービスの構成が変化した 2290 | virtual bool OnServiceUpdate() { return false; } 2291 | // 録画状態が変化した 2292 | virtual bool OnRecordStatusChange(int Status) { return false; } 2293 | // 全画面表示状態が変化した 2294 | virtual bool OnFullscreenChange(bool fFullscreen) { return false; } 2295 | // プレビュー表示状態が変化した 2296 | virtual bool OnPreviewChange(bool fPreview) { return false; } 2297 | // 音量が変化した 2298 | virtual bool OnVolumeChange(int Volume,bool fMute) { return false; } 2299 | // ステレオモードが変化した 2300 | virtual bool OnStereoModeChange(int StereoMode) { return false; } 2301 | // 色の設定が変化した 2302 | virtual bool OnColorChange() { return false; } 2303 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,3) 2304 | // 待機状態が変化した 2305 | virtual bool OnStandby(bool fStandby) { return false; } 2306 | // コマンドが選択された 2307 | virtual bool OnCommand(int ID) { return false; } 2308 | #endif 2309 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,4) 2310 | // 複数起動禁止時に複数起動された 2311 | virtual bool OnExecute(LPCWSTR pszCommandLine) { return false; } 2312 | #endif 2313 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,5) 2314 | // リセットされた 2315 | virtual bool OnReset() { return false; } 2316 | // ステータス(MESSAGE_GETSTUATUSで取得できる内容)がリセットされた 2317 | virtual bool OnStatusReset() { return false; } 2318 | // 音声ストリームが変更された 2319 | virtual bool OnAudioStreamChange(int Stream) { return false; } 2320 | #endif 2321 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,9) 2322 | // 設定が変更された 2323 | virtual bool OnSettingsChange() { return false; } 2324 | #endif 2325 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,10) 2326 | // TVTestのウィンドウが閉じられる 2327 | virtual bool OnClose() { return false; } 2328 | // 録画が開始される 2329 | virtual bool OnStartRecord(StartRecordInfo *pInfo) { return false; } 2330 | // 録画ファイルの切り替えが行われた 2331 | virtual bool OnRelayRecord(LPCWSTR pszFileName) { return false; } 2332 | #endif 2333 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,11) 2334 | // コントローラの対象の設定 2335 | virtual bool OnControllerFocus(HWND hwnd) { return false; } 2336 | #endif 2337 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,13) 2338 | // 起動処理が終了した 2339 | virtual void OnStartupDone() {} 2340 | // 番組表の初期化 2341 | virtual bool OnProgramGuideInitialize(HWND hwnd) { return true; } 2342 | // 番組表の終了 2343 | virtual bool OnProgramGuideFinalize(HWND hwnd) { return true; } 2344 | // 番組表のコマンドの実行 2345 | virtual bool OnProgramGuideCommand( 2346 | UINT Command,const ProgramGuideCommandParam *pParam) { return false; } 2347 | // 番組表のメニューの初期化 2348 | virtual int OnProgramGuideInitializeMenu( 2349 | const ProgramGuideInitializeMenuInfo *pInfo) { return 0; } 2350 | // 番組表のメニューが選択された 2351 | virtual bool OnProgramGuideMenuSelected(UINT Command) { return false; } 2352 | // 番組表の番組の背景描画 2353 | virtual bool OnProgramGuideProgramDrawBackground( 2354 | const ProgramGuideProgramInfo *pProgramInfo, 2355 | const ProgramGuideProgramDrawBackgroundInfo *pInfo) { return false; } 2356 | // 番組表の番組のメニュー初期化 2357 | virtual int OnProgramGuideProgramInitializeMenu( 2358 | const ProgramGuideProgramInfo *pProgramInfo, 2359 | const ProgramGuideProgramInitializeMenuInfo *pInfo) { return 0; } 2360 | // 番組表の番組のメニューが選択された 2361 | virtual bool OnProgramGuideProgramMenuSelected( 2362 | const ProgramGuideProgramInfo *pProgramInfo,UINT Command) { return false; } 2363 | #endif 2364 | 2365 | public: 2366 | virtual ~CTVTestEventHandler() {} 2367 | LRESULT HandleEvent(UINT Event,LPARAM lParam1,LPARAM lParam2,void *pClientData) 2368 | { 2369 | m_pClientData=pClientData; 2370 | switch (Event) { 2371 | case EVENT_PLUGINENABLE: return OnPluginEnable(lParam1!=0); 2372 | case EVENT_PLUGINSETTINGS: return OnPluginSettings((HWND)lParam1); 2373 | case EVENT_CHANNELCHANGE: return OnChannelChange(); 2374 | case EVENT_SERVICECHANGE: return OnServiceChange(); 2375 | case EVENT_DRIVERCHANGE: return OnDriverChange(); 2376 | case EVENT_SERVICEUPDATE: return OnServiceUpdate(); 2377 | case EVENT_RECORDSTATUSCHANGE: return OnRecordStatusChange((int)lParam1); 2378 | case EVENT_FULLSCREENCHANGE: return OnFullscreenChange(lParam1!=0); 2379 | case EVENT_PREVIEWCHANGE: return OnPreviewChange(lParam1!=0); 2380 | case EVENT_VOLUMECHANGE: return OnVolumeChange((int)lParam1,lParam2!=0); 2381 | case EVENT_STEREOMODECHANGE: return OnStereoModeChange((int)lParam1); 2382 | case EVENT_COLORCHANGE: return OnColorChange(); 2383 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,3) 2384 | case EVENT_STANDBY: return OnStandby(lParam1!=0); 2385 | case EVENT_COMMAND: return OnCommand((int)lParam1); 2386 | #endif 2387 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,4) 2388 | case EVENT_EXECUTE: return OnExecute((LPCWSTR)lParam1); 2389 | #endif 2390 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,5) 2391 | case EVENT_RESET: return OnReset(); 2392 | case EVENT_STATUSRESET: return OnStatusReset(); 2393 | case EVENT_AUDIOSTREAMCHANGE: return OnAudioStreamChange((int)lParam1); 2394 | #endif 2395 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,9) 2396 | case EVENT_SETTINGSCHANGE: return OnSettingsChange(); 2397 | #endif 2398 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,10) 2399 | case EVENT_CLOSE: return OnClose(); 2400 | case EVENT_STARTRECORD: return OnStartRecord((StartRecordInfo*)lParam1); 2401 | case EVENT_RELAYRECORD: return OnRelayRecord((LPCWSTR)lParam1); 2402 | #endif 2403 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,11) 2404 | case EVENT_CONTROLLERFOCUS: return OnControllerFocus((HWND)lParam1); 2405 | #endif 2406 | #if TVTEST_PLUGIN_VERSION>=TVTEST_PLUGIN_VERSION_(0,0,13) 2407 | case EVENT_STARTUPDONE: OnStartupDone(); return 0; 2408 | case EVENT_PROGRAMGUIDE_INITIALIZE: return OnProgramGuideInitialize((HWND)lParam1); 2409 | case EVENT_PROGRAMGUIDE_FINALIZE: return OnProgramGuideFinalize((HWND)lParam1); 2410 | case EVENT_PROGRAMGUIDE_COMMAND: 2411 | return OnProgramGuideCommand( 2412 | (UINT)lParam1, 2413 | (const ProgramGuideCommandParam*)lParam2); 2414 | case EVENT_PROGRAMGUIDE_INITIALIZEMENU: 2415 | return OnProgramGuideInitializeMenu( 2416 | (const ProgramGuideInitializeMenuInfo*)lParam1); 2417 | case EVENT_PROGRAMGUIDE_MENUSELECTED: 2418 | return OnProgramGuideMenuSelected((UINT)lParam1); 2419 | case EVENT_PROGRAMGUIDE_PROGRAM_DRAWBACKGROUND: 2420 | return OnProgramGuideProgramDrawBackground( 2421 | (const ProgramGuideProgramInfo*)lParam1, 2422 | (const ProgramGuideProgramDrawBackgroundInfo*)lParam2); 2423 | case EVENT_PROGRAMGUIDE_PROGRAM_INITIALIZEMENU: 2424 | return OnProgramGuideProgramInitializeMenu( 2425 | (const ProgramGuideProgramInfo*)lParam1, 2426 | (const ProgramGuideProgramInitializeMenuInfo*)lParam2); 2427 | case EVENT_PROGRAMGUIDE_PROGRAM_MENUSELECTED: 2428 | return OnProgramGuideProgramMenuSelected( 2429 | (const ProgramGuideProgramInfo*)lParam1,(UINT)lParam2); 2430 | #endif 2431 | } 2432 | return 0; 2433 | } 2434 | }; 2435 | 2436 | 2437 | } // namespace TVTest 2438 | 2439 | 2440 | #include 2441 | 2442 | 2443 | #ifdef TVTEST_PLUGIN_CLASS_IMPLEMENT 2444 | /* 2445 | プラグインをクラスとして記述できるようにするための、エクスポート関数の実装 2446 | です。 2447 | これを使えば、エクスポート関数を自分で実装する必要がなくなります。 2448 | 2449 | プラグイン側では CreatePluginClass 関数を実装して、CTVTestPlugin クラスから 2450 | 派生させたプラグインクラスのインスタンスを new で生成して返します。例えば、 2451 | 以下のように書きます。 2452 | 2453 | #include 2454 | #define TVTEST_PLUGIN_CLASS_IMPLEMENT 2455 | #include "TVTestPlugin.h" 2456 | 2457 | // プラグインクラスの宣言 2458 | class CMyPluginClass : public TVTest::CTVTestPlugin { 2459 | ... 2460 | }; 2461 | 2462 | // クラスのインスタンスを生成する 2463 | TVTest::CTVTestPlugin *CreatePluginClass() 2464 | { 2465 | return new CMyPluginClass; 2466 | } 2467 | */ 2468 | 2469 | 2470 | TVTest::CTVTestPlugin *CreatePluginClass(); 2471 | 2472 | HINSTANCE g_hinstDLL; // DLL のインスタンスハンドル 2473 | TVTest::CTVTestPlugin *g_pPlugin; // プラグインクラスへのポインタ 2474 | 2475 | 2476 | // エントリポイント 2477 | // プラグインクラスのインスタンスの生成と破棄を行っています 2478 | BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved) 2479 | { 2480 | switch (fdwReason) { 2481 | case DLL_PROCESS_ATTACH: 2482 | g_hinstDLL=hinstDLL; 2483 | g_pPlugin=CreatePluginClass(); 2484 | if (g_pPlugin==NULL) 2485 | return FALSE; 2486 | break; 2487 | case DLL_PROCESS_DETACH: 2488 | if (g_pPlugin) { 2489 | delete g_pPlugin; 2490 | g_pPlugin=NULL; 2491 | } 2492 | break; 2493 | } 2494 | return TRUE; 2495 | } 2496 | 2497 | // プラグインの準拠するプラグイン仕様のバージョンを返す 2498 | // プラグインがロードされると最初にこの関数が呼ばれ、 2499 | // 対応していないバージョンが返された場合はすぐにアンロードされます。 2500 | TVTEST_EXPORT(DWORD) TVTGetVersion() 2501 | { 2502 | return g_pPlugin->GetVersion(); 2503 | } 2504 | 2505 | // プラグインの情報を取得する 2506 | // TVTGetVersion の次に呼ばれるので、プラグインの情報を PluginInfo 構造体に設定します。 2507 | // FALSE が返された場合、すぐにアンロードされます。 2508 | TVTEST_EXPORT(BOOL) TVTGetPluginInfo(TVTest::PluginInfo *pInfo) 2509 | { 2510 | return g_pPlugin->GetPluginInfo(pInfo); 2511 | } 2512 | 2513 | // 初期化を行う 2514 | // TVTGetPluginInfo の次に呼ばれるので、初期化処理を行います。 2515 | // FALSE が返された場合、すぐにアンロードされます。 2516 | TVTEST_EXPORT(BOOL) TVTInitialize(TVTest::PluginParam *pParam) 2517 | { 2518 | g_pPlugin->SetPluginParam(pParam); 2519 | return g_pPlugin->Initialize(); 2520 | } 2521 | 2522 | // 終了処理を行う 2523 | // プラグインがアンロードされる前に呼ばれるので、終了処理を行います。 2524 | // この関数が呼ばれるのは TVTInitialize 関数が TRUE を返した場合だけです。 2525 | TVTEST_EXPORT(BOOL) TVTFinalize() 2526 | { 2527 | bool fOK=g_pPlugin->Finalize(); 2528 | delete g_pPlugin; 2529 | g_pPlugin=NULL; 2530 | return fOK; 2531 | } 2532 | 2533 | 2534 | #endif // TVTEST_PLUGIN_CLASS_IMPLEMENT 2535 | 2536 | 2537 | #endif // TVTEST_PLUGIN_H 2538 | -------------------------------------------------------------------------------- /TextFileReader.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "TextFileReader.h" 3 | 4 | CTextFileReader::CTextFileReader() 5 | : hFile_(INVALID_HANDLE_VALUE) 6 | , bEof_(false) 7 | { 8 | buf_[0] = '\0'; 9 | } 10 | 11 | CTextFileReader::~CTextFileReader() 12 | { 13 | Close(); 14 | } 15 | 16 | bool CTextFileReader::Open(LPCTSTR path, DWORD shareMode, DWORD flagsAndAttributes) 17 | { 18 | Close(); 19 | hFile_ = CreateFile(path, GENERIC_READ, shareMode, NULL, OPEN_EXISTING, flagsAndAttributes, NULL); 20 | return IsOpen(); 21 | } 22 | 23 | void CTextFileReader::Close() 24 | { 25 | if (IsOpen()) { 26 | CloseHandle(hFile_); 27 | hFile_ = INVALID_HANDLE_VALUE; 28 | } 29 | bEof_ = false; 30 | buf_[0] = '\0'; 31 | } 32 | 33 | // ファイルポインタを先頭に戻す 34 | bool CTextFileReader::ResetPointer() 35 | { 36 | if (IsOpen()) { 37 | if (SetFilePointer(hFile_, 0, NULL, FILE_BEGIN) != INVALID_SET_FILE_POINTER) { 38 | bEof_ = false; 39 | buf_[0] = '\0'; 40 | return true; 41 | } 42 | } 43 | return false; 44 | } 45 | 46 | // 1行またはNULを含む最大textMax(>0)バイト読み込む 47 | // 改行文字は取り除く 48 | // 戻り値はNULを含む読み込まれたバイト数、終端に達すると0を返す 49 | int CTextFileReader::ReadLine(char *text, int textMax) 50 | { 51 | if (!IsOpen()) { 52 | return 0; 53 | } 54 | int textLen = 0; 55 | for (;;) { 56 | if (!bEof_) { 57 | int bufLen = lstrlenA(buf_); 58 | DWORD read; 59 | if (!ReadFile(hFile_, buf_ + bufLen, BUF_SIZE - bufLen - 1, &read, NULL)) { 60 | buf_[bufLen] = '\0'; 61 | bEof_ = true; 62 | } else { 63 | buf_[bufLen + read] = '\0'; 64 | if (lstrlenA(buf_) < BUF_SIZE - 1) { 65 | bEof_ = true; 66 | } 67 | } 68 | } 69 | if (!textLen && !buf_[0]) { 70 | return 0; 71 | } 72 | int lineLen = StrCSpnA(buf_, "\n"); 73 | int copyNum = min(lineLen + 1, textMax - textLen); 74 | lstrcpynA(text + textLen, buf_, copyNum); 75 | textLen += copyNum - 1; 76 | if (lineLen < BUF_SIZE - 1) { 77 | if (buf_[lineLen] == '\n') ++lineLen; 78 | memmove(buf_, buf_ + lineLen, sizeof(buf_) - lineLen); 79 | if (textLen >= 1 && text[textLen-1] == '\r') { 80 | text[--textLen] = '\0'; 81 | } 82 | return textLen + 1; 83 | } 84 | buf_[0] = '\0'; 85 | } 86 | } 87 | 88 | // 最終行を1行またはNULを含む最大textMax(>0)バイト(収まらない場合行頭側をカット)読み込む 89 | // 改行文字は取り除く 90 | // ファイルポインタは先頭に戻る 91 | // 戻り値はNULを含む読み込まれたバイト数 92 | int CTextFileReader::ReadLastLine(char *text, int textMax) 93 | { 94 | if (!IsOpen()) { 95 | return 0; 96 | } 97 | // 2GB以上には対応しない 98 | DWORD fileSize = GetFileSize(hFile_, NULL); 99 | if (fileSize > 0x7FFFFFFF || 100 | SetFilePointer(hFile_, -min(textMax - 1, static_cast(fileSize)), NULL, FILE_END) == INVALID_SET_FILE_POINTER) { 101 | return 0; 102 | } 103 | DWORD read; 104 | if (!ReadFile(hFile_, text, textMax - 1, &read, NULL)) { 105 | ResetPointer(); 106 | return 0; 107 | } 108 | text[read] = '\0'; 109 | int textLen = lstrlenA(text); 110 | if (textLen >= 1 && text[textLen-1] == '\n') { 111 | text[--textLen] = '\0'; 112 | } 113 | if (textLen >= 1 && text[textLen-1] == '\r') { 114 | text[--textLen] = '\0'; 115 | } 116 | char *p = StrRChrA(text, text + textLen, '\n'); 117 | if (p) { 118 | ++p; 119 | memmove(text, p, textLen - static_cast(p - text) + 1); 120 | textLen -= static_cast(p - text); 121 | } 122 | ResetPointer(); 123 | return textLen + 1; 124 | } 125 | 126 | // 現在位置からファイルサイズ/scaleだけシークする 127 | // 戻り値はファイルポインタの移動バイト数 128 | int CTextFileReader::Seek(int scale) 129 | { 130 | if (!IsOpen() || scale == 0) { 131 | return 0; 132 | } 133 | DWORD fileSize = GetFileSize(hFile_, NULL); 134 | DWORD filePos = SetFilePointer(hFile_, 0, NULL, FILE_CURRENT); 135 | if (fileSize > 0x7FFFFFFF || filePos == INVALID_SET_FILE_POINTER) { 136 | return 0; 137 | } 138 | LONGLONG llNextPos = static_cast(fileSize) / (scale < 0 ? -scale : scale) * (scale < 0 ? -1 : 1) + filePos; 139 | DWORD nextPos = llNextPos < 0 ? 0 : llNextPos >= fileSize ? filePos : static_cast(llNextPos); 140 | if (nextPos == filePos) { 141 | return 0; 142 | } 143 | nextPos = SetFilePointer(hFile_, nextPos, NULL, FILE_BEGIN); 144 | if (nextPos == INVALID_SET_FILE_POINTER) { 145 | return 0; 146 | } 147 | bEof_ = false; 148 | buf_[0] = '\0'; 149 | return static_cast(nextPos) - static_cast(filePos); 150 | } 151 | -------------------------------------------------------------------------------- /TextFileReader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // マルチバイトテキストファイル読み込み(ReadFileのラッパ) 4 | class CTextFileReader 5 | { 6 | public: 7 | static const int BUF_SIZE = 512; 8 | CTextFileReader(); 9 | ~CTextFileReader(); 10 | bool Open(LPCTSTR path, DWORD shareMode, DWORD flagsAndAttributes); 11 | void Close(); 12 | bool ResetPointer(); 13 | int ReadLine(char *text, int textMax); 14 | int ReadLastLine(char *text, int textMax); 15 | int Seek(int scale); 16 | bool IsOpen() const { return hFile_ != INVALID_HANDLE_VALUE; } 17 | private: 18 | HANDLE hFile_; 19 | bool bEof_; 20 | char buf_[BUF_SIZE]; 21 | }; 22 | -------------------------------------------------------------------------------- /Util.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Util.h" 3 | 4 | static const struct { 5 | COLORREF color; 6 | char *command; 7 | } COMMAND2COLOR[] = { 8 | {RGB(0xFF, 0x00, 0x00), "red"}, 9 | {RGB(0xFF, 0x80, 0x80), "pink"}, 10 | {RGB(0xFF, 0xC0, 0x00), "orange"}, 11 | {RGB(0xFF, 0xFF, 0x00), "yellow"}, 12 | {RGB(0x00, 0xFF, 0x00), "green"}, 13 | {RGB(0x00, 0xFF, 0xFF), "cyan"}, 14 | {RGB(0x00, 0x00, 0xFF), "blue"}, 15 | {RGB(0xC0, 0x00, 0xFF), "purple"}, 16 | {RGB(0x00, 0x00, 0x00), "black"}, 17 | {RGB(0xCC, 0xCC, 0x99), "white2"}, 18 | {RGB(0xCC, 0xCC, 0x99), "niconicowhite"}, 19 | {RGB(0xCC, 0x00, 0x33), "red2"}, 20 | {RGB(0xCC, 0x00, 0x33), "truered"}, 21 | {RGB(0xFF, 0x33, 0xCC), "pink2"}, 22 | {RGB(0xFF, 0x66, 0x00), "orange2"}, 23 | {RGB(0xFF, 0x66, 0x00), "passionorange"}, 24 | {RGB(0x99, 0x99, 0x00), "yellow2"}, 25 | {RGB(0x99, 0x99, 0x00), "madyellow"}, 26 | {RGB(0x00, 0xCC, 0x66), "green2"}, 27 | {RGB(0x00, 0xCC, 0x66), "elementalgreen"}, 28 | {RGB(0x00, 0xCC, 0xCC), "cyan2"}, 29 | {RGB(0x33, 0x99, 0xFF), "blue2"}, 30 | {RGB(0x33, 0x99, 0xFF), "marineblue"}, 31 | {RGB(0x66, 0x33, 0xCC), "purple2"}, 32 | {RGB(0x66, 0x33, 0xCC), "nobleviolet"}, 33 | {RGB(0x66, 0x66, 0x66), "black2"}, 34 | }; 35 | 36 | // 必要なバッファを確保してGetPrivateProfileSection()を呼ぶ 37 | TCHAR *NewGetPrivateProfileSection(LPCTSTR lpAppName, LPCTSTR lpFileName) 38 | { 39 | TCHAR *pBuf = NULL; 40 | for (int bufSize = 4096; bufSize < 1024 * 1024; bufSize *= 2) { 41 | delete [] pBuf; 42 | pBuf = new TCHAR[bufSize]; 43 | if ((int)GetPrivateProfileSection(lpAppName, pBuf, bufSize, lpFileName) < bufSize - 2) { 44 | break; 45 | } 46 | pBuf[0] = 0; 47 | } 48 | return pBuf; 49 | } 50 | 51 | // GetPrivateProfileSection()で取得したバッファから、キーに対応する文字列を取得する 52 | void GetBufferedProfileString(LPCTSTR lpBuff, LPCTSTR lpKeyName, LPCTSTR lpDefault, LPTSTR lpReturnedString, DWORD nSize) 53 | { 54 | int nKeyLen = lstrlen(lpKeyName); 55 | if (nKeyLen <= 126) { 56 | TCHAR szKey[128]; 57 | lstrcpy(szKey, lpKeyName); 58 | lstrcpy(szKey + (nKeyLen++), TEXT("=")); 59 | while (*lpBuff) { 60 | int nLen = lstrlen(lpBuff); 61 | if (!StrCmpNI(lpBuff, szKey, nKeyLen)) { 62 | if ((lpBuff[nKeyLen] == TEXT('\'') || lpBuff[nKeyLen] == TEXT('"')) && 63 | nLen >= nKeyLen + 2 && lpBuff[nKeyLen] == lpBuff[nLen - 1]) { 64 | lstrcpyn(lpReturnedString, lpBuff + nKeyLen + 1, min(nLen-nKeyLen-1, static_cast(nSize))); 65 | } else { 66 | lstrcpyn(lpReturnedString, lpBuff + nKeyLen, nSize); 67 | } 68 | return; 69 | } 70 | lpBuff += nLen + 1; 71 | } 72 | } 73 | lstrcpyn(lpReturnedString, lpDefault, nSize); 74 | } 75 | 76 | // GetPrivateProfileSection()で取得したバッファから、キーに対応する数値を取得する 77 | int GetBufferedProfileInt(LPCTSTR lpBuff, LPCTSTR lpKeyName, int nDefault) 78 | { 79 | TCHAR sz[24]; 80 | GetBufferedProfileString(lpBuff, lpKeyName, TEXT(""), sz, _countof(sz)); 81 | int nRet; 82 | return StrToIntEx(sz, STIF_DEFAULT, &nRet) ? nRet : nDefault; 83 | } 84 | 85 | BOOL WritePrivateProfileInt(LPCTSTR lpAppName, LPCTSTR lpKeyName, int value, LPCTSTR lpFileName) 86 | { 87 | TCHAR sz[24]; 88 | wsprintf(sz, TEXT("%d"), value); 89 | return WritePrivateProfileString(lpAppName, lpKeyName, sz, lpFileName); 90 | } 91 | 92 | DWORD GetLongModuleFileName(HMODULE hModule, LPTSTR lpFileName, DWORD nSize) 93 | { 94 | TCHAR longOrShortName[MAX_PATH]; 95 | DWORD nRet = GetModuleFileName(hModule, longOrShortName, MAX_PATH); 96 | if (nRet && nRet < MAX_PATH) { 97 | nRet = GetLongPathName(longOrShortName, lpFileName, nSize); 98 | if (nRet < nSize) return nRet; 99 | } 100 | return 0; 101 | } 102 | 103 | // HTTPヘッダフィールドを連結付加する 104 | void AppendHttpHeader(char *str, const char *field, const char *value, const char *trail) 105 | { 106 | // valueが空文字列なら何もしない 107 | if (value[0]) { 108 | int n = lstrlenA(str); 109 | lstrcatA(&str[n], field); 110 | lstrcatA(&str[n], value); 111 | lstrcatA(&str[n], trail); 112 | } 113 | } 114 | 115 | size_t FindHttpBody(const char *str) 116 | { 117 | const char *p = strstr(str, "\r\n\r\n"); 118 | return p ? p + 4 - str : strlen(str); 119 | } 120 | 121 | bool HasToken(const char *str, const char *substr) 122 | { 123 | size_t len = strlen(substr); 124 | if (!strncmp(str, substr, len) && (!str[len] || str[len]==' ')) { 125 | return true; 126 | } 127 | for (; *str; ++str) { 128 | if (*str==' ' && !strncmp(str+1, substr, len) && (!str[1+len] || str[1+len]==' ')) { 129 | return true; 130 | } 131 | } 132 | return false; 133 | } 134 | 135 | void DecodeEntityReference(TCHAR *str) 136 | { 137 | static const struct { 138 | TCHAR ent; 139 | LPCTSTR ref; 140 | } ENT_REF[] = { 141 | {TEXT('<'), TEXT("lt;")}, 142 | {TEXT('>'), TEXT("gt;")}, 143 | {TEXT('&'), TEXT("amp;")}, 144 | {TEXT('"'), TEXT("quot;")}, 145 | {TEXT('\''), TEXT("apos;")}, 146 | {TEXT('\n'), TEXT("#10;")}, 147 | {TEXT('\r'), TEXT("#13;")}, 148 | }; 149 | TCHAR *p = str; 150 | for (; *str; ++p) { 151 | if ((*p = *str++) == TEXT('&')) { 152 | for (int i = 0; i < _countof(ENT_REF); ++i) { 153 | int len = lstrlen(ENT_REF[i].ref); 154 | if (!StrCmpN(str, ENT_REF[i].ref, len)) { 155 | str += len; 156 | *p = ENT_REF[i].ent; 157 | break; 158 | } 159 | } 160 | } 161 | } 162 | *p = TEXT('\0'); 163 | } 164 | 165 | void EncodeEntityReference(const char *src, char *dest, int destSize) 166 | { 167 | // 切り捨てを防ぐには'&'に対して5倍のバッファを見積もる 168 | dest[0] = '\0'; 169 | for (; *src; ++src) { 170 | char s[2] = {*src}; 171 | const char *p = *s=='<' ? "<" : *s=='>' ? ">" : *s=='&' ? "&" : s; 172 | if (lstrlenA(dest) + lstrlenA(p) >= destSize) { 173 | break; 174 | } 175 | lstrcatA(dest, p); 176 | } 177 | } 178 | 179 | COLORREF GetColor(const char *command) 180 | { 181 | static const std::regex re("(?:^| )#([0-9A-Fa-f]{6})(?: |$)"); 182 | std::cmatch m; 183 | if (std::regex_search(command, m, re)) { 184 | int color = strtol(m[1].first, NULL, 16); 185 | return RGB((color>>16)&0xFF, (color>>8)&0xFF, color&0xFF); 186 | } 187 | for (int i = 0; i < _countof(COMMAND2COLOR); ++i) { 188 | if (HasToken(command, COMMAND2COLOR[i].command)) { 189 | return COMMAND2COLOR[i].color; 190 | } 191 | } 192 | return RGB(0xFF, 0xFF, 0xFF); 193 | } 194 | 195 | bool GetChatDate(unsigned int *tm, const char *tag) 196 | { 197 | // TODO: dateは秒精度しかないので独自に属性値つけるかvposを解釈するとよりよいかも 198 | static const std::regex re("^]*? date=\"(\\d+)\""); 199 | std::cmatch m; 200 | if (std::regex_search(tag, m, re)) { 201 | *tm = strtoul(m[1].first, NULL, 10); 202 | return true; 203 | } 204 | return false; 205 | } 206 | 207 | void UnixTimeToFileTime(unsigned int tm, FILETIME *pft) 208 | { 209 | LONGLONG ll = static_cast(tm) * 10000000 + 116444736000000000; 210 | pft->dwLowDateTime = static_cast(ll); 211 | pft->dwHighDateTime = static_cast(ll >> 32); 212 | } 213 | 214 | unsigned int FileTimeToUnixTime(const FILETIME &ft) 215 | { 216 | LONGLONG ll = (static_cast(ft.dwHighDateTime) << 32) | ft.dwLowDateTime; 217 | return static_cast((ll - 116444736000000000) / 10000000); 218 | } 219 | 220 | FILETIME &operator+=(FILETIME &ft, LONGLONG offset) 221 | { 222 | LONGLONG ll = (static_cast(ft.dwHighDateTime) << 32) | ft.dwLowDateTime; 223 | ll += offset; 224 | ft.dwLowDateTime = static_cast(ll); 225 | ft.dwHighDateTime = static_cast(ll >> 32); 226 | return ft; 227 | } 228 | 229 | LONGLONG operator-(const FILETIME &ft1, const FILETIME &ft2) 230 | { 231 | LONGLONG ll1 = (static_cast(ft1.dwHighDateTime) << 32) | ft1.dwLowDateTime; 232 | LONGLONG ll2 = (static_cast(ft2.dwHighDateTime) << 32) | ft2.dwLowDateTime; 233 | return ll1 - ll2; 234 | } 235 | 236 | // 参考: ARIB STD-B10,TR-B13 237 | static void SplitAribMjd(WORD wAribMjd, WORD *pwYear, WORD *pwMonth, WORD *pwDay, WORD *pwDayOfWeek) 238 | { 239 | // MJD形式の日付を解析する 240 | DWORD dwYd = ((DWORD)wAribMjd * 20 - 301564) / 7305; 241 | DWORD dwMd = ((DWORD)wAribMjd * 10000 - 149561000 - dwYd * 1461 / 4 * 10000) / 306001; 242 | DWORD dwK = dwMd==14 || dwMd==15 ? 1 : 0; 243 | *pwDay = wAribMjd - 14956 - (WORD)(dwYd * 1461 / 4) - (WORD)(dwMd * 306001 / 10000); 244 | *pwYear = (WORD)(dwYd + dwK) + 1900; 245 | *pwMonth = (WORD)(dwMd - 1 - dwK * 12); 246 | *pwDayOfWeek = (wAribMjd + 3) % 7; 247 | } 248 | 249 | bool AribToSystemTime(const BYTE *pData, SYSTEMTIME *pst) 250 | { 251 | if (pData[0]==0xFF && pData[1]==0xFF && pData[2]==0xFF && pData[3]==0xFF && pData[4]==0xFF) { 252 | // 不指定 253 | return false; 254 | } 255 | SplitAribMjd((pData[0]<<8)|pData[1], &pst->wYear, &pst->wMonth, &pst->wDay, &pst->wDayOfWeek); 256 | pst->wHour = (pData[2]>>4) * 10 + (pData[2]&0x0F); 257 | pst->wMinute = (pData[3]>>4) * 10 + (pData[3]&0x0F); 258 | pst->wSecond = (pData[4]>>4) * 10 + (pData[4]&0x0F); 259 | pst->wMilliseconds = 0; 260 | return true; 261 | } 262 | 263 | // FindFirstFile()の結果をstd::vectorで返す 264 | void GetFindFileList(LPCTSTR pattern, std::vector *pList, std::vector *pSortedList) 265 | { 266 | pList->clear(); 267 | WIN32_FIND_DATA findData; 268 | HANDLE hFind = FindFirstFile(pattern, &findData); 269 | if (hFind != INVALID_HANDLE_VALUE) { 270 | do { 271 | pList->push_back(findData); 272 | } while (FindNextFile(hFind, &findData)); 273 | FindClose(hFind); 274 | } 275 | if (pSortedList) { 276 | pSortedList->clear(); 277 | std::vector::iterator it = pList->begin(); 278 | for (; it != pList->end(); ++it) { 279 | pSortedList->push_back(&(*it)); 280 | } 281 | std::sort(pSortedList->begin(), pSortedList->end(), LPWIN32_FIND_DATA_COMPARE()); 282 | } 283 | } 284 | 285 | // ファイルを開くダイアログ 286 | BOOL FileOpenDialog(HWND hwndOwner, LPCTSTR lpstrFilter, LPTSTR lpstrFile, DWORD nMaxFile) 287 | { 288 | OPENFILENAME ofn = {0}; 289 | ofn.lStructSize = sizeof(OPENFILENAME); 290 | ofn.hwndOwner = hwndOwner; 291 | ofn.lpstrFilter = lpstrFilter; 292 | ofn.lpstrTitle = TEXT("ファイルを開く"); 293 | ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR | OFN_EXPLORER; 294 | ofn.lpstrFile = lpstrFile; 295 | ofn.nMaxFile = nMaxFile; 296 | lpstrFile[0] = TEXT('\0'); 297 | return GetOpenFileName(&ofn); 298 | } 299 | 300 | // ローカル形式をタイムシフトする 301 | static bool TxtToLocalFormat(LPCTSTR srcPath, LPCTSTR destPath, unsigned int tmNew) 302 | { 303 | FILE *fpDest = NULL; 304 | FILE *fpSrc; 305 | if (!lstrcmpi(PathFindExtension(srcPath), TEXT(".txt")) && !_tfopen_s(&fpSrc, srcPath, TEXT("r"))) { 306 | const std::regex re("^]*? date=\"(\\d+)\""); 307 | std::cmatch m; 308 | char buf[4096]; 309 | unsigned int tmOld = 0; 310 | while (fgets(buf, _countof(buf), fpSrc)) { 311 | if (std::regex_search(buf, m, re)) { 312 | // chatタグが1行以上見つかれば書き込みを始める 313 | if (!fpDest && _tfopen_s(&fpDest, destPath, TEXT("w"))) { 314 | fpDest = NULL; 315 | break; 316 | } 317 | fwrite(buf, sizeof(char), m[1].first - buf, fpDest); 318 | unsigned int tm = strtoul(m[1].first, NULL, 10); 319 | if (!tmOld) { 320 | tmOld = tm; 321 | } 322 | fprintf(fpDest, "%u", !tmNew ? tm : tm - tmOld + tmNew); 323 | fputs(m[1].second, fpDest); 324 | } 325 | } 326 | fclose(fpSrc); 327 | } 328 | if (fpDest) { 329 | fclose(fpDest); 330 | } 331 | return fpDest != NULL; 332 | } 333 | 334 | static void WriteChatTag(FILE *fpDest, const std::cmatch &m, unsigned int *ptmOld, unsigned int tmNew) 335 | { 336 | fwrite(m[0].first, sizeof(char), m[1].first - m[0].first, fpDest); 337 | unsigned int tm = strtoul(m[1].first, NULL, 10); 338 | if (!*ptmOld) { 339 | *ptmOld = tm; 340 | } 341 | fprintf(fpDest, "%u", !tmNew ? tm : tm - *ptmOld + tmNew); 342 | const char *p = m[1].second; 343 | int len = 0; 344 | for (; p + len < m[0].second; ++len) { 345 | // 改行文字は数値文字参照に置換 346 | if (p[len] == '\n' || p[len] == '\r') { 347 | fwrite(p, sizeof(char), len, fpDest); 348 | fprintf(fpDest, "&#%d;", p[len]); 349 | p += len + 1; 350 | len = -1; 351 | } 352 | } 353 | fwrite(p, sizeof(char), len, fpDest); 354 | fputs("\n", fpDest); 355 | } 356 | 357 | // JikkyoRec.jklをローカル形式に変換する 358 | static bool JklToLocalFormat(LPCTSTR srcPath, LPCTSTR destPath, unsigned int tmNew) 359 | { 360 | FILE *fpDest = NULL; 361 | FILE *fpSrc; 362 | if (!lstrcmpi(PathFindExtension(srcPath), TEXT(".jkl")) && !_tfopen_s(&fpSrc, srcPath, TEXT("rb"))) { 363 | char buf[4096]; 364 | if (fread(buf, sizeof(char), 10, fpSrc) != 10 || memcmp(buf, "]*? date=\"(\\d+)\"[^]*?"); 372 | std::cmatch m; 373 | int bufLen = 0; 374 | unsigned int tmOld = 0; 375 | while ((c = fgetc(fpSrc)) != EOF) { 376 | if (bufLen >= _countof(buf)) { 377 | bufLen = 0; 378 | continue; 379 | } 380 | buf[bufLen++] = static_cast(c); 381 | if (c == '\0') { 382 | if (std::regex_search(buf, m, re)) { 383 | WriteChatTag(fpDest, m, &tmOld, tmNew); 384 | } 385 | bufLen = 0; 386 | } 387 | } 388 | } 389 | fclose(fpSrc); 390 | } 391 | if (fpDest) { 392 | fclose(fpDest); 393 | } 394 | return fpDest != NULL; 395 | } 396 | 397 | // ニコニコ実況コメントビューア.xmlをローカル形式に変換する 398 | static bool XmlToLocalFormat(LPCTSTR srcPath, LPCTSTR destPath, unsigned int tmNew) 399 | { 400 | FILE *fpDest = NULL; 401 | FILE *fpSrc; 402 | if (!lstrcmpi(PathFindExtension(srcPath), TEXT(".xml")) && !_tfopen_s(&fpSrc, srcPath, TEXT("r"))) { 403 | char buf[4096]; 404 | if (!fgets(buf, _countof(buf), fpSrc) || !strstr(buf, "]*? date=\"(\\d+)\"[^]*?"); 408 | std::cmatch m; 409 | char tag[8192]; 410 | tag[0] = '\0'; 411 | unsigned int tmOld = 0; 412 | while (fgets(buf, _countof(buf), fpSrc)) { 413 | if (lstrlenA(buf) >= static_cast(_countof(tag)) - lstrlenA(tag)) { 414 | tag[0] = '\0'; 415 | continue; 416 | } 417 | lstrcatA(tag, buf); 418 | if (std::regex_search(tag, m, re)) { 419 | WriteChatTag(fpDest, m, &tmOld, tmNew); 420 | tag[0] = '\0'; 421 | } 422 | } 423 | } 424 | fclose(fpSrc); 425 | } 426 | if (fpDest) { 427 | fclose(fpDest); 428 | } 429 | return fpDest != NULL; 430 | } 431 | 432 | bool ImportLogfile(LPCTSTR srcPath, LPCTSTR destPath, unsigned int tmNew) 433 | { 434 | return JklToLocalFormat(srcPath, destPath, tmNew) || 435 | XmlToLocalFormat(srcPath, destPath, tmNew) || 436 | TxtToLocalFormat(srcPath, destPath, tmNew); 437 | } 438 | 439 | // 指定プロセスを実行して標準出力の文字列を得る 440 | bool GetProcessOutput(LPTSTR commandLine, LPCTSTR currentDir, char *buf, int bufSize, int timeout) 441 | { 442 | bool bRet = false; 443 | SECURITY_ATTRIBUTES sa; 444 | sa.nLength = sizeof(sa); 445 | sa.lpSecurityDescriptor = NULL; 446 | sa.bInheritHandle = TRUE; 447 | HANDLE hReadPipe, hWritePipe; 448 | if (CreatePipe(&hReadPipe, &hWritePipe, &sa, 0)) { 449 | TCHAR lastDir[MAX_PATH]; 450 | DWORD dwRet; 451 | if (!currentDir || (dwRet = GetCurrentDirectory(MAX_PATH, lastDir)) < MAX_PATH && dwRet && SetCurrentDirectory(currentDir)) { 452 | STARTUPINFO si = {0}; 453 | si.cb = sizeof(si); 454 | si.dwFlags = STARTF_USESTDHANDLES; 455 | si.hStdOutput = hWritePipe; 456 | PROCESS_INFORMATION pi; 457 | if (CreateProcess(NULL, commandLine, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) { 458 | int bufCount = 0; 459 | bool bBreak = false; 460 | bRet = true; 461 | while (!bBreak) { 462 | timeout -= 100; 463 | if (WaitForSingleObject(pi.hProcess, 100) == WAIT_OBJECT_0) { 464 | bBreak = true; 465 | } else if (timeout <= 0) { 466 | bBreak = true; 467 | bRet = false; 468 | } 469 | DWORD avail; 470 | if (PeekNamedPipe(hReadPipe, NULL, 0, NULL, &avail, NULL) && avail != 0) { 471 | if (bufCount + (int)avail >= bufSize) { 472 | bBreak = true; 473 | bRet = false; 474 | } else { 475 | DWORD read; 476 | if (ReadFile(hReadPipe, &buf[bufCount], avail, &read, NULL)) { 477 | bufCount += read; 478 | } 479 | } 480 | } 481 | } 482 | buf[bufCount] = '\0'; 483 | CloseHandle(pi.hThread); 484 | CloseHandle(pi.hProcess); 485 | } 486 | if (currentDir) { 487 | SetCurrentDirectory(lastDir); 488 | } 489 | } 490 | CloseHandle(hWritePipe); 491 | CloseHandle(hReadPipe); 492 | } 493 | return bRet; 494 | } 495 | 496 | // DPAPIでプロテクトされた文字列を復号する 497 | std::string UnprotectDpapiToString(const char *src) 498 | { 499 | std::vector blob; 500 | for (int i = 0;; ++i) { 501 | char c = src[i]; 502 | if ('0' <= c && c <= '9') c -= '0'; 503 | else if ('A' <= c && c <= 'F') c -= 'A' - 10; 504 | else if ('a' <= c && c <= 'f') c -= 'a' - 10; 505 | else break; 506 | 507 | if (i % 2) blob[i / 2] += c; 508 | else blob.push_back(static_cast(c * 16)); 509 | } 510 | DATA_BLOB in, out = {}; 511 | in.cbData = static_cast(blob.size()); 512 | in.pbData = blob.data(); 513 | if (!in.cbData || !CryptUnprotectData(&in, NULL, NULL, NULL, NULL, CRYPTPROTECT_UI_FORBIDDEN, &out) || !out.pbData) { 514 | return ""; 515 | } 516 | std::string ret(reinterpret_cast(out.pbData), out.cbData); 517 | SecureZeroMemory(out.pbData, out.cbData); 518 | LocalFree(out.pbData); 519 | return ret; 520 | } 521 | -------------------------------------------------------------------------------- /Util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define FILETIME_MILLISECOND 10000LL 4 | 5 | TCHAR *NewGetPrivateProfileSection(LPCTSTR lpAppName, LPCTSTR lpFileName); 6 | void GetBufferedProfileString(LPCTSTR lpBuff, LPCTSTR lpKeyName, LPCTSTR lpDefault, LPTSTR lpReturnedString, DWORD nSize); 7 | int GetBufferedProfileInt(LPCTSTR lpBuff, LPCTSTR lpKeyName, int nDefault); 8 | BOOL WritePrivateProfileInt(LPCTSTR lpAppName, LPCTSTR lpKeyName, int value, LPCTSTR lpFileName); 9 | DWORD GetLongModuleFileName(HMODULE hModule, LPTSTR lpFileName, DWORD nSize); 10 | void AppendHttpHeader(char *str, const char *field, const char *value, const char *trail); 11 | size_t FindHttpBody(const char *str); 12 | bool HasToken(const char *str, const char *substr); 13 | void DecodeEntityReference(TCHAR *str); 14 | void EncodeEntityReference(const char *src, char *dest, int destSize); 15 | COLORREF GetColor(const char *command); 16 | bool GetChatDate(unsigned int *tm, const char *tag); 17 | void UnixTimeToFileTime(unsigned int tm, FILETIME *pft); 18 | unsigned int FileTimeToUnixTime(const FILETIME &ft); 19 | FILETIME &operator+=(FILETIME &ft, LONGLONG offset); 20 | LONGLONG operator-(const FILETIME &ft1, const FILETIME &ft2); 21 | bool AribToSystemTime(const BYTE *pData, SYSTEMTIME *pst); 22 | void GetFindFileList(LPCTSTR pattern, std::vector *pList, std::vector *pSortedList = NULL); 23 | BOOL FileOpenDialog(HWND hwndOwner, LPCTSTR lpstrFilter, LPTSTR lpstrFile, DWORD nMaxFile); 24 | bool ImportLogfile(LPCTSTR srcPath, LPCTSTR destPath, unsigned int tmNew); 25 | bool GetProcessOutput(LPTSTR commandLine, LPCTSTR currentDir, char *buf, int bufSize, int timeout = INT_MAX); 26 | std::string UnprotectDpapiToString(const char *src); 27 | 28 | struct LPWIN32_FIND_DATA_COMPARE { 29 | bool operator()(const WIN32_FIND_DATA *l, const WIN32_FIND_DATA *r) { return lstrcmpi(l->cFileName, r->cFileName) < 0; } 30 | }; 31 | 32 | class CCriticalLock 33 | { 34 | public: 35 | CCriticalLock() { InitializeCriticalSection(§ion_); } 36 | ~CCriticalLock() { DeleteCriticalSection(§ion_); } 37 | void Lock() { EnterCriticalSection(§ion_); } 38 | void Unlock() { LeaveCriticalSection(§ion_); } 39 | //CRITICAL_SECTION &GetCriticalSection() { return section_; } 40 | private: 41 | CRITICAL_SECTION section_; 42 | }; 43 | 44 | class CBlockLock 45 | { 46 | public: 47 | CBlockLock(CCriticalLock *pLock) : pLock_(pLock) { pLock_->Lock(); } 48 | ~CBlockLock() { pLock_->Unlock(); } 49 | private: 50 | CCriticalLock *pLock_; 51 | }; 52 | -------------------------------------------------------------------------------- /jkch.sh.txt: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 参考1:「ARIB TR-B14 第七編」 3 | # http://www.arib.or.jp/tyosakenkyu/kikaku_hoso/hoso_gijutsu_number.html 4 | # 参考2:「px-w3pe@ウィキ-TVTestでチャンネルスキャンして得られるBS/CS110用ch2ファイル(中継器番号順定義用)(2012年10月01日予定)」 5 | # http://www22.atwiki.jp/px-w3pe/pages/27.html#Satellite20121001KA 6 | (while read a; do 7 | if [ "$(echo "$a" | cut -f1)" -ge 0 ] ; then 8 | printf "\t{0x%04X%04X, %3d},\n" $(echo "$a" | cut -f3) $(echo "$a" | cut -f2) $(echo "$a" | cut -f1) 9 | fi 10 | # [JKID(-1=未定)] [NetworkID] [ServiceID] [地域名] [事業者名] 11 | done <<'__EOF__' 12 | 1 15 0x0400 関東広域 NHK総合 13 | 2 15 0x0408 関東広域 NHK教育 14 | 4 15 0x0410 関東広域 日本テレビ放送網 15 | 6 15 0x0418 関東広域 TBSテレビ 16 | 8 15 0x0420 関東広域 フジテレビジョン 17 | 5 15 0x0428 関東広域 テレビ朝日 18 | 7 15 0x0430 関東広域 テレビ東京 19 | 231 15 0x0440 関東広域 放送大学学園 20 | 2 15 0x0808 近畿広域 NHK教育 21 | 6 15 0x0810 近畿広域 毎日放送 22 | 5 15 0x0818 近畿広域 朝日放送 23 | 8 15 0x0820 近畿広域 関西テレビ放送 24 | 4 15 0x0828 近畿広域 讀賣テレビ放送 25 | 2 15 0x0C08 中京広域 NHK教育 26 | 8 15 0x0C10 中京広域 東海テレビ放送 27 | 6 15 0x0C18 中京広域 中部日本放送 28 | 5 15 0x0C20 中京広域 名古屋テレビ放送 29 | 4 15 0x0C28 中京広域 中京テレビ放送 30 | 6 15 0x1010 北海道域 北海道放送 31 | 4 15 0x1018 北海道域 札幌テレビ放送 32 | 5 15 0x1020 北海道域 北海道テレビ放送 33 | 8 15 0x1028 北海道域 北海道文化放送 34 | 7 15 0x1030 北海道域 テレビ北海道 35 | 4 15 0x1410 岡山香川 西日本放送 36 | 5 15 0x1418 岡山香川 瀬戸内海放送 37 | 6 15 0x1420 岡山香川 山陽放送 38 | 7 15 0x1428 岡山香川 テレビせとうち 39 | 8 15 0x1430 岡山香川 岡山放送 40 | 8 15 0x1810 島根鳥取 山陰中央テレビジョン放送 41 | 6 15 0x1818 島根鳥取 山陰放送 42 | 4 15 0x1820 島根鳥取 日本海テレビジョン放送 43 | 1 15 0x2800 北海道(札幌) NHK総合 44 | 2 15 0x2808 北海道(札幌) NHK教育 45 | 6 15 0x2810 北海道(札幌) 北海道放送 46 | 4 15 0x2818 北海道(札幌) 札幌テレビ放送 47 | 5 15 0x2820 北海道(札幌) 北海道テレビ放送 48 | 8 15 0x2828 北海道(札幌) 北海道文化放送 49 | 7 15 0x2830 北海道(札幌) テレビ北海道 50 | 1 15 0x2C00 北海道(函館) NHK総合 51 | 2 15 0x2C08 北海道(函館) NHK教育 52 | 6 15 0x2C10 北海道(函館) 北海道放送 53 | 4 15 0x2C18 北海道(函館) 札幌テレビ放送 54 | 5 15 0x2C20 北海道(函館) 北海道テレビ放送 55 | 8 15 0x2C28 北海道(函館) 北海道文化放送 56 | 7 15 0x2C30 北海道(函館) テレビ北海道 57 | 1 15 0x3000 北海道(旭川) NHK総合 58 | 2 15 0x3008 北海道(旭川) NHK教育 59 | 6 15 0x3010 北海道(旭川) 北海道放送 60 | 4 15 0x3018 北海道(旭川) 札幌テレビ放送 61 | 5 15 0x3020 北海道(旭川) 北海道テレビ放送 62 | 8 15 0x3028 北海道(旭川) 北海道文化放送 63 | 7 15 0x3030 北海道(旭川) テレビ北海道 64 | 1 15 0x3400 北海道(帯広) NHK総合 65 | 2 15 0x3408 北海道(帯広) NHK教育 66 | 6 15 0x3410 北海道(帯広) 北海道放送 67 | 4 15 0x3418 北海道(帯広) 札幌テレビ放送 68 | 5 15 0x3420 北海道(帯広) 北海道テレビ放送 69 | 8 15 0x3428 北海道(帯広) 北海道文化放送 70 | 7 15 0x3430 北海道(帯広) テレビ北海道 71 | 1 15 0x3800 北海道(釧路) NHK総合 72 | 2 15 0x3808 北海道(釧路) NHK教育 73 | 6 15 0x3810 北海道(釧路) 北海道放送 74 | 4 15 0x3818 北海道(釧路) 札幌テレビ放送 75 | 5 15 0x3820 北海道(釧路) 北海道テレビ放送 76 | 8 15 0x3828 北海道(釧路) 北海道文化放送 77 | 7 15 0x3830 北海道(釧路) テレビ北海道 78 | 1 15 0x3C00 北海道(北見) NHK総合 79 | 2 15 0x3C08 北海道(北見) NHK教育 80 | 6 15 0x3C10 北海道(北見) 北海道放送 81 | 4 15 0x3C18 北海道(北見) 札幌テレビ放送 82 | 5 15 0x3C20 北海道(北見) 北海道テレビ放送 83 | 8 15 0x3C28 北海道(北見) 北海道文化放送 84 | 7 15 0x3C30 北海道(北見) テレビ北海道 85 | 1 15 0x4000 北海道(室蘭) NHK総合 86 | 2 15 0x4008 北海道(室蘭) NHK教育 87 | 6 15 0x4010 北海道(室蘭) 北海道放送 88 | 4 15 0x4018 北海道(室蘭) 札幌テレビ放送 89 | 5 15 0x4020 北海道(室蘭) 北海道テレビ放送 90 | 8 15 0x4028 北海道(室蘭) 北海道文化放送 91 | 7 15 0x4030 北海道(室蘭) テレビ北海道 92 | 1 15 0x4400 宮城 NHK総合 93 | 2 15 0x4408 宮城 NHK教育 94 | 6 15 0x4410 宮城 東北放送 95 | 8 15 0x4418 宮城 仙台放送 96 | 4 15 0x4420 宮城 宮城テレビ放送 97 | 5 15 0x4428 宮城 東日本放送 98 | 1 15 0x4800 秋田 NHK総合 99 | 2 15 0x4808 秋田 NHK教育 100 | 4 15 0x4810 秋田 秋田放送 101 | 8 15 0x4818 秋田 秋田テレビ 102 | 5 15 0x4820 秋田 秋田朝日放送 103 | 1 15 0x4C00 山形 NHK総合 104 | 2 15 0x4C08 山形 NHK教育 105 | 4 15 0x4C10 山形 山形放送 106 | 5 15 0x4C18 山形 山形テレビ 107 | 6 15 0x4C20 山形 テレビユー山形 108 | 8 15 0x4C28 山形 さくらんぼテレビジョン 109 | 1 15 0x5000 岩手 NHK総合 110 | 2 15 0x5008 岩手 NHK教育 111 | 6 15 0x5010 岩手 アイビーシー岩手放送 112 | 4 15 0x5018 岩手 テレビ岩手 113 | 8 15 0x5020 岩手 岩手めんこいテレビ 114 | 5 15 0x5028 岩手 岩手朝日テレビ 115 | 1 15 0x5400 福島 NHK総合 116 | 2 15 0x5408 福島 NHK教育 117 | 8 15 0x5410 福島 福島テレビ 118 | 4 15 0x5418 福島 福島中央テレビ 119 | 5 15 0x5420 福島 福島放送 120 | 6 15 0x5428 福島 テレビユー福島 121 | 1 15 0x5800 青森 NHK総合 122 | 2 15 0x5808 青森 NHK教育 123 | 4 15 0x5810 青森 青森放送 124 | 6 15 0x5818 青森 青森テレビ 125 | 5 15 0x5820 青森 青森朝日放送 126 | 9 15 0x5C38 東京 東京メトロポリタンテレビジョン 127 | 11 15 0x6038 神奈川 テレビ神奈川 128 | 1 15 0x6400 群馬 NHK総合 129 | -1 15 0x6438 群馬 群馬テレビ 130 | 1 15 0x6800 茨城 NHK総合 131 | 12 15 0x6C38 千葉 千葉テレビ放送 132 | 1 15 0x7000 栃木 NHK総合 133 | -1 15 0x7038 栃木 とちぎテレビ 134 | 10 15 0x7438 埼玉 テレビ埼玉 135 | 1 15 0x7800 長野 NHK総合 136 | 2 15 0x7808 長野 NHK教育 137 | 4 15 0x7810 長野 テレビ信州 138 | 5 15 0x7818 長野 長野朝日放送 139 | 6 15 0x7820 長野 信越放送 140 | 8 15 0x7828 長野 長野放送 141 | 1 15 0x7C00 新潟 NHK総合 142 | 2 15 0x7C08 新潟 NHK教育 143 | 6 15 0x7C10 新潟 新潟放送 144 | 8 15 0x7C18 新潟 新潟総合テレビ 145 | 4 15 0x7C20 新潟 テレビ新潟放送網 146 | 5 15 0x7C28 新潟 新潟テレビ21 147 | 1 15 0x8000 山梨 NHK総合 148 | 2 15 0x8008 山梨 NHK教育 149 | 4 15 0x8010 山梨 山梨放送 150 | 6 15 0x8018 山梨 テレビ山梨 151 | 1 15 0x8400 愛知 NHK総合 152 | 7 15 0x8430 愛知 テレビ愛知 153 | 1 15 0x8800 石川 NHK総合 154 | 2 15 0x8808 石川 NHK教育 155 | 4 15 0x8810 石川 テレビ金沢 156 | 5 15 0x8818 石川 北陸朝日放送 157 | 6 15 0x8820 石川 北陸放送 158 | 8 15 0x8828 石川 石川テレビ放送 159 | 1 15 0x8C00 静岡 NHK総合 160 | 2 15 0x8C08 静岡 NHK教育 161 | 6 15 0x8C10 静岡 静岡放送 162 | 8 15 0x8C18 静岡 テレビ静岡 163 | 4 15 0x8C20 静岡 静岡第一テレビ 164 | 5 15 0x8C28 静岡 静岡朝日テレビ 165 | 1 15 0x9000 福井 NHK総合 166 | 2 15 0x9008 福井 NHK教育 167 | 4 15 0x9010 福井 福井放送 168 | 8 15 0x9018 福井 福井テレビジョン放送 169 | 1 15 0x9400 富山 NHK総合 170 | 2 15 0x9408 富山 NHK教育 171 | 4 15 0x9410 富山 北日本放送 172 | 8 15 0x9418 富山 富山テレビ放送 173 | 6 15 0x9420 富山 チューリップテレビ 174 | 1 15 0x9800 三重 NHK総合 175 | -1 15 0x9830 三重 三重テレビ放送 176 | 1 15 0x9C00 岐阜 NHK総合 177 | -1 15 0x9C30 岐阜 岐阜放送 178 | 1 15 0xA000 大阪 NHK総合 179 | 7 15 0xA030 大阪 テレビ大阪 180 | 1 15 0xA400 京都 NHK総合 181 | -1 15 0xA430 京都 京都放送 182 | 1 15 0xA800 兵庫 NHK総合 183 | -1 15 0xA830 兵庫 サンテレビジョン 184 | 1 15 0xAC00 和歌山 NHK総合 185 | -1 15 0xAC30 和歌山 テレビ和歌山 186 | 1 15 0xB000 奈良 NHK総合 187 | -1 15 0xB030 奈良 奈良テレビ放送 188 | 1 15 0xB400 滋賀 NHK総合 189 | -1 15 0xB430 滋賀 びわ湖放送 190 | 1 15 0xB800 広島 NHK総合 191 | 2 15 0xB808 広島 NHK教育 192 | 6 15 0xB810 広島 中国放送 193 | 4 15 0xB818 広島 広島テレビ放送 194 | 5 15 0xB820 広島 広島ホームテレビ 195 | 8 15 0xB828 広島 テレビ新広島 196 | 1 15 0xBC00 岡山 NHK総合 197 | 2 15 0xBC08 岡山 NHK教育 198 | 1 15 0xC000 島根 NHK総合 199 | 2 15 0xC008 島根 NHK教育 200 | 1 15 0xC400 鳥取 NHK総合 201 | 2 15 0xC408 鳥取 NHK教育 202 | 1 15 0xC800 山口 NHK総合 203 | 2 15 0xC808 山口 NHK教育 204 | 4 15 0xC810 山口 山口放送 205 | 6 15 0xC818 山口 テレビ山口 206 | 5 15 0xC820 山口 山口朝日放送 207 | 1 15 0xCC00 愛媛 NHK総合 208 | 2 15 0xCC08 愛媛 NHK教育 209 | 4 15 0xCC10 愛媛 南海放送 210 | 5 15 0xCC18 愛媛 愛媛朝日テレビ 211 | 6 15 0xCC20 愛媛 あいテレビ 212 | 8 15 0xCC28 愛媛 愛媛放送 213 | 1 15 0xD000 香川 NHK総合 214 | 2 15 0xD008 香川 NHK教育 215 | 1 15 0xD400 徳島 NHK総合 216 | 2 15 0xD408 徳島 NHK教育 217 | 4 15 0xD410 徳島 四国放送 218 | 1 15 0xD800 高知 NHK総合 219 | 2 15 0xD808 高知 NHK教育 220 | 4 15 0xD810 高知 高知放送 221 | 6 15 0xD818 高知 テレビ高知 222 | 8 15 0xD820 高知 高知さんさんテレビ 223 | 1 15 0xDC00 福岡 NHK総合 224 | 1 15 0xDE00 福岡 NHK総合(県複) 225 | 2 15 0xDC08 福岡 NHK教育 226 | 2 15 0xDE08 福岡 NHK教育(県複) 227 | 5 15 0xDC10 福岡 九州朝日放送 228 | 6 15 0xDC18 福岡 アール・ケー・ビー毎日放送 229 | 4 15 0xDC20 福岡 福岡放送 230 | 7 15 0xDC28 福岡 ティー・ヴィ-・キュー九州放送 231 | 8 15 0xDC30 福岡 テレビ西日本 232 | 1 15 0xE000 熊本 NHK総合 233 | 2 15 0xE008 熊本 NHK教育 234 | 6 15 0xE010 熊本 熊本放送 235 | 8 15 0xE018 熊本 テレビ熊本 236 | 4 15 0xE020 熊本 熊本県民テレビ 237 | 5 15 0xE028 熊本 熊本朝日放送 238 | 1 15 0xE400 長崎 NHK総合 239 | 2 15 0xE408 長崎 NHK教育 240 | 6 15 0xE410 長崎 長崎放送 241 | 8 15 0xE418 長崎 テレビ長崎 242 | 5 15 0xE420 長崎 長崎文化放送 243 | 4 15 0xE428 長崎 長崎国際テレビ 244 | 1 15 0xE800 鹿児島 NHK総合 245 | 2 15 0xE808 鹿児島 NHK教育 246 | 6 15 0xE810 鹿児島 南日本放送 247 | 8 15 0xE818 鹿児島 鹿児島テレビ放送 248 | 5 15 0xE820 鹿児島 鹿児島放送 249 | 4 15 0xE828 鹿児島 鹿児島讀賣テレビ 250 | 1 15 0xEC00 宮崎 NHK総合 251 | 2 15 0xEC08 宮崎 NHK教育 252 | 6 15 0xEC10 宮崎 MRT宮崎放送 253 | 8 15 0xEC18 宮崎 UMKテレビ宮崎 254 | 1 15 0xF000 大分 NHK総合 255 | 2 15 0xF008 大分 NHK教育 256 | 6 15 0xF010 大分 大分放送 257 | 4 15 0xF018 大分 テレビ大分 258 | 5 15 0xF020 大分 大分朝日放送 259 | 1 15 0xF400 佐賀 NHK総合 260 | 2 15 0xF408 佐賀 NHK教育 261 | 8 15 0xF410 佐賀 サガテレビ 262 | 1 15 0xF800 沖縄 NHK総合 263 | 2 15 0xF808 沖縄 NHK教育 264 | 6 15 0xF810 沖縄 琉球放送 265 | 5 15 0xF820 沖縄 琉球朝日放送 266 | 8 15 0xF838 沖縄 沖縄テレビ放送 267 | 101 4 101 * NHKBS1 268 | 101 4 102 * NHKBS1 269 | 103 4 103 * NHKBSプレミアム 270 | 103 4 104 * NHKBSプレミアム 271 | 141 4 141 * BS日テレ 272 | 141 4 142 * BS日テレ 273 | 141 4 143 * BS日テレ 274 | 151 4 151 * BS朝日1 275 | 151 4 152 * BS朝日2 276 | 151 4 153 * BS朝日3 277 | 161 4 161 * BS-TBS 278 | 161 4 162 * BS-TBS 279 | 161 4 163 * BS-TBS 280 | 171 4 171 * BSジャパン 281 | 171 4 172 * BSジャパン2 282 | 171 4 173 * BSジャパン3 283 | 181 4 181 * BSフジ・181 284 | 181 4 182 * BSフジ・182 285 | 181 4 183 * BSフジ・183 286 | 191 4 191 * WOWOWプライム 287 | 192 4 192 * WOWOWライブ 288 | 193 4 193 * WOWOWシネマ 289 | 200 4 200 * スター・チャンネル1 290 | 201 4 201 * スター・チャンネル2 291 | 202 4 202 * スター・チャンネル3 292 | 211 4 211 * BS11 293 | 222 4 222 * TwellV 294 | 231 4 231 * 放送大学BS1 295 | 231 4 232 * 放送大学BS2 296 | 231 4 233 * 放送大学BS3 297 | 234 4 234 * グリーンチャンネル 298 | 236 4 236 * BSアニマックス 299 | 238 4 238 * FOXbs238 300 | 241 4 241 * BSスカパー! 301 | 242 4 242 * J SPORTS 1 302 | 243 4 243 * J SPORTS 2 303 | 244 4 244 * J SPORTS 3 304 | 245 4 245 * J SPORTS 4 305 | 251 4 251 * BS釣りビジョン 306 | 252 4 252 * イマジカBS 307 | 255 4 255 * BS日本映画専門ch 308 | 256 4 256 * ディズニーチャンネル 309 | 258 4 258 * Dlife 310 | -1 4 291 * NHK総合1・東京 311 | -1 4 292 * NHKEテレ東京 312 | -1 4 294 * 日テレ1 313 | -1 4 295 * テレビ朝日 314 | -1 4 296 * TBS1 315 | -1 4 297 * テレビ東京1 316 | -1 4 298 * フジテレビ 317 | -1 4 531 * 放送大学ラジオ 318 | -1 4 700 * NHKデータ1 319 | -1 4 701 * NHKデータ2 320 | -1 4 755 * BS朝日データ755 321 | -1 4 778 * BSジャパン778 322 | -1 4 780 * BSフジ・780 323 | -1 4 791 * navi 324 | 910 4 910 * WNI・910 325 | -1 6 55 * ショップチャンネル 326 | -1 7 100 * スカパー!プロモ 327 | -1 7 161 * QVC 328 | -1 6 218 * 東映チャンネル 329 | -1 6 219 * 衛星劇場 330 | -1 7 223 * チャンネルNECO 331 | -1 7 227 * ザ・シネマ 332 | -1 7 229 * FOXムービー 333 | -1 7 240 * ムービープラスHD 334 | -1 7 250 * sky・Aスポーツ+ 335 | -1 7 254 * GAORA 336 | -1 7 257 * 日テレG+ HD 337 | -1 7 262 * ゴルフネットHD 338 | -1 7 290 * SKY STAGE 339 | -1 7 292 * 時代劇専門chHD 340 | -1 7 293 * ファミリー劇場HD 341 | -1 7 294 * ホームドラマCH 342 | -1 6 296 * TBSチャンネル1 343 | -1 7 297 * TBSチャンネル2 344 | -1 6 298 * テレ朝チャンネルHD 345 | -1 6 299 * 朝日ニュースターHD 346 | -1 7 300 * 日テレプラス 347 | -1 7 305 * チャンネル銀河 348 | -1 7 307 * フジテレビONE 349 | -1 7 308 * フジテレビTWO 350 | -1 7 309 * フジテレビNEXT 351 | -1 7 310 * スーパー!ドラマHD 352 | -1 7 311 * AXN 353 | -1 7 312 * FOX 354 | -1 7 314 * 女性ch/LaLa 355 | -1 7 315 * FOXプラス 356 | -1 7 321 * スペシャプラス 357 | -1 7 322 * スペースシャワーTV 358 | -1 7 323 * MTV 359 | -1 7 325 * エムオン!HD 360 | -1 6 326 * ミュージック・エア 361 | -1 7 329 * 歌謡ポップス 362 | -1 7 330 * キッズステーション 363 | -1 7 331 * カートゥーン 364 | -1 7 333 * AT-X 365 | -1 7 334 * ディズニーXD 366 | -1 6 339 * ディズニージュニア 367 | -1 7 340 * ディスカバリー 368 | -1 7 341 * アニマルプラネット 369 | -1 7 342 * ヒストリーチャンネル 370 | -1 7 343 * ナショジオチャンネル 371 | -1 7 350 * 日テレNEWS24 372 | -1 7 351 * TBSニュースバード 373 | -1 7 353 * BBCワールド 374 | -1 7 354 * CNNj 375 | -1 7 362 * 旅チャンネル 376 | -1 7 363 * 囲碁・将棋チャンネル 377 | -1 6 800 * スカチャン0 378 | -1 6 801 * スカチャン1 379 | -1 6 802 * スカチャン2 380 | -1 6 805 * スカチャン3 381 | __EOF__ 382 | ) | sort 383 | 384 | # [ニコニコ実況チャンネルリスト(2013-01-02時点)] 385 | # jk1 = NHK 総合 386 | # jk2 = Eテレ 387 | # jk4 = 日本テレビ 388 | # jk5 = テレビ朝日 389 | # jk6 = TBS テレビ 390 | # jk7 = テレビ東京 391 | # jk8 = フジテレビ 392 | # jk9 = TOKYO MX 393 | # jk10 = テレ玉 394 | # jk11 = tvk 395 | # jk12 = チバテレビ 396 | # jk101 = NHKBS-1 397 | # jk103 = NHK BSプレミアム 398 | # jk141 = BS 日テレ 399 | # jk151 = BS 朝日 400 | # jk161 = BS-TBS 401 | # jk171 = BSジャパン 402 | # jk181 = BSフジ 403 | # jk191 = WOWOWプライム 404 | # jk192 = WOWOWライブ 405 | # jk193 = WOWOWシネマ 406 | # jk200 = スターチャンネル1 407 | # jk201 = スターチャンネル2 408 | # jk202 = スターチャンネル3 409 | # jk211 = BSイレブン 410 | # jk222 = TwellV 411 | # jk231 = 放送大学 412 | # jk234 = BSグリーンチャンネル 413 | # jk236 = BSアニマックス 414 | # jk238 = FOX bs 238 415 | # jk241 = BSスカパー! 416 | # jk242 = J Sports 1 417 | # jk243 = J Sports 2 418 | # jk244 = J Sports 3 419 | # jk245 = J Sports 4 420 | # jk251 = BS釣りビジョン 421 | # jk252 = IMAGICA BS 422 | # jk255 = BS日本映画専門チャンネル 423 | # jk256 = ディズニー・チャンネル 424 | # jk258 = Dlife 425 | # jk910 = SOLiVE24 426 | -------------------------------------------------------------------------------- /resource.h: -------------------------------------------------------------------------------- 1 | #ifndef IDC_STATIC 2 | #define IDC_STATIC (-1) 3 | #endif 4 | 5 | #define IDD_FORCE 101 6 | #define IDC_RADIO_FORCE 1000 7 | #define IDC_RADIO_LOG 1001 8 | #define IDC_CHECK_SPECFILE 1002 9 | #define IDC_CHECK_RELATIVE 1003 10 | #define IDC_FORCELIST 1004 11 | #define IDC_CB_POST 1005 12 | #define IDC_SLIDER_OPACITY 1006 13 | -------------------------------------------------------------------------------- /stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : 標準インクルード NicoJK.pch のみを 2 | // 含むソース ファイルは、プリコンパイル済みヘッダーになります。 3 | // stdafx.obj にはプリコンパイル済み型情報が含まれます。 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: このファイルではなく、STDAFX.H で必要な 8 | // 追加ヘッダーを参照してください。 9 | -------------------------------------------------------------------------------- /stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : 標準のシステム インクルード ファイルのインクルード ファイル、または 2 | // 参照回数が多く、かつあまり変更されない、プロジェクト専用のインクルード ファイル 3 | // を記述します。 4 | // 5 | 6 | #pragma once 7 | 8 | #ifndef WINVER 9 | #define WINVER 0x0501 // Windows XP 10 | #endif 11 | 12 | #ifndef _WIN32_WINNT 13 | #define _WIN32_WINNT 0x0501 // Windows XP 14 | #endif 15 | 16 | #ifndef _WIN32_IE 17 | #define _WIN32_IE 0x0600 // Internet Explorer 6.0 18 | #endif 19 | 20 | #define WIN32_LEAN_AND_MEAN 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #pragma comment(lib, "ws2_32.lib") 38 | #pragma comment(lib, "winmm.lib") 39 | #pragma comment(lib, "shlwapi.lib") 40 | #pragma comment(lib, "gdiplus.lib") 41 | #pragma comment(lib, "dwmapi.lib") 42 | #pragma comment(lib, "imm32.lib") 43 | #pragma comment(lib, "crypt32.lib") 44 | --------------------------------------------------------------------------------