I'been developing a library on C# for the last days, and now, I need to build that library into a dll, and use that dll from Qt.
The library includes three classes I need to access, and my original idea was to simply build the dll, use dumpcpp to get the headers and use them from Qt along with activeqt, which I have used before.
The problem is that I cannot manage to get the headers from dumpcpp, it fails, returning:
dumpcpp: loading '.\Wrapper.dll' as a type library failed
dumpcpp: error processing type library '.\Wrapper.dll'
The Visual Studio project I'm using is a Class library (.Net Standard), and I'm using building it for x86 architecture. I've seen this link and tried using
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
with the three classes I need in order to get a COM dll which I suppose must be usable by dumpcpp, but it fails with the same error I mentioned before. Almost every documentation I have found is about using C++ dlls on C#, and there's nothing about using dumpcpp with C# dlls.
Do somebody has any ideas on how to get this dll working with dumpcpp, so that I can use it with Qt? I'd be really grateful.
Thanks a lot!
Edit: In case it helps, here it's the basic structure (without the complex funcionality) of the unique main .cs file the dll includes:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Wrapper
{
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class Device
{
public string host;
public string username;
public string password;
public uint port;
private bool _serverConnected;
public uint serverGroupId { get; private set; }
public uint serverId { get; private set; }
private object[] _cameraIds;
public Device(string host, string username, string password, uint port)
{
this.host = host;
this.username = username;
this.password = password;
this.port = port;
this._serverConnected = false;
Debug.WriteLine("Device Initialized");
}
public bool isConnected() => _serverConnected;
public void onServerConnected(uint serverGroupId, uint serverId)
{
Debug.WriteLine("ServerConnectedEventHandler"); // TODO: Remove, just for testing
_serverConnected = true;
}
public void onServerGroupDisconnected(uint serverGroupId)
{
Debug.WriteLine("ServerGroupDisconnectedEventHandler"); // TODO: Remove, just for testing
_serverConnected = false;
}
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
class Player
{
private Device _device;
private static readonly int NUM_FRAMES = 10;
private Frame[] _lastFrames = new Frame[NUM_FRAMES];
private int _toReadFrame, _toReceivedFrame;
public Player(Device device)
{
this._device = device;
_toReadFrame = 0;
_toReceivedFrame = 0;
}
public Frame Image()
{
Frame tmp = _lastFrames[_toReadFrame];
_toReadFrame = (++_toReadFrame) % NUM_FRAMES;
return tmp;
}
void FrameAvailableEventHandler(int width, int height, byte[] data)
{
_lastFrames[_toReceivedFrame] = new Frame(width, height, data);
_toReceivedFrame = (++_toReceivedFrame) % NUM_FRAMES;
}
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
class Frame
{
public int width { get; private set; }
public int height { get; private set; }
public byte[] data { get; private set; }
public Frame(int width, int height, byte[] data)
{
this.data = data;
this.width = width;
this.height = height;
}
}
}
Related
I'm currently working on a sonar named "Imagenex 831L" and I'm trying to extract the data published by a driver with ROS and send it to Unity with RosBridge and ROS#. So I'm trying to subscribe to this topic and visualize it on Unity.
My problem is that the topic generated by the driver isn't a native topic of ROS, it's created by the driver and it's not known by the ROS# library.
I tried this method to create a new MessageType : https://github.com/siemens/ros-sharp/wiki/Dev_NewMessageTypes but that doesn't work at all.
I've also thought to change the MessageType created by the driver but I'm a begginer in ROS and I don't want to messed up the driver.
So I started a script in C# to create a new message type but I'm really not sure if this gonna work. As you can see below my code to create a new MessageType :
using RosSharp.RosBridgeClient.MessageTypes.Std;
namespace RosSharp.RosBridgeClient.MessageTypes.imagenex831l
{
public class ProcessedRange : Message
{
public const string RosMessageName = "imagenex831l/ProcessedRange";
public float Head_position { get; set; }
public UInt8 Intensity { get; set; }
public ProcessedRange() { }
public ProcessedRange(Header header, UInt8[] Intensity, float Head_position) { }
public Header header { get; set; }
}
}
Then I tried to code a subscriber :
using RosSharp.RosBridgeClient.MessageTypes.imagenex831l;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using RosSharp.RosBridgeClient.MessageTypes.Std;
namespace RosSharp.RosBridgeClient
{
public class ProcessedRangeSuscriber : UnitySubscriber<MessageTypes.imagenex831l.ProcessedRange>
{
//public Transform PublishedTransform;
public UInt8[] Intensity;
public Float32 Head_position;
private bool isMessageReceived;
protected override void Start()
{
base.Start();
}
private void Update()
{
if (isMessageReceived)
ProcessMessage();
}
protected override void ReceiveMessage(MessageTypes.imagenex831l.ProcessedRange message)
{
//position = GetPosition(message).Ros2Unity();
//rotation = GetIntensity(message).Ros2Unity();
//isMessageReceived = true;
}
private void ProcessMessage()
{
//PublishedTransform.position = position;
//PublishedTransform.rotation = rotation;
}
private Float32 GetPosition(MessageTypes.imagenex831l.ProcessedRange message)
{
return new Float32(message.head_position);
}
private UInt8 GetIntensity(MessageTypes.imagenex831l.ProcessedRange message)
{
return new UInt8(message.intensity);
}
}
}
I get the following error message : CS1503 C# Argument 1: cannot convert from to 'byte'
If someone has also use this sonar or know ROS# I'm very interesting to discuss with them.
Thank you for your consideration regarding my request
Im building an Add-In for Outlook where I copy all exchange users from the global address list to the local contacts.
The problem is I want transfer the picture of the exchange user too, but exchUser.GetPicture() returns a stdole.stdPicture and I have not yet found a working solution to download or convert it into an image/jpg/...
Here the code to get the exchange User from the global address list:
private void EnumerateGAL()
{
Outlook.AddressList gal = Application.Session.GetGlobalAddressList();
if (gal != null)
{
for (int i = 1; i <= gal.AddressEntries.Count - 1; i++)
{
Outlook.AddressEntry addrEntry = gal.AddressEntries[i];
Outlook.ExchangeUser exchUser = addrEntry.GetExchangeUser();
if (addrEntry.AddressEntryUserType == Outlook.OlAddressEntryUserType.olExchangeUserAddressEntry
&& exchUser.CompanyName == "")
{
CreateContact(exchUser);
//exchUser.GetPicture() returns stdole.stdPicture
}
}
}
return;
}
The closest solution I found, was a conversion of stdole.IPictureDisp which returns a bitmap but IPuctureDisp and stdPicture isn´t the same as I read somewhere.
public static System.Drawing.Image ConvertPicture(stdole.IPictureDisp image)
{
int type = image.Type;
if (type == 1)
{
IntPtr hPal = (IntPtr)image.hPal;
return Image.FromHbitmap((IntPtr)image.Handle, hPal);
}
return null;
}
In the end I need to download the picture because I can only upload a picture to a contact with a path.
So, is there a way to download a stdPicture or convert it to be able to download it?
There are four main ways to get the job done.
The "traditional" approach is to use the GetIPictureDispFromPicture and GetPictureFromIPicture methods in the System.Windows.Forms.AxHost class. These are both protected members of the class, so you can't use them externally. For this reason, it is common to subclass the AxHost class and expose public methods that internally call the base class protected methods. This approach allows you to convert in both directions:
internal class AxHostConverter : AxHost
{
private AxHostConverter() : base("") { }
static public stdole.IPictureDisp ImageToPictureDisp(Image image)
{
return (stdole.IPictureDisp)GetIPictureDispFromPicture(image);
}
static public Image PictureDispToImage(stdole.IPictureDisp pictureDisp)
{
return GetPictureFromIPicture(pictureDisp);
}
}
Your second option is to use OleLoadPicture or OleCreatePictureIndirect. There's an old support article on the topic here. OleLoadPicture creates a new picture object and initializes it from the contents of a stream.
internal class OleCreateConverter
{
[DllImport("oleaut32.dll", EntryPoint = "OleCreatePictureIndirect",
CharSet = CharSet.Ansi, ExactSpelling = true, PreserveSig = true)]
private static extern int OleCreatePictureIndirect(
[In] PictDescBitmap pictdesc, ref Guid iid, bool fOwn,
[MarshalAs(UnmanagedType.Interface)] out object ppVoid);
const short _PictureTypeBitmap = 1;
[StructLayout(LayoutKind.Sequential)]
internal class PictDescBitmap
{
internal int cbSizeOfStruct = Marshal.SizeOf(typeof(PictDescBitmap));
internal int pictureType = _PictureTypeBitmap;
internal IntPtr hBitmap = IntPtr.Zero;
internal IntPtr hPalette = IntPtr.Zero;
internal int unused = 0;
internal PictDescBitmap(Bitmap bitmap)
{
this.hBitmap = bitmap.GetHbitmap();
}
}
public static stdole.IPictureDisp ImageToPictureDisp(Image image)
{
if (image == null || !(image is Bitmap))
{
return null;
}
PictDescBitmap pictDescBitmap = new PictDescBitmap((Bitmap)image);
object ppVoid = null;
Guid iPictureDispGuid = typeof(stdole.IPictureDisp).GUID;
OleCreatePictureIndirect(pictDescBitmap, ref iPictureDispGuid, true, out ppVoid);
stdole.IPictureDisp picture = (stdole.IPictureDisp)ppVoid;
return picture;
}
public static Image PictureDispToImage(stdole.IPictureDisp pictureDisp)
{
Image image = null;
if (pictureDisp != null && pictureDisp.Type == _PictureTypeBitmap)
{
IntPtr paletteHandle = new IntPtr(pictureDisp.hPal);
IntPtr bitmapHandle = new IntPtr(pictureDisp.Handle);
image = Image.FromHbitmap(bitmapHandle, paletteHandle);
}
return image;
}
}
Your third option is to use the VB6 compatibility library, documented here. To use this, you'll need to add a reference to Microsoft.VisualBasic.Compatibility.dll, which is listed on the .NET tab of the Add References dialog (it resides in the GAC). Then, you can use the ImageToIPictureDisp and IPictureDispToImage methods in the Support class. This is obviously by far the simplest approach, although it does pull in the VB6 compatibility DLL. Internally, the VB6 compatibility code looks a lot like the second option above – using OleCreatePictureIndirect.
using Microsoft.VisualBasic.Compatibility.VB6;
internal class VB6CompatibilityConverter
{
public static stdole.IPictureDisp ImageToPictureDisp(Image image)
{
return (stdole.IPictureDisp)Support.ImageToIPictureDisp(image);
}
public static Image PictureDispToImage(stdole.IPictureDisp pictureDisp)
{
return Support.IPictureDispToImage(pictureDisp);
}
}
Finally, you can implement IPictureDisp and IPicture yourself. This is fine if you just want to convert from an Image to an IPictureDisp, but doesn't help you converting in the other direction. The implementation below relies on the Image actually being a derived Bitmap type, because we call Bitmap.GetHbitmap internally. If you want to keep the support to the generic Image type, you'll have to do a lot more work to p/invoke to a bunch of undocumented GDI methods instead
internal class PictureDispConverter
{
public static stdole.IPictureDisp BitmapToPictureDisp(Bitmap bitmap)
{
return new PictureDispImpl(bitmap);
}
public static Image PictureDispToBitmap(stdole.IPictureDisp pictureDisp)
{
// TODO
return null;
}
}
internal class PictureDispImpl : stdole.IPictureDisp, stdole.IPicture
{
#region Init
[DllImport("gdi32.dll")]
static extern void DeleteObject(IntPtr handle);
private Bitmap _image;
private IntPtr _handle;
public PictureDispImpl(Bitmap image)
{
_image = image;
}
~PictureDispImpl()
{
if (_handle != IntPtr.Zero)
{
DeleteObject(_handle);
}
}
#endregion
#region IPictureDisp Members
public int Width
{
get { return _image.Width; }
}
public int Height
{
get { return _image.Height; }
}
public short Type
{
get { return 1; }
}
public int Handle
{
get
{
if (_handle == IntPtr.Zero)
{
_handle = _image.GetHbitmap();
}
return _handle.ToInt32();
}
}
public int hPal
{
get { return 0; }
set { }
}
public void Render(
int hdc, int x, int y, int cx, int cy, int xSrc, int ySrc, int cxSrc, int cySrc, IntPtr prcWBounds)
{
Graphics graphics = Graphics.FromHdc(new IntPtr(hdc));
graphics.DrawImage(
_image, new Rectangle(x, y, cx, cy), xSrc, ySrc, cxSrc, cySrc, GraphicsUnit.Pixel);
}
#endregion
#region IPicture Members
public int Attributes
{
get { return 0; }
}
public int CurDC
{
get { return 0; }
}
public bool KeepOriginalFormat
{
get { return false; }
set { }
}
public void PictureChanged()
{
}
public void SaveAsFile(IntPtr pstm, bool fSaveMemCopy, out int pcbSize)
{
pcbSize = 0;
}
public void SelectPicture(int hdcIn, out int phdcOut, out int phbmpOut)
{
phdcOut = 0;
phbmpOut = 0;
}
public void SetHdc(int hdc)
{
}
#endregion
}
I have been working with an interface which read measurement data from a sensor and use a library written in C++ to analyse that data.
The function is just about the following:
Set measurement parameters on the C++ library
Get data from the sensor (1200 measurements alltogether)
Write data to C++ library
Process all 1200 measurements in C++ library
Read results from C++ library
Calling this C++ library from C#-code is previously dealt with this question: Calling unmanaged C++ library (dll) from C# creates an access violation error (0xc0000005).
Now it seems, that the C++ library either
doesn't get data correctly
is not able to hold data
is not able to properly return results to my C#-code.
Bad thing is, that I'm not able to debug this C++ library.
What is wrong with my code?
1) Setting the measurement parameters
namespace PdWaveApi
{
[StructLayout(LayoutKind.Sequential)]
public struct PDDataInfo
{
public int nPings;
public int nDataRate;
public int nSamples;
public float fFrequency;
public float fBeamAngle;
public int nInstrument;
public int nCoordSystem;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)]
public short[] hBeamToXYZ;
public short hWaveT1;
// Constructor
public static PDDataInfo Create()
{
PDDataInfo DataStruct = new PDDataInfo();
DataStruct.hBeamToXYZ = new short[9];
return DataStruct;
}
}
}
public class PdWaveBaseLWrapper
{
[DllImport("PdWaveBase.dll", EntryPoint = "PDSetInstrumentConfig")]
public static extern int PDSetInstrumentConfig(ref PDDataInfo pDataInfo);
}
public void SetInstrumentConfiguration()
{
PdWaveApi.PDDataInfo InstrumentConfiguration = new PdWaveApi.PDDataInfo();
.................
Initializing the InstrumentConfiguration structure
...............
PdWaveBaseLWrapper.PDSetInstrumentConfig(ref InstrumentConfiguration);
}
3) Reading data from sensor and writing data to C++ library
namespace PdWaveApi
{
[StructLayout(LayoutKind.Sequential)]
public struct PDWaveSample
{
[MarshalAs(UnmanagedType.I1)]
public bool Valid;
public float fPressure;
public float fDistance;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.PD_MAX_WAVEBEAMS)]
public float[] fVel;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.PD_MAX_WAVEBEAMS)]
public ushort[] nAmp;
// Constructor
public static PDWaveSample Create()
{
PDWaveSample DataStruct = new PDWaveSample();
DataStruct.fVel = new float[Constants.PD_MAX_WAVEBEAMS];
DataStruct.nAmp = new ushort[Constants.PD_MAX_WAVEBEAMS];
return DataStruct;
}
}
}
public class PdWaveBaseLWrapper
{
[DllImport("PdWaveBase.dll", EntryPoint = "PDSetWaveSample")]
public static extern int PDSetWaveSample(ref PDWaveSample pWaveSample);
}
namespace SensorInterface
{
public partial class frmSensorInterface : Form
{
public PdWaveApi.PDWaveSample WaveSampleData = PdWaveApi.PDWaveSample.Create();
private void OnNewData(object sender, OnNewDataEvent e)
{
ReadWaveSample(ref WaveSampleData);
SetWaveSample(ref WaveSampleData);
}
public void ReadWaveSample(ref PdWaveApi.PDWaveSample WaveSampleData)
{
DateTime MeasurementTimeStamp;
float[] dVel = new float[4];
float dTemperature = new float();
float dPitch = new float();
float dRoll = new float();
float dHeading = new float();
float dPressure = new float();
short[] sAmp = new short[4];
// Read some of the latest data from the control
GetVelocity(ref dVel[0], ref dVel[1], ref dVel[2], ref dVel[3]);
GetAmplitude(ref sAmp[0], ref sAmp[1], ref sAmp[2], ref sAmp[2]);
..............
// Set other data to the structure
}
public void SetWaveSample(ref PdWaveApi.PDWaveSample WaveSampleData)
{
PdWaveBaseLWrapper.PDSetWaveSample(ref WaveSampleData);
}
}
}
4) Process all 1200 measurements in C++ library
[StructLayout(LayoutKind.Sequential)]
public struct PDWaveBurst
{
[MarshalAs(UnmanagedType.ByValArray , SizeConst = Constants.PD_MAX_WAVEMEAS_AST)]
public float[] fST;
public float fWinFloor;
public float fWinCeil;
[MarshalAs(UnmanagedType.I1)]
public bool bUseWindow;
[MarshalAs(UnmanagedType.I1)]
public bool bSTOk;
[MarshalAs(UnmanagedType.I1)]
public bool bGetRawAST;
[MarshalAs(UnmanagedType.I1)]
public bool bValidBurst;
public static PDWaveBurst Create()
{
PDWaveBurst DataStruct = new PDWaveBurst();
DataStruct.fST = new float[Constants.PD_MAX_WAVEMEAS_AST];
return DataStruct;
}
}
[DllImport("PdWaveBase.dll", EntryPoint = "PDPreProcess")]
public static extern int PDPreProcess(int nSample, ref PDWaveBurst pWaveBurst);
[DllImport("PdWaveBase.dll", EntryPoint = "PDProcessReturnInt")]
public static extern int PDProcessReturnInt();
public void PreprocessBurstData(int nSamples)
{
PdWaveApi.PDWaveBurst WaveBurstData = PdWaveApi.PDWaveBurst.Create();
WaveBurstData.fST = new float[4096];
WaveBurstData.fWinFloor = (float)1.25;
WaveBurstData.fWinCeil = 2;
WaveBurstData.bUseWindow = false;
WaveBurstData.bSTOk = false;
WaveBurstData.bGetRawAST = false;
WaveBurstData.bValidBurst = false;
PdWaveBaseLWrapper.PDPreProcess(nSamples, ref WaveBurstData);
}
public void ProcessData()
{
int ProcessError = PdWaveBaseLWrapper.PDProcessReturnInt();
}
5) Read results from C++ library
[StructLayout(LayoutKind.Sequential)]
public struct PDWavePar {
public float fTm02;
public float fTp;
public float fDirTp;
public float fSprTp;
public float fMainDir;
public float fUI;
public float fHm0;
public float fH3;
public float fT3;
public float fH10;
public float fT10;
public float fHmax;
public float fTmax;
public float fTz;
public float fMeanPres;
public int nNumNoDet;
public int nNumBadDet;
public int nErrCode;
public int nSpectrum;
public float fMeanAST;
}
[DllImport("PdWaveBase.dll", EntryPoint = "PDGetWavePar")]
public static extern int PDGetWavePar(ref PDWavePar pwWavePar);
public void GetOutput()
{
PdWaveApi.PDWavePar WaveParameters = new PdWaveApi.PDWavePar();
PdWaveBaseLWrapper.PDGetWavePar(ref WaveParameters);
}
So, as conclusion:
What should I change in my code
- to pass data correctly to unmanaged dll
- to have dll hold and process the data in its' internal structures
- to read results correctly from unmanaged code to my C# program?
(Sorry about the length of my question.)
The final solution to my problem was to change the alignment to 1 byte, like this:
C# struct definitions:
From:
[StructLayout(LayoutKind.Sequential)]
to
[StructLayout(LayoutKind.Sequential, Pack=1)]
This has been discussed at least here:
Calling C++ metro dll from c# metro app and returning filled structures
i had problem with application messaging, ...after some question and answer, i went to use Remoting namespace, under System.Runtime namespace...
it worked perfectly, but the matter is when application terminate with exception...
if server stop in not manner, the channel i register will stay registered, ...
i dont have much knowledge over remoting or other related matter...
but i checked some of things, and non didnt worked...
the article i went through done registering this way, and didnt unregister the application, and i use it in service, and seem service application host dont close just with service beign stopped...
here's my client class which is used in service applciation...
using System;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
namespace Remoting
{
public class Client
{
private RemotableObject remoteObject;
/// <summary>
/// Configure Client Class
/// </summary>
/// <param name="url">Something like: tcp://localhost:8080/HelloWorld</param>
public Client(string url)
{
TcpChannel chan = new TcpChannel();
ChannelServices.RegisterChannel(chan);
remoteObject = (RemotableObject)Activator.GetObject(typeof(RemotableObject), url);
}
public void SetMessage(string message)
{
remoteObject.SetMessage(message);
}
}
}
as i noticed, the article give no information to the channel, so i'm wonder for unregistering it how should i find it.....
in the server APP, the article done givin host post at last
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
namespace Remoting
{
public abstract class Server:IObserver
{
private RemotableObject remotableObject;
/// <summary>
/// Configure Server Class
/// </summary>
/// <param name="port">port number like: 8080</param>
/// <param name="url">Object url like: HelloWorld</param>
public Server(int port, string url)
{
remotableObject = new RemotableObject();
TcpChannel channel = new TcpChannel(port);
ChannelServices.RegisterChannel(channel);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemotableObject), url, WellKnownObjectMode.Singleton);
Cache.Attach(this);
}
public abstract void Notify(string message);
}
}
but, even know think i launch my application over a server that run an app with same port number, i do not want to un-register other application channels... what should i do?
BTW most issue is about the client that register a channel, with no information... how do i detect it? and unregister it, before service try to do that, and terminate with exception?
if it help, this is the error i already recieve:
Event Type: Error
Event Source: Event Reader Service
Event Category: None
Event ID: 0
Date: 8/20/2012
Time: 5:23:14 PM
User: N/A
Computer: HF-SERVER-PC
Description:
Service cannot be started.
System.Runtime.Remoting.RemotingException: The channel 'tcp' is
already registered. at
System.Runtime.Remoting.Channels.ChannelServices.RegisterChannelInternal(IChannel
chnl, Boolean ensureSecurity) at
System.Runtime.Remoting.Channels.ChannelServices.RegisterChannel(IChannel
chnl) at Remoting.Client..ctor(String url) at
FileEventReaderService.Services.Logger.EventLogger..ctor(String
source, String logName, String url) at
FileEventReaderService.EventReader..ctor(String sqlServer, String
instance, String integratedSecurityType, String username, String
password, String dataBase) at
FileEventReaderService.EventReaderService.OnStart(String[] args) at
System.ServiceProcess.ServiceBase.ServiceQueuedMainCallback(Object
state)
For more information, see Help and Support Center at
go.microsoft.com/fwlink/….
In my case the problem were with multiple registering the tcp channel, in same instance, so i made a singleton class, and just set client once, and all other time i just called that instance....
using Remoting;
namespace FileEventReaderService.Services.Remotable
{
class SingletonClient
{
private static SingletonClient _instance = new SingletonClient();
private Client _client = null;
public static SingletonClient GetSingletonClient()
{
return _instance;
}
public Client GetClient()
{
return _client;
}
public void SetClientConfiguration(string url)
{
_client=new Client(url);
}
}
}
BTW, if any one need to find the process... he can use this article:
http://www.timvw.be/2007/09/09/build-your-own-netstatexe-with-c/ download the demo source and use it...
i also edit it in my own way, you can use it: (i did not changed 2 main class 'TcpTable' and 'IpHelper')
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Net.NetworkInformation;
using System.Net;
using System.Diagnostics;
using System.Collections;
using System.IO;
namespace FileEventReaderUI.Services.Network
{
class NetworkInformation
{
public ListenerProcessInformation GetListenerProcessInformationByPort(int port)
{
string fileName;
List<string> processModules=new List<string>();
foreach (TcpRow tcpRow in ManagedIpHelper.GetExtendedTcpTable(true))
{
if (tcpRow.LocalEndPoint.Port.ToString(CultureInfo.InvariantCulture).Equals(
port.ToString(CultureInfo.InvariantCulture))
&& tcpRow.State==TcpState.Listen)
{
Process process = Process.GetProcessById(tcpRow.ProcessId);
if (process.ProcessName != "System")
{
foreach (ProcessModule processModule in process.Modules)
{
processModules.Add(processModule.FileName);
}
fileName = Path.GetFileName(process.MainModule.FileName);
}
else
{
//Console.WriteLine(" -- unknown component(s) --"); ProcessModules count=0
//Console.WriteLine(" [{0}]", "System");
fileName = "[System]";
}
return new ListenerProcessInformation(fileName
, processModules.ToArray()
, new IPEndPoint(tcpRow.LocalEndPoint.Address,
tcpRow.LocalEndPoint.Port)
, new IPEndPoint(tcpRow.RemoteEndPoint.Address,
tcpRow.RemoteEndPoint.Port)
, tcpRow.ProcessId
, tcpRow.State);
}
}
return null;
}
}
#region Managed IP Helper API
public class TcpTable : IEnumerable<TcpRow>
{
#region Private Fields
private IEnumerable<TcpRow> tcpRows;
#endregion
#region Constructors
public TcpTable(IEnumerable<TcpRow> tcpRows)
{
this.tcpRows = tcpRows;
}
#endregion
#region Public Properties
public IEnumerable<TcpRow> Rows
{
get { return this.tcpRows; }
}
#endregion
#region IEnumerable<TcpRow> Members
public IEnumerator<TcpRow> GetEnumerator()
{
return this.tcpRows.GetEnumerator();
}
#endregion
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
return this.tcpRows.GetEnumerator();
}
#endregion
}
public class TcpRow
{
#region Private Fields
private IPEndPoint localEndPoint;
private IPEndPoint remoteEndPoint;
private TcpState state;
private int processId;
#endregion
#region Constructors
public TcpRow(IpHelper.TcpRow tcpRow)
{
this.state = tcpRow.state;
this.processId = tcpRow.owningPid;
int localPort = (tcpRow.localPort1 << 8) + (tcpRow.localPort2) + (tcpRow.localPort3 << 24) + (tcpRow.localPort4 << 16);
long localAddress = tcpRow.localAddr;
this.localEndPoint = new IPEndPoint(localAddress, localPort);
int remotePort = (tcpRow.remotePort1 << 8) + (tcpRow.remotePort2) + (tcpRow.remotePort3 << 24) + (tcpRow.remotePort4 << 16);
long remoteAddress = tcpRow.remoteAddr;
this.remoteEndPoint = new IPEndPoint(remoteAddress, remotePort);
}
#endregion
#region Public Properties
public IPEndPoint LocalEndPoint
{
get { return this.localEndPoint; }
}
public IPEndPoint RemoteEndPoint
{
get { return this.remoteEndPoint; }
}
public TcpState State
{
get { return this.state; }
}
public int ProcessId
{
get { return this.processId; }
}
#endregion
}
public static class ManagedIpHelper
{
#region Public Methods
public static TcpTable GetExtendedTcpTable(bool sorted)
{
List<TcpRow> tcpRows = new List<TcpRow>();
IntPtr tcpTable = IntPtr.Zero;
int tcpTableLength = 0;
if (IpHelper.GetExtendedTcpTable(tcpTable, ref tcpTableLength, sorted, IpHelper.AfInet, IpHelper.TcpTableType.OwnerPidAll, 0) != 0)
{
try
{
tcpTable = Marshal.AllocHGlobal(tcpTableLength);
if (IpHelper.GetExtendedTcpTable(tcpTable, ref tcpTableLength, true, IpHelper.AfInet, IpHelper.TcpTableType.OwnerPidAll, 0) == 0)
{
IpHelper.TcpTable table = (IpHelper.TcpTable)Marshal.PtrToStructure(tcpTable, typeof(IpHelper.TcpTable));
IntPtr rowPtr = (IntPtr)((long)tcpTable + Marshal.SizeOf(table.length));
for (int i = 0; i < table.length; ++i)
{
tcpRows.Add(new TcpRow((IpHelper.TcpRow)Marshal.PtrToStructure(rowPtr, typeof(IpHelper.TcpRow))));
rowPtr = (IntPtr)((long)rowPtr + Marshal.SizeOf(typeof(IpHelper.TcpRow)));
}
}
}
finally
{
if (tcpTable != IntPtr.Zero)
{
Marshal.FreeHGlobal(tcpTable);
}
}
}
return new TcpTable(tcpRows);
}
#endregion
}
#endregion
#region P/Invoke IP Helper API
/// <summary>
/// <see cref="http://msdn2.microsoft.com/en-us/library/aa366073.aspx"/>
/// </summary>
public static class IpHelper
{
#region Public Fields
public const string DllName = "iphlpapi.dll";
public const int AfInet = 2;
#endregion
#region Public Methods
/// <summary>
/// <see cref="http://msdn2.microsoft.com/en-us/library/aa365928.aspx"/>
/// </summary>
[DllImport(IpHelper.DllName, SetLastError = true)]
public static extern uint GetExtendedTcpTable(IntPtr tcpTable, ref int tcpTableLength, bool sort, int ipVersion, TcpTableType tcpTableType, int reserved);
#endregion
#region Public Enums
/// <summary>
/// <see cref="http://msdn2.microsoft.com/en-us/library/aa366386.aspx"/>
/// </summary>
public enum TcpTableType
{
BasicListener,
BasicConnections,
BasicAll,
OwnerPidListener,
OwnerPidConnections,
OwnerPidAll,
OwnerModuleListener,
OwnerModuleConnections,
OwnerModuleAll,
}
#endregion
#region Public Structs
/// <summary>
/// <see cref="http://msdn2.microsoft.com/en-us/library/aa366921.aspx"/>
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct TcpTable
{
public uint length;
public TcpRow row;
}
/// <summary>
/// <see cref="http://msdn2.microsoft.com/en-us/library/aa366913.aspx"/>
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct TcpRow
{
public TcpState state;
public uint localAddr;
public byte localPort1;
public byte localPort2;
public byte localPort3;
public byte localPort4;
public uint remoteAddr;
public byte remotePort1;
public byte remotePort2;
public byte remotePort3;
public byte remotePort4;
public int owningPid;
}
#endregion
}
#endregion
}
and the Entity class i use to fill ...
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Net.NetworkInformation;
using System.Text;
namespace FileEventReaderUI.Services.Network
{
class ListenerProcessInformation
{
private string _fileName;
private string[] _processModules;
private IPEndPoint _localEndPoint;
private IPEndPoint _remoteEndPoint;
private int _processId;
private TcpState _state;
public ListenerProcessInformation(string fileName, string[] processModules, IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, int processId, TcpState state)
{
_fileName = fileName;
_processModules = processModules;
_localEndPoint = localEndPoint;
_remoteEndPoint = remoteEndPoint;
_processId = processId;
_state = state;
}
public string FileName
{
get { return _fileName; }
}
public string[] ProcessModules
{
get { return _processModules; }
}
public IPEndPoint LocalEndPoint
{
get { return _localEndPoint; }
}
public IPEndPoint RemoteEndPoint
{
get { return _remoteEndPoint; }
}
public int ProcessId
{
get { return _processId; }
}
public TcpState State
{
get { return _state; }
}
}
}
So I try to create opensource C# project for slicing FLVs I began with translating of existing project called flvslicer
Can any one please help me with translating one of their classes
package org.bytearray.video.events
{
import flash.events.Event;
import flash.utils.ByteArray;
public final class MergedEvent extends Event
{
public var time:Number;
public var stream:ByteArray;
public static const COMPLETE:String = "mergeComplete";
public function MergedEvent(type:String, stream:ByteArray, duration:Number)
{
super(type, false, false); // base
this.stream = stream;
this.time = duration;
}
}
}
In C# you have two separate items, an EventHandler<TArgs> declaration and the custom EventArgs subclass.
public event EventHandler<MergedEventArgs> MergeComplete;
public class MergedEventArgs : EventArgs {
public double Time { get; set; }
public byte[] Stream { get; set;
}