[Windows Mobile] How to play audio/video C# or DirectShow.NET CF Part I

“DirectShow is a multimedia framework and API produced by Microsoft for software developers to perform various operations with media files or streams.” (c) Wikipedia

I`m not sure what earliest version of Windows Mobile that supports DirectShow, but i`m totally sure that Windows Mobile 5.0 and higher definitly suppor DirectShow.

So if you developing you application on C++ you have all headers and libs and it aint problem to use DirectShow, but if you developing on C# then welcome thats article exactly for you :)

So to make work we need to import required Interfaces and as DirectShow based on COM technologies we need to import CoCreateInstance function

[DllImport("ole32.dll")]
public static extern int CoCreateInstance(
[In] ref Guid rclsid,
[In] IntPtr pUnkOuter,
[In] uint dwClsContext,
[In] ref Guid riid,
[Out, MarshalAs(UnmanagedType.Interface)] out object pv);

In this post i will explain how to play video or audio files. So to play media files we need 2 interfaces:
IGraphBuilder and IMediaControl

to play any media file (if codecs and required filters installed) it will be enough to call method RenderFile of IGraphBuilder interface and method Run of IMediaControl interface… thats easy, isnt it?

[ComVisible(true), ComImport,
Guid("56A868A9-0AD4-11ce-B03A-0020AF0BA770"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IGraphBuilder
{
[PreserveSig]
int AddFilter(
[In] IntPtr pFilter,
[In, MarshalAs(UnmanagedType.LPWStr)] string pName);

[PreserveSig]
int RemoveFilter([In, MarshalAs(UnmanagedType.Interface)] object pFilter);

[PreserveSig]
int EnumFilters([Out, MarshalAs(UnmanagedType.Interface)] out object ppEnum);

[PreserveSig]
int FindFilterByName(
[In, MarshalAs(UnmanagedType.LPWStr)] string pName,
[Out, MarshalAs(UnmanagedType.Interface)] out object ppFilter);

[PreserveSig]
int ConnectDirect(
[In, MarshalAs(UnmanagedType.Interface)] object ppinOut,
[In, MarshalAs(UnmanagedType.Interface)] object ppinIn,
[In, MarshalAs(UnmanagedType.LPStruct)] IntPtr pmt);

[PreserveSig]
int Reconnect([In, MarshalAs(UnmanagedType.Interface)] object ppin);

[PreserveSig]
int Disconnect([In, MarshalAs(UnmanagedType.Interface)] object ppin);

[PreserveSig]
int SetDefaultSyncSource();

[PreserveSig]
int Connect(
[In, MarshalAs(UnmanagedType.Interface)] object ppinOut,
[In, MarshalAs(UnmanagedType.Interface)] object ppinIn);

[PreserveSig]
int Render([In, MarshalAs(UnmanagedType.Interface)] object ppinOut);

[PreserveSig]
int RenderFile(
[In, MarshalAs(UnmanagedType.LPWStr)] string lpcwstrFile,
[In, MarshalAs(UnmanagedType.LPWStr)] string lpcwstrPlayList);

[PreserveSig]
int AddSourceFilter(
[In, MarshalAs(UnmanagedType.LPWStr)] string lpcwstrFileName,
[In, MarshalAs(UnmanagedType.LPWStr)] string lpcwstrFilterName,
[Out] out IntPtr ppFilter);

[PreserveSig]
int SetLogFile(IntPtr hFile);

[PreserveSig]
int Abort();

[PreserveSig]
int ShouldOperationContinue();
}

[ComVisible(true), ComImport,
Guid("56A868B1-0AD4-11CE-B03A-0020AF0BA770"),
InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IMediaControl
{
[PreserveSig]
int Run();

[PreserveSig]
int Pause();

[PreserveSig]
int Stop();

[PreserveSig]
int GetState(
int msTimeout,
out int pfs);

[PreserveSig]
int RenderFile(string strFilename);

[PreserveSig]
int AddSourceFilter(
[In] string strFilename,
[Out, MarshalAs(UnmanagedType.IDispatch)] out object ppUnk);

[PreserveSig]
int get_FilterCollection(
[Out, MarshalAs(UnmanagedType.IDispatch)] out object ppUnk);

[PreserveSig]
int get_RegFilterCollection(
[Out, MarshalAs(UnmanagedType.IDispatch)] out object ppUnk);

[PreserveSig]
int StopWhenReady();
}

To make life more easier i created class CFilterGraph (simplified version of TFilterGraph from DSPack that in Delphi) so here is class that exports 4 methods:
renderFile, play, stop and pause.

using System;

namespace DirectShowNETCF
{
public class CFilterGraph: IDisposable
{
private IGraphBuilder graph = null;
private IMediaControl control = null;

public CFilterGraph()
{
object obj = null;
Guid clsid = CLSID_.FilterGraph;
Guid riid = IID_.IFilterGraph2;
PInvoke.CoCreateInstance(ref clsid, IntPtr.Zero, (uint)CLSCTX_.INPROC_SERVER, ref riid, out obj);
graph = (IGraphBuilder)obj;
control = (IMediaControl)graph;
obj = null;
}

public void Dispose()
{
stop();
System.Runtime.InteropServices.Marshal.ReleaseComObject(graph);
graph = null;
control = null;
}

public bool renderFile(string fileName)
{
return ((graph != null) && (graph.RenderFile(fileName, null) >= 0));
}

public bool play()
{
return ((control != null) && (control.Run() >= 0));
}

public bool stop()
{
return ((control != null) && (control.Stop() >= 0));
}

public bool pause()
{
return ((control != null) && (control.Pause() >= 0));
}
}
}

Thats all :) enjoy and have fun, to play mediafiles use Player class from DirectShowNETCF

[Windows Mobile] Connection Manager API C#

Some posts ago i wrote about using RAS to establish internet connection in that post i mentioned about Connection Manager API. Full description you can find on MSDN, but in most cases developers use 2 functions:

ConnMgrEstablishConnection
ConnMgrReleaseConnection

So to establish connection we need just fill one struct and call ConnMgrEstablishConnection. Thats easy, isnt it?

public bool Connect()
{
ConnectionInfo connInfo_ = new ConnectionInfo();
connInfo_.cbSize = Marshal.SizeOf(connInfo_);
connInfo_.dwFlags = 0;
connInfo_.dwParams = 0x1;
connInfo_.guidDestNet = new Guid("436EF144-B4FB-4863-A041-8F905A62C572");
connInfo_.dwPriority = 0x08000;
connInfo_.bExclusive = 0;
connInfo_.bDisabled = 0;
connInfo_.hWnd = IntPtr.Zero;
connInfo_.lParam = 0;

IntPtr conn_ = IntPtr.Zero; //we dont need to save it because it aint work
return ConnMgrEstablishConnection(connInfo_, out conn_) == 0;
}

I dont know why, but ConnMgrReleaseConnection aint work for me :( i returns success result, but connection still established, so to Disconnect i still use RAS, but how? i can call RasHangUp if i dont know Connection Handle, so we need to use RasEnumConnections to get it and then call RasHangUp

//using ras to disconnect
public static void Disconnect()
{
RasConn[] rconn_ = new RasConn[1]; //as a rule 1 connection is enough
int out_ = Marshal.SizeOf(typeof(RasConn));
int cout_ = 1;

rconn_[0].dwSize = out_;
rconn_[0].szEntryName = null;

RasEnumConnections(rconn_, ref out_, out cout_);

if (cout_ > 0)
{
RasHangUp(rconn_[0].hRasconn);
System.Threading.Thread.Sleep(3000); //msdn says that we should do that
}
}

Sources you can donload here

MJPEG to JPEG C++/Delphi

Some years go i received task to receive/record/play from DCS IP camera, it support MPEG4 and MJPEG stream via RTSP/RTP, so problem was:

1. Implement RTSP (just part that will enough to receive stream)
2. Parse/Record received stream

To implement RTSP was enough 1 day of RFC and Sockets dump learning, to recording stream i wrote simple mpeg4/mjpeg parser that split stream to frames and than we can use methods from avifil32.dll

But when i done my employer said: “If we chose to receive mjpeg stream i wanna have possibility to save frame to jpeg file”. That was a problem. i spent much time for research :( but task was done :)

So what we need for that?

a) Write to file JPEG header
b) Write DHT color segment
c) Remove Avi header from MJPEG frame and write result
d) thats all :)

#include "mjpegtojpeg.hpp"

bool mjpeg2Jpeg(const char *fileName, const byte *buffer, const int size)
{
HANDLE file_ = CreateFile(fileName,
GENERIC_WRITE | GENERIC_READ,
0, NULL,
CREATE_ALWAYS,
0, NULL);

if (file_ == INVALID_HANDLE_VALUE)
{
return false;
}

byte jpgHdr[] =
{
0xff, 0xd8,                  // SOI
0xff, 0xe0,                  // APP0
0x00, 0x10,                  // APP0 Hdr size
0x4a, 0x46, 0x49, 0x46, 0x00, // ID string
0x01, 0x01,                  // Version
0x00,                      // Bits per type
0x00, 0x00,                  // X density
0x00, 0x00,                  // Y density
0x00,                      // X Thumbnail size
0x00                      // Y Thumbnail size
};

unsigned long wrote = 0;
//write header
if (!WriteFile(file_, jpgHdr, sizeof (jpgHdr), &wrote, NULL))
{
CloseHandle(file_);
return false;
}

byte MJPGDHTSeg[0x1A4] =
{
/* JPEG DHT Segment for YCrCb omitted from MJPG data */
0xFF, 0xC4, 0x01, 0xA2,
0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00,
0x00, 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61,
0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24,
0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34,
0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56,
0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9,
0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9,
0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
0xF8, 0xF9, 0xFA, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01,
0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62,
0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A,
0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56,
0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8,
0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8,
0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
0xF9, 0xFA
};
//Write DHT color segment
if (!WriteFile (file_, MJPGDHTSeg, sizeof (MJPGDHTSeg), &wrote, NULL))
{
CloseHandle(file_);
return false;
}

//removing avi header
int tmp = *(buffer + 4);
tmp <<= 8;
tmp += *(buffer + 5) + 4;

//write frame
if (!WriteFile (file_, buffer + tmp, size - tmp, &wrote, NULL))
{
CloseHandle(file_);
return false;
}

CloseHandle(file_);
return true;
}
unit mjpegtojpeg;

interface
uses windows;

const
MJPGDHTSeg : array[1..$1A4] of byte =
(
{ JPEG DHT Segment for YCrCb omitted from MJPG data }
$FF, $C4, $01, $A2,
$00, $00, $01, $05, $01, $01, $01, $01, $01, $01, $00, $00, $00, $00, $00, $00, $00, $00,
$01, $02, $03, $04, $05, $06, $07, $08, $09, $0A, $0B, $01, $00, $03, $01, $01, $01, $01,
$01, $01, $01, $01, $01, $00, $00, $00, $00, $00, $00, $01, $02, $03, $04, $05, $06, $07,
$08, $09, $0A, $0B, $10, $00, $02, $01, $03, $03, $02, $04, $03, $05, $05, $04, $04, $00,
$00, $01, $7D, $01, $02, $03, $00, $04, $11, $05, $12, $21, $31, $41, $06, $13, $51, $61,
$07, $22, $71, $14, $32, $81, $91, $A1, $08, $23, $42, $B1, $C1, $15, $52, $D1, $F0, $24,
$33, $62, $72, $82, $09, $0A, $16, $17, $18, $19, $1A, $25, $26, $27, $28, $29, $2A, $34,
$35, $36, $37, $38, $39, $3A, $43, $44, $45, $46, $47, $48, $49, $4A, $53, $54, $55, $56,
$57, $58, $59, $5A, $63, $64, $65, $66, $67, $68, $69, $6A, $73, $74, $75, $76, $77, $78,
$79, $7A, $83, $84, $85, $86, $87, $88, $89, $8A, $92, $93, $94, $95, $96, $97, $98, $99,
$9A, $A2, $A3, $A4, $A5, $A6, $A7, $A8, $A9, $AA, $B2, $B3, $B4, $B5, $B6, $B7, $B8, $B9,
$BA, $C2, $C3, $C4, $C5, $C6, $C7, $C8, $C9, $CA, $D2, $D3, $D4, $D5, $D6, $D7, $D8, $D9,
$DA, $E1, $E2, $E3, $E4, $E5, $E6, $E7, $E8, $E9, $EA, $F1, $F2, $F3, $F4, $F5, $F6, $F7,
$F8, $F9, $FA, $11, $00, $02, $01, $02, $04, $04, $03, $04, $07, $05, $04, $04, $00, $01,
$02, $77, $00, $01, $02, $03, $11, $04, $05, $21, $31, $06, $12, $41, $51, $07, $61, $71,
$13, $22, $32, $81, $08, $14, $42, $91, $A1, $B1, $C1, $09, $23, $33, $52, $F0, $15, $62,
$72, $D1, $0A, $16, $24, $34, $E1, $25, $F1, $17, $18, $19, $1A, $26, $27, $28, $29, $2A,
$35, $36, $37, $38, $39, $3A, $43, $44, $45, $46, $47, $48, $49, $4A, $53, $54, $55, $56,
$57, $58, $59, $5A, $63, $64, $65, $66, $67, $68, $69, $6A, $73, $74, $75, $76, $77, $78,
$79, $7A, $82, $83, $84, $85, $86, $87, $88, $89, $8A, $92, $93, $94, $95, $96, $97, $98,
$99, $9A, $A2, $A3, $A4, $A5, $A6, $A7, $A8, $A9, $AA, $B2, $B3, $B4, $B5, $B6, $B7, $B8,
$B9, $BA, $C2, $C3, $C4, $C5, $C6, $C7, $C8, $C9, $CA, $D2, $D3, $D4, $D5, $D6, $D7, $D8,
$D9, $DA, $E2, $E3, $E4, $E5, $E6, $E7, $E8, $E9, $EA, $F2, $F3, $F4, $F5, $F6, $F7, $F8,
$F9, $FA
);

jpgHdr : array[1..20] of byte =
(
$ff, $d8,                     // SOI
$ff, $e0,                     // APP0
$00, $10,                     // APP0 Hdr size
$4a, $46, $49, $46, $00, // ID string
$01, $01,                     // Version
$00,                           // Bits per type
$00, $00,                     // X density
$00, $00,                     // Y density
$00,                           // X Thumbnail size
$00                           // Y Thumbnail size
);

function mjpeg2Jpeg(const fileName: string; const buffer : Pointer; const size : integer) : boolean;

implementation

function mjpeg2Jpeg(const fileName: string; const buffer : Pointer; const size : integer) : boolean;
var
wrote : longword;
tmp : integer;
file_ : THandle;
begin
Result := False;
file_ := CreateFile(PChar(fileName),
GENERIC_WRITE or GENERIC_READ,
0, nil,
CREATE_ALWAYS,
0, 0);

if (file_ = INVALID_HANDLE_VALUE) then
begin
exit;
end;
//write header
if (not WriteFile(file_, jpgHdr[1], 20, wrote, nil)) then
begin
CloseHandle(file_);
exit;
end;

if (not WriteFile (file_, MJPGDHTSeg[1], $1A4, wrote, nil)) then
begin
CloseHandle(file_);
exit;
end;

//removing avi header
tmp := Integer(Pointer(Integer(buffer) + 4));
tmp := tmp shl 8;
tmp := tmp + Integer(Pointer(Integer(buffer) + 5)) + 4;

//write frame
if (not WriteFile (file_, Pointer(Integer(buffer) + tmp)^, size - tmp, wrote, nil)) then
begin
CloseHandle(file_);
exit;
end;

CloseHandle(file_);
Result := True;
end;

end.

you can download sources here

[Windows CE/Mobile] Get Process List C#

Some monthes ago i found article on RSDN that explains how to enumerate process for windows, there was like 5 or 6 methods, one of them says to use ToolHelp api for that, and i asked my self “is it possible to use ToolHelph API on Windows CE, Windows Mobile?”… 10 minutes on MSDN and we got answer, yes we can!
So for that we need 4 API function from toolhelp.dll:

CreateToolhelp32Snapshot  -  This function takes a snapshot of the processes, heaps, modules, and threads used by the processes

CloseToolhelp32Snapshot  -  This function closes a handle to a snapshot.

Process32First  -  This function retrieves information about the first process encountered in a system snapshot.

Process32Next  -  This function retrieves information about the next process recorded in a system snapshot.

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace ToolHelpApi
{
public class ProcEntry
{
public string ExeName;
public uint ID;
}

public class ProcessEnumerator
{
#region Constants
private const uint TH32CS_SNAPPROCESS = 0x00000002;
private const int MAX_PATH = 260;
#endregion

#region Structs
public struct PROCESSENTRY
{
public uint dwSize;
public uint cntUsage;
public uint th32ProcessID;
public uint th32DefaultHeapID;
public uint th32ModuleID;
public uint cntThreads;
public uint th32ParentProcessID;
public int pcPriClassBase;
public uint dwFlags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
public string szExeFile;
uint th32MemoryBase;
uint th32AccessKey;
}
#endregion

#region P/Invoke
[DllImport("toolhelp.dll")]
private static extern IntPtr CreateToolhelp32Snapshot(uint flags, uint processID);

[DllImport("toolhelp.dll")]
private static extern int CloseToolhelp32Snapshot(IntPtr snapshot);

[DllImport("toolhelp.dll")]
private static extern int Process32First(IntPtr snapshot, ref PROCESSENTRY processEntry);

[DllImport("toolhelp.dll")]
private static extern int Process32Next(IntPtr snapshot, ref PROCESSENTRY processEntry);
#endregion

#region public Methods
public static bool Enumerate(ref List<ProcEntry> list)
{
if (list == null)
{
return false;
}
list.Clear();

IntPtr snapshot_ = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snapshot_ == IntPtr.Zero)
{
return false;
}

PROCESSENTRY entry_ = new PROCESSENTRY();
entry_.dwSize = (uint)Marshal.SizeOf(entry_);
if (Process32First(snapshot_, ref entry_) == 0)
{
CloseToolhelp32Snapshot(snapshot_);
return false;
}

do
{
ProcEntry procEntry = new ProcEntry();
procEntry.ExeName = entry_.szExeFile;
procEntry.ID = entry_.th32ProcessID;
list.Add(procEntry);
entry_.dwSize = (uint)Marshal.SizeOf(entry_);
}
while (Process32Next(snapshot_, ref entry_) != 0);

CloseToolhelp32Snapshot(snapshot_);

return true;
}
public static bool KillProcess(uint procID)
{
try
{
System.Diagnostics.Process proc_ = System.Diagnostics.Process.GetProcessById((int)procID);
proc_.Kill();
proc_.Dispose();
return true;
}
catch (ArgumentException)
{
return false; //process does not exist
}
catch (Exception)
{
return false; //cannot kill process (perhaps its system process)
}
}
#endregion

}
}

You can download sources here

[Windows CE] Using Ras C#

If we will ask somebody experienced questions like:”What should we use to establish dial up connection on Windows”, i`m totally sure that 90% of asked will answer use RAS library!

If some somebody will ask me what do to establish GPRS connection on Windows Mobile i answer use Connection Manager API, but there is nothing regarding Connection Manager API on Windows CE, but we can use RAS API!

If you developing on C++ or C thats not a problem, but what to do if your project on C#? I googled and found that opennet cf got ras components, but it aint free(!), so we need to create our own :)

using System;
using System.Text;
using System.Runtime.InteropServices;

namespace CERas
{
/// <summary>
/// CERAS
/// </summary>
public class CERAS : IDisposable
{
#region Constants
private const int ENTRY_SIZE = 1464;
#endregion

#region P/Invoke
[DllImport("coredll.dll")]
public static extern uint RasDial(
IntPtr dialExtensions,
IntPtr phoneBookPath,
IntPtr rasDialParam,
uint notifierType,
IntPtr notifier,
ref IntPtr pRasConn);

[DllImport("coredll.dll")]
public static extern uint RasHangUp(IntPtr pRasConn);
#endregion

#region Private Declarations
private IntPtr rasConn_ = IntPtr.Zero; //Connection Handle
private uint result_ = 0;
private IntPtr rasEntry_ = IntPtr.Zero; //Entry Container
private string connName_ = ""; //connection name
private string userName_ = ""; //user name (could be empty string)
private string password_ = ""; // password (could be empty string)
#endregion

#region Properties
//property, sets or gets connection name
public string ConnectionName
{
get
{
return connName_;
}
set
{
if (value != connName_)
{
connName_ = value;
}
}
}

//property, sets or gets connection login
public string Login
{
get
{
return userName_;
}

set
{
if (value != userName_)
{
userName_ = value;
}
}
}

//property, sets or gets connection password
public string Password
{
get
{
return password_;
}
set
{
if (value != password_)
{
password_ = value;
}
}
}

//property, checks if connection established
public bool Established
{
get
{
return ((rasConn_ != IntPtr.Zero) && (result_ == 0));
}
}
#endregion

#region Public Methods
//Constructor
public CERAS()
{
rasConn_ = IntPtr.Zero;
result_ = 0;
rasEntry_ = Marshal.AllocHGlobal(ENTRY_SIZE); //Allocating 1464 bytes (size of Entry structure)
if (rasEntry_ == IntPtr.Zero)
{
throw new Exception("Error cannot get Allocate memory");
}
}

// Destructor
public void Dispose()
{
Marshal.FreeHGlobal(rasEntry_); //Free allocated memory
}

//Establishing connection, it will block thread that called this method
public bool Connect()
{
if (rasConn_ != IntPtr.Zero)
{
Disconnect();
}

FillEntry();
try
{
result_ = RasDial(IntPtr.Zero, IntPtr.Zero, rasEntry_, 0, IntPtr.Zero, ref rasConn_);
}
catch
{
//exception
}

if (result_ != 0)
{
Disconnect(); //we need call disconnect even if connection was not established
return false;
}
return true;
}

//Closing internet connection
public void Disconnect()
{
if (rasConn_ != IntPtr.Zero)
{
RasHangUp(rasConn_);
rasConn_ = IntPtr.Zero;
result_ = 0;
System.Threading.Thread.Sleep(3000); //read msdn, it says that we need wail like 3 seconds to release connection(!)
}
else
{
result_ = 0;
}
}
#endregion

#region Private Methods
//Clearing Entry Structure
private void ClearPtr()
{
//I`m totally sure that there should be easier way
for (int i = 0; i < ENTRY_SIZE; i++)
{
Marshal.WriteByte((IntPtr)(rasEntry_.ToInt32() + i), 0);
}
}

//Filling Entry structure
private void FillEntry()
{
ClearPtr();
IntPtr pCurrent = rasEntry_;
Marshal.WriteInt32(pCurrent, ENTRY_SIZE);

pCurrent = (IntPtr)(pCurrent.ToInt32() + 4);
foreach (byte b in Encoding.Unicode.GetBytes(connName_))
{
Marshal.WriteByte(pCurrent, b);
pCurrent = (IntPtr)(pCurrent.ToInt32() + 1);
}

pCurrent = (IntPtr)(rasEntry_.ToInt32() + 0x192);
foreach (byte b in Encoding.Unicode.GetBytes(userName_))
{
Marshal.WriteByte(pCurrent, b);
pCurrent = (IntPtr)(pCurrent.ToInt32() + 1);
}

pCurrent = (IntPtr)(rasEntry_.ToInt32() + 0x394);
foreach (byte b in Encoding.Unicode.GetBytes(password_))
{
Marshal.WriteByte(pCurrent, b);
pCurrent = (IntPtr)(pCurrent.ToInt32() + 1);
}
}
#endregion
}
}

Yau can download sources from here

BTW it should work on win mobile too :)

[Android] How to set proxy for android browser

There are many reasons to make browser serf pages through proxy server:

  • someone wanna catch http requests/responses
  • someone wanna hide his IP
  • so on

What to do if you want set proxy for android browser? there some ways:

  • add record to database: /data/data/com.android.providers.settings/databases/settings.db
  1. pull database to pc add record (using for example sdk tool sqlite3) and replace existing db
  2. make changes in database directly on device

but as for me there exist simplier way, do it by your Java application using Settings provider:

Settings.System.putString(getContentResolver(), Settings.System.HTTP_PROXY, "proxy_ip:proxy_port");

where proxy_ip/proxy_port = IP/port of proxy that you going to use.

there left one problem, it will not work if we will not add one string to manifest file, here it is:

<uses-permission android:name=”android.permission.WRITE_SETTINGS” />

Thats all, now it works, here is code:

package com.BrowserSettings;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.provider.Settings;

public class BrowserSettingsUI extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

final Button button = (Button) findViewById(R.id.Button01);
button.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
try
{
Settings.System.putString(getContentResolver(), Settings.System.HTTP_PROXY, "127.0.0.1:100");//enable proxy
}catch (Exception ex){
}
}
});

final Button button2 = (Button) findViewById(R.id.Button02);
button2.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {

try
{
Settings.System.putString(getContentResolver(), Settings.System.HTTP_PROXY, "");//disable proxy
}catch (Exception ex){
}
}
});

}
}

manifest file:

<?xml version=”1.0″ encoding=”utf-8″?>
<manifest xmlns:android=”http://schemas.android.com/apk/res/android”
package=”com.BrowserSettings”
android:versionCode=”1″
android:versionName=”1.0.0″>
<application android:icon=”@drawable/icon” android:label=”@string/app_name”>
<activity android:name=”.BrowserSettingsUI”
android:label=”@string/app_name”>
<intent-filter>
<action android:name=”android.intent.action.MAIN” />
<category android:name=”android.intent.category.LAUNCHER” />
</intent-filter>
</activity>
</application>
<uses-permission android:name=”android.permission.WRITE_SETTINGS” />
</manifest>

[Windows] Send sms using gsm modem Delphi/Lazarus

In previous post i wrote small description how asynchronously work with com port, in this post i gave small list where we can use it.

Today i wanna explain how to send sms if you have GSM modem connected to Com Port using created class and AT commands.

The simpliest way if your GSM modem support text mode (i think you have spend some time to find modem that aint support text mode).

So to send sms we need:

  • Open Com Port where modem plugged in
  • Enable Text mode (write to port command “AT+CMGF=1″, if you you will receive error response that means that you modem does not support text mode)
  • Send SMS:
  1. Send command: write to port AT+CMGS=”cell_number” (cell_number = destination number)
  2. Send sms text: after you send command AT+CMGS=”cell_number” you will receive response “>” then you need to write sms text to port

if you will receive response “OK”, congrats message was sent :)

here small class on delphi that sends sms (inherited from TThread):

unit SmsSender;

interface
uses
//  Windows,
Classes, SysUtils, ComPort, messages, Windows;

const
Steps : array[0..3] of string = (
'ATZ',
'AT+CMGF=',
'&gt;',
'+CMGS');

type

PMessageSet = ^TMessageSet;
TMessageSet = record
Number : string; //without any + symbols (example: 80993294258)
Text : string;
Unicode : boolean; //not implemented in this version
end;

TSmsSender = class(TThread)
private
FTerminate : boolean;
FToSend : TList;
FNextStep : TStringList;
FCurrent : string;
FIndex : Integer;
FComPort : TComPort;
public
Constructor Create(PortBoudRate : Integer; PortIndex : Integer);
Destructor Destroy; override;
Procedure SendSms(messageSet : TMessageSet);
Procedure Stop();
Procedure Execute; override;
end;

implementation

Constructor TSmsSender.Create(PortBoudRate : Integer; PortIndex : Integer);
begin
inherited Create(True);
FComPort := TComPort.Create(PortBoudRate, PortIndex);
Priority := tpNormal;
FreeOnTerminate := false;
FTerminate := false;
FToSend := TList.Create;
FNextStep := TStringList.Create;
FIndex := -1;
FCurrent := '';
if (not FComPort.Open()) then
raise Exception.Create('Cannot open Com Port');

Resume();
end;

Destructor TSmsSender.Destroy;
var
SmsItem : PMessageSet;
begin
while (FToSend.Count &gt; 0) do
begin
SmsItem := FToSend[0];
Dispose(SmsItem);
FToSend.Delete(0);
end;
FToSend.Free;
FComPort.Close();
FComPort.Free;
FNextStep.Clear();
FNextStep.Free;
inherited Destroy;
end;

Procedure TSmsSender.SendSms(messageSet : TMessageSet);
var
SmsItem : PMessageSet;
begin
New(SmsItem);
SmsItem^.Number :=  messageSet.Number;
SmsItem^.Text := messageSet.Text;
SmsItem^.Unicode := false; //unicode not implemented
FToSend.Add(SmsItem);
end;

Procedure TSmsSender.Execute;
var
res, tmp : string;
x : Integer;
SmsItem : PMessageSet;
begin
res := '';
tmp := '';

while (not FTerminate) do
begin
if ((FToSend.Count = 0) and (FNextStep.Count = 0) and (FCurrent = '')) then
begin
Sleep(200);
end else
begin
tmp := FComPort.Read();
res := res + tmp;
if (res &lt;&gt; '') then
begin
x := Pos(#13#10 + 'OK', res);
if (x &gt; 0) then
begin
if (Pos(FCurrent, res) &gt; 0) then
begin
if (FNextStep.Count &gt; 0) then
begin
Inc(FIndex);
FCurrent := Steps[FIndex];
tmp := FNextStep[0];
FNextStep.Delete(0);
FComPort.Write(tmp);
end else
begin
MessageBox(0, PChar('Message was sent'), PChar('Congratulations'), 0);
FCurrent := '';
FIndex := -1;
end;
end;
res := '';
end else
begin
x := Pos('ERROR', res);
if (x &gt; 0) then
begin
MessageBox(0, PChar('Message was not sent'), PChar('Error'), 0);
FIndex := -1;
FCurrent := '';
res := '';
FNextStep.Clear();
end else
begin
if (Pos('&gt;', res) &gt; 0) then
begin
Inc(FIndex);
FCurrent := Steps[FIndex];
tmp := FNextStep[0];
FNextStep.Delete(0);
FComPort.Write(tmp);
res := '';
end;
end;
end;
end;
end;

if ((FNextStep.Count = 0) and (FCurrent = '') and (FToSend.Count &gt; 0) and (not FTerminate)) then
begin
SmsItem := FToSend[0];
FIndex := 0;
FCurrent := Steps[FIndex];
FNextStep.Add('AT+CMGF=1' + #13#10);
FNextStep.Add('AT+CMGS="' + SmsItem^.Number + '"' + #13#10);
FNextStep.Add(SmsItem^.Text + #26);
Dispose(SmsItem);
FToSend.Delete(0);
FComPort.Write('ATZ' + #13#10);
Sleep(500);
end;

end;

end;

procedure TSmsSender.Stop();
begin
FTerminate := true;
end;

end.

Sources and Test application you can download here

[Android] Building Free Pascal Compiler for Android

I think most of us heard about young mobile platform Android by Google.

Google recomend to use Java for developing applications for Android, but there nothing dificult to use gcc cross compiler to build applications on C or C++, in one of next post i will write how to build application/library on c/c++ using android toolchain.

So we can use Java or C/C++ but what should developers dothat prefer Pascal?

Today i will tell how to build Free Pascal Compiler that can build applications for android.

To build cross compiler we will need:

  1. Free Pascal Compiler (you can get it from http://freepascal.org/download.var)
  2. arm-eabi toolchain (android eabi will not work, we got error on linking) so we need download toolchain (you can get it from [there windows and linux versions] http://www.codesourcery.com/sgpp/lite/arm/portal/release644)
  3. Last Free Pascal Sources (get if ftom svn http://svn.freepascal.org/svn/fpc/trunk)

Thats all, install toolchain packages and we can build crosscompiler.

To build crosscompiler you need:

a) in terminal (cmd for Windows) go to root folder that contatin fpc sources from svn

b) and type:

make crossall CPU_TARGET=arm OS_TARGET=linux OPT=”-dFPC_ARMEL -O- -gl” CROSSPORT=”-O-” CROSSBINDIR=/home/dabeat/toolchain/arm-none-linux-gnueabi/arm-eabi/bin

Note: (CROSSBINDIR – this is full path to downloaded and installedtoolchain)

That should be enough, if everything ok in folder that contain fpc in folder compiler you will find ppcrossarm, this is our cross compiler.

Lets build simple application:

program Hello;
begin
WriteLn(‘Hello World’);
end.

to build in terminal (cmd for windows) go to folder that contain crosscompiler and type:

./ppcrossarm -Tlinux -O- -XP -Fu/home/dabeat/fpc/rtl/units/arm-linux/ -FD/home/dabeat/toolchain/arm-none-linux-gnueabi/arm-eabi/bin /home/dabeat/Hello.pp

Note: -FD key that say to crosscompiler path to toolchain

-Fu key that say to crosscompiler path to cross rlt

if there wasnt errors then lets test built application:

1) Run emulator (you can find it in sdk`s tools folder)

2) In tools folder you will also find tool adb use it too load application on emulator:

./adb push /home/dabeat/Hello data/Hello

3) Run loaded application:

./adb shell data/Hello

as result you will see:

Hello Word

Yep we got it :) There left one problem application aint exit (only Ctrl + C helps) :(

P.S. I built cross compiler on Linux Ubuntu but I`m sure that if you will do on Windows the same steps you will have the same result.

[Windows] Working asynchronously with Com port on Delphi/Lazarus

From time to time i have tasks to read/write data to Com port, for example:

1. Sending/Receiving sms (using GSM modem)

2. Working with com port connected printer

3. GPS device

4. Some exotic devices, so on

there tons components you can find using google, but perhaps i was so lazy to find what i need or something else… anyway there werent anything dificult so  i did my own :)

for that we need 8 WinApi functions:


CreateFile
GetCommState
SetCommState
SetCommTimeouts
EscapeCommFunction
CloseHandle
WriteFile
ReadFile

Opening Port:


function TComPort.Open() : Boolean;
var
PortDCB : TDCB;
Timeouts : COMMTIMEOUTS;
begin
Result := False;
FHandle := CreateFile(PChar(FName),
GENERIC_READ or GENERIC_WRITE,
0, nil, OPEN_EXISTING,
0, 0); //trying to open com port

if (FHandle = INVALID_HANDLE_VALUE) then
exit;//com port was nor oppened for some reasons

FillChar(PortDCB, sizeof(TDCB), #0);
PortDCB.DCBlength := sizeof(TDCB);
GetCommState(FHandle, PortDCB); //getting port state

PortDCB.BaudRate := FBaudRate;
PortDCB.ByteSize := 8;
PortDCB.Parity := NOPARITY;
PortDCB.StopBits := ONESTOPBIT;
PortDCB.Flags := FFlags;//4243;

if (not SetCommState(FHandle, PortDCB)) then
exit;

Timeouts.ReadIntervalTimeout := MAXDWORD;
Timeouts.ReadTotalTimeoutMultiplier := MAXDWORD;
Timeouts.ReadTotalTimeoutConstant := FReadTimeOut; //read timeout
Timeouts.WriteTotalTimeoutMultiplier := MAXDWORD;
Timeouts.WriteTotalTimeoutConstant := FWriteTimeOut; //write timeout

if (not SetCommTimeouts(FHandle, Timeouts)) then
exit;

EscapeCommFunction(FHandle, 11);

Result := True;
end;

Reading from port:


function TComPort.Read() : String;
var
dwRead : Cardinal;
begin
Result := '';
//reading from port
ReadFile(FHandle, m_pBuf^, 1024, dwRead, nil);
Result := String(m_pBuf);
SetLength(Result, dwRead);
end;

Writing to port:


Function TComPort.Write(AData : string) : boolean;
var
m_ppBuf : Pointer;
dwWrote, dwCurWrote : Cardinal;
begin
Result := False;
m_ppBuf := @Pointer(AData)^;
dwWrote := 0;
while (dwWrote &amp;amp;lt; Length(AData)) do

begin
//writing to port
if (not WriteFile(FHandle, Pointer(LongInt(m_ppBuf) + dwWrote)^, length(AData) - dwWrote, dwCurWrote, nil)) then
begin
exit;
end;

Inc(dwWrote, dwCurWrote);
end;

Result := True;
end;

P.S. Download class, sources and example application you can from:

http://alexmogurenko.com/Examples/ComPort.zip

cout << “hello world” << endl;

subj :)