.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

plugin problem in vb .net

25 REPLIES 25
Reply
Message 1 of 26
dj-nemo
2043 Views, 25 Replies

plugin problem in vb .net

Hi everyone

 

I want to make plugin for AutoCAD but i have some problems. 

 

I want to make plugin that connect to server, send there current image and then server do something with it and send back results.

So I am actualy making 2 plugins. One on server side, other on client side.

 

Server side code: 

Imports System.Net.Sockets
Imports System.Text
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports System.Net
Imports System.Threading
Imports Autodesk.AutoCAD.EditorInput

Namespace serverACDrendering

    Public Class Commands
        Dim close As Boolean = False
        Dim MAX_CLIENTS As Integer = 5
        Dim queue(MAX_CLIENTS) As ClientWrapper
        Dim currentClient As Integer = 0

        <CommandMethod("StartServer")>
        Public Sub StartServer()
            For i As Integer = 0 To MAX_CLIENTS
                queue(i) = Nothing
            Next
            Dim receiverThread As Thread = New Thread(AddressOf receiver)
            Dim transmitterThread As Thread = New Thread(AddressOf transmitter)
            receiverThread.Start()
            Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor
            ed.WriteMessage("\nreceiver thread started\n}")
            transmitterThread.Start()
            ed.WriteMessage("\ntransmitter thread Started\n")
            While (Not close)
                ed.WriteMessage("\nCreated both threads... Time to rock ...\n")
            End While
        End Sub

 

 <CommandMethod("StopServer")>
        Public Sub StopServer()
            close = False
        End Sub
    End Class

 

So i have two more threads receiver thread and transmitter thread. First is getting  clients and get file from them, second send results back to them. 

 

The problem 

 While (Not close)
          ed.WriteMessage("\nCreated both threads... Time to rock ...\n")
 End While

 In this while loop i shold take one client and do something with it.

When this loop starts i cant stop it from autocad with StopServer command (I think because autocad is busy). 

I can't do this in seperate thread because autoCAD don't do multithreading.

 

What can i do to put this work in background ?

 

Regards Domen

 

 

25 REPLIES 25
Message 2 of 26
khoa.ho
in reply to: dj-nemo

You make AutoCAD to work as a server for both a receiver (get files from clients) and a transmitter (send results back to clients). When you start the server, both two methods receiver() and transmitter() send to execution at nearly the same time. Then the code goes to an infinite loop, write to the editor and keeps AutoCAD non-stopped busy. So there is no chance to enter the command StopServer on AutoCAD, as the editor is busy.

To stop the server, you may think to use the Timer (instead of while loop), set an interval time to check the clients. By that way, the method StartServer will have chance to avoid the infinite loop that does not allow this command to finish.

Because AutoCAD .NET API is single-threaded, make sure that there is a lock key to switch between receiver() and transmitter(). This static variable will allow only one method (receiver OR transmitter) to execute AutoCAD .NET functions at the time. We cannot let AutoCAD go multithreading.

-Khoa

Message 3 of 26
dj-nemo
in reply to: dj-nemo

Thanks for answer i repair it but ...

 

I put timer in code but i got another error: eNotApplicable

 

    Public Class Commands
        Dim close As Boolean = False
        Dim MAX_CLIENTS As Integer = 5
        Dim queue(MAX_CLIENTS) As ClientWrapper
        Dim currentClient As Integer = 0
        Dim timer As New System.Timers.Timer
        Dim editor As Editor = Application.DocumentManager.MdiActiveDocument.Editor

        <CommandMethod("StartServer")>
        Public Sub StartServer()
            For i As Integer = 0 To MAX_CLIENTS
                queue(i) = Nothing
            Next
            Dim receiverThread As Thread = New Thread(AddressOf Receiver)
            Dim transmitterThread As Thread = New Thread(AddressOf Transmitter)
            receiverThread.Start()
            editor.WriteMessage(vbNewLine & " receiver thread started" & vbNewLine)
            transmitterThread.Start()
            editor.WriteMessage(vbNewLine & " transmitter thread Started" & vbNewLine)
            timer.Enabled = True
            timer.Interval = 15000 'every 15 seconds
            AddHandler timer.Elapsed, AddressOf Work
        End Sub


        Private Sub Work()
            editor.WriteMessage(vbNewLine & "working ..." & vbNewLine)
        End Sub

 Error is rised in line "End Sub" from subroutine Work()

The Subroutines Receiver and Transmitter are empty functions for now

 

I would like that Receiver work non-stop so it can get clients all the time. Is there any way to do this?

 

Message 4 of 26
khoa.ho
in reply to: dj-nemo

I think the problem "eNotApplicable" came from the Timer running on another thread to trigger the time event. When it hit the time, this non-AutoCAD thread calls the AutoCAD editor and causes the thread violation with the current AutoCAD thread. We cannot have two threads refer to the same AutoCAD instance.

AutoCAD .NET (ObjectARX wrapper) is single-threaded (as it is not fully .NET managed code), so only one main thread allows to run per AutoCAD instance. I did a test without the Timer; it also caused an error of "CrossThreadMessagingException". So the problem is not from the Timer, it was from the new thread.

Using threads in AutoCAD .NET is very dangerous because it actually calls ObjectARX native code behind the scene. I would not use threads to call AutoCAD .NET functions. I don't know it may have another solution from official Autodesk developers.

You may try to remove threads from your code, and use TWO AutoCAD instances. One AutoCAD will work as a receiver; another AutoCAD will work as a transmitter. Then you open two AutoCAD and run different commands, one for receiver to get files from clients, another for transmitter to send results back to clients. Those two AutoCAD plugins refer to another DLL file just for data communication (non-AutoCAD code) between two AutoCAD instances. You may use While Loop again instead of Timer (as Timer may cause thread issue).

Hope it may help.
-Khoa

Message 5 of 26
dj-nemo
in reply to: dj-nemo

Thanks it helped me a lot. 

So i decided to make plugin that will work for only one client at the time, when client connected i will render his file and send back photos.

 

I make some progress but got problem with socket. When i want read from socket on client side it say it's closed.

 

 

Sorry for having so much work with me

 

Server Side code:

Imports System.Net.Sockets
Imports System.Text
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports System.Net
Imports System.IO
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD

Namespace serverACDrendering

    Public Class Command
        Dim close As Boolean = False 'when true server ends
        Dim client As ClientWrapper 'queue that holds clients and their files
        Dim editor As Editor = Application.DocumentManager.MdiActiveDocument.Editor 'editor for writing to command line
        Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
        Private Const portNum = 8000
        Private Const ipServer = "127.0.0.1"
        Private PACKET_SIZE As UInt16 = 4096
        Dim path As String = "c:\renderPluginACD\redering.dwg"

        <CommandMethod("StartServer")>
        Public Sub StartServer()
            editor.WriteMessage(vbNewLine & "starting ..." & vbNewLine)
            ' While (Not close)
            client = New ClientWrapper
            Receiver()
            Render()
            Transmitter()
            System.Threading.Thread.Sleep(2000)
            ' End While
        End Sub

        Private Sub Render()
            Dim Mstream As MemoryStream = client.GetFile
            If (Not Directory.Exists("c:\renderPluginACD")) Then
                Directory.CreateDirectory("c:\renderPluginACD")
            End If
            If (File.Exists(path)) Then
                File.Delete(path)
            End If
            Dim fs As FileStream = File.OpenWrite(path)
            Mstream.WriteTo(fs)
            client.SetResult(fs)
            fs.Close()
        End Sub

        'receive connection and put file in queue
        Private Sub Receiver()
            Dim tcpListener As TcpListener
            Dim ip As IPAddress = IPAddress.Parse(ipServer)
            tcpListener = New TcpListener(ip, portNum)
            tcpListener.Start()
            Try
                Dim TcpClient = tcpListener.AcceptTcpClient()
                If (TcpClient.Connected) Then
                    client.SetTcpClient(TcpClient)

                    Dim Reader As BinaryReader
                    Dim ReadBuffer(PACKET_SIZE) As Byte
                    Dim NData As Int32
                    Dim MStream As MemoryStream
                    Dim LData As Int32

                    Reader = New BinaryReader(TcpClient.GetStream)
                    NData = Reader.ReadInt32
                    MStream = New MemoryStream
                    While NData > 0
                        LData = TcpClient.GetStream.Read(ReadBuffer, 0, PACKET_SIZE)
                        MStream.Write(ReadBuffer, 0, LData)
                        NData -= LData
                    End While
                    editor.WriteMessage(vbNewLine & "received file ..." & vbNewLine)
                    client.SetFile(MStream)
                End If
            Catch e As Exception
            End Try
            'tcpListener.Stop()
        End Sub

        'send back the resutls
        Private Sub Transmitter()
            Dim fs As FileStream = New FileStream(path, FileMode.Open, FileAccess.Read)
            Dim length As Integer = CType(fs.Length, Integer)
            Dim reader As New BinaryReader(fs)
            Dim buffer() As Byte ' Data buffer

            Dim Writer As New BinaryWriter(client.GetTcpClient.GetStream)
            Writer.Write(length)
            Do
                'read data from file
                buffer = reader.ReadBytes(PACKET_SIZE)
                'write data to Network Stream
                Writer.Write(buffer)
            Loop While buffer.Length = PACKET_SIZE
            Writer.Flush()
            Writer.Close()
            reader.Close()
            fs.Close()
        End Sub

        'stops server
        <CommandMethod("StopServer")>
        Public Sub StopServer()
            close = False
        End Sub
    End Class


    'wrapper for clients in queue
    Public Class ClientWrapper
        Dim tcpClient As TcpClient
        Dim file As Object
        Dim result As Object
        Dim flag As Integer

        Public Function GetTcpClient() As TcpClient
            Return tcpClient
        End Function

        Public Sub SetTcpClient(_tcpClient As TcpClient)
            tcpClient = _tcpClient
        End Sub

        Public Function GetFile() As Object
            Return file
        End Function

        Public Sub SetFile(_file As Object)
            file = _file
        End Sub

        Public Function GetResult() As Object
            Return result
        End Function

        Public Sub SetResult(_result As Object)
            result = _result
        End Sub

    End Class
End Namespace

 

 

Client side Code:

Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.ApplicationServices
Imports System.Net.Sockets
Imports System.Text
Imports System
Imports System.IO
Imports Autodesk.AutoCAD.DatabaseServices

Imports app = Autodesk.AutoCAD.ApplicationServices.Application

Namespace Plugin1

    Public Class Commands
        Private Const portNum = 8000
        Private Const ipServer = "127.0.0.1"
        Private Const BUFFER_SIZE As Integer = 8192
        Dim isActive As Boolean = False
        Dim acDoc As Document
        Dim receive As Object
        Private PACKET_SIZE As UInt16 = 4096
        Dim tcpClient As New System.Net.Sockets.TcpClient()

        <CommandMethod("RenderOnHPC")>
        Public Sub SendToRenderer()
            Save()
            Connect()
            Send()
            ReceivePhoto()
        End Sub

        Private Sub Save()
            acDoc = Application.DocumentManager.MdiActiveDocument
            Dim strDWGName As String = acDoc.Name
            Dim obj As Object = Application.GetSystemVariable("DWGTITLED")
            strDWGName = "c:\renderPluginACD\MyDrawing.dwg"
            'Save the active drawing 
            If (Not Directory.Exists("c:\renderPluginACD")) Then
                Directory.CreateDirectory("c:\renderPluginACD")
            End If
            acDoc.Database.SaveAs(strDWGName, False, DwgVersion.Current, acDoc.Database.SecurityParameters)
            acDoc.Database.Dispose()
        End Sub

        Private Sub Connect()
            tcpClient.Connect(ipServer, portNum)
        End Sub

        Private Sub Send()
            Dim fs As FileStream = New FileStream("c:\renderPluginACD\MyDrawing.dwg", FileMode.Open, FileAccess.Read)
            Dim length As Integer = CType(fs.Length, Integer)
            Dim reader As New BinaryReader(fs)
            Dim buffer() As Byte ' Data buffer
            Try
                tcpClient.GetStream()
                Dim Writer As New BinaryWriter(tcpClient.GetStream())
                Writer.Write(length)
                Do
                    'read data from file
                    buffer = reader.ReadBytes(PACKET_SIZE)
                    'write data to Network Stream
                    Writer.Write(buffer)
                Loop While buffer.Length = PACKET_SIZE
                Writer.Flush()
                Writer.Close()
                reader.Close()
            Catch ex As System.Exception
                ' Handle errors
            End Try
            fs.Close()
        End Sub

        Private Sub ReceivePhoto()
            Dim renderedPath As String = "c:\renderPluginACD\return.dwg"
            Dim reader2 As BinaryReader
            Dim readBuffer(PACKET_SIZE) As Byte
            Dim nData As Int32
            Dim mStream As MemoryStream
            Dim lData As Int32

            reader2 = New BinaryReader(tcpClient.GetStream())
            nData = reader2.ReadInt32
            MStream = New MemoryStream
            While NData > 0
                LData = tcpClient.GetStream.Read(ReadBuffer, 0, PACKET_SIZE)
                MStream.Write(ReadBuffer, 0, LData)
                NData -= LData
            End While
            If (File.Exists(RenderedPath)) Then
                File.Delete(RenderedPath)
            End If
            Dim fs As FileStream = File.OpenWrite(RenderedPath)
            MStream.WriteTo(fs)
        End Sub

    End Class
End Namespace

 

 

 

Message 6 of 26
khoa.ho
in reply to: dj-nemo

Hi,

I ran your code and saw the error came from the disconnected TcpClient. On the client Send() function, when you close the BinaryWriter, it will also dispose the NetworkStream and close the reference TcpClient connection. So just comment out writer.Close() and it's good to go.

We need to open two AutoCAD instances, one types the command "StartServer", another types the command "RenderOnHPC" and we will see how the client saves DWG files.

It is interesting to make two AutoCAD working as a server and a client, and then they communicate each other by network streams using TCP (http://127.0.0.1:8000). With the TCP listening event, it does not need to use While Loop. I am guessing it still has a lot of work with this idea.

I copied your code, did some minor changes and had the final working code:

Public Class ServerPlugin
	Private Const PortNum As Integer = 8000
	Private Const IpServer As String = "127.0.0.1"
	Private Const PACKET_SIZE As UInt16 = 4096
	'when true server ends
	Private close As Boolean = False
	'queue that holds clients and their files
	Private client As ClientWrapper
	'editor for writing to command line
	Private ReadOnly editor As Editor = Application.DocumentManager.MdiActiveDocument.Editor
	Private acDoc As Document = Application.DocumentManager.MdiActiveDocument
	Private path As String = "c:\renderPluginACD\rendering.dwg"
	Private tcpClient As System.Net.Sockets.TcpClient

	<CommandMethod("StartServer")> _
	Public Sub StartServer()
		editor.WriteMessage(vbLf + "starting ..." + vbLf)
		' While (Not close)
		client = New ClientWrapper()
		Receiver()
		Render()
		Transmitter()
		Disconnect()
		System.Threading.Thread.Sleep(2000)
		' End While
	End Sub

	'receive connection and put file in queue
	Private Sub Receiver()
		Dim ip As IPAddress = IPAddress.Parse(IpServer)
		Dim tcpListener = New TcpListener(ip, PortNum)
		tcpListener.Start()
		Try
			' perform a blocking call to accept requests
			tcpClient = tcpListener.AcceptTcpClient()
			' keep waiting until a client is connected at http://127.0.0.1:8000
			If tcpClient.Connected Then
				client.SetTcpClient(tcpClient)

				Dim readBuffer = New Byte(PACKET_SIZE) {}

				Dim reader = New BinaryReader(tcpClient.GetStream())
				Dim nData As Integer = reader.ReadInt32()
				Dim mStream = New MemoryStream()
				While nData > 0
					Dim lData As Integer = tcpClient.GetStream().Read(readBuffer, 0, PACKET_SIZE)
					mStream.Write(readBuffer, 0, lData)
					nData -= lData
				End While
				editor.WriteMessage(vbLf + "received file ..." + vbLf)
				client.SetFile(mStream)
			End If
		Catch e As System.Exception
		End Try
		'tcpListener.Stop()
	End Sub

	Private Sub Render()
		Dim mStream = DirectCast(client.GetFile(), MemoryStream)
		If Not Directory.Exists("c:\renderPluginACD") Then
			Directory.CreateDirectory("c:\renderPluginACD")
		End If
		If File.Exists(path) Then
			File.Delete(path)
		End If
		Dim fs As FileStream = File.OpenWrite(path)
		mStream.WriteTo(fs)
		client.SetResult(fs)
		fs.Close()
	End Sub

	'send back the resutls
	Private Sub Transmitter()
		Dim fs = New FileStream(path, FileMode.Open, FileAccess.Read)
		Dim length As Integer = Convert.ToInt32(fs.Length)
		Dim reader = New BinaryReader(fs)
		Dim buffer As Byte()
		' Data buffer
		Dim writer = New BinaryWriter(client.GetTcpClient().GetStream())
		writer.Write(length)
		Do
			'read data from file
			buffer = reader.ReadBytes(PACKET_SIZE)
			'write data to Network Stream
			writer.Write(buffer)
		Loop While buffer.Length = PACKET_SIZE
		writer.Flush()
		writer.Close()
		reader.Close()
		fs.Close()
	End Sub

	Private Sub Disconnect()
		' shutdown and end connection
		tcpClient.Close()
	End Sub

	'stops server
	<CommandMethod("StopServer")> _
	Public Sub StopServer()
		close = False
	End Sub
End Class

'wrapper for clients in queue
Public Class ClientWrapper
	Private tcpClient As TcpClient
	Private file As Object
	Private result As Object
	Private flag As Integer

	Public Function GetTcpClient() As TcpClient
		Return tcpClient
	End Function

	Public Sub SetTcpClient(_tcpClient As TcpClient)
		tcpClient = _tcpClient
	End Sub

	Public Function GetFile() As Object
		Return file
	End Function

	Public Sub SetFile(_file As Object)
		file = _file
	End Sub

	Public Function GetResult() As Object
		Return result
	End Function

	Public Sub SetResult(_result As Object)
		result = _result
	End Sub
End Class

Public Class ClientPlugin
	Private Const PortNum As Integer = 8000
	Private Const IpServer As String = "127.0.0.1"
	Private Const BUFFER_SIZE As Integer = 8192
	Private Const PACKET_SIZE As UInt16 = 4096
	Private isActive As Boolean = False
	Private receive As Object
	Private tcpClient As System.Net.Sockets.TcpClient

	<CommandMethod("RenderOnHPC")> _
	Public Sub SendToRenderer()
		Save()
		Connect()
		Send()
		ReceivePhoto()
		Disconnect()
	End Sub

	Private Sub Save()
		Dim doc As Document = Application.DocumentManager.MdiActiveDocument
		Dim db As Database = doc.Database
		Using db
			Dim strDWGName As String = doc.Name
			Dim obj As Object = Application.GetSystemVariable("DWGTITLED")
			strDWGName = "c:\renderPluginACD\MyDrawing.dwg"
			'Save the active drawing 
			If Not Directory.Exists("c:\renderPluginACD") Then
				Directory.CreateDirectory("c:\renderPluginACD")
			End If
			db.SaveAs(strDWGName, False, DwgVersion.Current, doc.Database.SecurityParameters)
		End Using
	End Sub

	Private Sub Connect()
		tcpClient = New System.Net.Sockets.TcpClient()
		tcpClient.Connect(IpServer, PortNum)
	End Sub

	Private Sub Disconnect()
		' shutdown and end connection
		tcpClient.Close()
	End Sub

	Private Sub Send()
		Dim fs = New FileStream("c:\renderPluginACD\MyDrawing.dwg", FileMode.Open, FileAccess.Read)
		Dim length As Integer = Convert.ToInt32(fs.Length)
		Dim reader = New BinaryReader(fs)
		' Data buffer
		Try
			Dim stream As NetworkStream = tcpClient.GetStream()
			Dim writer = New BinaryWriter(stream)
			writer.Write(length)
			Dim buffer As Byte()
			Do
				'read data from file
				buffer = reader.ReadBytes(PACKET_SIZE)
				'write data to Network Stream
				writer.Write(buffer)
			Loop While buffer.Length = PACKET_SIZE
			writer.Flush()
			'writer.Close();	// do not close the TcpClient connection
			reader.Close()
				' Handle errors
		Catch ex As System.Exception
		End Try
		fs.Close()
	End Sub

	Private Sub ReceivePhoto()
		Dim renderedPath As String = "c:\renderPluginACD\return.dwg"
		Dim readBuffer = New Byte(PACKET_SIZE) {}

		Dim reader2 = New BinaryReader(Me.tcpClient.GetStream())
		Dim nData As Integer = reader2.ReadInt32()
		Using mStream = New MemoryStream()
			While nData > 0
				Dim lData As Integer = Me.tcpClient.GetStream().Read(readBuffer, 0, PACKET_SIZE)
				mStream.Write(readBuffer, 0, lData)
				nData -= lData
			End While
			If File.Exists(renderedPath) Then
				File.Delete(renderedPath)
			End If
			Dim fs As FileStream = File.OpenWrite(renderedPath)
			mStream.WriteTo(fs)
			fs.Close()
		End Using
	End Sub
End Class

 

-Khoa

Message 7 of 26
dj-nemo
in reply to: khoa.ho

Thanks it works great.

 

Now i want to upgrade code that it will actualy render file and instead returning dwg send back picture.

I was looking throu internet for some exsamples and found only one useful link. So i try use it and do following:

 

        Private Sub Render()
            Dim mStream = DirectCast(client.GetFile(), MemoryStream)
            If Not Directory.Exists("c:\renderPluginACD") Then
                Directory.CreateDirectory("c:\renderPluginACD")
            End If
            If File.Exists(path) Then
                File.Delete(path)
            End If
            Dim fs As FileStream = File.OpenWrite(path)
            mStream.WriteTo(fs)
            fs.Close()
'i saved file to here
' now i want to open it and render it Dim doc As Document = Application.DocumentManager.MdiActiveDocument doc.Database.ReadDwgFile(path, FileOpenMode.OpenTryForReadShare, True, Nothing) Dim fileName As String = "c:\renderPluginACD\picture.png" Dim vpn As Integer = System.Convert.ToInt32(Application.GetSystemVariable("CVPORT")) Dim gsv As View = doc.GraphicsManager.GetGsView(vpn, True) Dim view As View = gsv.Clone(True, True) Dim dev As Device = doc.GraphicsManager.CreateAutoCADOffScreenDevice() 'dev.OnSize(doc.GraphicsManager.DeviceIndependentDisplaySize) dev.DeviceRenderType = RendererType.FullRender dev.Add(view) Dim bitmap As Bitmap = view.RenderToImage bitmap.Save(fileName) fs = File.OpenRead(fileName) client.SetResult(fs) End Sub

 

The problems occurs with reading dwg file. 

Message 8 of 26
khoa.ho
in reply to: dj-nemo

I am a bit late to answer as I am working at day time (US CST).

There are some points to solve the problem:

1. You should not use ReadDwgFile() from the current database of MdiActiveDocument as it will cause "eRepeatedDwgRead" error. Reading an external DWG file from the current DWG file is not allowed. It's better to use database.Insert method. Instead, we will use Application.DocumentManager.Open(dwgPath).

2. There is nothing to render on the DWG source file (c:\renderPluginACD\rendering.dwg). This file should not be empty or have no Modelling entities. The DWG rendering file should have some Modelling objects (Sphere, Box, Cylinder...) to render. Otherwise, it will cause error at view.RenderToImage() method. I already added the code to check this exception error (view.BackgroundId == ObjectId.Null).

3. If I put some Modelling entities on rendering.dwg, the code will output an image (picture.png) correctly. So you have to work to pass entities to render. There is nothing to render now so you won't see anything.

 

4. You should use Using to wrap the code to release unmanaged objects after finishing the method. I put the code with Using from Kean's code back.

Please see my fixed code:

Private Sub Render()
	Dim mStream = DirectCast(client.GetFile(), MemoryStream)
	If Not Directory.Exists("c:\renderPluginACD") Then
		Directory.CreateDirectory("c:\renderPluginACD")
	End If
	If File.Exists(path) Then
		File.Delete(path)
	End If
	Dim fs As FileStream = File.OpenWrite(path)
	mStream.WriteTo(fs)
	fs.Close()
	'i saved file to here
	' now i want to open it and render it
	Dim doc As Document = Application.DocumentManager.Open(path)

	Dim fileName As String = "c:\renderPluginACD\picture.png"
	Dim vpn As Integer = System.Convert.ToInt32(Application.GetSystemVariable("CVPORT"))
	Dim gsv As GraphicsSystem.View = doc.GraphicsManager.GetGsView(vpn, True)
	Using view As GraphicsSystem.View = gsv.Clone(True, True)
		' Do not render the drawing if there are no rendering objects
		If view.BackgroundId = ObjectId.Null Then
			Return
		End If

		Using dev As Device = doc.GraphicsManager.CreateAutoCADOffScreenDevice()
			'dev.OnSize(doc.GraphicsManager.DeviceIndependentDisplaySize)
			dev.DeviceRenderType = RendererType.FullRender
			dev.Add(view)
			Using bitmap As Bitmap = view.RenderToImage()
				bitmap.Save(fileName)
				fs = File.OpenRead(fileName)
				client.SetResult(fs)
			End Using
		End Using
	End Using
End Sub

 

-Khoa

Message 9 of 26
dj-nemo
in reply to: khoa.ho

Hi

 

the solution you wrote don't work for me because i am working on AutoCAD 2013 and therefor ObjectARX for AutoCAD 2013. 

 

I repaired in this way:

Private Sub Render()
            Dim mStream = DirectCast(client.GetFile(), MemoryStream)
            If Not Directory.Exists("c:\renderPluginACD") Then
                Directory.CreateDirectory("c:\renderPluginACD")
            End If
            If File.Exists(path) Then
                File.Delete(path)
            End If
            Dim fs As FileStream = File.OpenWrite(path)
            mStream.WriteTo(fs)
            fs.Close()
            Dim docCol As DocumentCollection = Application.DocumentManager
            Dim doc As Document
            doc = DocumentCollectionExtension.Open(docCol, path)
            Dim fileName As String = "c:\renderPluginACD\picture.png"
            Dim vpn As Integer = System.Convert.ToInt32(Application.GetSystemVariable("CVPORT"))
            Dim gsv As GraphicsSystem.View = doc.GraphicsManager.GetGsView(vpn, True)
            Using view As GraphicsSystem.View = gsv.Clone(True, True)
                ' Do not render the drawing if there are no rendering objects
                If view.BackgroundId = ObjectId.Null Then
                    Return
                End If
                Using dev As Device = doc.GraphicsManager.CreateAutoCADOffScreenDevice()
                    dev.DeviceRenderType = RendererType.FullRender
                    dev.Add(view)
                    Using bitmap As Bitmap = view.RenderToImage()
                        bitmap.Save(fileName)
                        fs = File.OpenRead(fileName)
                        client.SetResult(fs)
                    End Using
                End Using
            End Using
        End Sub

 

Problem happens when it's called renderToImage() function. I think that's because on server they are actualy opened 2 files. First is empty drawing that is there from the start and another drawing that i send from the client(it openes in new window)

 

Message 10 of 26
khoa.ho
in reply to: dj-nemo

I use AutoCAD 2009 at work so I did not test it with 2013. The code was from C# that converted to VB.

 

To bypass the error of RenderToImage() function, you need to put some modelling entities in the file rendering.dwg to render. I have to use breakpoints on VS debugging to stop the code execution, open file rendering.dwg in AutoCAD, draw some 3D objects, save and close it. Then release the breakpoint to allow .NET code to continue. It works for me to produce an image (picture.png).

 

I will review the whole code by the end of the day. The code is not completed so I have to debug and insert something during the whole process to make it works.

 

-Khoa

Message 11 of 26
khoa.ho
in reply to: khoa.ho

I rewrote your code to make it more logical and understandable to read. There is only one class ClientServerPlugin for both client and server. The problem is that the code is not completed for the client side to send DWG file to the server. So there is nothing to render on the server then it causes error on RenderToImage() method. Before going further to fix, there are some questions to clarify:

1. What is the purpose for this server-client project? Do we need one server and many clients connected? By that way, the server will work asynchronously to listen for requests from many clients. We assume one client is one AutoCAD instance in one user machine.

2. Each client sends its drawing with 3D objects to render. The server will take it and render to an image (PNG format), save it to a network drive, and return WHAT to the client? It is quite confusing that the client then generates a result DWG file but what's inside this file?

For testing, we need to open two AutoCAD, one (server side) types "StartServer" command, then another (client side) types "RenderOnServer" command. But the image is not saved yet. It will get fixed later.

I get to sleep now. The following is my new refactoring code:

''' <summary>
''' Wrapper for clients in queue
''' </summary>
Public Structure ClientWrapper
	Public Property TcpClient() As TcpClient
		Get
			Return m_TcpClient
		End Get
		Set
			m_TcpClient = Value
		End Set
	End Property
	Private m_TcpClient As TcpClient
	Public Property File() As MemoryStream
		Get
			Return m_File
		End Get
		Set
			m_File = Value
		End Set
	End Property
	Private m_File As MemoryStream
	Public Property Result() As FileStream
		Get
			Return m_Result
		End Get
		Set
			m_Result = Value
		End Set
	End Property
	Private m_Result As FileStream
End Structure

''' <summary>
''' Client server plugin
''' </summary>
Public Class ClientServerPlugin
	Private Const IpServer As String = "127.0.0.1"
	Private Const PortNum As Integer = 8000
	Private Const PacketSize As Integer = 4096
	Private Const SavedDirectory As String = "C:\\RenderPluginACD\\"
	Private _client As ClientWrapper
	' Queue that holds clients and their files
	Private ReadOnly _editor As Editor = Application.DocumentManager.MdiActiveDocument.Editor
	Private _tcpClient As System.Net.Sockets.TcpClient

	#Region "ClientPlugin"
	<CommandMethod("RenderOnServer")> _
	Public Sub SendToRenderer()
		Connect()
		Dim inputFileName As String = "MyDrawing.dwg"
		Dim outputFileName As String = "Return.dwg"
		Save(inputFileName)
		Send(inputFileName)
		ReceivePhoto(outputFileName)
		Disconnect()
	End Sub

	Private Sub Connect()
		_tcpClient = New System.Net.Sockets.TcpClient()
		_tcpClient.Connect(IpServer, PortNum)
	End Sub

	Private Sub Disconnect()
		' Shutdown and end connection
		_tcpClient.Close()
	End Sub

	''' <summary>
	''' Save the current drawing to a file
	''' </summary>
	''' <param name="fileName">file name to save</param>
	Private Sub Save(fileName As String)
		Dim doc As Document = Application.DocumentManager.MdiActiveDocument
		Dim db As Database = doc.Database
		Using db
			'object obj = Application.GetSystemVariable("DWGTITLED");
			' Save the active drawing 
			If Not Directory.Exists(SavedDirectory) Then
				Directory.CreateDirectory(SavedDirectory)
			End If
			db.SaveAs(SavedDirectory + fileName, False, DwgVersion.Current, doc.Database.SecurityParameters)
		End Using
	End Sub

	''' <summary>
	''' Send a drawing file to a network stream
	''' </summary>
	''' <param name="fileName">file name to open and send to TCP</param>
	Private Sub Send(fileName As String)
		Dim fs = New FileStream(SavedDirectory + fileName, FileMode.Open, FileAccess.Read)
		Dim length As Integer = Convert.ToInt32(fs.Length)
		Dim reader = New BinaryReader(fs)
		Try
			Dim stream As NetworkStream = _tcpClient.GetStream()
			Dim writer = New BinaryWriter(stream)
			writer.Write(length)
			Dim buffer As Byte()
			Do
				' Read data from file
				buffer = reader.ReadBytes(PacketSize)
				' Write data to Network Stream
				writer.Write(buffer)
			Loop While buffer.Length = PacketSize
			writer.Flush()
			'writer.Close();	// do not close the TcpClient connection
			reader.Close()
				' Handle errors
		Catch ex As System.Exception
		End Try
		fs.Close()
	End Sub

	''' <summary>
	''' Receive the rendered photo file back
	''' </summary>
	''' <param name="fileName">photo file name</param>
	Private Sub ReceivePhoto(fileName As String)
		Dim filePath As String = SavedDirectory + fileName
		Dim readBuffer = New Byte(PacketSize) {}
		Dim receivedStream As NetworkStream = _tcpClient.GetStream()
		Dim reader = New BinaryReader(receivedStream)
		Dim streamLength As Integer = reader.ReadInt32()
		Using mStream = New MemoryStream()
			While streamLength > 0
				Dim lData As Integer = receivedStream.Read(readBuffer, 0, PacketSize)
				mStream.Write(readBuffer, 0, lData)
				streamLength -= lData
			End While
			If File.Exists(filePath) Then
				File.Delete(filePath)
			End If
			Dim fs As FileStream = File.OpenWrite(filePath)
			mStream.WriteTo(fs)
			fs.Close()
		End Using
	End Sub
	#End Region

	#Region "ServerPlugin"
	<CommandMethod("StartServer")> _
	Public Sub StartServer()
		Dim dwgFileName As String = "Rendering.dwg"
		Dim imageFileName As String = "Picture.png"
		_editor.WriteMessage(vbLf + "Starting ..." + vbLf)
		Receiver()
		Render(dwgFileName, imageFileName)
		Transmitter(dwgFileName)
		Disconnect()
		System.Threading.Thread.Sleep(2000)
	End Sub

	''' <summary>
	''' Receive connection and put file in queue
	''' </summary>
	Private Sub Receiver()
		Dim ipAddress__1 As IPAddress = IPAddress.Parse(IpServer)
		Dim tcpListener = New TcpListener(ipAddress__1, PortNum)
		tcpListener.Start()
		Try
			' Perform a blocking call to accept requests
			_tcpClient = tcpListener.AcceptTcpClient()
			' Keep waiting until a client is connected at http://127.0.0.1:8000
			If _tcpClient.Connected Then
				_client = New ClientWrapper()
				_client.TcpClient = _tcpClient

				Dim readBuffer = New Byte(PacketSize) {}
				Dim requestStream As NetworkStream = _tcpClient.GetStream()
				Dim reader = New BinaryReader(requestStream)
				Dim streamLength As Integer = reader.ReadInt32()
				' convert a network stream to a memory stream
				Dim responseStream = New MemoryStream()
				While streamLength > 0
					Dim lData As Integer = requestStream.Read(readBuffer, 0, PacketSize)
					responseStream.Write(readBuffer, 0, lData)
					streamLength -= lData
				End While
				_editor.WriteMessage(vbLf + "Received file ..." + vbLf)
				_client.File = responseStream
			End If
		Catch e As System.Exception
		End Try
		tcpListener.[Stop]()
	End Sub

	''' <summary>
	''' Render a DWG drawing to a PNG image
	''' </summary>
	''' <param name="dwgFileName">DWG file name to render</param>
	''' <param name="imageFileName">PNG file name of the output</param>
	Private Sub Render(dwgFileName As String, imageFileName As String)
		Dim filePath As String = SavedDirectory + dwgFileName
		Dim mStream As MemoryStream = _client.File
		If Not Directory.Exists(SavedDirectory) Then
			Directory.CreateDirectory(SavedDirectory)
		End If
		If File.Exists(filePath) Then
			File.Delete(filePath)
		End If
		Dim fs As FileStream = File.OpenWrite(filePath)
		mStream.WriteTo(fs)
		fs.Close()

		' Open a drawing in AutoCAD 2009
		Dim doc As Document = Application.DocumentManager.Open(filePath)

		' Open a drawing in AutoCAD 2013
		'Dim docCol As DocumentCollection = Application.DocumentManager
		'Dim doc As Document
		'doc = DocumentCollectionExtension.Open(docCol, filePath)

		filePath = SavedDirectory + imageFileName
		Dim vpn As Integer = System.Convert.ToInt32(Application.GetSystemVariable("CVPORT"))
		Dim gsv As GraphicsSystem.View = doc.GraphicsManager.GetGsView(vpn, True)
		Using view As GraphicsSystem.View = gsv.Clone(True, True)
			' Do not render the drawing if there are no rendering objects
			'if (view.BackgroundId == ObjectId.Null) return;

			Using dev As Device = doc.GraphicsManager.CreateAutoCADOffScreenDevice()
				'dev.OnSize(doc.GraphicsManager.DeviceIndependentDisplaySize)
				dev.DeviceRenderType = RendererType.FullRender
				dev.Add(view)
				Try
					Dim bitmap As Bitmap = view.RenderToImage()
					Using bitmap
						bitmap.Save(filePath)
						fs = File.OpenRead(filePath)
						_client.Result = fs
					End Using

				Catch ex As System.Exception
				End Try
			End Using
		End Using
	End Sub

	''' <summary>
	''' Send back the result
	''' </summary>
	''' <param name="fileName"></param>
	Private Sub Transmitter(fileName As String)
		Dim fs = New FileStream(SavedDirectory + fileName, FileMode.Open, FileAccess.Read)
		Dim length As Integer = Convert.ToInt32(fs.Length)
		Dim reader = New BinaryReader(fs)
		Dim buffer As Byte()
		' Data buffer
		Dim writer = New BinaryWriter(_client.TcpClient.GetStream())
		writer.Write(length)
		Do
			'read data from file
			buffer = reader.ReadBytes(PacketSize)
			'write data to Network Stream
			writer.Write(buffer)
		Loop While buffer.Length = PacketSize
		writer.Flush()
		writer.Close()
		reader.Close()
		fs.Close()
	End Sub

	'stops server
	<CommandMethod("StopServer")> _
	Public Sub StopServer()

	End Sub
	#End Region
End Class

 

-Khoa

Message 12 of 26
dj-nemo
in reply to: khoa.ho

Hi Khoa

 

Let's say i am an arhitect. i made drawing of some building and i want some photos of my new building. I set up everything to render, but instead to push the button render i use my "SENDTORENDER" command. Rendering can be sometimes operation that takes a really long time. So when i will use command i will send this current drawing to some more powerful PC and so it will take less time to render file. After rendering on powerful PC ends it' will send image back to my PC.

 

So in short we have one powerfull PC in office that will render files and all the employees will send to this computer work. Since we can't make it multithreading i can't have one thread taking clients all the time. So server will work in while(true) loop and thaking clients. If it will be busy nobody can't connect.

 

Sorry for confusion other thay with sending back dwg file i just want to test if tcp conversation works both ways fine.

 

Thank for so much help 

 

 

Message 13 of 26
khoa.ho
in reply to: dj-nemo

You are welcome. This is a very interesting topic to deal with multi-threading and parallel programming in AutoCAD. Gopinath Target from Autodesk had a lesson about it on AU, but it was dealing with how to invoke the main AutoCAD UI thread in the background process. He also uses a BackgroundWorker to perform asynchronous operations in a background thread. Let me time to play with his solution.

 

The idea to use TCP as an asynchronous communication between server and clients is very similar to the popular Node.js (Server-side JavaScript based on Google's V8 engine). This Google engine is also internally single-threaded like AutoCAD or RealDWG. The TCP solution will become the cloud computing one as seen on the ADN DevBlog ( http://adndevblog.typepad.com/cloud_and_mobile/ ). Autodesk already has Autodesk 360 Rendering ( http://rendering.360.autodesk.com/ ) service to remotely render images on the cloud. However, we want to learn the technology secrets behind. It's tough to catch all those new good things as we have to spend time on company projects every day.

 

To keep it simple with your project, I will go back to use TCP concept for non-blocking requests to render images on the server.

 

-Khoa

Message 14 of 26
khoa.ho
in reply to: khoa.ho

Hi dj-nemo,

The problem of view.RenderToImage() is the missing of HostApplicationServices.WorkingDatabase = doc.Database. Now it works to produce a PNG image.

We use TcpClient to connect, send, and receive stream data over a network in synchronous blocking mode. Each server and client has its own TcpClient to request and response network stream back to the central TCP/IP. This HTTP address is the gateway for communication between server and client.

The order of communication between server and client shows as below:

1. Server.ListenAndReceive
2. Client.SendStreamToServer
3. Server.Render
4. Server.ResponeStreamToClient
5. Client.ReceiveStreamFromServer

Open two AutoCAD, one works as a server with command StartRenderServer first, and another works as a client with command SendToRender. After running the server AutoCAD, on the client AutoCAD, draw some 3D objects, then hit command SendToServer. The client will save a new rendered image (Picture.png) to folder C:\ClientServer.

I rewrote the new code with better reusable methods. But you still have to test and add more features in your project. This code is just basic without multiple connected clients and something more, and has some possible potential bugs. I keep it simple and fundamental to easily understand.

 

#Region "Client-Server"
''' <summary>
''' Wrapper for clients in queue
''' </summary>
Public Structure ClientWrapper
	Public Property File() As MemoryStream
		Get
			Return m_File
		End Get
		Set
			m_File = Value
		End Set
	End Property
	Private m_File As MemoryStream
	Public Property Result() As FileStream
		Get
			Return m_Result
		End Get
		Set
			m_Result = Value
		End Set
	End Property
	Private m_Result As FileStream
End Structure

''' <summary>
''' Server-Client plugin
''' </summary>
Public Class ServerClientPlugin
	Private Const IpServer As String = "127.0.0.1"
	Private Const PortNum As Integer = 8000
	Private Const PacketSize As Integer = 4096
	Private Const ServerFolder As String = "C:\ServerFolder\"
	' A shared folder in a network drive
	Private Const ClientFolder As String = "C:\ClientFolder\"
	' A local folder at client machine
	Private _client As ClientWrapper
	Private ReadOnly _editor As Editor = Application.DocumentManager.MdiActiveDocument.Editor
	Private _tcpClient As System.Net.Sockets.TcpClient

	#Region "ServerPlugin"
	<CommandMethod("StartRenderServer")> _
	Public Sub StartRenderServer()
		Dim dwgFileName As String = "ServerDrawing.dwg"
		Dim imageFileName As String = "Picture.png"
		_editor.WriteMessage(vbLf + "Starting ..." + vbLf)
		ListenAndReceive()
		Render(dwgFileName, imageFileName)
		ResponseStreamToClient(imageFileName)
		DisconnectTCP()
		'System.Threading.Thread.Sleep(2000);
	End Sub

	''' <summary>
	''' Receive connection and put file in queue
	''' </summary>
	Private Sub ListenAndReceive()
		Dim ipAddress__1 As IPAddress = IPAddress.Parse(IpServer)
		Dim tcpListener = New TcpListener(ipAddress__1, PortNum)
		tcpListener.Start()
		Try
			' Perform a blocking call to accept requests
			_tcpClient = tcpListener.AcceptTcpClient()
			' Keep waiting until a client is connected at http://127.0.0.1:8000
			If _tcpClient.Connected Then
					'TcpClient = _tcpClient,
				_client = New ClientWrapper() With { _
					.File = ReadStreamFromTCP() _
				}
				_editor.WriteMessage(vbLf + "Received file ..." + vbLf)
			End If
		Catch ex As System.Exception
			_editor.WriteMessage(ex.Message + vbLf + ex.StackTrace)
		End Try
		tcpListener.[Stop]()
	End Sub

	''' <summary>
	''' Render a DWG drawing to a PNG image
	''' </summary>
	''' <param name="dwgFileName">DWG file name to render</param>
	''' <param name="imageFileName">PNG file name of the output</param>
	Private Sub Render(dwgFileName As String, imageFileName As String)
		Try
			Dim filePath As String = ServerFolder + dwgFileName
			Dim responseStream As MemoryStream = _client.File
			If Not Directory.Exists(ServerFolder) Then
				Directory.CreateDirectory(ServerFolder)
			End If
			If File.Exists(filePath) Then
				File.Delete(filePath)
			End If
			Dim fileStream As FileStream = File.OpenWrite(filePath)
			responseStream.WriteTo(fileStream)
			fileStream.Close()

			' Open the new saved drawing in AutoCAD 2009
			Dim doc As Document = Application.DocumentManager.Open(filePath)

			' Open the new saved drawing in AutoCAD 2013
			'Dim docCol As DocumentCollection = Application.DocumentManager
			'Dim doc As Document
			'doc = DocumentCollectionExtension.Open(docCol, filePath)

			Using doc
				Dim workDb As Database = HostApplicationServices.WorkingDatabase
				HostApplicationServices.WorkingDatabase = doc.Database

				filePath = ServerFolder + imageFileName
				Dim vpn As Integer = System.Convert.ToInt32(Application.GetSystemVariable("CVPORT"))
				Dim gsv As GraphicsSystem.View = doc.GraphicsManager.GetGsView(vpn, True)
				Using view As GraphicsSystem.View = gsv.Clone(True, True)
					Using dev As Device = doc.GraphicsManager.CreateAutoCADOffScreenDevice()
						'dev.OnSize(doc.GraphicsManager.DeviceIndependentDisplaySize)
						dev.DeviceRenderType = RendererType.FullRender
						dev.Add(view)
						Dim bitmap As Bitmap = view.RenderToImage()
						Using bitmap
							bitmap.Save(filePath)
							fileStream = File.OpenRead(filePath)
							_client.Result = fileStream
						End Using
					End Using
				End Using
				' Restore the previous working database back
				HostApplicationServices.WorkingDatabase = workDb
			End Using
		Catch ex As System.Exception
			_editor.WriteMessage(ex.Message + vbLf + ex.StackTrace)
		End Try
	End Sub

	''' <summary>
	''' Send back the result
	''' </summary>
	''' <param name="fileName"></param>
	Private Sub ResponseStreamToClient(fileName As String)
		Try
			Dim fileStream = New FileStream(ServerFolder + fileName, FileMode.Open, FileAccess.Read)
			WriteStreamToTCP(fileStream)
			fileStream.Close()
		Catch ex As System.Exception
			_editor.WriteMessage(ex.Message + vbLf + ex.StackTrace)
		End Try
	End Sub

	'stops server
	<CommandMethod("StopRenderServer")> _
	Public Sub StopRenderServer()

	End Sub
	#End Region

	#Region "ClientPlugin"
	<CommandMethod("SendToRender")> _
	Public Sub SendToRender()
		Dim inputFileName As String = "ClientDrawing.dwg"
		Dim outputFileName As String = "Picture.png"
		ConnectTCP()
		SaveCurrentDrawingToFile(inputFileName)
		SendStreamToServer(inputFileName)
		ReceiveStreamFromServer(outputFileName)
		DisconnectTCP()
	End Sub

	Private Sub ConnectTCP()
		Try
			_tcpClient = New System.Net.Sockets.TcpClient()
			_tcpClient.Connect(IpServer, PortNum)
		Catch ex As System.Exception
			_editor.WriteMessage(ex.Message + vbLf + ex.StackTrace)
		End Try
	End Sub

	Private Sub DisconnectTCP()
		' Shutdown and end connection
		_tcpClient.Close()
	End Sub

	''' <summary>
	''' Save the current drawing to a file
	''' </summary>
	''' <param name="fileName">file name to save</param>
	Private Sub SaveCurrentDrawingToFile(fileName As String)
		Dim doc As Document = Application.DocumentManager.MdiActiveDocument
		Dim db As Database = doc.Database
		Using db
			'object obj = Application.GetSystemVariable("DWGTITLED");
			' Save the active drawing 
			If Not Directory.Exists(ClientFolder) Then
				Directory.CreateDirectory(ClientFolder)
			End If
			db.SaveAs(ClientFolder + fileName, False, DwgVersion.Current, doc.Database.SecurityParameters)
		End Using
	End Sub

	''' <summary>
	''' Send a drawing file to a network stream
	''' </summary>
	''' <param name="fileName">file name to open and send to TCP</param>
	Private Sub SendStreamToServer(fileName As String)
		Try
			Dim fileStream = New FileStream(ClientFolder + fileName, FileMode.Open, FileAccess.Read)
			WriteStreamToTCP(fileStream)
			fileStream.Close()
		Catch ex As System.Exception
			_editor.WriteMessage(ex.Message + vbLf + ex.StackTrace)
		End Try
	End Sub

	''' <summary>
	''' Receive the rendered photo file back
	''' </summary>
	''' <param name="fileName">photo file name</param>
	Private Sub ReceiveStreamFromServer(fileName As String)
		Try
			Dim responseStream = ReadStreamFromTCP()

			Dim filePath As String = ClientFolder + fileName
			If File.Exists(filePath) Then
				File.Delete(filePath)
			End If
			Dim fileStream As FileStream = File.OpenWrite(filePath)
			' Save memory stream to physical file
			responseStream.WriteTo(fileStream)
			fileStream.Close()
		Catch ex As System.Exception
			_editor.WriteMessage(ex.Message + vbLf + ex.StackTrace)
		End Try
	End Sub
	#End Region

	#Region "Shared methods"
	Private Function ReadStreamFromTCP() As MemoryStream
		Dim readBuffer = New Byte(PacketSize) {}
		' Get a network stream from TCP/IP address
		Dim requestStream As NetworkStream = _tcpClient.GetStream()
		' Read binary stream from TCP/IP address
		Dim reader = New BinaryReader(requestStream)
		Dim streamLength As Integer = reader.ReadInt32()
		' Convert a network stream to a memory stream
		Dim responseStream = New MemoryStream()
		While streamLength > 0
			Dim lData As Integer = requestStream.Read(readBuffer, 0, PacketSize)
			responseStream.Write(readBuffer, 0, lData)
			streamLength -= lData
		End While
		Return responseStream
	End Function

	Private Sub WriteStreamToTCP(stream As Stream)
		Dim reader = New BinaryReader(stream)
		' Get a network stream from TCP/IP address
		Dim requestStream As NetworkStream = _tcpClient.GetStream()
		' Write binary stream to TCP/IP address
		Dim writer = New BinaryWriter(requestStream)
		Dim length As Integer = Convert.ToInt32(stream.Length)
		writer.Write(length)
		Dim buffer As Byte()
		Do
			' Read data from file
			buffer = reader.ReadBytes(PacketSize)
			' Write data to Network Stream
			writer.Write(buffer)
		Loop While buffer.Length = PacketSize
		writer.Flush()
		'writer.Close();	// do not close the TcpClient connection
		reader.Close()
	End Sub
	#End Region
End Class

 

-Khoa

Message 15 of 26
dj-nemo
in reply to: khoa.ho

I found one more problem in line with type Bitmap

 

Dim bitmap As Bitmap = view.RenderToImage()

 

The problem is i can't import System.Drawing

 

It's says 

 Namespace or type specified in the Imports 'System.Drawing' doesn't contain any public member or cannot be found. Make sure the namespace or the type is defined and contains at least one public member. Make sure the imported element name doesn't use any aliases.

 

Should i use something instead or can i inport somehow dll that i had downloaded from internet?

 

 

 

Message 16 of 26
khoa.ho
in reply to: dj-nemo

Hi dj-nemo,

 

I hope you may solve this .NET reference issue. System.Drawing namespace is seen from all .NET frameworks since 1.1, 2.0, 3.0, 3.5, 4.0 and 4.5. See the MSDN link: http://msdn.microsoft.com/en-us/library/xs6ftd89(v=vs.100)

 

Please check the "Add Reference" dialog in Visual Studio to import the correct System.Drawing version in your project. It will also work if it has lower .NET version with your current AutoCAD plug-in.

 

-Khoa

Message 17 of 26
dj-nemo
in reply to: khoa.ho

Hi

 

after adding System.drawing via add reference it is ok.

 

Now i have picture rendered from the top in 2D mode. How can i put view in same position cient has.

 

I am attaching example of my simple dwg file, wanted bitmap and bitmap i get

 

Message 18 of 26
dj-nemo
in reply to: dj-nemo

Hi

i found another question. I was wondering if there is any document from autodesk to tell me how it's rendering made. As i saw autocad can use moltiple cores. How is this made. Is it using data paralelism or process paralelism and so on. Which rendering technics are used.

If you ever saw some data about that pleaselet me know

 

Domen

Message 19 of 26
dj-nemo
in reply to: dj-nemo

Dear Khoa i hope you are still there. 

 

can you in few words explain me what this code is doing.

                Using doc
                    Dim workDb As Database = HostApplicationServices.WorkingDatabase
                    HostApplicationServices.WorkingDatabase = doc.Database
                    filePath = ServerFolder + imageFileName
                    Dim vpn As Integer = System.Convert.ToInt32(Application.GetSystemVariable("CVPORT"))
                    Dim gsv As GraphicsSystem.View = doc.GraphicsManager.GetGsView(vpn, True)
                    Using view As GraphicsSystem.View = doc.GraphicsManager.v
                        Using dev As Device = doc.GraphicsManager.CreateAutoCADOffScreenDevice()
                            dev.DeviceRenderType = RendererType.FullRender
                            dev.Add(view)
                            Dim bitmap As Bitmap = view.RenderToImage()
                            Using bitmap
                                bitmap.Save(filePath)
                                fileStream = File.OpenRead(filePath)
                                _client.Result = fileStream
                            End Using
                        End Using
                    End Using

                    ' Restore the previous working database back
                    HostApplicationServices.WorkingDatabase = workDb
                End Using

 

What is CVPORT system variable for? in my case it's 2 (i think this mean we have 3D scene am i right?)

After that we are prepering view for render, am i right?

 

 

 

 

Message 20 of 26
khoa.ho
in reply to: dj-nemo

Hi dj-nemo,

 

I will have a look again on your code around the end of my working day (US Central Time). Last week I was very busy and did not have time to track this .NET forum. I will be back to see this issue.

 

-Khoa

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost