问题描述
我有一个以管理员身份运行并充当命名管道服务器的 VB.NET 进程(非服务)。 DLL 被注入到某些进程中,并且 DLL 尝试连接到服务器进程。这一切都在同一台主机上。
我收到来自客户端的 ACCESS_DENIED (5) 错误,但仅在前两个客户端成功连接到服务器后才会发生。因此,至少有两个可以成功连接,然后所有其他尝试都被拒绝。
在我的测试 VM 中,至少创建了 4 个管道服务器实例,因此它似乎不是管道繁忙的简单情况(无论如何我假设返回 STATUS_PIPE_BUSY 而不是 ACCESS_DENIED)。我还添加了最宽松的管道安全性 (WorldSid/FullControl),但它仍然失败。
这是服务器管道代码:
tidyr::separate
在 DLLMain() 期间,使用以下调用进行连接尝试,这是连接失败并显示 ACCESS_DENIED 的地方。
Private Sub PipeSetup()
For x = 1 To Environment.ProcessorCount '4 in my test VM
t = New Thread(AddressOf PipeSetupProc)
t.IsBackground = True
t.Start()
Next
End Sub
Private Sub PipeSetupProc()
Dim s As NamedPipeServerStream = nothing
Dim x As PipeSecurity = nothing
While True
Try
'I've made the access rule the most permissive possible
'and I'm still getting ACCESS_DENIED from the client.
x = New PipeSecurity()
x.AddAccessRule(New PipeAccessRule(New SecurityIdentifier(WellKNownSidType.WorldSid,nothing),PipeAccessRights.FullControl,Security.AccessControl.AccessControlType.Allow))
s = New NamedPipeServerStream(MY_PIPE_NAME,PipeDirection.InOut,NamedPipeServerStream.MaxAllowedServerInstances,PipeTransmissionMode.Message,PipeOptions.Asynchronous,4096,x)
s.WaitForConnection()
'Do stuff here...
s.Close()
s = nothing
Catch ex As Exception
'logerror()
End Try
End While
End Sub
解决方法
检查两边的 MY_PIPE_NAME。对于 C++,它应该类似于“\\.\pipe\MY_PIPE”,而在 vb 方面,它只是“MY_PIPE”。
如果数据总是从 vb 到 dll,你可以在 c++ 中声明一个函数从 vb 调用(在'extern "c"' 内)。
_stdcall int Send2Cpp(char * msg,int length){ /*...*/}
我习惯于在 module.def 中定义我的导出。如果没有,请添加 nessasary dll 导出条款。否则,将文件 module.def 添加到您的 vs c++ 项目中,内容
LIBRARY
EXPORTS
Send2Cpp
然后从vb中,添加
Public Declare Function Send2Cpp Lib "mydll.dll" (byval S as byte,byval L as integer) as integer
您也可以从 vb 提供回调。
Public Delegate Function GetCppString(ByVal str As IntPtr)
Function LogC(ByVal LI As IntPtr,ByVal lc As Int64) As Int64
Dim F(lc) As Byte
Marshal.Copy(LI,F,lc)
Debug.Print(System.Text.Encoding.ASCII.GetString(F))
End Function
'make sure these vars persist untill dll is done with pointer
'or you will get errors when they are GC'd
dim CBD as GetCppString=AddressOf(GetCppString)
dim CB_PTR as IntPtr = Marshal.GetFunctionPointerForDelegate(CBD)
然后你将 CB_PTR 传递给一个 dll 函数,在那里你可以从他们那里调用这个函数。在 C++ 中
typedef int(*send2vb)(char *,int);
void RegCB(send2vb f){ /*do something with function pointer*/}
在这种情况下,将 RegCB 添加到您的 module.def 并在 vb 中为其声明。 然后你有 dll 和 vb 之间的双向通信。 (当然,您必须将它们全部连接在一起。在您的 dllmain 中,只需在发送数据之前等待函数指针为非空即可。 附注我只是提到了这一点,因为事实证明它比管道或类似的东西更有效,特别是如果您使用与您的用例相匹配的函数(在我的情况下,它是从 c++ dll 到 vb 和返回的视频)。