71707


マルチバイト文字セットで作成したMFCアプリで  
<http://7ujm.net/C++/MFC%20ODBC.html>  
上記のようなプログラムで、ODBC接続してNVARCHARA(unicode）の文字列を取得しようとしています。  
特に問題なく、アプリ上で取得して表示できているのですが、  
MFCもしくはODBC側でShift-jisに変換しているのでしょうか？  
また変換されている場合、変換のON/OFFの切り替えはどこで行うのでしょうか？


CC BY-SA 4.0
2020-10-30T11:15:48.133
71623
2020-11-04T05:33:29.310
2020-11-03T01:48:49.160
31497
31497
question
mfc
MFCアプリ（マルチバイト文字セットで作成）からNvarcharのカラムのデータを取得時について


MFCおよびODBCではクエリ結果を変換していないことを確認しました。

  * Visual Studio 2019 
    * Unicode
    * Multi-Byte
  * ドライバ 
    * Microsoft SQL Server ODBC ドライバー Version 10.00.19041
    * Microsoft ODBC Driver for SQL Server Version 13.00.0811
    * Microsoft ODBC Driver for SQL Server Version 17.05.0001
    * Microsoft SQL Server Native Client Version 11.00.7462
  * データ型 
    * `varchar(50)`
    * `nvarchar(50)`

これらの組み合わせで確認しましたが、いずれにおいても、

  * `varchar(50)`
    * `CRecordset::GetODBCFieldInfo()` によるカラム型： `SQL_VARCHAR`
    * `CDBVariant` のデータ型： `DBVT_ASTRING`
  * `nvarchar(50)`
    * `CRecordset::GetODBCFieldInfo()` によるカラム型： `SQL_WVARCHAR`
    * `CDBVariant` のデータ型： `DBVT_WSTRING`

が得られました。質問文で提示されたサイトでは`CDBVariant` のデータ型として `DBVT_STRING`
を処理していますが、そもそもこのデータ型が返されることがありませんでした。

というわけで、受け取ったデータを`CString`で扱っているうちに変換していると思われます。

* * *

kunifさんが答えられていますが、[`CRecordset::GetFieldValue()`](https://docs.microsoft.com/en-
us/cpp/mfc/reference/crecordset-class?view=msvc-160#getfieldvalue)のオーバーロードのうち

  * `CString` / `CStringA` / `CStringW` を渡すものは、指定された形式に変換された文字列を得ることができる
  * `CDBVariant` を渡すものは、`nFieldType`で受け取る形式を指定できる 
    * 更にデフォルトの`DEFAULT_FIELD_TYPE`を使用するとカラムのデータ形式そのままの文字列を得ることができる

となります。ですので

> 変換のON/OFFの切り替えはどこで行う

  * Multi-Byte / Unicode特定の型に変換された文字列を取得したい場合 
    * `CString` / `CStringA` / `CStringW` を渡す
    * `CDBVariant` を渡しつつ、`nFieldType`を指定する
  * カラムのデータ形式そのままの文字列を取得したい場合 
    * `CDBVariant` を渡しつつ、`nFieldType`として`DEFAULT_FIELD_TYPE`を指定する

となるかと思います。

* * *

Visual Studio 2003までさかのぼると、`DBVT_ASTRING` / `DBVT_WSTRING`が存在しなかったようですが…。


CC BY-SA 4.0
2020-10-30T12:21:56.497
71624
2020-11-04T05:33:29.310
2020-11-04T05:33:29.310
4236
4236
71623
answer


フィールドデータ取得のために指定した変数の型に応じて変換されているのではないでしょうか？

参照先で「NVARCHARA(unicode）の文字列を取得」しているのはこの部分だと思われますが、  
DBアクセス変数定義：

>
[code]

>     //実行
>     CRecordset rs( &db );
>  
[/code]

途中省略して以下が値取得：

>
[code]

>     //値を表示
>     while( !rs.IsEOF() )
>     {
>         for(short index = 0; index < rs.GetODBCFieldCount(); index++ )   {
>             CString strValue;
>             rs.GetFieldValue( index, _T( strValue ) );
>             TRACE("%s\n",strValue);
>         }
>         rs.MoveNext();
>     }
>  
[/code]

`GetFieldValue`仕様のドキュメントでは以下のようになっていて、UNICODE(CStringW), Shift-
jisというかANSI(CStringA)の両方サポートされています。

[CRecordset:: GetFieldValue](https://docs.microsoft.com/ja-
jp/cpp/mfc/reference/crecordset-class?view=msvc-160#crecordsetgetfieldvalue)

>
[code]

>     void GetFieldValue(
>         short nIndex,
>         CStringA& strValue);
>  
>     void GetFieldValue(
>         short nIndex,
>         CStringW& strValue);
>  
>     nIndex
>     フィールドの0から始まるインデックス。
>  
>     strValue
>     フィールドのデータ型に関係なく、テキストに変換されたフィールドの値を格納するCStringオブジェクトへの参照。
>  
[/code]

MFCの`CString`型は、末尾の`A`,`W`が指定されていなければコンパイル時の`UNICODE`,`MBCS`マクロ指定の有無に応じて置換されるはずです。

[CString の使用](https://docs.microsoft.com/ja-jp/cpp/atl-mfc-shared/using-
cstring?view=msvc-160)

> オブジェクトは、 CString char wchar_t MBCS シンボルまたは UNICODE
> シンボルがコンパイル時に定義されているかどうかに応じて、型または型のいずれかをサポートします。

[CStringAクラス、CStringWクラス、CString クラス](http://hp30.blog.fc2.com/blog-
entry-8.html)

>
> CStringクラスはプロジェクトの文字セットがマルチバイト文字セットのときはCStringA、Unicode文字セットのときはCStringWにおきかえられるようになっている。
[code]

>     #ifdef _UNICODE
>     typedef CStringW CString;
>     #else
>     typedef CStringA CString;
>     #endif
>  
[/code]

* * *

なので、取得したデータを格納するためのパラメータ変数を、明示的に`CStringA`, `CStringW`で宣言し、`GetFieldValue(
index, _T( strValue ) );`呼び出し時の`_T( )`マクロを外して(?)、`GetFieldValue( index,
strValue );`のようにすれば、取得するデータのShift-jis/Unicode切り替えが明示的に出来るのではないでしょうか？

**試してみてください。**


CC BY-SA 4.0
2020-11-04T01:59:36.430
71707
2020-11-04T01:59:36.430
26370
71623
answer