C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

C入門

[トピック内 23 記事 (1 - 20 表示)]  << 0 | 1 >>

■86095 / inTopicNo.1)  C入門
  
□投稿者/ masa (10回)-(2017/12/18(Mon) 14:02:17)

分類:[C/C++] 

当方、VB系の経験しかなくC系の学習(特にデータ型)をする必要があると
感じています。まったく無知な発言があるかもしれませんが御容赦を。
以下に疑問に思う点を列挙しますのでどれか一つでも結構ですので
御助言いただけないでしょうか?

(1)C系の学習を始めるのにCやC++のどの言語がお勧ですか?
無償環境を整えることも含めてVisual Studio 2017 Community(無償)
をインストールすればよいですか?
2013の頃、一度インストールしましたが、動作が重く、以来Visual Studio
を起動しようという気になれません。
そこまで深く掘り下げる気はなくデータ型について理解が深まればと思っています。
VBの経験は30年以上になります。(一般職なので実質は5年位です)

(2)Cのデーター型一覧が載っているURL又は、書籍があれば教えてください。
Cのデーター型、サイズが理解できていない為、Cで作成された関数をコール
する場合、VBにないデーター型は、サイズが同じ類似の型で代用するわけですが、
これを調査するのにいつも苦労しています。


(3)例えばVBからWin32APIをコールする場合、構造体とそのサイズを引数にとる関数が
結構あります。VB側ではサイズとアライメントを合わせる為、パッキング指定します。
C言語の理解不足の為、いつも1,4,8と適当に指定して動作すればOKにしています。
ヘッダーファイルで冒頭に#include <pshpack1.h>とあったりすればいいのですが、
まったくない場合もあります。既定値が4であることは承知しております。
どのように調査すれば良いのでしょうか?

(4)以下のVARIANT構造体について具体例でお聞きします。
https://msdn.microsoft.com/ja-jp/library/ms931135.aspx

全体で16バイトらしいのですがどこを調査すれば解るのでしょうか?
まずいきなり先頭のVARTYPEが2バイトというのが解りません。
VBAで同じ名前の関数がIntegerの戻り値なので何となく「ああそうなんだ」と言う程度です。
https://msdn.microsoft.com/ja-jp/vba/language-reference-vba/articles/vartype-function
続く6バイトの予約領域のunsigned shortは英単語から想像できます。
続く共用体の8バイトについても何故8バイトなのか解りません。
union共用体についてはWeb検索で理解できました。
64bitシステムでポインタを表すには8バイト必要だからと思いますが、
リファレンス元が解りません。

引用返信 編集キー/
■86097 / inTopicNo.2)  Re[1]: C入門
□投稿者/ ぶなっぷ (151回)-(2017/12/18(Mon) 15:31:54)
いきなりC系言語だときついので、まずはVB.NETをやられたらどうでしょう。
VB.NETが理解できたら、VB.NETとC#は方言みたいなものなので、
すんなりC#に移行できるかと思います。

引用返信 編集キー/
■86099 / inTopicNo.3)  Re[2]: C入門
□投稿者/ masa (12回)-(2017/12/18(Mon) 15:47:57)
No86097 (ぶなっぷ さん) に返信
返信ありがとうございます。

VB.NETは2005の頃から10年以上利用していて一通りの事は理解しています。
C#は文法の差こそあれVB.NETとほぼ同じなので、コード見れば内容は理解できます。
C#ではなくC/C++をターゲットにしています。

引用返信 編集キー/
■86100 / inTopicNo.4)  Re[1]: C入門
□投稿者/ 774RR (580回)-(2017/12/18(Mon) 15:51:32)
えっと、そういう内容は決して入門レベルではないです。特定処理系の独自仕様の話は高度な部類に入ります。
入門書には「特定処理系固有の話」は出てないのが普通。

んで、質問内容から言って Windows における manage/native の marshalling の話っすよね?
そういうのは Windows 固有のお話なので権威あるリファレンスは MSDN しかありません。

2.MSDN ページ内の検索ボックスから unsigned short を引くと
https://msdn.microsoft.com/ja-jp/library/s3f49ktz.aspx

基本型を組み合わせて struct/class にする場合には padding があります。よって struct のサイズは
メンバのサイズの和にはなりません。その辺は理解しておかないと DllImport はできないです。

4. VARTYPE
オイラがこういうのを探すとしたら直接 Visual C/C++ の include ディレクトリで grep しちゃいます。が、
ネットで検索して C/C++ の情報を一発ヒットさせるのであれば例えば google 様で
VARTYPE include Visualc
などとキーワードを与えることでしょう。すると
https://msdn.microsoft.com/ja-jp/library/windows/desktop/ms221127(v=vs.85).aspx
とかヒットしたり、この ja-jp を us-en に代えたりとか。

すると typedef unsigned short VARTYPE; であることがわかったので
先のページからサイズは 16bit と判断することができます。

あと提示の VARIANT 型の説明はちょっと古いので参照するならこっち。
https://msdn.microsoft.com/en-us/library/windows/desktop/ms221627(v=vs.85).aspx
によると union の中に long long が入っているので union 部は 64bit とわかったりします。
(Windows 64bit ではポインタが 64bit ですし、その辺からも判断できます)

3.オイラも考えるのめんどくさいので Win32 API などを呼ぶなら
http://www.pinvoke.net/
からそのまま戴いたりしますな。

1.やっぱり「入門なら」 Visual Studio で良いのでは?重いのは仕方ないっつか。
重いのがイヤなら使い慣れたエディタ+コマンドラインコンパイラとか(そういうのがあれば)。
VB から marshal するだけなら http://www.pinvoke.net みてコピペするだけっす。
Visual C++ を起動するまでも無くて VB 環境の中からできるはず。

引用返信 編集キー/
■86101 / inTopicNo.5)  Re[2]: C入門
□投稿者/ masa (13回)-(2017/12/18(Mon) 16:15:19)
No86100 (774RR さん) に返信
774RR さん、前回に引き続き回答、ありがとうございます。
一旦、解決後にレスを付けていただいたお陰で、理解が一層深まりました。
この場を借りて、お礼申し上げます。

さて、表題の件ですがおっしゃる通りVBからのマーシャリングに関する事でCの知識
を深めたいと思っています。
書かれた内容やURLを十分精査させていただきます。

引用返信 編集キー/
■86102 / inTopicNo.6)  Re[3]: C入門
□投稿者/ ぶなっぷ (152回)-(2017/12/18(Mon) 16:30:21)
失礼しました、ターゲットはC/C++言語ということですね。

>(4)以下のVARIANT構造体について具体例でお聞きします。
>https://msdn.microsoft.com/ja-jp/library/ms931135.aspx
>
>全体で16バイトらしいのですがどこを調査すれば解るのでしょうか?
>まずいきなり先頭のVARTYPEが2バイトというのが解りません。

これについては、リンク先のページの下の方に行くと、
「Header file: Declared in Oaidl.h」
と書かれているかと思います。

なので、C/C++プロジェクト(C++/CLIでも良い)において、
  #include "Oaidl.h"
として、
どこかの関数内で、
  VARTYPE
と記述します。
その上で、VARTYPEの上にマウスカーソルを持っていって、
「宣言へ移動」を選択します。
すると、以下の定義であることが分かります。
  typedef unsigned short VARTYPE;
つまり、VARTYPEの実体は、unsigned shortであることが分かります。
よって、2バイトとなります。

次に全体で16バイトの件ですが、まず先頭の4フィールドで、
 VARTYPE vt;
 unsigned short wReserved1;
 unsigned short wReserved2;
 unsigned short wReserved3;
8バイトなのは分かるかと思います。
その後にunionというのがありますが、これは共用体といって、
全てのメンバでメモリを共用します。
なので、サイズは最大サイズのメンバに合わさります。
最大サイズのメンバは、
  double dblVal;
なので、8バイトです。

よって、合わせて16バイトです。

引用返信 編集キー/
■86103 / inTopicNo.7)  Re[4]: C入門
□投稿者/ ぶなっぷ (153回)-(2017/12/18(Mon) 16:42:08)
もっと、楽な方法として、

#include "Oaidl.h"
して、
関数内に以下のように記述し、
  size_t size = sizeof(VARIANT);
デバッガでsizeの値を参照すれば16と表示されます。

引用返信 編集キー/
■86104 / inTopicNo.8)  Re[5]: C入門
□投稿者/ とっちゃん (479回)-(2017/12/18(Mon) 17:59:30)
いろいろ細かいところは774RRさんが指摘しているので全部割愛。

ほしいのは、P/Invokeを効率よく書くにはどうすればいいか?という次元ですよね。
では、その手の情報をどうやって集め、どういう形で定義を盛り込んでいくか?ですが。。。

まずは、WindowsSDK(Native)をインストールします。
今なら、Visual Studio 2017(Communityでもいいし、ライセンスがあるならProやそれ以上のエディションでもいい)を
インストールしそこでC++のデスクトップ開発用のオプションをセットします。

これで、C++的な情報を集める環境が整います(利用に際して重いという場合は、マシンスペックを上げることを検討してください)。


あとは、知りたい構造体を、ヘッダーファイルからひたすら検索。
現在のWindows10のSDKをインストールすると
C:\Program Files (x86)\Windows Kits\10\Include に
各バージョンごとのNativeヘッダーがインストールされます。

私個人の環境だと
"C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0"
"C:\Program Files (x86)\Windows Kits\10\Include\10.0.14393.0"
"C:\Program Files (x86)\Windows Kits\10\Include\10.0.15063.0"
"C:\Program Files (x86)\Windows Kits\10\Include\10.0.16299.0"
の4つのバージョンが入っています。

これらのどこか(内容はほとんど一緒)を対象に、VARIANT で検索すると定義を探せます。

ちなみに、VARIANTの定義は、OAIdl.hにあり
https://msdn.microsoft.com/en-us/library/windows/desktop/ms221627(v=vs.85).aspx
と同じ内容です。

もちろん、ぶなっぷさんが書いているように、プロジェクトを作ってビルドしてみるという
やり方でもOKです。

その場合は、定義なども検索ではなく、VSの機能で定義に移動ということができるので
かなり効率よく探すことができます。

ちなみに。。。VARIANTの構造体サイズは16ではなく、環境依存です。
具体的には WORD*4 + sizeof(ポインタ)*2 という構造で
32bitなら16、64bitなら24になります。

引用返信 編集キー/
■86106 / inTopicNo.9)  Re[1]: C入門
□投稿者/ 魔界の仮面弁士 (1511回)-(2017/12/18(Mon) 19:02:31)
2017/12/18(Mon) 19:18:18 編集(投稿者)

No86095 (masa さん) に返信
> 当方、VB系の経験しかなく

自分の専門分野も Visual Basic なので、
質問は「C入門」ですが、VB 系の視点で伸べてみます。



> C系の学習(特にデータ型)をする必要があると感じています。

ゴールが見えていないと【手段】と【目的】が入れ替わってしまいそうです。
その学習は、何のために必要としているのでしょうか?


今回の話は、いわゆる低レベル処理になりますので、
目的が明かされないまま手段を問われても答えにくいかと思います。


構造体などは自作できるので、ここでいうデータ型というのが
言語機能で組み込まれた基本型のみを指しているのか、あるいは
特定のプラットフォーム向けに限定した話なのかで、
学習する方向も変わってくるかと思いますよ。


もし、Win32 SDK での開発をターゲットにしているわけではなく、
単純な C 言語の学習という点だけに限定した話であるのなら、データ型のメモリ構造に関する
最低限の知識は、既にあるような印象を受けました。それで十分かどうかは別として。


> Cで作成された関数をコールする場合、
> VBにないデーター型は、サイズが同じ類似の型で代用するわけですが、

たとえば VB/VBA 内で完結する処理に限定するのなら、「データ型」の構造に関しては
ヘルプに載っている以上の知識が必要になることはそうそう無いでしょう。


しかし、他のプラットフォームとのデータ交換・マーシャリングが発生するのなら、
どのプラットフォームとやりとりするのか、個別の知識が必要になってきます。
ですから、学習するにしても「目的」ははっきりさせておくべきかと。


No86101 (masa さん) に返信
> おっしゃる通りVBからのマーシャリングに関する事でCの知識
> を深めたいと思っています。

VB/VBA からの Declare 呼び出しで必要な知識を得ることが目的なのでしょうか。

たとえば、Visual Basic で利用可能な DLL を作成するのが目的だとしても、
 「VBA から Declare で利用可能な DLL を作る場合」
 「VBA から呼び出し可能な ActiveX DLL を作る場合」
 「VBS から呼び出し可能な ActiveX DLL を作る場合」
では、それぞれ求められる知識が微妙に異なります。
(もちろん、共通する部分も多いですが)

VBScript が相手なら、Variant 型前提で設計せねばならず、かつその場合、
VT_BYREF の受け渡しについても異なってきたりします。
http://program.station.ez-net.jp/special/vc/atl-com/variant.asp


VBA と VB.NET でもかなり違いがあります。

たとえば WindowFromPoint API などは、
 HWND WindowFromPoint(POINT Point);
という定義になっており、引数の型が LPPOINT ではなく POINT です。


VBA の場合、ユーザー定義型を値渡しできないので、
stdcall 規約に従い、引数を展開して
 (ByVal xPoint As Long, ByVal yPoint As Long) As OLE_HANDLE
などと定義しますが、VB.NET の場合は構造体の値渡しが可能なので、
 (ByVal Point As POINTAPI) As IntPtr
のような宣言が可能です。

この他、.NET Framework と Unamaged DLL の間での Platform Invoke(P/Invoke) や
.NET Framework と ActiveX DLL の間での COM Interop などにおいても、
.NET 側のマーシャリングルールに関する知識が必要になります。
http://www5b.biglobe.ne.jp/~yone-ken/VBNET/Reference/ref2_GetPrivateProfileString.html
https://msdn.microsoft.com/ja-jp/library/eshywdt7.aspx
https://msdn.microsoft.com/ja-jp/library/s9ts558h.aspx
(特には OS の違いや、.NET バージョンの違いも考慮せねばならないことがあります)


このような事情もあるので、単純にそれぞれのデータ型(たとえば Decimal)の
内部構造を把握していく学習スタイルは、効果が薄いかと思います。


API に限った話ではなく、VB からの単純なバイナリファイルの入出力でさえ、
手順が変われば、その際のデータ構造は大きく異なってきます。

例として、VBA の「Put ステートメント」のヘルプを見てみると
可変長文字列変数の出力に際して

 『文字列の長さを示す 2 バイトの記述子を書き込み、
  次に変数内の文字列データを書き込みます。』

という記載があります。

この仕様は BSTR の構造に似ており、最初の 2 バイトは、BSTR でいうとことの
オフセット -4 にあるサイズ情報に相当しますが、だからといって、
Put #/Get # を行う際に、BSTR の仕様を把握している必要があるかと問われれば、
その答えは 否 でしょう。

仮に BSTR の仕様を把握していたとしても、レイアウトとしては同じではありませんから、直接は関係しません。
たとえば、BSTR が持つ終端 NULL 部はデータとしては余剰なので出力されませんし、文字列本体部も
元のバイナリではなく CP932(というか、OS 既定のコードページ)への文字コード変換が行われてしまうためです。


もう一つ例を挙げると、同じく VBA ヘルプの「Put ステートメント」において、
配列を出力する場合に、識別子として「(2 + 8 * 配列の次元数)バイト」分の領域が
消費されるとあります。これの内訳も、VB のヘルプ内では明確にされていません。

https://msdn.microsoft.com/en-us/vba/language-reference-vba/articles/put-statement
https://msdn.microsoft.com/en-us/vba/language-reference-vba/articles/get-statement

SAFEARRAY 構造体の仕様を知っていれば、この識別子の内訳を知る手がかりにはなりますが、
だからといって、SAFEARRAY の仕様を知らなければならないかは別問題ですよね。

しかもこの件に関しては、ヘルプの解説さえも間違っています。ここの記述では
 Dim MyArray(1 To 5,1 To 10) As Integer
が 118 バイト(= 2 + 8 * (5 * 10 * 2)) になると書かれていますが、
実際にはこの場合、100 バイトしか確保されない仕様です。

これが 118 バイトになるパターンというのは、
 Private Type UDT
  MyArray() As Integer
 End Type
なユーザー定義型を
 Dim t As Test
 ReDim t.MyArray(1 To 5, 1 To 10) As Integer
と確保していた場合であり、この場合の内訳は、
 [00-01] 2 バイト 02,00 … 次元数 2 を意味する / cDims
 [02-05] 4 バイト 0A,00,00,00 … 1 次元目の要素数10 を意味する / rgsabound[0].cElements
 [06-09] 4 バイト 01,00,00,00 … 1 次元目の下限値 1 を意味する / rgsabound[0].lLbound
 [0A-0D] 4 バイト 05,00,00,00 … 2 次元目の要素数 5 を意味する / rgsabound[1].cElements
 [0E-11] 4 バイト 01,00,00,00 … 2 次元目の下限値 1 を意味する / rgsabound[1].lLbound
 [12-75] 配列データの本体 100バイト (
となります。

そしてこれも、SAFEARRAY 構造体のバイナリ構造と類似はしていますが、同一ではありません。
データと直接関係の無い Features / cbElements / cLocks 等は確保されません。
引用返信 編集キー/
■86109 / inTopicNo.10)  Re[1]: C入門
□投稿者/ 魔界の仮面弁士 (1512回)-(2017/12/18(Mon) 20:50:20)
No86095 (masa さん) に返信
> (2)Cのデーター型一覧が載っているURL又は、書籍があれば教えてください。

Win32 API の型(WTypes.h)と、C 言語の組み込み型との対応表
https://msdn.microsoft.com/ja-jp/library/ac7ay120.aspx

代表的な Windows API のデータ型と VBA のデータ型の対応表
https://books.google.co.jp/books?id=JZAuDQAAQBAJ&lpg=PA62&ots=I2rCE6PdII&hl=ja&pg=PA62#v=onepage&q&f=false
https://pf-j.sakura.ne.jp/program/tips/vbw32api.htm

Visual Basic で使用する DLL の開発に関する注意点
https://www.microsoft.com/japan/msdn/vs_previous/vbasic/docs/dll/

「ハンガリアン記法のプレフィックス」にみるデータ型の対応(資料中盤の表)
https://msdn.microsoft.com/ja-jp/library/cc326057.aspx



> (3)例えばVBからWin32APIをコールする場合、構造体とそのサイズを引数にとる関数が
> 結構あります。VB側ではサイズとアライメントを合わせる為、パッキング指定します。
VB.NET はパッキング指定できますが、VBA だとそれが無いので、呼び出し前後で
RtlMoveMemory でズラしたりして調整しますね。(例:SHFileOperation API)


> ヘッダーファイルで冒頭に#include <pshpack1.h>とあったりすればいいのですが、
> まったくない場合もあります。既定値が4であることは承知しております。

#include <pshpack某.h> と #include <poppack.h> の代わりに、
#pragma pack(〜) が使われていることもありますが、
それらが無い場合は既定値じゃないですかね。追加でマクロが組まれてると厄介ですが。


> どのように調査すれば良いのでしょうか?
C 言語で実験できるなら、<stddef.h> に offsetof マクロがあったかと思います。
.NET で言うところの Marshal.OffsetOf メソッドに相当する機能です。


> union共用体についてはWeb検索で理解できました。
代表例としては、プリンターとディスプレイの両方で使われる DEVMODEW 構造体や
SendInput API で使う INPUT 構造体などですね。


> 続く共用体の8バイトについても何故8バイトなのか解りません。
> 64bitシステムでポインタを表すには 8 バイト必要だからと思いますが、
> リファレンス元が解りません。
既に回答が付いていますが、共用体メンバーの最大サイズです。VARIANT の場合は、
前回のスレッド( No86024 )の最後に挙げた VT_RECORD タイプが最大(Win64 だと 24 バイト)ですね。
>>  _PVOID pvRecord;     // a reference to a database record.
>>  IRecordInfo *pRecInfo;  // a reference to a User-Defined-Type


.NET で共用体を作る場合は StructLayoutAttribute(Explicit) と
FieldOffsetAttribute(offset) で表現します。
https://msdn.microsoft.com/ja-jp/library/acxa5b99.aspx

たとえば下記の、SendInput API 用の構造体の宣言例を見てみると:
https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/NativeMethods.cs#5568
この場合、
 Marshal.SizeOf(Of MOUSEINPUT)() は 24 バイト
 Marshal.SizeOf(Of KEYBDINPUT)() は 16 バイト
 Marshal.SizeOf(Of HARDWAREINPUT)() は 8 バイト
を返し、その結果、最大値となる
 Marshal.SizeOf(Of INPUTUNION)() は 24 バイト
になります。


とはいえ、メンバー構成によっては、FieldOffsetAttribute では対応できないケースも
少なからずあります。その場合は AllocCoTaskMem に自前で詰め込んで呼び出したり、
共用体とはせず別々の構造体に分離して対応することになります。
引用返信 編集キー/
■86122 / inTopicNo.11)  Re[2]: C入門
□投稿者/ masa (14回)-(2017/12/19(Tue) 15:56:22)
2017/12/19(Tue) 15:58:29 編集(投稿者)

皆様、返信ありがとうございます。
まとめての返信となることをお許し下さい。

色々な角度からの情報を頂き感謝いたします。頂いた情報を自分なりに精査しました。
知らなかった情報も多くあり、すべて理解できたわけでは有りませんが、今後頭の片隅に
留めておきたいと思います。

特にぶなっぷさんのデーター型サイズの取得方法は目から鱗でした。
今までWeb検索で欲する情報に辿りつくまでに費やした時間はなんだったのかと。。。。

とっちゃんさんや魔界の仮面弁士さんは前回のスレッドでもお世話になりましたがとても博学ですね。
前回もそうでしたが私の質問の主旨が抽象的なんですかね。
先読みして自分の期待以上の回答を頂戴しているようです。自分としては大いにありがたい
ですが今後注意します。今後共、よろしくご指導お願いします。


(以下、余談です。)
今日、Visual Studio 2017 Communityをインストールしました。
Hello, Worldからはじめて、ぶなっぷさんの方法でデーター型サイズの取得まで出来ました。
30年前にTurbo Pascalという言語をやっていた経験があり、#includeや命令末尾の;は
その頃を思い出しました。当時からこれからはCを勉強するほうが良いと言われていましたが
30年越しで実現しました。

引用返信 編集キー/
■86128 / inTopicNo.12)  Re[6]: C入門
□投稿者/ masa (15回)-(2017/12/20(Wed) 10:37:51)
すみません。理解したつもりでしたが不十分でした。
申し訳ありませんが再度、ご指導いただけないでしょうか?

No86104のとっちゃんさんの以下の発言について
> ちなみに。。。VARIANTの構造体サイズは16ではなく、環境依存です。
> 具体的には WORD*4 + sizeof(ポインタ)*2 という構造で
> 32bitなら16、64bitなら24になります。

確かにぶなっぷさんに教わった方法で64bitモードで実行すると24となりました。
共用体部分の最後の*2の意味が解りません。

以下のどこが間違っていますか?
32ビット環境==>WORD*4 +共用体部分の最大値(=LongLongなどで8バイト,ポインタは4バイト)=16
64ビット環境==>WORD*4 +共用体部分の最大値(=LongLongなどで8バイト,ポインタも8バイト)=16

引用返信 編集キー/
■86129 / inTopicNo.13)  Re[7]: C入門
□投稿者/ 魔界の仮面弁士 (1517回)-(2017/12/20(Wed) 10:58:20)
No86128 (masa さん) に返信
> 共用体部分の最後の*2の意味が解りません。

No86109 で述べた、
>> VARIANT の場合は、前回のスレッド( No86024 )の最後に挙げた
>> VT_RECORD タイプが最大(Win64 だと 24 バイト)ですね。
のことではなく?


すなわち
  [00-01] VARTYPE vt;
  [02-03] WORD wReserved1;
  [04-05] WORD wReserved2;
  [06-07] WORD wReserved3;
の後が、Win32 だと
  [08-0B] PVOID pvRecord;
  [0C-0F] IRecordInfo *pRecInfo;
なので合計 16 バイトになり、Win64 だと
  [08-0F] PVOID pvRecord;
  [10-17] IRecordInfo *pRecInfo;
に配置されて、合計 24 バイトになるということで。
引用返信 編集キー/
■86130 / inTopicNo.14)  Re[8]: C入門
□投稿者/ masa (16回)-(2017/12/20(Wed) 11:29:57)
No86129 (魔界の仮面弁士 さん) に返信

あちゃ..魔界の仮面弁士さん、申し訳ありません。
既に御教示があったのですね。
ちゃんと全文読むには読んでいるのですが、VT_RECORDは初めて聞いたタイプで
VBAでユーザー定義型(UDT)を格納したVariantて何?まず使うことはないからいいか。。
みたな所がありました。

普通VBAではユーザー定義型をTypeで宣言して
Type MyType
.
.
End Type
として
Dim t as MyType としますよね。

この場合もVT_RECORDになるのでしょうか?
あるいはVB.NETでは構造体のメンバーに別の構造体をもっているみたいなイメージですか?

引用返信 編集キー/
■86131 / inTopicNo.15)  Re[9]: C入門
□投稿者/ 魔界の仮面弁士 (1518回)-(2017/12/20(Wed) 13:06:48)
No86130 (masa さん) に返信
> Dim t as MyType としますよね。
> この場合もVT_RECORDになるのでしょうか?

それを As Variant で扱う状態にあたります。

'---------------
Dim t As MyType
t.Member1 = 123

Dim v As Variant
v = t

' 36 (VT_RECORD と同じ値)
Debug.Print vbUserDefinedType

'True
Debug.Print VarType(v) = vbUserDefinedType

'MyType
Debug.Print TypeName(v)
'---------------

このタイプのデータ型の利用は、非常に限定的です。

そもそも VB5 までは、ユーザー定義型を外部に公開はできませんでした。
Private や Friend でのみ、引数や戻り値に使用できます。
(VB4 に至っては、そもそも Friend すら無いですね)

VB6 からは、Public な プロパティやメソッドの引数または戻り値で
ユーザー定義型を使用できるよう、言語機能が拡張されています。

言語仕様という点で言えば、このあたりの事情は VBA でも同様です。

ただし、外部公開するためのユーザー定義型というのは、
パブリックなオブジェクトモジュールで定義されていなければなりません。

すなわち、その Public Type の宣言が Form や標準モジュールではなく、
「Instancing プロパティが 1 (Private) 以外に設定されているクラスモジュール」
で行われていないなければならないということです。
(もしくはタイプライブラリにて定義しておく)
引用返信 編集キー/
■86132 / inTopicNo.16)  Re[10]: C入門
□投稿者/ masa (17回)-(2017/12/20(Wed) 15:16:34)
No86131 (魔界の仮面弁士 さん) に返信
返信、ありがとうございます。
Cの話題から全く外れてしまいますが・・・これで最後にしますのでご容赦を。

自分でも質問する前に以下のようにやったのですが、以下のエラーでコンパイル通らず
断念しました。
「パブリック オブジェクト モジュールで定義されたユーザー定義型に限り、変数に
割り当てることができ、実行時バインディングの関数に渡すことができます。」

Dim v As Variant
v = t
Debug.Print VarType(v) 

> すなわち、その Public Type の宣言が Form や標準モジュールではなく、
> 「Instancing プロパティが 1 (Private) 以外に設定されているクラスモジュール」
> で行われていないなければならないということです。
> (もしくはタイプライブラリにて定義しておく)


そこで↑の御教示から以下のようにしましたがどうしてもコンパイルエラーになります。
どうすればvbUserDefinedTypeを確認できるのでしょうか?

'クラス:Class1
'Instancingプロパティ==>PublicNotCreatableに変更
Private Type MyType
    Member1 As Integer
End Type

Public Property Get GetMyType() As Integer
    Dim t As MyType
    Dim v As Variant
    v = t
    GetMyType = VarType(v)
End Property

'標準モジュール
Sub test1()
    Dim cls As Class1
    Set cls = New Class1
    Debug.Print cls.GetMyType
End Sub

引用返信 編集キー/
■86133 / inTopicNo.17)  Re[11]: C入門
□投稿者/ 魔界の仮面弁士 (1519回)-(2017/12/20(Wed) 16:17:30)
No86132 (masa さん) に返信
> Private Type MyType

クラスモジュールだけではなく、
ユーザー定義型も Public にしましょう。

Private の場合は外部公開されないので、
VARIANT の型システムに渡すことが出来ません。
引用返信 編集キー/
■86134 / inTopicNo.18)  Re[11]: C入門
□投稿者/ 魔界の仮面弁士 (1520回)-(2017/12/20(Wed) 16:31:31)
No86132 (masa さん) に返信
> Cの話題から全く外れてしまいますが・・・これで最後にしますのでご容赦を。

話のネタついでにもう一つ。

Variant 型は UInt32 相当の型などもサポートしていますが、
VB6 / VBA では、そのような Variant 型を扱うことが出来ません。


VB6 をお持ちなら、マスクエディット コントロールをコントロール配列にし、
下記のようなコードを実行してみると、VT_UI4 型の Variant 値を取得できます。


Dim txt As TextBox
Dim msk As MaskEdBox
Dim ctl As Control

'TextBox コントロール配列のメンバーを TextBox 型へ
For Each txt In Me.Text1
  Debug.Print VarType(txt.ForeColor)
  Debug.Assert txt.ForeColor = vbWindowText
Next

'MaskEdBox コントロール配列のメンバーを MaskEdBox 型へ
For Each msk In Me.MaskEdBox1
  Debug.Print VarType(msk.ForeColor)
  Debug.Assert msk.ForeColor = vbWindowText
Next

'TextBox コントロール配列のメンバーを Control 型へ
For Each ctl In Me.Text1
  Debug.Print VarType(ctl.ForeColor)
  Debug.Assert ctl.ForeColor = vbWindowText
Next

'MaskEdBox コントロール配列のメンバーを Control 型へ
For Each ctl In Me.MaskEdBox1
  
  '3 (vbLong / VT_I4) ではなく
  '19 (VT_UI4) が返却される
  Debug.Print VarType(ctl.ForeColor)
  
  'これはOK
  Debug.Assert CLng(ctl.ForeColor) = vbWindowText
  
  '実行時エラー 458
  'Visual Basic でサポートされていないオートメーションが変数で使用されています。
  Debug.Assert ctl.ForeColor = vbWindowText
Next

引用返信 編集キー/
■86142 / inTopicNo.19)  Re[12]: C入門
□投稿者/ masa (18回)-(2017/12/21(Thu) 13:52:44)
No86134 (魔界の仮面弁士 さん) に返信
何度もありがとうございます。

VT_UI4の件、追加情報ありがとうございます。VB6を持ち合わせていないので、
確認できませんが頭の片隅に置いておきます。

VT_RECORDについてはギブアップです。
VBAでクラスのInstancingプロパティをPublicNotCreatableに変更して
Type宣言もPublicにしましたがコンパイルが通りません。
アドインにして外部プロジェクトとしてアクセスしたり、
クラス内にPublicな関数、メソッド、プロパティを用意してみたり
Friendスコ−プにしてみたりしましたが全滅。。
Debug.Print vbUserDefinedTypeは36を返してくるのでサポートはしてると思うのですが・・・
EXCELのバージョンは2007ですがVB6以降ですよね。サポート対象外なんでしょうか?
引用返信 編集キー/
■86145 / inTopicNo.20)  Re[13]: C入門
 
□投稿者/ とっちゃん (480回)-(2017/12/21(Thu) 15:32:11)
No86142 (masa さん) に返信
> EXCELのバージョンは2007ですがVB6以降ですよね。サポート対象外なんでしょうか?

ここだけ。
VBA(Visual Basic for Applications) と、VB6(Visual Basic Version 6)は異なるものです。

「VB6を持っているなら」と前置きしたうえで、いろいろやってみたら?となっています。

引用返信 編集キー/

このトピックをツリーで一括表示

次の20件>
トピック内ページ移動 / << 0 | 1 >>

管理者用

- Child Tree -