山本ワールド
Windowsプログラミング
アルゴリズム Vitual C++ 2008/2013によるWin32/Win64 APIレベルのプログラム 基礎 Vitual C++ 2008/2013によるAPIレベルのプログラム(32/64bit) Wix3でインストーラーを作る Visual C++ 2008 Standard Editonによるフォームアプリケーションのプログラム(32/64bit) Vitual C++ 2008 Standard EditonによるAPIレベルのプログラム(32/64bit) Windows 7対応 Visual C++ 2008 ExpressによるAPIレベルのプログラム Visual C++ 2005 ExpressによるAPIレベルのプログラム Visual C++ Versiosn 5 BORLAND C++ Windowsプログラム全般 Excel VBA その他インターネットよりファイルを1行ずつ読み出しEUC文字列をUNICODE又はSJISに変換してファイルへ保存する
概要
指定したURLのファイルをインターネットから1行ずつ取得しEUC文字列をUNICODEでコンパイルした場合はUNICODE、マルチバイトでコンパイルした場合はSJISに変換してファイルに保存します。
EUCはExtended UNIX Code Packed Format for Japaneseの略であり名称の通り昔UnixやLinux等で広く使われた文字コードです。
現在はUTF-8を使用している例が多いようです。
半角文字コードの0x00~0x7fまではANSI文字列と同一であり、0x80~0xffの場合、漢字の1バイト目、2バイト目であることを示します。さらに0x8fの場合は、補助漢字を示し次の2バイト目、3バイト目が文字コードを文字コードとなります。
漢字の文字コードはJISコードをシフトさせたものとなりますのでJISとの親和性は高いものとなります。
EUCで保存されたファイルをメモ帳で開くと文字化けのオンパレードとなります。
本プログラムの使用方法はコマンドプロンプトを実行し、以下のように入力します。
以下の場合、私のホームページのEUC文字列を含むeuc.htmlをファイルtest.htmlに保存します。
WININETは1行ずつの読み込みに対応していないので、バッファリングと1行読み込みをサポートしたクラスを作成しています。
EUC文字列は一度UNICODEに変換します。MultiByteToWideChar APIはEUC文字列をUNICODEに変換できなかったので、IEの一部であるMLANG.DLL(IE5.5以上が対象なのでWindows 95以上)に含まれるConvertINetMultiByteToUnicodeを用います。
このConvertINetMultiByteToUnicodeは、EUC以外の文字コードをUNICODEに変換することができます。
Visual C++ 2008/2013をインストールした状態では、MLANG.DLL用のライブライファイルが存在しません。ここでは、動的リンクでConvertINetMultiByteToUnicodeを呼び出します。
静的にリンクしたい場合は、DLLファイルからLIBファイルを作成する(_stdcall宣言)を参照してLIBファイルを作成してリンクしてください。
EUCはExtended UNIX Code Packed Format for Japaneseの略であり名称の通り昔UnixやLinux等で広く使われた文字コードです。
現在はUTF-8を使用している例が多いようです。
半角文字コードの0x00~0x7fまではANSI文字列と同一であり、0x80~0xffの場合、漢字の1バイト目、2バイト目であることを示します。さらに0x8fの場合は、補助漢字を示し次の2バイト目、3バイト目が文字コードを文字コードとなります。
漢字の文字コードはJISコードをシフトさせたものとなりますのでJISとの親和性は高いものとなります。
EUCで保存されたファイルをメモ帳で開くと文字化けのオンパレードとなります。
本プログラムの使用方法はコマンドプロンプトを実行し、以下のように入力します。
以下の場合、私のホームページのEUC文字列を含むeuc.htmlをファイルtest.htmlに保存します。
wgeteuc http://yamatyuu.net/computer/html/charset/euc.html test.htmlインターネットからの読み込みにはWININETを使用しています。
WININETは1行ずつの読み込みに対応していないので、バッファリングと1行読み込みをサポートしたクラスを作成しています。
EUC文字列は一度UNICODEに変換します。MultiByteToWideChar APIはEUC文字列をUNICODEに変換できなかったので、IEの一部であるMLANG.DLL(IE5.5以上が対象なのでWindows 95以上)に含まれるConvertINetMultiByteToUnicodeを用います。
このConvertINetMultiByteToUnicodeは、EUC以外の文字コードをUNICODEに変換することができます。
Visual C++ 2008/2013をインストールした状態では、MLANG.DLL用のライブライファイルが存在しません。ここでは、動的リンクでConvertINetMultiByteToUnicodeを呼び出します。
静的にリンクしたい場合は、DLLファイルからLIBファイルを作成する(_stdcall宣言)を参照してLIBファイルを作成してリンクしてください。
テスト環境
コンパイラ
Visual C++ 2008 Standard 32/64bitVisual C++ 2013 Express 32/64bit
プロジェクトの作成
Win32プロジェクト Windowsコンソールアプリケーション実行環境
Windows 8.1 Enterprise 64bitWindows 7 EnterPrise Service Pack 1 64bit
Windows Vista Ultimate Service Pack 2 32bit
Windows XP Professional Service Pack 3 32bit
プログラムソースの概要
_tmain
UNICODE文字を標準エラー出力に正しく表示させるために_tsetlocale関数によりロケールを設定します。 webEucTextGet関数で使用するConvertINetMultiByteToUnicode APIを動的にリンクして使用するために、LoadLibrary APIを用いてmlang.dllをロードします。次にGetProcAddress APIを用いてConvertINetMultiByteToUnicode APIのアドレスを取得しグローバル変数に格納します。
InternetOpen APIによりインタネットハンドルを取得します。
APIが0を返した場合は、インタネットハンドルを取得できなかったので 標準エラー出力にエラーメッセージを表示しプログラムを終了させます。
_tfopen_sにより取得したデータを保存するためのファイルを書き込みでバイナリモードで開きファイルハンドルを取得します。
ファイルが開けなかった場合は、InternetCloseHandle APIによりインターネットハンドルを閉じて 標準エラー出力にエラーメッセージを表示しプログラムを終了させます。
webEucTextGet関数によりインタネット上のファイルを読み取り、ファイルに保存します。
InternetCloseHandle APIによりインターネットハンドルを閉じます。
fclose関数によりファイルハンドルを閉じます。
webEucTextGet
行単位での入力が可能なようにINETクラスを作成し、メンバー関数openで指定URLをオープンしハンドルを取得します。オープンできなかった場合は、関数を終了します。
INETクラスgetsメンバー関数で1行を取得します。
ConvertINetMultiByteToUnicode APIによりEUC文字列をUNICODE文字列に変換します。
マルチバイトでコンパイルされている場合は、WideCharToMultiByte APIによりUNICODE文字列をSJIS文字列に変換します。
_ftprintf関数でファイルに書き込みます。
読み込める行がなくなるまで、繰り返します。
INETクラス
inet.hで定義されています。WININETは行単位の入力をサポートしていないので、クラス内でバッファリングを行い、 getsメンバー関数により行単位を要求された場合、バッファ内の行部分をコピーして返します。バッファが空になったらバッファサイズ分読み込みを行います。
¥nか¥rが行末であると解釈して処理を行います。
プログラムソース
wgeteuc.cpp
// インターネットより指定したurlを読み出しEUC文字をUNICODE又はSJISに変換して指定したファイルへ保存します。
// Visual C++ 2008/2013 Unicode/マルチバイト
#include <windows.h>
#include <stdio.h>
#include <wininet.h>
#include <tchar.h>
#include <locale.h>
#include "inet.h"
#pragma comment(lib,"wininet.lib")
typedef HRESULT (WINAPI *ConvertINetMultiByteToUnicode_p)(LPDWORD , DWORD , LPCSTR , LPINT , LPWSTR , LPINT );
ConvertINetMultiByteToUnicode_p ConvertINetMultiByteToUnicode=0;
// 指定したURLのEUCテキストをUNICODEまたはSJISに変換して指定ファイルに保存する
int webEucTextGet(HINTERNET hInet, TCHAR* url, FILE* fp);
int _tmain(int argc,TCHAR** argv){
HMODULE hMod;
// UNICODE文字を標準エラー出力に正しく表示させるためにロケールを設定
_tsetlocale(LC_ALL, _TEXT(""));
if (argc != 3){
_tprintf(_TEXT("使用方法¥nwgeteuc [url] [保存ファイル名]¥n"));
return 1;
}
hMod = LoadLibrary(_TEXT("mlang.dll")); // 文字コード変換用のDLLをロード
if (hMod==0){
perror("MLANG.DLLがロードできません¥n");
return 1;
}
::ConvertINetMultiByteToUnicode = (ConvertINetMultiByteToUnicode_p)GetProcAddress(hMod, "ConvertINetMultiByteToUnicode");
HINTERNET hInet;
//インターネット(WinInet)開始
hInet = InternetOpen(TEXT("wxz123"),
INTERNET_OPEN_TYPE_PRECONFIG,
NULL, NULL, 0);
if (hInet == NULL) {
FreeLibrary(hMod);
perror("オープンエラー¥n");
return 2;
}
FILE* fp;
#ifdef _UNICODE
_tfopen_s(&fp, argv[2], _TEXT("w,ccs=UNICODE"));
#else
_tfopen_s(&fp, argv[2], _TEXT("w"));
#endif
webEucTextGet(hInet,argv[1],fp);
fclose(fp);
InternetCloseHandle(hInet);
FreeLibrary(hMod);
}
// 指定したURLのEUCテキストをUNICODEまたはSJISに変換して指定ファイルに保存する
int webEucTextGet(HINTERNET hInet, TCHAR* url, FILE* fp){
HINTERNET h;
INET inet(hInet);
h = inet.open(url);
if (h == 0)
return -1;
char src[1024];
int size = 0;
while (inet.gets(src, sizeof(src))){
WCHAR utf16[1024];
DWORD mode;
TCHAR* dtc;
int len = sizeof(utf16) / sizeof(WCHAR);
// EUCをUNICODEに変換
ConvertINetMultiByteToUnicode(&mode, 51932, src, 0, utf16, &len);
utf16[len] = 0;
#ifdef _UNICODE
dtc = utf16;
#else
char sjis[1024]; // UNICODEをSJISに変換
WideCharToMultiByte(932, 0, utf16, -1, sjis, sizeof(sjis), NULL, NULL);
dtc = sjis;
#endif
size += len;
_ftprintf(fp, _TEXT("%s¥n"), dtc);
}
return size;
}
inet.h
#ifndef INET_H
// インターネットから1行ずつ読み取るクラス
#define INET_H 0x3000
#define INET_BUF_SIZE_DEF 65536
#include <stdio.h>
#include <time.h>
#include <windows.h>
#include <wininet.h>
#include <assert.h>
#include <TCHAR.H>
class INET{
HINTERNET hInet;
HINTERNET hUrl;
char* buf; // 読み取りバッファ(文字コード変換なし)
unsigned p; // バッファ内の位置
DWORD len; // バッファの有効データー数
int wpos;
int n; // バッファ内の読み出し可能先頭位置
int INET_BUF_SIZE;
bool new_mem_f;
public:
UINT64 total_read;
void init(HINTERNET h,void* bp,int sz){
hInet=h;
hUrl=0;
p=len=0;
INET_BUF_SIZE=sz;
buf=(char*)bp;
new_mem_f=false;
}
INET(){
hInet=0;
hUrl=0;
p=len=0;
INET_BUF_SIZE=0;
buf=0;
new_mem_f=false;
total_read=0;
}
INET(HINTERNET h){
hInet=h;
hUrl=0;
p=len=0;
INET_BUF_SIZE=INET_BUF_SIZE_DEF;
buf=new char[INET_BUF_SIZE+1];
new_mem_f=true;
}
INET(HINTERNET h,int sz){
hInet=h;
hUrl=0;
p=len=0;
INET_BUF_SIZE=sz;
buf=new char[INET_BUF_SIZE];
new_mem_f=true;
}
HINTERNET open(TCHAR* url){
wpos=0;
n=0;
return hUrl=InternetOpenUrl(hInet, url, NULL, 0, INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_RELOAD, 0);
}
int read(char* buf,int max){
int len;
InternetReadFile(hUrl, buf, max - 1, (LPDWORD)&len);
total_read += len;
return len;
}
char* gets(char* b,int max){ // 1行分取得 改行コードを除去する
int i=0;
for(;;){
if(p==0 || len==0){ // バッファ内に有効データーがないのでサイトから読み取る
len=read(buf,INET_BUF_SIZE);
}
if(len==0){
return 0;
}
for(;p<len;p++){
if(i==max-1){
b[i]='¥0';
return b;
}
if(buf[p]=='¥n' || buf[p]=='¥r'){
b[i]='¥0';
++p;
return b;
}else{
b[i++]=buf[p];
}
}
p=0;
}
}
void close(void){
if(hUrl)
InternetCloseHandle(hUrl);
hUrl=0;
}
~INET(){
if(hUrl)
InternetCloseHandle(hUrl);
if(new_mem_f==true && buf)
delete buf;
INET_BUF_SIZE=0;
}
};
#endif
ソースファイルと実行ファイルのダウンロード
Copyright (C) 2012 山本ワールド All Rights Reserved.