機能を開発しようとしているのですが、WNetAddConnection3を呼び出すとNotSupportedExceptionエラーが発生し困っています。
※C++で実装するとNotSupportedExceptionエラーは発生しません。
【環境】
OS :WindowsMobile5(WindowsCE5)
機体:hx2790b
開発環境:VisualStudio2005
言語:VB.net
【やりたい事】
LAN上のWindows2000の共有フォルダからファイルをコピーしたい。
その際に、ログイン画面(ユーザー、パスワード、ドメインを入力する
画面)を表示させずに共有フォルダを利用可能にしたい。
【ソース】
Private Declare Function WNetAddConnection3 Lib "CoreDll.dll" Alias "WNetAddConnection3W" (ByRef hwndOwner As Object, ByRef lpNetResource As NETRESOURCE, ByRef lpPassword As String, ByRef lpUserName As String, ByVal dwFlags As Integer) As Integer
:
略
:
Dim netrs As NETRESOURCE
netrs.dwType = RESURCETYPE_ANY
netrs.lpLocalName = vbNullString
netrs.lpRemoteName = "\\hogeWin2k\share"
netrs.lpProvider = vbNullString
'API呼び出し!
lngRet = WNetAddConnection3(vbNullString, netrs, "USERNAME", "PASSWORD", CONNECT_INTERACTIVE)
よろしくお願い致します。
.NET Compact Frameworkのマーシャル機能はかなり限定されていますので、文字列を含んだ構造体などは自動的に適切な処理を行ってくれません。この場合、自分でマーシャリング処理を実装して適切なアンマネージド形式の構造体を作ってAPIにポインタを渡す必要があります。
こちらにやり方が書かれています。
Microsoft .NET Compact Framework での高度な P/Invoke
VBでやる場合は、3つめの方法「マネージ文字列ポインタの使用」を使って実装することになります。
時間が作れたらサンプルを作って回答追加しますが、C++の経験もおありのようなので、後学のために自分で挑戦してみるのもよろしいかと思います。
またはサックリ済ませるのであれば、1つめの方法(C++でサンクDLLを作って経由する)の方が手っ取り早いです。
.NET Compact Frameworkのマーシャル機能はかなり限定されていますので、文字列を含んだ構造体などは自動的に適切な処理を行ってくれません。この場合、自分でマーシャリング処理を実装して適切なアンマネージド形式の構造体を作ってAPIにポインタを渡す必要があります。
こちらにやり方が書かれています。
Microsoft .NET Compact Framework での高度な P/Invoke
VBでやる場合は、3つめの方法「マネージ文字列ポインタの使用」を使って実装することになります。
時間が作れたらサンプルを作って回答追加しますが、C++の経験もおありのようなので、後学のために自分で挑戦してみるのもよろしいかと思います。
またはサックリ済ませるのであれば、1つめの方法(C++でサンクDLLを作って経由する)の方が手っ取り早いです。
ardarim様
ありがとうございます。
教えていただいたURLを参考にこちらでもやろうと思うのですが、
なかなか作業時間を確保するのが難しく、、、
もしよろしければ「マネージ文字列ポインタの使用」でサンプルまでご提示いただけるとうれしいです。
いちおう動くみたいですが、バグ等は保証の限りでありませんので自己責任でお願いします。
MemoryとStringPtrはMicrosoftのページからそのままコピペしています。
いろいろ調べたらこのMicrosoftのページで紹介されているMemoryというクラスもメモリリークのバグがあるようですので見直したほうが良いと思います。
Imports System.ComponentModel Imports System.Runtime.InteropServices Public Class Form1 Private Structure NETRESOURCE Public dwScope As Integer Public dwType As Integer Public dwDisplayType As Integer Public dwUsage As Integer Public lpLocalName As StringPtr Public lpRemoteName As StringPtr Public lpComment As StringPtr Public lpProvider As StringPtr Public Sub Free() lpLocalName.Free() lpRemoteName.Free() lpComment.Free() lpProvider.Free() End Sub End Structure Private Declare Function WNetAddConnection3 Lib "coredll" Alias "WNetAddConnection3W" ( _ ByVal hwndOwner As Integer, _ ByRef lpNetResource As NETRESOURCE, _ ByVal lpPassword As String, _ ByVal lpUserName As String, _ ByVal dwFlags As Integer _ ) As Integer Private Const RESOURCETYPE_ANY As Integer = &H0 Private Const CONNECT_INTERACTIVE As Integer = &H8 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim lngRet As Integer Dim netrs As NETRESOURCE netrs.dwType = RESOURCETYPE_ANY netrs.lpLocalName = New StringPtr() netrs.lpRemoteName = New StringPtr("\\hogeWin2k\share") netrs.lpComment = New StringPtr() netrs.lpProvider = New StringPtr() lngRet = WNetAddConnection3(System.IntPtr.Zero, netrs, "password", "username", CONNECT_INTERACTIVE) MsgBox(lngRet) netrs.Free() End Sub End Class Public Class Memory <DllImport("coredll.dll", SetLastError:=True)> _ Private Shared Function LocalAlloc(ByVal uFlags As Integer, _ ByVal uBytes As Integer) As IntPtr End Function <DllImport("coredll.dll", SetLastError:=True)> _ Private Shared Function LocalFree(ByVal hMem As IntPtr) As IntPtr End Function <DllImport("coredll.dll", SetLastError:=True)> _ Private Shared Function LocalReAlloc(ByVal hMem As IntPtr, _ ByVal uBytes As Integer, ByVal fuFlags As Integer) As IntPtr End Function Private Const LMEM_FIXED As Integer = 0 Private Const LMEM_MOVEABLE As Integer = 2 Private Const LMEM_ZEROINIT As Integer = &H40 Private Const LPTR = (LMEM_FIXED Or LMEM_ZEROINIT) ' LocalAlloc を使用して、メモリ ブロックを割り当てます。 Public Shared Function AllocHLocal(ByVal cb As Integer) As IntPtr Return LocalAlloc(LPTR, cb) End Function ' AllocHLocal で割り当てられたメモリを解放します。 Public Shared Sub FreeHLocal(ByVal hlocal As IntPtr) If Not hlocal.Equals(IntPtr.Zero) Then If Not IntPtr.Zero.Equals(LocalFree(hlocal)) Then Throw New Win32Exception(Marshal.GetLastWin32Error()) End If hlocal = IntPtr.Zero End If End Sub ' 以前に AllocHLocal で割り当てられたメモリ ブロックのサイズを変更します。 Public Shared Function ReAllocHLocal(ByVal pv As IntPtr, _ ByVal cb As Integer) As IntPtr Dim newMem As IntPtr = LocalReAlloc(pv, cb, LMEM_MOVEABLE) If newMem.Equals(IntPtr.Zero) Then Throw New OutOfMemoryException End If Return newMem End Function ' マネージ文字列の内容をアンマネージ メモリにコピーします。 Public Shared Function StringToHLocalUni( _ ByVal s As String) As IntPtr If s Is Nothing Then Return IntPtr.Zero Else Dim nc As Integer = s.Length Dim len As Integer = 2 * (1 + nc) Dim hLocal As IntPtr = AllocHLocal(len) If hLocal.Equals(IntPtr.Zero) Then Throw New OutOfMemoryException Else Marshal.Copy(s.ToCharArray(), 0, hLocal, s.Length) Return hLocal End If End If End Function End Class Public Structure StringPtr Private szString As IntPtr Public Sub New(ByVal s As String) Me.szString = Memory.StringToHLocalUni(s) End Sub Public Overrides Function ToString() As String Return Marshal.PtrToStringUni(Me.szString) End Function Public Sub Free() Memory.FreeHLocal(Me.szString) End Sub End Structure
ardarim様
サンプルの提示までいただきありがとうございました。
今回はC#でDLLを作成しそれをVB.net側から利用することにします。
(メモリリークの可能性があるのであればVB.netで実装するのは怖いです)
ardarim様
ありがとうございます。
教えていただいたURLを参考にこちらでもやろうと思うのですが、
なかなか作業時間を確保するのが難しく、、、
もしよろしければ「マネージ文字列ポインタの使用」でサンプルまでご提示いただけるとうれしいです。