Q&A-ネットワーク編

ネットワークに関する質問をまとめました。

ユーザ名を取得するには
Winsock コントロールで、TCPの再接続がうまく行かない
ネットワークに接続されている全てのコンピュータ名を取得するには?
サーバの日付、時刻を取得するには?


Q ユーザ名を取得するには

ログインしたユーザ名を取得するにはどうしたらよいのですか?

A APIの GetUserName または WSH のオブジェクトを使用します

ユーザ名を取得する方法は、大きく分けてAPIを使用する方法と、WSH (Windows Script Host)のオブジェクトを使用する方法があります。APIを使用する場合は、APIの宣言等が面倒ですが、環境に依存しないコードが作成できます。一方、WSH を使用する場合、APIの宣言等は不要で手軽にコードを作成できるのですが、反面、WSH がインストールされている環境でなければ使用できません。

■ APIを使用する場合

ユーザ名を取得する API は GetUserName を使用すれば取得できますが、1つだけ注意することがあります。ユーザ名を取得する時バッファーのサイズを指定する UNLEN という定数が APIビューアに現れません。このサイズは、Visual C++ の ヘッダーファイルを検索すると以下のように定義されてます。

#define UNLEN 256

これを、VBで宣言するには、以下の宣言を標準モジュールに入れます。

Public Const UNLEN = 256

Declare Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" _
    (ByVal lpBuffer As String, nSize As Long) As Long


これで、以下のようにユーザ名が取得できます。

Dim strBuf As String

strBuf = Space(UNLEN + 1)
GetUserName strBuf, UNLEN

'ラベルにユーザ名を表示

lblName.Caption = strBuf

また、この strBuf の内容は、C言語で使用する NULL文字(Chr$(0))で終了する文字列になっているので、ユーザ名の後ろに Chr$(0)と空白が付加されています。VBで扱い易いように、このChr$(0)以降の文字を以下のように削除します。

Dim strBuf As String
Dim intPos As Integer

strBuf = Space(UNLEN + 1)
GetUserName strBuf, UNLEN

'Chr$(0)以降の文字を削除
intPos = InStr(strBuf, Chr$(0))
If intPos > 0 Then
    strBuf = Left$(strBuf, intPos - 1)
End If

'ラベルにユーザ名を表示

lblName.Caption = strBuf


■ WSHを使用する場合


WSH を使用する場合のコードは簡単です。

Dim WshNetwork As Object
Dim strUserName As Object

Set WshNetwork = CreateObject("WScript.Network")

stUserName = WshNetwork.UserName
MsgBox strUserName

Set WshNetwork = Nothing

見ても分かる通り、CreateObject で "WScript.Network" のオブジェクトを WshNetwork に作成して、WshNetwork のUserNameプロパティを参照するだけです。
同様に WshNetwork のプロパティには、以下のようなプロパティがあります。

ComputerName コンピュータ名
UserDomain ドメイン名
UserName ユーザ名

(注意)WSHを使用する場合には、以下のような環境のいずれかが必要です。

・Internet Explorer の 5.0 以上
・Windows NT 4.0 のOption Pach
・Windows 98

・MSのサイトよりダウンロード

詳細に付いては以下を参照してください。
http://www.asia.microsoft.com/Japan/Developer/Scripting/

(注意)このページの内容は、Visual Basic5.0(SP3)Visual Basic6.0(SP3)を対象に記述されています。他のバージョンでは、対応できないこともあるので、ご注意願います。
(注意) ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います


Q Winsock コントロールで、TCPの再接続がうまく行かない

Winsock コントロールで、TCP/IPのプログラムを作成していますが、一旦 Connect メソッドで接続を行うと、Close を行っても再接続がうまく行きません。どうしたらよいのですか?

A LocalPort に 0 を設定します

TCP で接続する場合、ローカル ポート番号を指定しないときは LocalPort プロパティに 0 を設定してください。これを行わないと、一旦 Connect メソッドで接続を行うと、接続が自動的に解除するまで次の Connect が成功しません(解除の時間はサーバの設定などでまちまちです)。
詳細に付いては、Microsoft の以下のサイトを参考にしてください。(1999/5/26 のアドレスです、見つからない場合は、検索で文書番号の J030442 を検索してください)

http://www.asia.microsoft.com/japan/support/kb/articles/j030/4/42.htm

(注意)このページの内容は、Visual Basic5.0(SP3) を対象に記述されています。他のバージョンでは、対応できないこともあるので、ご注意願います。

(注意) ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います。


Q ネットワークに接続されている全てのコンピュータ名を取得するには?

エクスプローラが表示するような、ネットワークに接続されているコンピュータ名をすべて取得するにはどうしたら良いでしょうか?

A WNetOpenEnum、WNetEnumResource 等のAPIで取得できます。

ネットワークに接続されているコンピュータ名を、取得するには、以下のようなAPIを使用すれば、取得できます。

Dim nr As NETRESOURCE
Dim lpnr As LPNETRESOURCE
Dim bnr(1000) As Byte
Dim strRemoteName As String
Dim hEnum As Long
Dim BufSize As Long
Dim ret As Long

strRemoteName = String$(512, 0)

' NETRESOURCE構造体を設定
nr.dwScope = RESOURCE_GLOBALNET
nr.dwType = RESOURCETYPE_ANY
nr.dwDisplayType = RESOURCEDISPLAYTYPE_DOMAIN
nr.dwUsage = RESOURCEUSAGE_CONTAINER
nr.lpRemoteName = "DomainName"
nr.lpProvider = "Microsoft Windows Network"

' 設定された NETRESOURCE でオープン
ret = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_ANY, 0, nr, hEnum)


BufSize = 1000

' WNetEnumResource で接続されているコンピュータの情報を取得
Do While WNetEnumResource(hEnum, 1, bnr(0), BufSize) = NO_ERROR

    '取得したデータを strRemoteName にコピー
    MoveMemory lpnr, bnr(0), Len(lpnr)
    lstrcpy strRemoteName, lpnr.lpRemoteName


   'strRemoteName の後ろの Chr$(0) をカット
    Debug.Print Left$(strRemoteName, InStr(strRemoteName, vbNullChar) - 1)
Loop

WNetCloseEnum hEnum

strRemoteName に取得したコンピュータ名が入ります。
ここで、重要なのは lpRemoteName で指定されている、ドメインの名称です。ここで指定されたドメインに接続されている、全てのコンピュータ名が取得できます。この例では DomainName というドメインに接続されている全てのコンピュータ名を取得できます。
また、ドメイン名が不明の場合は、lpRemoteName に "" を設定してください。strRemoteName に接続されたドメイン名が入ります。取得されたドメイン名を、再度 lpRemoteName にセットして、上記のコードを実行すれば、コンピュータ名が取得できます。

以下は、宣言部です。標準モジュールに入れてください。

Type NETRESOURCE
    dwScope As Long
    dwType As Long
    dwDisplayType As Long
    dwUsage As Long
    lpLocalName As String
    lpRemoteName As String
    lpComment As String
    lpProvider As String
End Type

Type LPNETRESOURCE
    dwScope As Long
    dwType As Long
    dwDisplayType As Long
    dwUsage As Long
    lpLocalName As Long
    lpRemoteName As Long
    lpComment As Long
    lpProvider As Long
End Type

'================================================
'dwScope // リソースの範囲
'列挙するリソースの範囲を指定します。次の値のいずれかを指定します
'================================================
'現在接続されているすべてのリソース(dwUsage パラメータ
'は無視されます)
Public Const RESOURCE_CONNECTED = &H1
'呼び出し側のネットワークコンテキスト内([ネットワーク
'コンピュータ]に表示される範囲)のリソース(dwUsage
'パラメータは無視されます)
Public Const RESOURCE_CONTEXT = &H5
'ネットワーク上のすべてのリソース
Public Const RESOURCE_GLOBALNET = &H2
'記憶されている接続(dwUsage パラメータは無視されます)
Public Const RESOURCE_REMEMBERED = &H3

'================================================
'dwType // リソースの種類
'列挙するリソースの種類を指定します。次の値を組み合わせて指定します
'================================================
'すべてのリソース(RESOURCETYPE_DISK または RESOURCETYPE_PRINT
'との組み合わせは不可)
Public Const RESOURCETYPE_ANY = &H0
'すべてのディスクリソース
Public Const RESOURCETYPE_DISK = &H1
'すべての印刷リソース
Public Const RESOURCETYPE_PRINT = &H2

'================================================
'dwUsage // リソースの用途
'列挙するリソースの用途を指定します。次の値を組み合わせて指定します。
'================================================
'0 すべてのリソース
' すべての接続可能なリソース
Public Const RESOURCEUSAGE_CONNECTABLE = &H1
' すべてのコンテナリソース
Public Const RESOURCEUSAGE_CONTAINER = &H2

'================================================
'dwDisplayType // 表示タイプ
'エクスプローラなどで表示されるオブジェクトのタイプ
'================================================
'一般
Public Const RESOURCEDISPLAYTYPE_GENERIC = &H0
'ドメイン
Public Const RESOURCEDISPLAYTYPE_DOMAIN = &H1
'サーバ
Public Const RESOURCEDISPLAYTYPE_SERVER = &H2
'共有
Public Const RESOURCEDISPLAYTYPE_SHARE = &H3

'================================================
'WNetOpenEnum 戻り値
'================================================
'lpNetResource パラメータがコンテナリソースを指していません。
Public Const ERROR_NOT_CONTAINER = 1207&
'dwScope パラメータまたは dwType パラメータの値が無効です。
Public Const ERROR_INVALID_PARAMETER = 87 ' dderror
'ネットワークがありません。
Public Const ERROR_NO_NETWORK = 1222&
'ネットワーク固有のエラーが発生しました。エラーの詳細は、
'WNetGetLastError 関数で取得できます。
Public Const ERROR_EXTENDED_ERROR = 1208&

'================================================
'WNetEnumResource 戻り値
'================================================
'列挙が成功し、要求したデータがバッファに格納されました。
'アプリケーションは、引き続きこの関数を呼び出して、列挙
'を続けることができます。
Public Const NO_ERROR = 0
'これ以上列挙するエントリはありません。このときのバッファ
'の内容は、未定義です。
Public Const ERROR_NO_MORE_ITEMS = 259&
'================================================
'まだ列挙できるエントリが残っています。
Public Const ERROR_MORE_DATA = 234
'hEnum ハンドルが無効です。
Public Const ERROR_INVALID_HANDLE = 6&
'ERROR_EXTENDED_ERROR、ERROR_NO_NETWORK も返されます。
'================================================

Declare Function WNetOpenEnum Lib "mpr.dll" Alias "WNetOpenEnumA" ( _
    ByVal dwScope As Long, _
    ByVal dwType As Long, _
    ByVal dwUsage As Long, _
    LPNETRESOURCE As Any, _
    lphEnum As Long) As Long

Declare Function WNetEnumResource Lib "mpr.dll" Alias "WNetEnumResourceA" ( _
    ByVal hEnum As Long, _
    lpcCount As Long, _
    lpBuffer As Any, _
    lpBufferSize As Long) As Long

Declare Function WNetCloseEnum Lib "mpr.dll" ( _
    ByVal hEnum As Long) As Long

Declare Sub MoveMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
    Destination As Any, _
    Source As Any, _
    ByVal Length As Long)

Declare Function lstrcpy Lib "kernel32" Alias "lstrcpyA" ( _
    ByVal lpString1 As Any, _
    ByVal lpString2 As Any) As Long


(注意)このページの内容は、Visual Basic5.0(SP3)Visual Basic6.0(SP3) を対象に記述されています。他のバージョンでは、対応できないこともあるので、ご注意願います。

(注意) ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います。


Q サーバの日付、時刻を取得するには?

サーバの日付、時刻を取得するには、どうしたら良いでしょうか?

A net time コマンドまたは API の NetRemoteTOD を使用します

サーバの日付、時刻を取得するには、WindowsNT または Windows2000 では NetRemoteTOD というAPIが用意されていますが、Windows95 や Windows98 では、NetRemoteTOD が使用できないので、DOSプロンプトの Net Time コマンドを使用してください。

■ NetRemoteTOD の場合

以下のようなAPIを使用してください。

Dim ret As Long
Dim lngPtr As Long
Dim b() As Byte
Dim todi As TIME_OF_DAY_INFO

b = "\\Server" & Chr$(0)   'サーバ名
ret = NetRemoteTOD(b(0), lngPtr)

If lngPtr <> 0 Then
    MoveMemory todi, ByVal lngPtr, Len(todi)
    NetApiBufferFree lngPtr
End If

todi の各変数に、日付、時刻が設定されます。意味は、次の構造体の宣言を見れば、わかりますよね(^^
以下は、宣言部です。標準モジュールに入れてください。

Type TIME_OF_DAY_INFO
    tod_elapsedt As Long
    tod_msecs As Long
    tod_hours As Long
    tod_mins As Long
    tod_secs As Long
    tod_hunds As Long
    tod_timezone As Long
    tod_tinterval As Long
    tod_day As Long
    tod_month As Long
    tod_year As Long
    tod_weekday As Long
End Type

Public Const NERR_Success = 0

Declare Function NetRemoteTOD Lib "netapi32.dll" ( _
    lpBuffer As Byte, _
    lpbyteptr As Long) As Long

Declare Function NetApiBufferFree Lib "netapi32.dll" ( _
    lpbyteptr As Long) As Long

Declare Sub MoveMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
    Destination As Any, _
    Source As Any, _
    ByVal Length As Long)


■ Net Time コマンド の場合


以下のような、コマンドを実行してください。

Shell "command.com /c net time \\Server>c:\temp\temp"

ここで、\\Server がサーバ名です。これを実行すると、以下のような文字列が c:\temp\temp にセットされます。

\\kitsvr の現在の時刻は 00/03/15 午後 05:14 です

コマンドは正常に終了しました。

このファイルを開いて、文字列を解析すれば、日付、時刻が取得できます。

(注意)このページの内容は、Visual Basic6.0(SP3) を対象に記述されています。他のバージョンでは、対応できないこともあるので、ご注意願います。

(注意) ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います。