Is it possible to address high Ports with Inpout32.dll? - c#

I want to address Port 0xE020 (Hex -> Dec = 57.376) but it is out of bounds for a short. Now, I need this to test PCI-E Extension Parallel Ports.
Thanks to the answer to this question (https://stackoverflow.com/a/4618383/3391678) I use the following working code for 32-bit environments:
using System;
using System.Runtime.InteropServices;
namespace LPTx86
{
public class LPT
{
//inpout.dll
[DllImport("inpout32.dll")]
private static extern void Out32(short PortAddress, short Data);
[DllImport("inpout32.dll")]
private static extern char Inp32(short PortAddress);
private short _PortAddress;
public LPT(short PortAddress)
{
_PortAddress = PortAddress;
}
public void Write(short Data)
{
Out32(_PortAddress, Data);
}
public byte Read()
{
return (byte)Inp32(_PortAddress);
}
}
}
And for 64-bit environments:
using System;
using System.Runtime.InteropServices;
namespace LPTx64
{
class LPT
{
[DllImport("inpoutx64.dll", EntryPoint = "Out32")]
private static extern void Out32_x64(short PortAddress, short Data);
[DllImport("inpoutx64.dll", EntryPoint = "Inp32")]
private static extern char Inp32_x64(short PortAddress);
private short _PortAddress;
public LPT64(short PortAddress)
{
_PortAddress = PortAddress;
}
public void Write(short Data)
{
Out32_x64(_PortAddress, Data);
}
public byte Read()
{
return (byte)Inp32_x64(_PortAddress);
}
}
}
(Yes, I removed every piece of safeties and sanity checking, my second name is "Danger" ;) )
Is it possible and how can I address ports that do not fit into a short?

My header looks like this
void _stdcall Out32(short PortAddress, short data);
short _stdcall Inp32(short PortAddress);
The accepted answer works, but I think a more idiomatic way of using longer addresses is keeping the signatures consistent and casting to short in an unchecked context
[DllImport("inpout32.dll")]
private static extern void Out32(short PortAddress, short data);
[DllImport("inpout32.dll")]
private static extern short Inp32(short PortAddress);
public void Write(int address, short data) {
short portAddress;
unchecked {
portAddress = (short)address;
}
Out32(portAddress, data);
}
public short Read(int address) {
short portAddress;
unchecked {
portAddress = (short)address;
}
return Inp32(portAddress);
}

It's possible:
I tried and changed the type of the port variable from short to int, i tested it and it seems to work:
Edit: Refactored Code to combine the data/control/status ports into one Package
using System;
using System.Runtime.InteropServices;
namespace LPTtestdrive
{
class LPT_X
{
//inpout.dll
[DllImport("inpout32.dll")]
private static extern UInt32 IsInpOutDriverOpen();
[DllImport("inpout32.dll")]
private static extern void Out32(int PortAddress, short Data);
[DllImport("inpout32.dll")]
private static extern char Inp32(int PortAddress);
//inpoutx64.dll
[DllImport("inpoutx64.dll", EntryPoint = "IsInpOutDriverOpen")]
private static extern UInt32 IsInpOutDriverOpen_x64();
[DllImport("inpoutx64.dll", EntryPoint = "Out32")]
private static extern void Out32_x64(int PortAddress, short Data);
[DllImport("inpoutx64.dll", EntryPoint = "Inp32")]
private static extern char Inp32_x64(int PortAddress);
private bool _X64;
private int DataAddress;
private int StatusAddress;
private int ControlAddress;
public LPT_X(int PortAddress)
{
DataAddress = PortAddress;
StatusAddress = (int)(DataAddress + 1);
ControlAddress = (int)(DataAddress + 2);
//now the code tries to determine if it should use inpout32.dll or inpoutx64.dll
uint nResult = 0;
try
{
Console.WriteLine("trying 32 bits");
nResult = IsInpOutDriverOpen();
if (nResult != 0)
{
Console.WriteLine("using 32 bits");
return;
}
}
catch (BadImageFormatException)
{
Console.WriteLine("32 bits failed");
}
catch (DllNotFoundException)
{
throw new ArgumentException("Unable to find InpOut32.dll");
}
catch (Exception exc)
{
Console.WriteLine(exc.Message);
}
try
{
Console.WriteLine("trying 64 bits");
nResult = IsInpOutDriverOpen_x64();
if (nResult != 0)
{
Console.WriteLine("using 64 bits");
_X64 = true;
return;
}
}
catch (BadImageFormatException)
{
Console.WriteLine("64 bits failed");
}
catch (DllNotFoundException)
{
throw new ArgumentException("Unable to find InpOutx64.dll");
}
catch (Exception exc)
{
Console.WriteLine(exc.Message);
}
throw new ArgumentException("Unable to open either inpout32 and inpoutx64");
}
public void WriteData(short Data)
{
if (_X64)
{
Out32_x64(DataAddress, Data);
}
else
{
Out32(DataAddress, Data);
}
}
public void WriteControl(short Data)
{
if (_X64)
{
Out32_x64(ControlAddress, Data);
}
else
{
Out32(ControlAddress, Data);
}
}
public byte ReadData()
{
if (_X64)
{
return (byte)Inp32_x64(DataAddress);
}
else
{
return (byte)Inp32(DataAddress);
}
}
public byte ReadControl()
{
if (_X64)
{
return (byte)Inp32_x64(ControlAddress);
}
else
{
return (byte)Inp32(ControlAddress);
}
}
public byte ReadStatus()
{
if (_X64)
{
return (byte)Inp32_x64(StatusAddress);
}
else
{
return (byte)Inp32(StatusAddress);
}
}
}
}
Use it like this:
LPT_X LPT;
int read;
int Adress = 0xE020;
try
{
LPT = new LPT_X(Address);
LPT.WriteData(251);
LPT.WriteControl(0);
read = LPT.ReadStatus();
...
}

Related

How do I convert stdole.stdPicture to a .net image in C#?

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
}

Trying to Hook DoDragDrop to explorer but delegate method is not calling

"Ole32","DoDragDrop" function Hooking to the explorer is
successful but whenever i drag a file in explorer my
DoDragDropHook function is not calling, am new to the hooking concepts and i trying for this from last 3 months but till now no
proper result. please help me where am going wrong
namespace DragDrop_DLL
{
public class Main : EasyHook.IEntryPoint
{
DragDrop_Console.RemoteMon Interface;
public LocalHook dragDropHook;
public Main(RemoteHooking.IContext InContext, String InChannelName)
{
try
{
Interface = RemoteHooking.IpcConnectClient<DragDrop_Console.RemoteMon>(InChannelName);
File.AppendAllText(#"F:\DragDropLog.txt", "Main : Channel Name passed" + Environment.NewLine);
}
catch (Exception ex)
{
Interface.ErrorHandle(ex);
File.AppendAllText(#"F:\DragDropLog.txt", "Main Exception :"+ ex.ToString() + Environment.NewLine);
}
}
public void Run(RemoteHooking.IContext InContext, String InChannelName)
{
try
{
dragDropHook = LocalHook.Create(LocalHook.GetProcAddress("Ole32.dll", "DoDragDrop"), new DragDropDelegate(DoDragDropHook), null);
dragDropHook.ThreadACL.SetInclusiveACL(new Int32[] { 0 });
//Also tried with setExclusiveACL
//dragDropHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });
File.AppendAllText(#"F:\DragDropLog.txt", "Run : LocalHook Created" + Environment.NewLine);
}
catch (Exception ex)
{
Interface.ErrorHandle(ex);
File.AppendAllText(#"F:\DragDropLog.txt", "Run Exception :" + ex.ToString() + Environment.NewLine);
return;
}
Interface.IsInstalled(RemoteHooking.GetCurrentProcessId());
RemoteHooking.WakeUpProcess();
while (true)
{
Thread.Sleep(1000);
}
}
[DllImport("Ole32.dll",CharSet=CharSet.Unicode,SetLastError =true,CallingConvention =CallingConvention.StdCall)]
static extern int DoDragDrop(
IDataObject pDataObj,
IDropSource pDropSource,
UInt32 dwOKEffects,
UInt32[] pdwEffect);
[UnmanagedFunctionPointer(CallingConvention.StdCall,CharSet =CharSet.Ansi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.I4)]
delegate int DragDropDelegate(
IDataObject pDataObj,
IDropSource pDropSource,
UInt32 dwOKEffects,
UInt32[] pdwEffect);
static int DoDragDropHook(
IDataObject pDataObj,
IDropSource pDropSource,
UInt32 dwOKEffects,
UInt32[] pdwEffect)
{
try
{
((Main)HookRuntimeInfo.Callback).Interface.GotDragFileObject(pDataObj);
File.AppendAllText(#"F:\DragDropLog.txt", "DoDragDrop Hit :" + pDataObj.ToString() + Environment.NewLine);
}
catch(Exception ex)
{
File.AppendAllText(#"F:\DragDropLog.txt", "DoDragDropHook Exception :" + ex.ToString() + Environment.NewLine);
}
return DoDragDrop(pDataObj, pDropSource, dwOKEffects, pdwEffect);
}
}
internal interface IDropSource
{
}
}
this is a pseudo code:
private void CanvasLP_Drop(object sender, DragEventArgs e)
{
if (e.Handled == false)
{
Thumb thumb = (Thumb)e.Data.GetData("Object");
//thumb is used to store the dropped item, as in my case it is of type Thumb
//Object here is the item being dragged
//You can get file path from file name by using:
//Path.Combine(Directory.GetCurrentDirectory(), filename)
}
}

Error: CallbackOnCollectedDelegate was detected

I am currently working on a third party dll, and randomly when the delegate OnReceive is invoked I get the following error:
CallbackOnCollectedDelegate was detected
I read that GC.Collect() can solve the problem using static but also not as, I have hours and trying every way CallbackOnCollectedDelegate get the error, please help...
namespace Interfaz
{
class TMPDlg:
{
public CTMIF m_objTMPInterface;
public uint m_dwLocalIP;
public ushort m_nPort;
public byte m_nSubNet;
public uint m_nRadioID;
public uint m_nIndex;
public uint m_dwMobileID;
public int nLength;
public string mensaje_destino;
public string mensaje_recibido;
public TMPDlg()
{
m_objTMPInterface = null;
}
unsafe public void OnReceive(ushort wOpcode, System.IntPtr pbPayload, uint dwSize, uint dwLocalIP)
{
TMReceive(wOpcode, (byte*)pbPayload, dwSize, dwLocalIP);
}
unsafe public void TMReceive(ushort wOpcode, byte * pbPayload, uint dwSize, uint dwLocalIP)
{
// Some Work....
}
public void Send_PrivateMsg(string textBoxMensaje, string labelID)
{
m_nRadioID = uint.Parse(labelID);
mensaje_destino = textBoxMensaje;
nLength = textBoxMensaje.Length;
m_objTMPInterface.SendPrivateMsg(m_nRadioID, mensaje_destino, nLength, 0);
}
public void conect_master(ushort port, string ip)
{
m_objTMPInterface = new CTMIF();
m_dwLocalIP = (uint)IPAddressToNumber(ip);
ADKCALLBACK myOnReceive = new ADKCALLBACK(OnReceive);
m_objTMPInterface.SetCallBackFn(myOnReceive);
//m_objTMPInterface.SetCallBackFn(OnReceive);
m_objTMPInterface.OpenSocket(m_dwLocalIP, port, m_dwMobileID, 10)<
}
Presumably this part is the problem?
ADKCALLBACK myOnReceive = new ADKCALLBACK(OnReceive);
m_objTMPInterface.SetCallBackFn(myOnReceive);
If you have an instance variable of type ADKCALLBACK, then so long as your instance isn't garbage collected before (or while) the callback function is executing, you should be okay. What controls your instance's lifetime?
class TMPDlg
{
// Instance variable to protect from garbage collection
private readonly ADKCALLBACK receiveCallback;
public TMPDlg()
{
receiveCallback = myOnReceive;
}
...
public void ConnectMaster(ushort port, string ip)
{
...
m_objTMPInterface.SetCallBackFn(receiveCallback);
...
}
}
(As an aside, your naming could be improved significantly, and you should avoid having public fields.)

Redirect cout from C++ dll to a textbox in C#

I'm trying to display the console output (cout) of a method in a dll to a textbox in C# program. Every time I call the method, the console output will be displayed in the Output Pane of Visual Studio. Is there a way to redirect the content of the Output Pane to the textbox?
The dll was written by someone else in C++ and I have no control in changing it.
The dll is wrapped using SWIG so that it can be called by my C# code.
After following the link suggested by David, I decided to write a solution to your problem which is more specific to your case. This version allows you to receive the stdout in your GUI via a BackgroundWorker PropertyChangedEventHandler call back.
Here's the code for the ConsoleRedirector:
public class ConsoleRedirector : IDisposable
{
private static ConsoleRedirector _instance;
public static void attach(ProgressChangedEventHandler handler, bool forceConsoleRedirection)
{
Debug.Assert(null == _instance);
_instance = new ConsoleRedirector(handler, forceConsoleRedirection);
}
public static void detatch()
{
_instance.Dispose();
_instance = null;
}
public static bool isAttached
{
get
{
return null != _instance;
}
}
private static void ResetConsoleOutStream()
{
//Force console to recreate its output stream the next time Write/WriteLine is called
typeof(Console).GetField("_out", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).SetValue(null, null);
}
private const int PERIOD = 500;
private const int BUFFER_SIZE = 4096;
private volatile bool _isDisposed;
private BackgroundWorker _worker;
private readonly IntPtr _stdout;
private readonly Mutex _sync;
private readonly System.Threading.Timer _timer;
private readonly char[] _buffer;
private readonly AnonymousPipeServerStream _outServer;
private readonly TextReader _outClient;
private readonly bool _forceConsoleRedirection;
private StreamWriter _consoleStandardOut;
private ConsoleRedirector(ProgressChangedEventHandler handler, bool forceConsoleRedirection)
{
bool ret;
_forceConsoleRedirection = forceConsoleRedirection;
if (!_forceConsoleRedirection)
{
//Make sure Console._out is initialized before we redirect stdout, so the redirection won't affect it
TextWriter temp = Console.Out;
}
AnonymousPipeClientStream client;
_worker = new BackgroundWorker();
_worker.ProgressChanged += handler;
_worker.DoWork += _worker_DoWork;
_worker.WorkerReportsProgress = true;
_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
_sync = new Mutex();
_buffer = new char[BUFFER_SIZE];
_outServer = new AnonymousPipeServerStream(PipeDirection.Out);
client = new AnonymousPipeClientStream(PipeDirection.In, _outServer.ClientSafePipeHandle);
Debug.Assert(_outServer.IsConnected);
_outClient = new StreamReader(client, Encoding.Default);
ret = SetStdHandle(STD_OUTPUT_HANDLE, _outServer.SafePipeHandle.DangerousGetHandle());
Debug.Assert(ret);
if (_forceConsoleRedirection)
{
ResetConsoleOutStream(); //calls to Console.Write/WriteLine will now get made against the redirected stream
}
_worker.RunWorkerAsync(_outClient);
_timer = new System.Threading.Timer(flush, null, PERIOD, PERIOD);
}
void _worker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = (BackgroundWorker)sender;
TextReader client = (TextReader)e.Argument;
try
{
while (true)
{
int read = client.Read(_buffer, 0, BUFFER_SIZE);
if (read > 0)
worker.ReportProgress(0, new string(_buffer, 0, read));
}
}
catch (ObjectDisposedException)
{
// Pipe was closed... terminate
}
catch (Exception ex)
{
}
}
private void flush(object state)
{
_outServer.Flush();
}
public void Dispose()
{
Dispose(true);
}
~ConsoleRedirector()
{
Dispose(false);
}
private void Dispose(bool disposing)
{
if (!_isDisposed)
{
lock (_sync)
{
if (!_isDisposed)
{
_isDisposed = true;
_timer.Change(Timeout.Infinite, Timeout.Infinite);
_timer.Dispose();
flush(null);
try { SetStdHandle(STD_OUTPUT_HANDLE, _stdout);}
catch (Exception) { }
_outClient.Dispose();
_outServer.Dispose();
if (_forceConsoleRedirection)
{
ResetConsoleOutStream(); //Calls to Console.Write/WriteLine will now get redirected to the original stdout stream
}
}
}
}
}
private const int STD_OUTPUT_HANDLE = -11;
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetStdHandle(int nStdHandle, IntPtr hHandle);
[DllImport("kernel32.dll")]
private static extern IntPtr GetStdHandle(int nStdHandle);
}
Here's a link to a complete sample form which demonstrates how to use it: ConsoleRedirector Example Form

How to Invoke and use WSAAsyncSelect() in C#?

I edited my question when I set the bounty.
I want to Invoke/DllImport WSAAsyncSelect() from WinAPI and use it much like I use it in Delphi/C++
For example - Delphi
//Async CallBack handler Declaration
procedure MessageHandler(var Msg:Tmessage);Message WM_WINSOCK_ASYNC_MSG;
//Where i setup the Async
dwError := WSAAsyncSelect(Sock, form1.handle, WM_WINSOCK_ASYNC_MSG, FD_CLOSE or FD_READ);
//Async Callback Handler
procedure Tform1.MessageHandler(var Msg:Tmessage);
begin
case WSAGetSelectEvent(MSG.LParam) of //LParam is FD_READ/FR_CLOSE/FD_WRITE
FD_READ: OnSocketRead(MSG.WParam); //WPARAM is the Socket itself.
FD_CLOSE: OnSocketClose(MSG.WParam);
end;
end;
Thanks in advance!
I made it! Finaly!!!
WSAAsyncSelect() structure
[DllImport("wsock32.dll")]
public static extern int WSAAsyncSelect(
int socket,
int hWnd,
int wMsg,
int lEvent
);
WS2 Class
public class WS2
{
public static Socket sock;
public static byte[] data = new byte[8096];
public static int server = 0;
public static bool forced = true;
public static void Close()
{
//Extern.closesocket(sock.Handle.ToInt32());
//Extern.WSACleanup();
sock.Shutdown(SocketShutdown.Both);
sock.Close();
if (forced)
{
Connect();
}
}
public static void ConnectTo(string ip,int port)
{
sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sock.Connect(ip, port);
int handle = 0;
var form1 = Form.ActiveForm as FormMain;
if (form1 != null)
handle = form1.GetHandle;
if (handle == 0)
{
FormMain.PerformActionOnMainForm(form => form.memo.Text += "An error occured: Error code WS_01_ASYNC_HANDLE");
return;
}
Extern.WSAAsyncSelect(sock.Handle.ToInt32(), handle, Values.MESSAGE_ASYNC, Values.FD_READ | Values.FD_CLOSE);
}
public static void Connect()
{
//Get IP && port
string ip = GetIPFromHost("gwgt1.joymax.com");
if (ip == "")
{
ip = GetIPFromHost("gwgt2.joymax.com");
if (ip == "")
{
}
server +=2;
}
else
server +=1;
int port = 15779;
//
ConnectTo(ip, port);
}
public static void Receive()
{
int size = sock.Receive(data);
if (size == 0)
{
FormMain.PerformActionOnMainForm(form => form.memo.Text += "An error occured: Error Code WS_02_RECV_BEGN");
}
Main.Handle(data, size);
}
public static string GetIPFromHost(string HostName)
{
IPHostEntry ip;
try
{
ip = Dns.GetHostEntry(HostName);
}
catch (Exception)
{
return "";
}
return ip.AddressList[0].ToString();
}
}
WndProc in the Form class.
protected override void WndProc(ref Message m)
{
if (m.Msg == Values.MESSAGE_ASYNC)
{
switch (m.LParam.ToInt32())
{
case Values.FD_READ:
WS2.Receive();
break;
case Values.FD_WRITE: break;
case Values.FD_CLOSE:
WS2.Close();
break;
default: break;
}
}
else
{
base.WndProc(ref m);
}
}
Get Handle:
public int GetHandle
{
get
{
if (this.InvokeRequired)
{
return (int)this.Invoke((GetHandleDelegate)delegate
{
return this.Handle.ToInt32();
});
}
return this.Handle.ToInt32();
}
}
private delegate int GetHandleDelegate();
(edit: relates mainly to the original question, before it was edited and a bounty added)
I've been looking at this problem recently - see Async without the pain. Note the comment at the end about using the delegate version - this simplifies the calling slightly.
As an update, the final code would look something like below, and as it transpires is very similar to what F# uses under the bonnet:
public static void RunAsync<T>(
Func<AsyncCallback, object, IAsyncResult> begin,
Func<IAsyncResult, T> end,
Action<Func<T>> callback) {
begin(ar => {
T result;
try {
result = end(ar); // ensure end called
callback(() => result);
} catch (Exception ex) {
callback(() => { throw ex; });
}
}, null);
}

Categories