はじめまして。へいろーと申します。
業務で以下の仕様のプログラムを作成することになりまして
いろいろと検索したのですがうまい方法やよいサンプルが見つからなかったので
ここに参りました。
仕様
1:IPアドレスの変更
2:ワークグループの変更
3:コンピュータ名の変更
これらを半自動で行うプログラムをVB.NETで作成をするということです。
ワークグループの変更についてはNetJoinDomain
IPについてはWMIのサンプルを見つけたのですが、
NetJoinDomainではCのサンプルしかなくVB.NETで使える形にできません。
WMIのサンプルについてはVB6?で動くもののようで、そのままでは.NET
上ではエラーになりました。
VB.NETでは多くのプログラムを書いたこともなく、他言語からの移植となる
とちんぷんかんぷんです。
うまい方法やVB.NETで利用できそうなサンプルがあれば教えていただけませんでしょうか?
よろしくお願いいたします。
> 他言語からの移植となるとちんぷんかんぷんです。
APIはC/C++で書かれたサンプル、WMI は VB6/VBScriptで書かれたサンプルが
多いので、他の言語もある程度は読めるようになっておくと便利ですよ。
# まぁ、その前に VB.NET の勉強の方が優先されるでしょうけれども。
> 1:IPアドレスの変更
netsh コマンドを呼び出してみては。これなら言語は関係無いですし。
http://www.monyo.com/technical/windows/26.html
もちろん、WMI の Win32_NetworkAdapterConfiguration.EnableStatic を
使っても良いですけれどね。
> 2:ワークグループの変更
> NetJoinDomainではCのサンプルしかなくVB.NETで使える形にできません。
google で、ウェブやグループを「NetJoinDomain VB.NET」で検索したら、
幾つかサンプルが見つかりましたよ。(間違ったサンプルも多いようですが…)
なお、このあたりの API群(Net-Functions)は、Unicode 文字列を要求する事に注意。
> 3:コンピュータ名の変更
WMI なら、Win32_ComputerSystem クラスの Rename メソッドが使えるかも。
API なら、SetComputerNameEx とか、NetRenameMachineInDomain とか。
> WMIのサンプルについてはVB6?で動くもののようで、そのままでは.NET
> 上ではエラーになりました。
そのまま移植するのも一つの手ですが…いっその事、WMIの使い方自体を
覚えてしまった方が、今後のためにも良いかも知れません。(^^;
VB.NET から WMI を使う際には、System.Management を参照設定して利用します。
(Mgmtclassgen.exe を併用する方法もあります)
ありがとうございます。
1:IPアドレスの変更
についてはWMIを利用しました。
ただし、VB.NETから使用するときの変数の型?みたいなものが
分からなかったのでWMIスクリプトをShell関数でよぶようにしました。
2:ワークグループの変更
についてVB.NETで使えそうなサンプルを英語のページでみつけることが
できましたが、独自の関数を使っているようなかんじで、まだうまくい
っていません。引き続き、情報をお願いしたいと思います。
3:コンピュータ名の変更
これについてもなかなかうまくいきません。
APIを利用したところ、フルコンピュータ名は変わっていないのに、
GetComputerNameで取得できる名前は変わっていました。
システムのプロパティから変更できるコンピュータ名の変更方法を
引き続きお願いしたいと思います。
よろしくお願いいたします
ちょっと話はそれますが・・・
アプリケーションによっては設定ファイルやレジストリにIPアドレスやコンピュータ名等を保存しているため、後から変更されると矛盾が生じて意図したとおりに動作しなくなる可能性がある物があります。
業務システムで使うのであれば、そういった物の調査もお忘れ無く。
> ただし、VB.NETから使用するときの変数の型?みたいなものが分からなかったので
これについては、既に
>> VB.NET から WMI を使う際には、System.Management を参照設定して利用します。
>> (Mgmtclassgen.exe を併用する方法もあります)
と回答したかと思います。(ヘルプやWebにサンプルがいろいろありますよ)
実際には、Mgmtclassgen.exeを利用するとスマートなコードを書けますが、
それを使わないのであれば……たとえば、Win32_NetworkAdapterConfiguration の
「Caption プロパティ」を読み取る場合には、このように書けます。
=============================
Dim X As New System.Management.ManagementClass("Win32_NetworkAdapterConfiguration")
For Each mo As System.Management.ManagementObject In X.GetInstances()
MessageBox.Show(CStr(mo.Properties("Caption").Value))
Next
=============================
その他のプロパティも、同様にして呼び出せます。
WMI の Win32_NetworkAdapterConfiguration クラスが持っている
プロパティやメソッドの一覧については、下記を参照してください。
http://msdn.microsoft.com/library/en-us/wmisdk/wmi/win32_networkadapterconfiguration.asp
また、WMI のメソッドを呼び出したい場合……たとえば、
Win32_NetworkAdapterConfiguration の EnableStatic メソッドなら、
=============================
Dim IP() As String = {"172.18.0.1"}
Dim Mask() As String = {"255.255.0.0"}
Dim Args() As Object = {IP, Mask}
Dim r As Object = mo.InvokeMethod("EnableStatic", Args)
=============================
などのようになります。(変数 mo については、先のコードを参考に)
EnableStatic メソッドの場合、その戻り値は System.UInt32 型になります。
そしてその結果を見れば、正しく変更されたか、また、再起動が必要かどうかなどを
判断する事ができます。
http://msdn.microsoft.com/library/en-us/wmisdk/wmi/enablestatic_method_in_class_win32_networkadapterconfiguration.asp
> 独自の関数を使っているようなかんじで、まだうまくいっていません。
> 引き続き、情報をお願いしたいと思います。
どういった情報を提示すればよいでしょうか?
参考にしたページの中で、よくわからない表現があったのであれば、
それを具体的に示していただければ、何かしらの回答ができるかも知れません。
> GetComputerNameで取得できる名前は変わっていました。
再起動しても状況は変わりませんか?
また、SetComputerNameEx API の引数は、どのように指定されましたか?
魔界の仮面弁士様、ひろ様 ご回答ありがとうございます。
>ひろ様
このプログラムを動かすクライアントは閉じたネットワークに属しており
外部へつなぐこともなければ、他のアプリけーションを動かすことも
多くはなく、初期の設定を行うための支援プログラムと考えています。
(現に、先日クライアントPCの交換を行った実務者がIPの設定ができない
とか言われましたのでこのような支援プログラムを作成する事となりました)
>魔界の仮面弁士様
VB6では以下の変数宣言でWMIのプログラムが書かれていました。
**********************************************************
Dim NicSet As SWbemObjectSet
Dim Nic As SWbemObject
Dim Locator As SWbemLocator
Dim Service As Object
***********************************************************
.NETではSystem.Managementを参照設定したのですが、
SWbemObjectSetやSWbemLocatorという型は存在しないということで
この部分に詰まってしまいました。
魔界の仮面弁士様に掲示いただいたURLを参考に調べてみたいと思います。
ワークグループについて参考にしたページでは
************************************************************
Private Declare Function NetJoinDomain _
Lib "NETAPI32.dll" (ByVal lpServer As String, _
ByVal lpDomain As String, ByVal lpAccountOU As String, _
ByVal lpAccount As String, ByVal lpPassword As String, _
ByVal fJoinOptions As Int32) As Int32Public Sub ChangeDomain()
Private Sub ChangeDomain()
Dim d() As Char
Dim u() As Char
Dim p() As Char
d = insertNulls("myDomain")
u = insertNulls("myUserName")
p = insertNulls("MyPassword")
err = NetJoinDomain("", d, "", u, p, JoinOptions.NETSETUP_DOMAIN_JOIN_IF_JOINED Or JoinOptions.NETSETUP_JOIN_DOMAIN)
End Sub
*********************************************************
というプログラムでしたが、insertnullsという関数が見つかりませんでした。
insertnullsを使用せずに文字型配列に設定したいワークグループ名を
入れてみましたが、エラーにもならず変更もされていませんでした。
NETSETUP_DOMAIN_JOIN_IF_JOINEDという値についてもエラーとなっていた
と思います。
>> GetComputerNameで取得できる名前は変わっていました。
> 再起動しても状況は変わりませんか?
> また、SetComputerNameEx API の引数は、どのように指定されましたか?
**********************************************************
Dim nName As String
Dim Ret As Long
nName = "PC100"
Ret = SetComputerName(nName)
**********************************************************
このように作成しました。
再起動をしてもNetBIOS名?は変わっているようなのですが、
フルコンピューター名が変更されていませんでした。
自己レスです。
SetComputerNameExではなくSetComputerNameを使ってしまっていました。
現在、SetComputerNameEx(5, "PC100")としましたが、
やはりかわっていないようでした。
> SWbemObjectSetやSWbemLocatorという型は存在しないということで
それらは、(COMの) Microsoft WMI Scripting V1.2 Library を
参照設定した場合のデータ型です。
(.NETの) System.Management.DLL を参照設定した場合とは異なります。
VB.NET から、COM のオブジェクトを利用する事も可能ですが、
ここはやはり、.NET のオブジェクトを使う事をおすすめします。
> 魔界の仮面弁士様に掲示いただいたURLを参考に調べてみたいと思います。
あれは、"WMI" のヘルプであって、.NETからの利用方法とは別だったりします。
.NET からの使用方法は、.NET側のヘルプをご覧下さい。
たとえば、データベース製品(Oracle や SQL Server)の使い方を調べようと
すれば、接続手段(ADO.NET とか ADO とか oo4o とか)のヘルプと、
データベース自体のヘルプの両方を見る事になりますよね。
WMI の場合も同様で、接続手段(WMI Scripting Library、System.Management)の
ヘルプと、WMI自体のヘルプの両方を見ておくべき、という事です。
とりあえず、『System.Management VB.NET』などのキーワードで、Google 等に
検索をかけてみると、国内外に、幾つかの解説やサンプルを発見できるかと。
> Private Declare Function NetJoinDomain _
Private Declare Unicode Function NetJoinDomain の方が安全かと。
> NETSETUP_DOMAIN_JOIN_IF_JOINEDという値についてもエラーとなっていた
Const NETSETUP_DOMAIN_JOIN_IF_JOINED As Int32 = &H20
などの宣言がされているかを確認してみてください。
> Dim Ret As Long
Long?
> 現在、SetComputerNameEx(5, "PC100")としましたが、
5、という事は、ComputerNamePhysicalDnsHostname の指定ですね。
宣言の方はどうなっていますか?
>魔界の仮面弁士さま
ありがとうございます。
ワークグループの変更については以下のコードでできました。
-----------------------------------------------------------------
NetJoinDomain(Nothing, WorkGrp, Nothing, Nothing, Nothing, 40)
-----------------------------------------------------------------
あとはコンピュータ名の変更です。
外部関数の宣言部は
Declare Function SetComputerNameEx Lib "kernel32.dll" Alias "SetComputerNameExA" (ByVal NameType As Long, ByVal lpBuffer As String) As Long
呼び出し部分は
Dim strName As String
Dim lngType As Long
.
.
.
strName = "NewPCName"
strName = strName & Chr(0)
lngType = 5
lngRet = SetComputerNameEx(lngType, strName)
です。lngRetにはかなり大きな数字が戻り値として帰ってきていました。
また、別言語で同等のやり方でうまくいくことは確認したのですが、
別言語の場合はワークグループの変更ができないので(Unicode文字列を扱えない仕様なので)VB.NETで構築している次第です。
> あとはコンピュータ名の変更です。
> 外部関数の宣言部は
それ、宣言部が間違っていますよ。
それは.NET以前の、旧バージョンのVB用の宣言です。
かわりに、System.Runtime.InteropServices を Imports した上で
Declare Auto Function SetComputerNameEx Lib "kernel32.dll" (ByVal NameType As Integer, ByVal lpBuffer As String) As <MarshalAs(UnmanagedType.Bool)> Boolean
としてみてください。もしくは、
Declare Auto Function SetComputerNameEx Lib "kernel32.dll" (ByVal NameType As Integer, ByVal lpBuffer As String) As Integer
などと書く事もできます。
> 別言語の場合はワークグループの変更ができないので(Unicode文字列を扱えない仕様なので)
VB6 で Unicode 文字列を API に渡す場合は、ByVal String ではなく、
ByRef Byte で宣言して、バイナリデータとして渡す事になります。
>魔界の仮面弁士様
ありがとうございます。
サンプルをそのまま利用していたため(エラーにもならなかったため)
呼び出しの仕様がかわっていたことすらも知りませんでした。
(数年ぶりにVBを使うからこういう事に・・・)
呼び出しの方法を変えたところPC名の変更も無事完了しました。
あとは、配布環境を整える次第です。
>> 別言語の場合はワークグループの変更ができないので(Unicode文字列を扱えない仕様なので)
>VB6 で Unicode 文字列を API に渡す場合は、ByVal String ではなく、
>ByRef Byte で宣言して、バイナリデータとして渡す事になります。
別言語(=PowerBuilder)なのですが、同一の方法で実行可能か確認をしてみます。
ありがとうございました。
ツイート | ![]() |