Browse Source

add dde driver

pull/16/head
Gavin 8 years ago
parent
commit
2c63d87a75
  1. BIN
      SCADA/Program/.vs/DataExchange/v15/.suo
  2. BIN
      SCADA/Program/.vs/DataExchange/v15/Server/sqlite3/storage.ide
  3. BIN
      SCADA/Program/.vs/DataExchange/v15/sqlite3/storage.ide
  4. 743
      SCADA/Program/DDEDriver/DDEDriver.cs
  5. 64
      SCADA/Program/DDEDriver/DDEDriver.csproj
  6. 481
      SCADA/Program/DDEDriver/DDELib.cs
  7. 620
      SCADA/Program/DDEDriver/DDEServer.cs
  8. 36
      SCADA/Program/DDEDriver/Properties/AssemblyInfo.cs
  9. 18
      SCADA/Program/DataExchange.sln
  10. BIN
      SCADA/dll/DDEDriver.dll

BIN
SCADA/Program/.vs/DataExchange/v15/.suo

Binary file not shown.

BIN
SCADA/Program/.vs/DataExchange/v15/Server/sqlite3/storage.ide

Binary file not shown.

BIN
SCADA/Program/.vs/DataExchange/v15/sqlite3/storage.ide

Binary file not shown.

743
SCADA/Program/DDEDriver/DDEDriver.cs

@ -0,0 +1,743 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using DataService;
namespace DDEDriver
{
[Description("DDE 通讯协议")]
public class DDEReader : IDriver
{
//DDE用常量定义#region DDE用常量定义
/**/
/// <summary>
/// ///////////////////////////////////////////////////////////////////////////
/// /***** conversation states (usState) *****/
/**/
/// </summary>
private int dwDDEInst; // DDE Instance value
private IntPtr hconvCurrent;
//private bool bAutoConnect;
//public string LinkDesc;
private DdeCallback _Callback;
short _id;
public string LinkName;
public short ID
{
get
{
return _id;
}
}
string _name;
public string Name
{
get
{
return _name;
}
}
string _server;
public string ServerName
{
get { return _server; }
set { _server = value; }
}
string _topic;
public string Topic
{
get
{
return _topic;
}
set
{
_topic = value;
}
}
internal bool _connected;
public bool IsClosed
{
get { return !_connected; }
}
int _timeOut;
public int TimeOut
{
get { return _timeOut; }
set { _timeOut = value; }
}
List<IGroup> _groups = new List<IGroup>(3);
public IEnumerable<IGroup> Groups
{
get { return _groups; }
}
IDataServer _parent;
public IDataServer Parent
{
get { return _parent; }
}
public DDEValueChangeEventHandler DDEValueChange;
public DDEReader(IDataServer parent, short id, string name, string server, int timeOut = 2000, string topic = null, string spare2 = null)
{
_id = id;
_parent = parent;
_name = name;
_server = server;
_timeOut = timeOut;
_topic = topic;
LinkName = _server + "|" + _topic;
_Callback = DdeClientCallback;
}
public unsafe bool Connect()
{
IntPtr hConv, hszService, hszTopic;
if (dwDDEInst != 0)
{
Ddeml.DdeUninitialize(dwDDEInst);
dwDDEInst = 0;
}
if (hconvCurrent != IntPtr.Zero)
{
Ddeml.DdeDisconnect(hconvCurrent);
hconvCurrent = IntPtr.Zero;
};
//如果是第一次,则什么也不做
Ddeml.DdeInitialize(ref dwDDEInst, _Callback, 0x3f000, 0);
// Connect to the server
hszTopic = Ddeml.DdeCreateStringHandle(dwDDEInst, _topic, Ddeml.CP_WINANSI);
hszService = Ddeml.DdeCreateStringHandle(dwDDEInst, _server, Ddeml.CP_WINANSI);
CONVCONTEXT cc = new CONVCONTEXT();
cc.cb = sizeof(CONVCONTEXT);
hConv = Ddeml.DdeConnect(dwDDEInst, hszService, hszTopic, ref cc);
//int DdeErrcode = Win32.DdeGetLastError(dwDDEInst);
Ddeml.DdeFreeStringHandle(dwDDEInst, hszTopic);
Ddeml.DdeFreeStringHandle(dwDDEInst, hszService);
if (hConv != IntPtr.Zero)
{
if (hconvCurrent != IntPtr.Zero)
{
Ddeml.DdeDisconnect(hconvCurrent);
}
hconvCurrent = hConv;
_connected = true;
return true;
}
else
{
_connected = false;
return false;
}
}
private IntPtr DdeClientCallback(int uType, ConversionFormat uFmt, IntPtr hConv, IntPtr hsz1, IntPtr hsz2, IntPtr hData, uint dwData1, uint dwData2)
{
int dwLength = 0;
//DateTime time = DateTime.Now;
unsafe
{
switch (uType)
{
case Ddeml.XTYP_ADVDATA:
try
{
sbyte* pData = (sbyte*)Ddeml.DdeAccessData(hData, ref dwLength);
if (pData != null)
{
sbyte* pSZ = stackalloc sbyte[0xFF];
Ddeml.DdeQueryString(dwDDEInst, hsz2, pSZ, 0xFF, Ddeml.CP_WINANSI);
if (DDEValueChange != null)
DDEValueChange(this, new DDEValueChangeEventArgs(new string(pSZ).ToUpper(), new string(pData, 0, dwLength)));
}
}
catch { }
finally
{
if (hData != IntPtr.Zero) Ddeml.DdeUnaccessData(hData);
}
break;
case Ddeml.XTYP_DISCONNECT:
if (OnError != null)
OnError(this, new IOErrorEventArgs("XTYP_DISCONNECT"));
_connected = false;
break;
case Ddeml.XTYP_XACT_COMPLETE:
break;
default:
break;
}
}
return new IntPtr(Ddeml.DDE_FACK);
}
//与Server建立Hoot连接
public unsafe bool TransactItem(string name)
{
IntPtr hszItem, hDDEData;
int dwResult = 0;
if (string.IsNullOrEmpty(name)) return false;
if (hconvCurrent != IntPtr.Zero)
{
hszItem = Ddeml.DdeCreateStringHandle(dwDDEInst, name, Ddeml.CP_WINANSI);
hDDEData = Ddeml.DdeClientTransaction(null,
0,
hconvCurrent,
hszItem,
ConversionFormat.TEXT,//CF_TEXT,
Ddeml.XTYP_ADVSTART,
Ddeml.TIMEOUT_ASYNC, // ms timeout
ref dwResult);
Ddeml.DdeFreeStringHandle(dwDDEInst, hszItem);
if (hDDEData != IntPtr.Zero)
{
try
{
int dwLength = 0;
sbyte* pData = (sbyte*)Ddeml.DdeAccessData(hDDEData, ref dwLength);
if ((pData != null) && (dwLength != 0))
{
if (DDEValueChange != null)
DDEValueChange(this, new DDEValueChangeEventArgs(name, new string(pData, 0, dwLength)));
}
}
catch { }
finally
{
Ddeml.DdeUnaccessData(hDDEData);
}
return true;
}
else
{
return false;
}
}
else
return false;
}
public int Execute(string command)
{
int res = 0;
byte[] data = Encoding.ASCII.GetBytes(command);
Ddeml.DdeClientTransaction(data, data.Length, hconvCurrent, IntPtr.Zero, ConversionFormat.NONE, Ddeml.XTYP_EXECUTE, _timeOut, ref res);
return res;
}
//必须设置item.ItemName和item.ItemValue后调用
public int Poke(string name, string value)
{
IntPtr hszItem, hDDEData;
int dwResult = 0;
if (string.IsNullOrEmpty(name)) return -2;
if (hconvCurrent != IntPtr.Zero)
{
hszItem = Ddeml.DdeCreateStringHandle(dwDDEInst, name, Ddeml.CP_WINANSI);
if (!string.IsNullOrEmpty(name))
{
//int errcode=Win32.DdeGetLastError(dwDDEInst);
byte[] ByteArray = Encoding.ASCII.GetBytes(value);
IntPtr hd = Ddeml.DdeCreateDataHandle(dwDDEInst, ByteArray, ByteArray.Length, 0, hszItem, ConversionFormat.TEXT, 0);
hDDEData = Ddeml.DdeClientTransaction(
ByteArray, ByteArray.Length,
hconvCurrent, hszItem,
ConversionFormat.TEXT,//CF_TEXT,
Ddeml.XTYP_POKE,
Ddeml.TIMEOUT_ASYNC, // ms timeout
ref dwResult);
Ddeml.DdeFreeStringHandle(dwDDEInst, hszItem);
if (hDDEData != IntPtr.Zero)
{
return 1;
}
}
return -1;
}
else
return -1;
}
// [10/24/2003]
//主动请求Item的值
public unsafe string Request(string name)
{
IntPtr hszItem, hDDEData;
int dwResult = 0;
int dwLength = 0;
if (name != null && hconvCurrent != IntPtr.Zero)
{
hszItem = Ddeml.DdeCreateStringHandle(dwDDEInst, name, Ddeml.CP_WINANSI);
hDDEData = Ddeml.DdeClientTransaction(null,
0,
hconvCurrent,
hszItem,
ConversionFormat.TEXT,//CF_TEXT,
(int)Ddeml.XTYP_REQUEST,
5000, // ms timeout
ref dwResult);
Ddeml.DdeFreeStringHandle(dwDDEInst, hszItem);
if (hDDEData != IntPtr.Zero)
{
sbyte* pData = (sbyte*)Ddeml.DdeAccessData(hDDEData, ref dwLength);
{
if ((pData != null) && (dwLength != 0))
{
return new string(pData, 0, dwLength);
}
}
}
}
return null;
}
public IGroup AddGroup(string name, short id, int updateRate, float deadBand = 0f, bool active = false)
{
if (_groups.Count > 0)
return null;
DDEGroup grp = new DDEGroup(id, name, updateRate, active, this);
_groups.Add(grp);
return grp;
}
public bool RemoveGroup(IGroup grp)
{
grp.IsActive = false;
return _groups.Remove(grp);
}
public void Dispose()
{
foreach (IGroup grp in _groups)
{
grp.Dispose();
}
_groups.Clear();
Ddeml.DdeDisconnect(hconvCurrent);
}
public event IOErrorEventHandler OnError;
}
public class DDEGroup : IGroup
{
bool _isActive;
public bool IsActive
{
get
{
return _isActive;
}
set
{
_isActive = value;
}
}
short _id;
public short ID
{
get
{
return _id;
}
}
int _updateRate;
public int UpdateRate
{
get
{
return _updateRate;
}
set
{
_updateRate = value;
}
}
string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
float deadband;
public float DeadBand
{
get
{
return deadband;
}
set
{
deadband = value;
}
}
DDEReader _plcReader;
public IDriver Parent
{
get
{
return _plcReader;
}
}
List<short> _changedList;
public List<short> ChangedList
{
get
{
return _changedList;
}
}
List<ITag> _items;
public IEnumerable<ITag> Items
{
get { return _items; }
}
IDataServer _server;
public IDataServer Server
{
get
{
return _server;
}
}
Dictionary<short, string> _mapping;
public DDEGroup(short id, string address, int updateRate, bool active, DDEReader plcReader)
{
this._id = id;
this._updateRate = updateRate;
this._isActive = active;
this._plcReader = plcReader;
this._name = address;
this._server = _plcReader.Parent;
this._changedList = new List<short>(100);
plcReader.DDEValueChange += new DDEValueChangeEventHandler(plcReader_DDEValueChange);
}
void plcReader_DDEValueChange(object sender, DDEValueChangeEventArgs e)
{
string name = e.Name;
string data = e.Data;
ITag tag = _server[name];
if (tag != null)
{
Storage value = Storage.Empty;
switch (tag.Address.VarType)
{
case DataType.BOOL:
value.Boolean = bool.Parse(data);
break;
case DataType.BYTE:
value.Byte = byte.Parse(data);
break;
case DataType.WORD:
case DataType.SHORT:
value.Int16 = short.Parse(data);
break;
case DataType.INT:
value.Int32 = int.Parse(data);
break;
case DataType.STR:
var stag = tag as StringTag;
if (stag != null)
{
stag.String = data;
}
break;
}
tag.Update(value, DateTime.Now, QUALITIES.QUALITY_GOOD);
if (DataChange != null)
DataChange(this, new DataChangeEventArgs(1, new HistoryData[]{
new HistoryData(tag.ID,QUALITIES.QUALITY_GOOD,tag.Value,tag.TimeStamp)}));
}
}
public bool AddItems(IList<TagMetaData> items)
{
int count = items.Count;
if (_items == null)
{
_items = new List<ITag>(count);
_mapping = new Dictionary<short, string>(count);
}
lock (_server.SyncRoot)
{
for (int i = 0; i < count; i++)
{
ITag dataItem = null;
TagMetaData meta = items[i];
if (meta.GroupID == this._id)
{
DeviceAddress addr = new DeviceAddress { Start = meta.ID, DataSize = meta.Size, VarType = meta.DataType };
switch (meta.DataType)
{
case DataType.BOOL:
dataItem = new BoolTag(meta.ID, addr, this);
break;
case DataType.BYTE:
dataItem = new ByteTag(meta.ID, addr, this);
break;
case DataType.WORD:
case DataType.SHORT:
dataItem = new ShortTag(meta.ID, addr, this);
break;
case DataType.DWORD:
case DataType.INT:
dataItem = new IntTag(meta.ID, addr, this);
break;
case DataType.FLOAT:
dataItem = new FloatTag(meta.ID, addr, this);
break;
case DataType.STR:
dataItem = new StringTag(meta.ID, addr, this);
break;
}
if (dataItem != null)
{
//dataItem.Active = meta.Active;
_items.Add(dataItem);
_plcReader.TransactItem(meta.Name);
_mapping.Add(meta.ID, meta.Address);
_server.AddItemIndex(meta.Name, dataItem);
}
}
}
return true;
}
}
public bool AddTags(IEnumerable<ITag> tags)
{
if (_items == null)
{
_items = new List<ITag>();
}
foreach (ITag tag in tags)
{
if (tag != null)
{
_items.Add(tag);
}
}
return true;
}
public bool RemoveItems(params ITag[] items)
{
foreach (var item in items)
{
_server.RemoveItemIndex(item.GetTagName());
_mapping.Remove(item.ID);
_items.Remove(item);
}
return true;
}
public bool SetActiveState(bool active, params short[] items)
{
return true;
}
public ITag FindItemByAddress(DeviceAddress addr)
{
return null;
}
public ITag GetItemByID(short id)
{
return _server[id];
}
public HistoryData[] BatchRead(DataSource source, bool isSync, params ITag[] itemArray)
{
return ExtMethods.BatchRead(source, itemArray);
}
public int BatchWrite(SortedDictionary<ITag, object> items, bool isSync = true)
{
int rev = ExtMethods.BatchWrite(items);
if (DataChange != null && rev >= 0)
{
int len = items.Count;
HistoryData[] data = new HistoryData[len];
int i = 0;
foreach (var item in items)
{
ITag tag = item.Key;
data[i].ID = tag.ID;
data[i].TimeStamp = tag.TimeStamp;
data[i].Quality = tag.Quality;
//data[i].Value = item.Value.ToStorge();
i++;
}
foreach (DataChangeEventHandler deleg in DataChange.GetInvocationList())
{
deleg.BeginInvoke(this, new DataChangeEventArgs(1, data), null, null);
}
}
return rev;
}
public ItemData<int> ReadInt32(DeviceAddress address, DataSource source = DataSource.Cache)
{
string data = _plcReader.Request(_mapping[(short)address.Start]);
return string.IsNullOrEmpty(data) ? new ItemData<int>(0, 0, QUALITIES.QUALITY_BAD) :
new ItemData<int>(int.Parse(data), 0, QUALITIES.QUALITY_GOOD);
}
public ItemData<short> ReadInt16(DeviceAddress address, DataSource source = DataSource.Cache)
{
string data = _plcReader.Request(_mapping[(short)address.Start]);
return string.IsNullOrEmpty(data) ? new ItemData<short>(0, 0, QUALITIES.QUALITY_BAD) :
new ItemData<short>(short.Parse(data), 0, QUALITIES.QUALITY_GOOD);
}
public ItemData<uint> ReadUInt32(DeviceAddress address, DataSource source = DataSource.Cache)
{
string data = _plcReader.Request(_mapping[(short)address.Start]);
return string.IsNullOrEmpty(data) ? new ItemData<uint>(0, 0, QUALITIES.QUALITY_BAD) :
new ItemData<uint>(uint.Parse(data), 0, QUALITIES.QUALITY_GOOD);
}
public ItemData<ushort> ReadUInt16(DeviceAddress address, DataSource source = DataSource.Cache)
{
string data = _plcReader.Request(_mapping[(short)address.Start]);
return string.IsNullOrEmpty(data) ? new ItemData<ushort>(0, 0, QUALITIES.QUALITY_BAD) :
new ItemData<ushort>(ushort.Parse(data), 0, QUALITIES.QUALITY_GOOD);
}
public ItemData<byte> ReadByte(DeviceAddress address, DataSource source = DataSource.Cache)
{
string data = _plcReader.Request(_mapping[(short)address.Start]);
return string.IsNullOrEmpty(data) ? new ItemData<byte>(0, 0, QUALITIES.QUALITY_BAD) :
new ItemData<byte>(byte.Parse(data), 0, QUALITIES.QUALITY_GOOD);
}
public ItemData<float> ReadFloat(DeviceAddress address, DataSource source = DataSource.Cache)
{
string data = _plcReader.Request(_mapping[(short)address.Start]);
return string.IsNullOrEmpty(data) ? new ItemData<float>(0, 0, QUALITIES.QUALITY_BAD) :
new ItemData<float>(float.Parse(data), 0, QUALITIES.QUALITY_GOOD);
}
public ItemData<bool> ReadBool(DeviceAddress address, DataSource source = DataSource.Cache)
{
string data = _plcReader.Request(_mapping[(short)address.Start]);
return string.IsNullOrEmpty(data) ? new ItemData<bool>(false, 0, QUALITIES.QUALITY_BAD) :
new ItemData<bool>(bool.Parse(data), 0, QUALITIES.QUALITY_GOOD);
}
public ItemData<string> ReadString(DeviceAddress address, DataSource source = DataSource.Cache)
{
string data = _plcReader.Request(_mapping[(short)address.Start]);
return string.IsNullOrEmpty(data) ? new ItemData<string>(null, 0, QUALITIES.QUALITY_BAD) :
new ItemData<string>(data, 0, QUALITIES.QUALITY_GOOD);
}
public int WriteInt32(DeviceAddress address, int value)
{
return _plcReader.Poke(_mapping[(short)address.Start], value.ToString());
}
public int WriteInt16(DeviceAddress address, short value)
{
return _plcReader.Poke(_mapping[(short)address.Start], value.ToString());
}
public int WriteUInt32(DeviceAddress address, uint value)
{
return _plcReader.Poke(_mapping[(short)address.Start], value.ToString());
}
public int WriteUInt16(DeviceAddress address, ushort value)
{
return _plcReader.Poke(_mapping[(short)address.Start], value.ToString());
}
public int WriteFloat(DeviceAddress address, float value)
{
return _plcReader.Poke(_mapping[(short)address.Start], value.ToString());
}
public int WriteString(DeviceAddress address, string value)
{
return _plcReader.Poke(_mapping[(short)address.Start], value);
}
public int WriteBit(DeviceAddress address, bool value)
{
return _plcReader.Poke(_mapping[(short)address.Start], value.ToString());
}
public int WriteBits(DeviceAddress address, byte value)
{
return _plcReader.Poke(_mapping[(short)address.Start], value.ToString());
}
public event DataChangeEventHandler DataChange;
public void Dispose()
{
_plcReader.DDEValueChange -= new DDEValueChangeEventHandler(plcReader_DDEValueChange);
_items.Clear();
_mapping.Clear();
_items = null;
_mapping = null;
}
}
public delegate void DDEValueChangeEventHandler(object sender, DDEValueChangeEventArgs e);
public class DDEValueChangeEventArgs : EventArgs
{
public DDEValueChangeEventArgs(string name, string data)
{
this.Name = name;
this.Data = data;
}
public string Name;
public string Data;
}
}

64
SCADA/Program/DDEDriver/DDEDriver.csproj

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{14938033-7870-477D-925C-A447933A44E7}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>DDEDriver</RootNamespace>
<AssemblyName>DDEDriver</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="DDEDriver.cs" />
<Compile Include="DDELib.cs" />
<Compile Include="DDEServer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="C:\Users\ADOLF\Documents\GitHub\SharpSCADA\SCADA\SourceCode\DataService\DataService.csproj">
<Project>{8965e389-6466-4b30-bd43-83c909044637}</Project>
<Name>DataService</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

481
SCADA/Program/DDEDriver/DDELib.cs

@ -0,0 +1,481 @@
using System;
using System.Runtime.InteropServices;
namespace DDEDriver
{
public delegate IntPtr DdeCallback(
int uType, ConversionFormat uFmt, IntPtr hConv, IntPtr hsz1, IntPtr hsz2, IntPtr hData, uint dwData1, uint dwData2);
public static class Ddeml
{
public const int MAX_STRING_SIZE = 255;
public const int APPCMD_CLIENTONLY = unchecked((int)0x00000010);
public const int APPCMD_FILTERINITS = unchecked((int)0x00000020);
public const int APPCMD_MASK = unchecked((int)0x00000FF0);
public const int APPCLASS_STANDARD = unchecked((int)0x00000000);
public const int APPCLASS_MONITOR = unchecked((int)0x00000001);
public const int APPCLASS_MASK = unchecked((int)0x0000000F);
public const int CBR_BLOCK = unchecked((int)0xFFFFFFFF);
public const int CBF_FAIL_SELFCONNECTIONS = unchecked((int)0x00001000);
public const int CBF_FAIL_CONNECTIONS = unchecked((int)0x00002000);
public const int CBF_FAIL_ADVISES = unchecked((int)0x00004000);
public const int CBF_FAIL_EXECUTES = unchecked((int)0x00008000);
public const int CBF_FAIL_POKES = unchecked((int)0x00010000);
public const int CBF_FAIL_REQUESTS = unchecked((int)0x00020000);
public const int CBF_FAIL_ALLSVRXACTIONS = unchecked((int)0x0003f000);
public const int CBF_SKIP_CONNECT_CONFIRMS = unchecked((int)0x00040000);
public const int CBF_SKIP_REGISTRATIONS = unchecked((int)0x00080000);
public const int CBF_SKIP_UNREGISTRATIONS = unchecked((int)0x00100000);
public const int CBF_SKIP_DISCONNECTS = unchecked((int)0x00200000);
public const int CBF_SKIP_ALLNOTIFICATIONS = unchecked((int)0x003c0000);
public const int CF_TEXT = 1;
public const int CP_WINANSI = 1004;
public const int CP_WINUNICODE = 1200;
public const int DDE_FACK = unchecked((int)0x8000);
public const int DDE_FBUSY = unchecked((int)0x4000);
public const int DDE_FDEFERUPD = unchecked((int)0x4000);
public const int DDE_FACKREQ = unchecked((int)0x8000);
public const int DDE_FRELEASE = unchecked((int)0x2000);
public const int DDE_FREQUESTED = unchecked((int)0x1000);
public const int DDE_FAPPSTATUS = unchecked((int)0x00ff);
public const int DDE_FNOTPROCESSED = unchecked((int)0x0000);
public const int DMLERR_NO_ERROR = unchecked((int)0x0000);
public const int DMLERR_FIRST = unchecked((int)0x4000);
public const int DMLERR_ADVACKTIMEOUT = unchecked((int)0x4000);
public const int DMLERR_BUSY = unchecked((int)0x4001);
public const int DMLERR_DATAACKTIMEOUT = unchecked((int)0x4002);
public const int DMLERR_DLL_NOT_INITIALIZED = unchecked((int)0x4003);
public const int DMLERR_DLL_USAGE = unchecked((int)0x4004);
public const int DMLERR_EXECACKTIMEOUT = unchecked((int)0x4005);
public const int DMLERR_INVALIDPARAMETER = unchecked((int)0x4006);
public const int DMLERR_LOW_MEMORY = unchecked((int)0x4007);
public const int DMLERR_MEMORY_ERROR = unchecked((int)0x4008);
public const int DMLERR_NOTPROCESSED = unchecked((int)0x4009);
public const int DMLERR_NO_CONV_ESTABLISHED = unchecked((int)0x400A);
public const int DMLERR_POKEACKTIMEOUT = unchecked((int)0x400B);
public const int DMLERR_POSTMSG_FAILED = unchecked((int)0x400C);
public const int DMLERR_REENTRANCY = unchecked((int)0x400D);
public const int DMLERR_SERVER_DIED = unchecked((int)0x400E);
public const int DMLERR_SYS_ERROR = unchecked((int)0x400F);
public const int DMLERR_UNADVACKTIMEOUT = unchecked((int)0x4010);
public const int DMLERR_UNFOUND_QUEUE_ID = unchecked((int)0x4011);
public const int DMLERR_LAST = unchecked((int)0x4011);
public const int DNS_REGISTER = unchecked((int)0x0001);
public const int DNS_UNREGISTER = unchecked((int)0x0002);
public const int DNS_FILTERON = unchecked((int)0x0004);
public const int DNS_FILTEROFF = unchecked((int)0x0008);
public const int EC_ENABLEALL = unchecked((int)0x0000);
public const int EC_ENABLEONE = unchecked((int)0x0080);
public const int EC_DISABLE = unchecked((int)0x0008);
public const int EC_QUERYWAITING = unchecked((int)0x0002);
public const int HDATA_APPOWNED = unchecked((int)0x0001);
public const int MF_HSZ_INFO = unchecked((int)0x01000000);
public const int MF_SENDMSGS = unchecked((int)0x02000000);
public const int MF_POSTMSGS = unchecked((int)0x04000000);
public const int MF_CALLBACKS = unchecked((int)0x08000000);
public const int MF_ERRORS = unchecked((int)0x10000000);
public const int MF_LINKS = unchecked((int)0x20000000);
public const int MF_CONV = unchecked((int)0x40000000);
public const int MH_CREATE = 1;
public const int MH_KEEP = 2;
public const int MH_DELETE = 3;
public const int MH_CLEANUP = 4;
public const int QID_SYNC = unchecked((int)0xFFFFFFFF);
public const int TIMEOUT_ASYNC = unchecked((int)0xFFFFFFFF);
public const int XTYPF_NOBLOCK = unchecked((int)0x0002);
public const int XTYPF_NODATA = unchecked((int)0x0004);
public const int XTYPF_ACKREQ = unchecked((int)0x0008);
public const int XCLASS_MASK = unchecked((int)0xFC00);
public const int XCLASS_BOOL = unchecked((int)0x1000);
public const int XCLASS_DATA = unchecked((int)0x2000);
public const int XCLASS_FLAGS = unchecked((int)0x4000);
public const int XCLASS_NOTIFICATION = unchecked((int)0x8000);
public const int XTYP_ERROR = unchecked((int)(0x0000 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK));
public const int XTYP_ADVDATA = unchecked((int)(0x0010 | XCLASS_FLAGS));
public const int XTYP_ADVREQ = unchecked((int)(0x0020 | XCLASS_DATA | XTYPF_NOBLOCK));
public const int XTYP_ADVSTART = unchecked((int)(0x0030 | XCLASS_BOOL));
public const int XTYP_ADVSTOP = unchecked((int)(0x0040 | XCLASS_NOTIFICATION));
public const int XTYP_EXECUTE = unchecked((int)(0x0050 | XCLASS_FLAGS));
public const int XTYP_CONNECT = unchecked((int)(0x0060 | XCLASS_BOOL | XTYPF_NOBLOCK));
public const int XTYP_CONNECT_CONFIRM = unchecked((int)(0x0070 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK));
public const int XTYP_XACT_COMPLETE = unchecked((int)(0x0080 | XCLASS_NOTIFICATION));
public const int XTYP_POKE = unchecked((int)(0x0090 | XCLASS_FLAGS));
public const int XTYP_REGISTER = unchecked((int)(0x00A0 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK));
public const int XTYP_REQUEST = unchecked((int)(0x00B0 | XCLASS_DATA));
public const int XTYP_DISCONNECT = unchecked((int)(0x00C0 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK));
public const int XTYP_UNREGISTER = unchecked((int)(0x00D0 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK));
public const int XTYP_WILDCONNECT = unchecked((int)(0x00E0 | XCLASS_DATA | XTYPF_NOBLOCK));
public const int XTYP_MONITOR = unchecked((int)(0x00F0 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK));
public const int XTYP_ADVSTARTNODATA = unchecked(XTYP_ADVSTART | XTYPF_NODATA);
public const int XTYP_ADVSTARTACKREQ = unchecked(XTYP_ADVSTART | XTYPF_ACKREQ);
public const int XTYP_MASK = unchecked((int)0x00F0);
public const int XTYP_SHIFT = unchecked((int)0x0004);
[DllImport("user32.dll", EntryPoint = "DdeAbandonTransaction", CharSet = CharSet.Ansi)]
public static extern bool DdeAbandonTransaction(int idInst, IntPtr hConv, int idTransaction);
[DllImport("user32.dll", EntryPoint = "DdeAccessData", CharSet = CharSet.Ansi)]
public static extern IntPtr DdeAccessData(IntPtr hData, ref int pcbDataSize);
[DllImport("user32.dll", EntryPoint = "DdeAddData", CharSet = CharSet.Ansi)]
public static extern IntPtr DdeAddData(IntPtr hData, byte[] pSrc, int cb, int cbOff);
[DllImport("user32.dll", EntryPoint = "DdeClientTransaction", CharSet = CharSet.Ansi)]
public static extern IntPtr DdeClientTransaction(
byte[] pData, int cbData, IntPtr hConv, IntPtr hszItem, ConversionFormat wFmt, int wType, int dwTimeout, ref int pdwResult);
[DllImport("user32.dll", EntryPoint = "DdeCmpStringHandles", CharSet = CharSet.Ansi)]
public static extern int DdeCmpStringHandles(IntPtr hsz1, IntPtr hsz2);
[DllImport("user32.dll", EntryPoint = "DdeConnect", CharSet = CharSet.Ansi)]
public static extern IntPtr DdeConnect(int idInst, IntPtr hszService, IntPtr hszTopic, ref CONVCONTEXT pCC);
[DllImport("user32.dll", EntryPoint = "DdeConnectList", CharSet = CharSet.Ansi)]
public static extern IntPtr DdeConnectList(int idInst, IntPtr hszService, IntPtr hszTopic, IntPtr hConvList, ref CONVCONTEXT pCC);
[DllImport("user32.dll", EntryPoint = "DdeCreateDataHandle", CharSet = CharSet.Ansi)]
public static extern IntPtr DdeCreateDataHandle(int idInst, byte[] pSrc, int cb, int cbOff, IntPtr hszItem, ConversionFormat wFmt, int afCmd);
[DllImport("user32.dll", EntryPoint = "DdeCreateStringHandle", CharSet = CharSet.Ansi)]
public static extern IntPtr DdeCreateStringHandle(int idInst, string psz, int iCodePage);
[DllImport("user32.dll", EntryPoint = "DdeDisconnect", CharSet = CharSet.Ansi)]
public static extern bool DdeDisconnect(IntPtr hConv);
[DllImport("user32.dll", EntryPoint = "DdeDisconnectList", CharSet = CharSet.Ansi)]
public static extern bool DdeDisconnectList(IntPtr hConvList);
[DllImport("user32.dll", EntryPoint = "DdeEnableCallback", CharSet = CharSet.Ansi)]
public static extern bool DdeEnableCallback(int idInst, IntPtr hConv, int wCmd);
[DllImport("user32.dll", EntryPoint = "DdeFreeDataHandle", CharSet = CharSet.Ansi)]
public static extern bool DdeFreeDataHandle(IntPtr hData);
[DllImport("user32.dll", EntryPoint = "DdeFreeStringHandle", CharSet = CharSet.Ansi)]
public static extern bool DdeFreeStringHandle(int idInst, IntPtr hsz);
[DllImport("user32.dll", EntryPoint = "DdeGetData", CharSet = CharSet.Ansi)]
public unsafe static extern int DdeGetData(IntPtr hData, [Out] byte* pDst, int cbMax, int cbOff);
[DllImport("user32.dll", EntryPoint = "DdeGetLastError", CharSet = CharSet.Ansi)]
public static extern int DdeGetLastError(int idInst);
[DllImport("user32.dll", EntryPoint = "DdeImpersonateClient", CharSet = CharSet.Ansi)]
public static extern bool DdeImpersonateClient(IntPtr hConv);
[DllImport("user32.dll", EntryPoint = "DdeInitialize", CharSet = CharSet.Ansi)]
public static extern int DdeInitialize(ref int pidInst, DdeCallback pfnCallback, int afCmd, int ulRes);
[DllImport("user32.dll", EntryPoint = "DdeKeepStringHandle", CharSet = CharSet.Ansi)]
public static extern bool DdeKeepStringHandle(int idInst, IntPtr hsz);
[DllImport("user32.dll", EntryPoint = "DdeNameService", CharSet = CharSet.Ansi)]
public static extern IntPtr DdeNameService(int idInst, IntPtr hsz1, IntPtr hsz2, int afCmd);
[DllImport("user32.dll", EntryPoint = "DdePostAdvise", CharSet = CharSet.Ansi)]
public static extern bool DdePostAdvise(int idInst, IntPtr hszTopic, IntPtr hszItem);
[DllImport("user32.dll", EntryPoint = "DdeQueryConvInfo", CharSet = CharSet.Ansi)]
public static extern int DdeQueryConvInfo(IntPtr hConv, int idTransaction, IntPtr pConvInfo);
[DllImport("user32.dll", EntryPoint = "DdeQueryNextServer", CharSet = CharSet.Ansi)]
public static extern IntPtr DdeQueryNextServer(IntPtr hConvList, IntPtr hConvPrev);
[DllImport("user32.dll", EntryPoint = "DdeQueryString", CharSet = CharSet.Ansi)]
public unsafe static extern int DdeQueryString(int idInst, IntPtr hsz, sbyte* psz, int cchMax, int iCodePage);
[DllImport("user32.dll", EntryPoint = "DdeReconnect", CharSet = CharSet.Ansi)]
public static extern IntPtr DdeReconnect(IntPtr hConv);
[DllImport("user32.dll", EntryPoint = "DdeSetUserHandle", CharSet = CharSet.Ansi)]
public static extern bool DdeSetUserHandle(IntPtr hConv, int id, IntPtr hUser);
[DllImport("user32.dll", EntryPoint = "DdeUnaccessData", CharSet = CharSet.Ansi)]
public static extern bool DdeUnaccessData(IntPtr hData);
[DllImport("user32.dll", EntryPoint = "DdeUninitialize", CharSet = CharSet.Ansi)]
public static extern bool DdeUninitialize(int idInst);
public static String DDEGetErrorMsg(int error)
{
switch (error)
{
case DMLERR_NO_ERROR:
return "no DDE error.";
case DMLERR_ADVACKTIMEOUT:
return "a request for a synchronous advise transaction has timed out.";
case DMLERR_BUSY:
return "the response to the transaction caused the DDE_FBUSY bit to be set.";
case DMLERR_DATAACKTIMEOUT:
return "a request for a synchronous data transaction has timed out.";
case DMLERR_DLL_NOT_INITIALIZED:
return "a DDEML function was called without first calling the DdeInitialize function,\nor an invalid instance identifier\nwas passed to a DDEML function.";
case DMLERR_DLL_USAGE:
return "an application initialized as APPCLASS_MONITOR has\nattempted to perform a DDE transaction,\nor an application initialized as APPCMD_CLIENTONLY has \nattempted to perform server transactions.";
case DMLERR_EXECACKTIMEOUT:
return "a request for a synchronous execute transaction has timed out.";
case DMLERR_INVALIDPARAMETER:
return "a parameter failed to be validated by the DDEML.";
case DMLERR_LOW_MEMORY:
return "a DDEML application has created a prolonged race condition.";
case DMLERR_MEMORY_ERROR:
return "a memory allocation failed.";
case DMLERR_NO_CONV_ESTABLISHED:
return "a client's attempt to establish a conversation has failed.";
case DMLERR_NOTPROCESSED:
return "a transaction failed.";
case DMLERR_POKEACKTIMEOUT:
return "a request for a synchronous poke transaction has timed out.";
case DMLERR_POSTMSG_FAILED:
return "an internal call to the PostMessage function has failed. ";
case DMLERR_REENTRANCY:
return "reentrancy problem.";
case DMLERR_SERVER_DIED:
return "a server-side transaction was attempted on a conversation\nthat was terminated by the client, or the server\nterminated before completing a transaction.";
case DMLERR_SYS_ERROR:
return "an internal error has occurred in the DDEML.";
case DMLERR_UNADVACKTIMEOUT:
return "a request to end an advise transaction has timed out.";
case DMLERR_UNFOUND_QUEUE_ID:
return "an invalid transaction identifier was passed to a DDEML function.\nOnce the application has returned from an XTYP_XACT_COMPLETE callback,\nthe transaction identifier for that callback is no longer valid.";
default:
return "Unknown DDE error %08x";
}
}
}
[StructLayout(LayoutKind.Sequential)]
public struct HSZPAIR
{
public IntPtr hszSvc;
public IntPtr hszTopic;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_QUALITY_OF_SERVICE
{ // sqos
public ushort Length;
public int ImpersonationLevel; //SECURITY_IMPERSONATION_LEVEL
public int ContextTrackingMode; //SECURITY_CONTEXT_TRACKING_MODE
public bool EffectiveOnly;
}
[StructLayout(LayoutKind.Sequential)]
public struct CONVINFO
{
public int cb;
public IntPtr hUser;
public IntPtr hConvPartner;
public IntPtr hszSvcPartner;
public IntPtr hszServiceReq;
public IntPtr hszTopic;
public IntPtr hszItem;
public int wFmt;
public int wType;
public int wStatus;
public int wConvst;
public int wLastError;
public IntPtr hConvList;
public CONVCONTEXT ConvCtxt;
public IntPtr hwnd;
public IntPtr hwndPartner;
} // struct
[StructLayout(LayoutKind.Sequential)]
public struct CONVCONTEXT
{
public int cb;
public int wFlags;
public int wCountryID;
public int iCodePage;
public int dwLangID;
public int dwSecurity;
public SECURITY_QUALITY_OF_SERVICE qos;
} // struct
[StructLayout(LayoutKind.Sequential)]
public struct MONCBSTRUCT
{
public int cb;
public int dwTime;
public IntPtr hTask;
public IntPtr dwRet;
public int wType;
public int wFmt;
public IntPtr hConv;
public IntPtr hsz1;
public IntPtr hsz2;
public IntPtr hData;
public uint dwData1;
public uint dwData2;
public CONVCONTEXT cc;
public int cbData;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public byte[] Data;
} // struct
[StructLayout(LayoutKind.Sequential)]
public struct MONCONVSTRUCT
{
public int cb;
public bool fConnect;
public int dwTime;
public IntPtr hTask;
public IntPtr hszSvc;
public IntPtr hszTopic;
public IntPtr hConvClient;
public IntPtr hConvServer;
} // struct
[StructLayout(LayoutKind.Sequential)]
public struct MONERRSTRUCT
{
public int cb;
public int wLastError;
public int dwTime;
public IntPtr hTask;
} // struct
[StructLayout(LayoutKind.Sequential)]
public struct MONHSZSTRUCT
{
public int cb;
public int fsAction;
public int dwTime;
public IntPtr hsz;
public IntPtr hTask;
public IntPtr str;
} // struct
[StructLayout(LayoutKind.Sequential)]
public struct MONLINKSTRUCT
{
public int cb;
public int dwTime;
public IntPtr hTask;
public bool fEstablished;
public bool fNoData;
public IntPtr hszSvc;
public IntPtr hszTopic;
public IntPtr hszItem;
public int wFmt;
public bool fServer;
public IntPtr hConvClient;
public IntPtr hConvServer;
} // struct
[StructLayout(LayoutKind.Sequential)]
public struct MONMSGSTRUCT
{
public int cb;
public IntPtr hwndTo;
public int dwTime;
public IntPtr hTask;
public int wMsg;
public IntPtr wParam;
public IntPtr lParam;
public DDEML_MSG_HOOK_DATA dmhd;
} // struct
[StructLayout(LayoutKind.Sequential)]
public struct DDEML_MSG_HOOK_DATA
{
public IntPtr uiLo;
public IntPtr uiHi;
public int cbData;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public byte[] Data;
} // struct
public enum ConversionFormat : uint
{
NONE = 0,
TEXT = 1,
BITMAP = 2,
METAFILEPICT = 3,
SYLK = 4,
DIF = 5,
TIFF = 6,
OEMTEXT = 7,
DIB = 8,
PALETTE = 9,
PENDATA = 10,
RIFF = 11,
WAVE = 12,
UNICODETEXT = 13,
ENHMETAFILE = 14,
HDROP = 15,
LOCALE = 16,
DIBV5 = 17,
OWNERDISPLAY = 0x0080,
DSPTEXT = 0x0081,
DSPBITMAP = 0x0082,
DSPMETAFILEPICT = 0x0083,
DSPENHMETAFILE = 0x008E,
// "Private" formats don't get GlobalFree()'d
PRIVATEFIRST = 0x0200,
PRIVATELAST = 0x02FF,
// "GDIOBJ" formats do get DeleteObject()'d
GDIOBJFIRST = 0x0300,
GDIOBJLAST = 0x03FF
}
[Flags]
public enum DDEResult : uint
{
FACK = 0x8000U,
FBUSY = 0x4000U,
FDEFERUPD = 0x4000,
FACKREQ = 0x8000,
FRELEASE = 0x2000,
FREQUESTED = 0x1000,
FAPPSTATUS = 0x00ff,
FNOTPROCESSED = 0x0,
FACKRESERVED = (~(FACK | FBUSY | FAPPSTATUS)),
FADVRESERVED = (~(FACKREQ | FDEFERUPD)),
FDATRESERVED = (~(FACKREQ | FRELEASE | FREQUESTED)),
FPOKRESERVED = (~(FRELEASE))
}
}

620
SCADA/Program/DDEDriver/DDEServer.cs

@ -0,0 +1,620 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace DDEDriver
{
public abstract class DdemlServer : IDisposable
{
private int _InstanceId; // DDEML instance identifier
private string _Service; // DDEML service name
private IntPtr _ServiceHandle = IntPtr.Zero; // DDEML service handle
private bool _Disposed = false;
private HashSet<IntPtr> _ConversationTable = new HashSet<IntPtr>();
private DdeCallback _Callback;
public DdemlServer()
{
_Callback = OnDdeCallback;
}
~DdemlServer()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected void Dispose(bool disposing)
{
if (!_Disposed)
{
_Disposed = true;
if (IsRegistered)
{
// Unregister the service name.
Unregister();
if (disposing)
{
_ServiceHandle = IntPtr.Zero;
_InstanceId = 0;
}
}
}
}
public string Service
{
get { return _Service; }
}
public bool IsRegistered
{
get { return _ServiceHandle != IntPtr.Zero; }
}
internal bool IsDisposed
{
get { return _Disposed; }
}
public int Initialize(int afCmd)
{
int instanceId = 0;
Ddeml.DdeInitialize(ref instanceId, _Callback, afCmd, 0);
return instanceId;
}
public void Uninitialize()
{
Ddeml.DdeUninitialize(_InstanceId);
}
public string Register(string service)
{
if (IsRegistered || _InstanceId != 0)
{
throw new InvalidOperationException("AlreadyRegisteredMessage");
}
if (service == null || service.Length > Ddeml.MAX_STRING_SIZE)
{
throw new ArgumentNullException("service");
}
_Service = service;
_ConversationTable.Clear();
_InstanceId = Initialize(Ddeml.APPCLASS_STANDARD);
_ServiceHandle = Ddeml.DdeCreateStringHandle(_InstanceId, _Service, Ddeml.CP_WINANSI);
// Register the service name.
if (Ddeml.DdeNameService(_InstanceId, _ServiceHandle, IntPtr.Zero, Ddeml.DNS_REGISTER) == IntPtr.Zero)
{
Ddeml.DdeFreeStringHandle(_InstanceId, _ServiceHandle);
_ServiceHandle = IntPtr.Zero;
}
// If the service handle is null then the service name could not be registered.
if (_ServiceHandle == IntPtr.Zero)
{
int error = Ddeml.DdeGetLastError(_InstanceId);
return Ddeml.DDEGetErrorMsg(error);
}
return null;
}
public void Unregister()
{
Ddeml.DdeNameService(_InstanceId, _ServiceHandle, IntPtr.Zero, Ddeml.DNS_UNREGISTER);
// Free the service string handle.
Ddeml.DdeFreeStringHandle(_InstanceId, _ServiceHandle);
// Indicate that the service name is no longer registered.
_ServiceHandle = IntPtr.Zero;
_InstanceId = 0;
}
private IntPtr OnDdeCallback(int uType, ConversionFormat uFmt, IntPtr hConv, IntPtr hsz1, IntPtr hsz2, IntPtr hData, uint dwData1, uint dwData2)
{
// Create a new transaction object that will be dispatched to a DdemlClient, DdemlServer, or ITransactionFilter.
// Dispatch the transaction.
switch (uType)
{
case Ddeml.XTYP_MONITOR:
switch (dwData2)
{
case Ddeml.MF_CALLBACKS:
{
// Get the MONCBSTRUCT object.
int length = 0;
IntPtr phData = Ddeml.DdeAccessData(hData, ref length);
MONCBSTRUCT mon = (MONCBSTRUCT)Marshal.PtrToStructure(phData, typeof(MONCBSTRUCT));
Ddeml.DdeUnaccessData(hData);
OnCallback(mon);
return IntPtr.Zero;
}
case Ddeml.MF_CONV:
{
// Get the MONCONVSTRUCT object.
int length = 0;
IntPtr phData = Ddeml.DdeAccessData(hData, ref length);
MONCONVSTRUCT mon = (MONCONVSTRUCT)Marshal.PtrToStructure(phData, typeof(MONCONVSTRUCT));
Ddeml.DdeUnaccessData(hData);
OnConversation(mon);
return IntPtr.Zero;
}
case Ddeml.MF_ERRORS:
{
// Get the MONERRSTRUCT object.
int length = 0;
IntPtr phData = Ddeml.DdeAccessData(hData, ref length);
MONERRSTRUCT mon = (MONERRSTRUCT)Marshal.PtrToStructure(phData, typeof(MONERRSTRUCT));
Ddeml.DdeUnaccessData(hData);
OnError(mon);
return IntPtr.Zero;
}
case Ddeml.MF_HSZ_INFO:
{
// Get the MONHSZSTRUCT object.
int length = 0;
IntPtr phData = Ddeml.DdeAccessData(hData, ref length);
MONHSZSTRUCT mon = (MONHSZSTRUCT)Marshal.PtrToStructure(phData, typeof(MONHSZSTRUCT));
Ddeml.DdeUnaccessData(hData);
OnString(mon);
return IntPtr.Zero;
}
case Ddeml.MF_LINKS:
{
// Get the MONLINKSTRUCT object.
int length = 0;
IntPtr phData = Ddeml.DdeAccessData(hData, ref length);
MONLINKSTRUCT mon = (MONLINKSTRUCT)Marshal.PtrToStructure(phData, typeof(MONLINKSTRUCT));
Ddeml.DdeUnaccessData(hData);
OnLink(mon);
return IntPtr.Zero;
}
case Ddeml.MF_POSTMSGS:
{
// Get the MONMSGSTRUCT object.
int length = 0;
IntPtr phData = Ddeml.DdeAccessData(hData, ref length);
MONMSGSTRUCT mon = (MONMSGSTRUCT)Marshal.PtrToStructure(phData, typeof(MONMSGSTRUCT));
Ddeml.DdeUnaccessData(hData);
OnPost(mon);
return IntPtr.Zero;
}
case Ddeml.MF_SENDMSGS:
{
// Get the MONMSGSTRUCT object.
int length = 0;
IntPtr phData = Ddeml.DdeAccessData(hData, ref length);
MONMSGSTRUCT mon = (MONMSGSTRUCT)Marshal.PtrToStructure(phData, typeof(MONMSGSTRUCT));
Ddeml.DdeUnaccessData(hData);
OnSend(mon);
return IntPtr.Zero;
}
}
break;
case Ddeml.XTYP_ADVDATA:
unsafe
{
sbyte* pSZ = stackalloc sbyte[Ddeml.MAX_STRING_SIZE];
int len = Ddeml.DdeQueryString(_InstanceId, hsz1, pSZ, Ddeml.MAX_STRING_SIZE, Ddeml.CP_WINANSI);
string topic = new string(pSZ);
len = Ddeml.DdeQueryString(_InstanceId, hsz2, pSZ, Ddeml.MAX_STRING_SIZE, Ddeml.CP_WINANSI);
string item = new string(pSZ);
byte* bt = stackalloc byte[Ddeml.MAX_STRING_SIZE];
len = Ddeml.DdeGetData(hData, bt, Ddeml.MAX_STRING_SIZE, 0);
byte[] bytes = new byte[len]; for (int i = 0; i < len; i++) { bytes[i] = *bt++; };
if (hData != IntPtr.Zero) Ddeml.DdeUnaccessData(hData);
return new IntPtr((int)OnAdvData(uFmt, topic, item, bytes));
}
case Ddeml.XTYP_ADVREQ:
unsafe
{
sbyte* pSZ = stackalloc sbyte[Ddeml.MAX_STRING_SIZE];
int len = Ddeml.DdeQueryString(_InstanceId, hsz1, pSZ, Ddeml.MAX_STRING_SIZE, Ddeml.CP_WINANSI);
string topic = new string(pSZ);
len = Ddeml.DdeQueryString(_InstanceId, hsz2, pSZ, Ddeml.MAX_STRING_SIZE, Ddeml.CP_WINANSI);
string item = new string(pSZ);
byte[] data = OnAdvReq(uFmt, topic, item);
// Create and return the data handle representing the data being advised.
if (data != null && data.Length > 0)
{
return Ddeml.DdeCreateDataHandle(_InstanceId, data, data.Length, 0, hsz2, uFmt, 0); ;
}
// This transaction could not be Ddeml.DDE_FACK here.
return IntPtr.Zero;
}
case Ddeml.XTYP_ADVSTART:
unsafe
{
// Get the item name from the hsz2 string handle.
sbyte* pSZ = stackalloc sbyte[Ddeml.MAX_STRING_SIZE];
int len = Ddeml.DdeQueryString(_InstanceId, hsz1, pSZ, Ddeml.MAX_STRING_SIZE, Ddeml.CP_WINANSI);
string topic = new string(pSZ);
len = Ddeml.DdeQueryString(_InstanceId, hsz2, pSZ, Ddeml.MAX_STRING_SIZE, Ddeml.CP_WINANSI);
string item = new string(pSZ);
// Get a value indicating whether an advise loop should be initiated from the subclass.
//AdvStart(hConv, item, uFmt, Ddeml.XTYPF_ACKREQ);
return OnAdvStart(uFmt, topic, item) ? new IntPtr(1) : IntPtr.Zero;
}
case Ddeml.XTYP_ADVSTOP:
unsafe
{
// Get the item name from the hsz2 string handle.
sbyte* pSZ = stackalloc sbyte[Ddeml.MAX_STRING_SIZE];
int len = Ddeml.DdeQueryString(_InstanceId, hsz1, pSZ, Ddeml.MAX_STRING_SIZE, Ddeml.CP_WINANSI);
string topic = new string(pSZ);
len = Ddeml.DdeQueryString(_InstanceId, hsz2, pSZ, Ddeml.MAX_STRING_SIZE, Ddeml.CP_WINANSI);
string item = new string(pSZ);
// Inform the subclass that the advise loop has been terminated.
//AdvStop(hConv, item, uFmt);
OnAdvStop(uFmt, topic, item);
break;
}
case Ddeml.XTYP_CONNECT:
unsafe
{
sbyte* pSZ = stackalloc sbyte[Ddeml.MAX_STRING_SIZE];
int len = Ddeml.DdeQueryString(_InstanceId, hsz1, pSZ, Ddeml.MAX_STRING_SIZE, Ddeml.CP_WINANSI);
string topic = new string(pSZ);
// Get a value from the subclass indicating whether the connection should be allowed.
return OnConnect(topic, new CONVCONTEXT(), true) ? new IntPtr(1) : IntPtr.Zero;
}
case Ddeml.XTYP_CONNECT_CONFIRM:
unsafe
{
sbyte* pSZ = stackalloc sbyte[Ddeml.MAX_STRING_SIZE];
int len = Ddeml.DdeQueryString(_InstanceId, hsz1, pSZ, Ddeml.MAX_STRING_SIZE, Ddeml.CP_WINANSI);
string topic = new string(pSZ);
// Create a Conversation object and add it to the hConv table.
_ConversationTable.Add(hConv);
// Inform the subclass that a hConv has been established.
OnConnectConfirm(topic, true);
break;
}
case Ddeml.XTYP_DISCONNECT:
{
// Remove the Conversation from the hConv table.
_ConversationTable.Remove(hConv);
// Inform the subclass that the hConv has been disconnected.
OnDisconnect(true);
// Return zero to indicate that there are no problems.
return IntPtr.Zero;
}
case Ddeml.XTYP_EXECUTE:
unsafe
{
// Get the command from the data handle.
sbyte* pSZ = stackalloc sbyte[Ddeml.MAX_STRING_SIZE];
int len = Ddeml.DdeQueryString(_InstanceId, hsz1, pSZ, Ddeml.MAX_STRING_SIZE, Ddeml.CP_WINANSI);
string topic = new string(pSZ);
byte* bt = stackalloc byte[Ddeml.MAX_STRING_SIZE];
len = Ddeml.DdeGetData(hData, bt, Ddeml.MAX_STRING_SIZE, 0);
string command = new string((sbyte*)bt);
// Send the command to the subclass and get the resul
return new IntPtr((int)OnExecute(topic, command.TrimEnd('\0')));
}
case Ddeml.XTYP_POKE:
unsafe
{
// Get the item name from the hsz2 string handle.
sbyte* pSZ = stackalloc sbyte[Ddeml.MAX_STRING_SIZE];
int len = Ddeml.DdeQueryString(_InstanceId, hsz1, pSZ, Ddeml.MAX_STRING_SIZE, Ddeml.CP_WINANSI);
string topic = new string(pSZ);
len = Ddeml.DdeQueryString(_InstanceId, hsz2, pSZ, Ddeml.MAX_STRING_SIZE, Ddeml.CP_WINANSI);
string item = new string(pSZ);
byte* bt = stackalloc byte[Ddeml.MAX_STRING_SIZE];
len = Ddeml.DdeGetData(hData, bt, Ddeml.MAX_STRING_SIZE, 0);
byte[] data = new byte[len]; for (int i = 0; i < len; i++) { data[i] = *bt++; };
// Send the data to the subclass and get the resul
return new IntPtr((int)OnPoke(uFmt, topic, item, data));
}
case Ddeml.XTYP_REQUEST:
unsafe
{
// Get the item name from the hsz2 string handle.
sbyte* pSZ = stackalloc sbyte[Ddeml.MAX_STRING_SIZE];
int len = Ddeml.DdeQueryString(_InstanceId, hsz1, pSZ, Ddeml.MAX_STRING_SIZE, Ddeml.CP_WINANSI);
string topic = new string(pSZ);
len = Ddeml.DdeQueryString(_InstanceId, hsz2, pSZ, Ddeml.MAX_STRING_SIZE, Ddeml.CP_WINANSI);
string item = new string(pSZ);
// Send the request to the subclass and get the resul
var result = OnRequest(uFmt, topic, item);
// Return a data handle if the subclass Ddeml.DDE_FACK the request successfully.
if (result != null)
{
return Ddeml.DdeCreateDataHandle(_InstanceId, result, result.Length, 0, hsz2, uFmt, 0);
}
// Return DDE_FDdeml.DDE_FNOTDdeml.DDE_FACK if the subclass did not process the command.
return new IntPtr(Ddeml.DDE_FNOTPROCESSED);
}
case Ddeml.XTYP_XACT_COMPLETE:
unsafe
{
sbyte* pSZ = stackalloc sbyte[Ddeml.MAX_STRING_SIZE];
int len = Ddeml.DdeQueryString(_InstanceId, hsz1, pSZ, Ddeml.MAX_STRING_SIZE, Ddeml.CP_WINANSI);
string topic = new string(pSZ);
len = Ddeml.DdeQueryString(_InstanceId, hsz2, pSZ, Ddeml.MAX_STRING_SIZE, Ddeml.CP_WINANSI);
string item = new string(pSZ);
OnXactComplete(uFmt, topic, item, hData, dwData1);
break;
}
case Ddeml.XTYP_WILDCONNECT:
{
// This library does not support wild connects.
return IntPtr.Zero;
}
case Ddeml.XTYP_ERROR:
{
// Get the error code, but do nothing with it at this time.
return IntPtr.Zero;
}
case Ddeml.XTYP_REGISTER:
unsafe
{
// Get the service name from the hsz1 string handle.
sbyte* pSZ = stackalloc sbyte[Ddeml.MAX_STRING_SIZE];
int len = Ddeml.DdeQueryString(_InstanceId, hsz1, pSZ, Ddeml.MAX_STRING_SIZE, Ddeml.CP_WINANSI);
string bas = new string(pSZ);
len = Ddeml.DdeQueryString(_InstanceId, hsz2, pSZ, Ddeml.MAX_STRING_SIZE, Ddeml.CP_WINANSI);
string inst = new string(pSZ);
OnRegister(bas, inst);
return IntPtr.Zero;
}
case Ddeml.XTYP_UNREGISTER:
unsafe
{
sbyte* pSZ = stackalloc sbyte[Ddeml.MAX_STRING_SIZE];
int len = Ddeml.DdeQueryString(_InstanceId, hsz1, pSZ, Ddeml.MAX_STRING_SIZE, Ddeml.CP_WINANSI);
string bas = new string(pSZ);
len = Ddeml.DdeQueryString(_InstanceId, hsz2, pSZ, Ddeml.MAX_STRING_SIZE, Ddeml.CP_WINANSI);
string inst = new string(pSZ);
OnUnRegister(bas, inst);
return IntPtr.Zero;
}
}
return IntPtr.Zero;
}
public void Advise(string topic, string item)
{
if (IsDisposed)
{
throw new ObjectDisposedException(this.GetType().ToString());
}
if (!IsRegistered)
{
throw new InvalidOperationException("NotRegisteredMessage");
}
if (topic == null || topic.Length > Ddeml.MAX_STRING_SIZE)
{
throw new ArgumentNullException("topic");
}
if (item == null || item.Length > Ddeml.MAX_STRING_SIZE)
{
throw new ArgumentNullException("item");
}
// Assume the topic name and item name are wild.
IntPtr topicHandle = topic != "*" ? Ddeml.DdeCreateStringHandle(_InstanceId, topic, Ddeml.CP_WINANSI) : IntPtr.Zero;
IntPtr itemHandle = item != "*" ? Ddeml.DdeCreateStringHandle(_InstanceId, item, Ddeml.CP_WINANSI) : IntPtr.Zero;
// Check the result to see if the post failed.
if (!Ddeml.DdePostAdvise(_InstanceId, topicHandle, itemHandle))
{
int error = Ddeml.DdeGetLastError(_InstanceId);
var msg = Ddeml.DDEGetErrorMsg(error); if (msg != null) { }
}
Ddeml.DdeFreeStringHandle(_InstanceId, itemHandle);
Ddeml.DdeFreeStringHandle(_InstanceId, topicHandle);
}
public void Pause(IntPtr hConv)
{
if (IsDisposed)
{
throw new ObjectDisposedException(this.GetType().ToString());
}
if (!IsRegistered)
{
throw new InvalidOperationException("NotRegisteredMessage");
}
// Check the result to see if the DDEML callback was disabled.
if (!Ddeml.DdeEnableCallback(_InstanceId, hConv, Ddeml.EC_DISABLE))
{
int error = Ddeml.DdeGetLastError(_InstanceId);
Ddeml.DDEGetErrorMsg(error);
}
}
public void Resume(IntPtr hConv)
{
if (IsDisposed)
{
throw new ObjectDisposedException(this.GetType().ToString());
}
if (!IsRegistered)
{
throw new InvalidOperationException("NotRegisteredMessage");
}
// Check the result to see if the DDEML callback was enabled.
if (!Ddeml.DdeEnableCallback(_InstanceId, hConv, Ddeml.EC_ENABLEALL))
{
int error = Ddeml.DdeGetLastError(_InstanceId);
Ddeml.DDEGetErrorMsg(error);
}
}
public void Disconnect(IntPtr hConv)
{
if (IsDisposed)
{
throw new ObjectDisposedException(this.GetType().ToString());
}
if (!IsRegistered)
{
throw new InvalidOperationException("NotRegisteredMessage");
}
if (_ConversationTable.Contains(hConv))
{
// Terminate the hConv.
Ddeml.DdeDisconnect(hConv);
// Remove the Conversation from the hConv table.
_ConversationTable.Remove(hConv);
}
}
public void Disconnect()
{
if (IsDisposed)
{
throw new ObjectDisposedException(this.GetType().ToString());
}
if (!IsRegistered)
{
throw new InvalidOperationException("NotRegisteredMessage");
}
// Terminate all conversations.
foreach (IntPtr hConv in _ConversationTable)
{
Ddeml.DdeDisconnect(hConv);
}
// clear the hConv table.
_ConversationTable.Clear();
}
// Démarre une transaction Advise.
public bool AdvStart(IntPtr hConv, string item, ConversionFormat wFormat, int wFlag)
{
if (!IsRegistered)
return false;
int res = 0;
// Création de la chaîne DDE de l'élément.
IntPtr hszItem = Ddeml.DdeCreateStringHandle(_InstanceId, item, Ddeml.CP_WINANSI);
if ((hszItem == IntPtr.Zero) && (item.Length != 0))
return false;
// Exécution de la transaction.
Ddeml.DdeClientTransaction(null, 0, hConv, hszItem, wFormat, (wFlag == Ddeml.XTYPF_ACKREQ) ?
(Ddeml.XTYP_ADVSTARTACKREQ) : ((wFlag == Ddeml.XTYPF_NODATA) ? (Ddeml.XTYP_ADVSTARTNODATA) : (Ddeml.XTYP_ADVSTART)), Ddeml.TIMEOUT_ASYNC, ref res);
// Libération de la chaîne DDE.
if (hszItem != IntPtr.Zero)
Ddeml.DdeFreeStringHandle(_InstanceId, hszItem);
return res != 0;
}
// Arrête une transaction Advise.
public void AdvStop(IntPtr hConv, string item, ConversionFormat wFormat)
{
if (!IsRegistered)
return;
// Création de la chaîne DDE de l'élément.
IntPtr hszItem = Ddeml.DdeCreateStringHandle(_InstanceId, item, Ddeml.CP_WINANSI);
if ((hszItem == IntPtr.Zero) && (item.Length != 0))
return;
// Exécution de la transaction.
int res = 0;
Ddeml.DdeClientTransaction(null, 0, hConv, hszItem, wFormat, Ddeml.XTYP_ADVSTOP, Ddeml.TIMEOUT_ASYNC, ref res);
// Libération de la chaîne DDE.
if (hszItem != IntPtr.Zero)
Ddeml.DdeFreeStringHandle(_InstanceId, hszItem);
}
protected virtual DDEResult OnAdvData(ConversionFormat uFormat, string topic, string item, byte[] data)
{
return DDEResult.FNOTPROCESSED;
}
protected virtual byte[] OnAdvReq(ConversionFormat uFormat, string topic, string item)
{
return null;
}
protected virtual bool OnAdvStart(ConversionFormat uFormat, string topic, string item)
{
return true;
}
protected virtual void OnAdvStop(ConversionFormat uFormat, string topic, string item)
{
}
protected virtual bool OnConnect(string topic, CONVCONTEXT context, bool sameInstance)
{
return true;
}
protected virtual void OnConnectConfirm(string topic, bool sameInstance)
{
}
protected virtual void OnDisconnect(bool sameInstance)
{
}
protected virtual void OnError(ushort errorCode)
{
}
protected virtual DDEResult OnExecute(string topic, string command)
{
return DDEResult.FNOTPROCESSED;
}
protected virtual byte[] OnRequest(ConversionFormat ufmt, string topic, string item)
{
return null;
}
protected virtual DDEResult OnPoke(ConversionFormat uFormat, string topic, string item, byte[] data)
{
return DDEResult.FNOTPROCESSED;
}
protected virtual void OnRegister(string baseServiceName, string instanceServiceName)
{
}
protected virtual void OnUnRegister(string baseServiceName, string instanceServiceName)
{
}
protected virtual void OnXactComplete(ConversionFormat uFormat, string topic, string item, IntPtr data, uint transactionID)
{
}
protected virtual void OnCallback(MONCBSTRUCT mon)
{
}
protected virtual void OnConversation(MONCONVSTRUCT mon)
{
}
protected virtual void OnError(MONERRSTRUCT mon)
{
}
protected virtual void OnString(MONHSZSTRUCT mon)
{
}
protected virtual void OnLink(MONLINKSTRUCT mon)
{
}
protected virtual void OnPost(MONMSGSTRUCT mon)
{
}
protected virtual void OnSend(MONMSGSTRUCT mon)
{
}
/// <summary>
/// This class is needed to dispose of DDEML resources correctly since the DDEML is thread specific.
} // class
}

36
SCADA/Program/DDEDriver/Properties/AssemblyInfo.cs

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("DDEDriver")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("DDEDriver")]
[assembly: AssemblyCopyright("Copyright © 2013")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("6d9e7bae-896d-4ac9-a3c3-2b8e01c96fe0")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

18
SCADA/Program/DataExchange.sln

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27130.2020
VisualStudioVersion = 15.0.27130.2027
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OPCDriver", "OPCDriver\OPCDriver.csproj", "{054DB7AC-EB2C-439F-80D4-63E823B279C8}"
EndProject
@ -37,6 +37,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OmronPlcDriver", "OmronPlcD
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ABPLCDriver", "ABPLCReader\ABPLCDriver.csproj", "{02EA8F3A-29F0-4E11-B4F6-3BF87242D99F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DDEDriver", "DDEDriver\DDEDriver.csproj", "{14938033-7870-477D-925C-A447933A44E7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -343,6 +345,20 @@ Global
{02EA8F3A-29F0-4E11-B4F6-3BF87242D99F}.Release|x64.Build.0 = Release|x64
{02EA8F3A-29F0-4E11-B4F6-3BF87242D99F}.Release|x86.ActiveCfg = Release|Any CPU
{02EA8F3A-29F0-4E11-B4F6-3BF87242D99F}.Release|x86.Build.0 = Release|Any CPU
{14938033-7870-477D-925C-A447933A44E7}.Debug|Any CPU.ActiveCfg = Debug|x86
{14938033-7870-477D-925C-A447933A44E7}.Debug|Itanium.ActiveCfg = Debug|x86
{14938033-7870-477D-925C-A447933A44E7}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
{14938033-7870-477D-925C-A447933A44E7}.Debug|Mixed Platforms.Build.0 = Debug|x86
{14938033-7870-477D-925C-A447933A44E7}.Debug|x64.ActiveCfg = Debug|x86
{14938033-7870-477D-925C-A447933A44E7}.Debug|x86.ActiveCfg = Debug|x86
{14938033-7870-477D-925C-A447933A44E7}.Debug|x86.Build.0 = Debug|x86
{14938033-7870-477D-925C-A447933A44E7}.Release|Any CPU.ActiveCfg = Release|x86
{14938033-7870-477D-925C-A447933A44E7}.Release|Itanium.ActiveCfg = Release|x86
{14938033-7870-477D-925C-A447933A44E7}.Release|Mixed Platforms.ActiveCfg = Release|x86
{14938033-7870-477D-925C-A447933A44E7}.Release|Mixed Platforms.Build.0 = Release|x86
{14938033-7870-477D-925C-A447933A44E7}.Release|x64.ActiveCfg = Release|x86
{14938033-7870-477D-925C-A447933A44E7}.Release|x86.ActiveCfg = Release|x86
{14938033-7870-477D-925C-A447933A44E7}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

BIN
SCADA/dll/DDEDriver.dll

Binary file not shown.
Loading…
Cancel
Save