Blog Archive

Tuesday, December 16, 2008

Add execution timeout for a block of code


delegate void EndProcessingWithTimeoutDelegate(ManualResetEvent m);

.....

bool TimedOut = true;
EndProcessingWithTimeoutDelegate d = delegate
{
ret = acctsAlloc.EndProcessing(MxEnumProcessAction.MxeProcessActionSave);
TimedOut = false;
m.Set();
};
d.BeginInvoke(m, null, null);
m.WaitOne(60000);
if (TimedOut) {
...
}
else
{
}

Note that Timeout in 60 seconds

Tuesday, November 18, 2008

WCF MSMQ Integration Binding Configurations


WCF service is just as normal:



public interface IGMOWCFTrace
{
[OperationContract(IsOneWay = true, Action = "*")]
void WriteLine(MsmqMessage gmoLogMsmq);
}



host = new ServiceHost(typeof(GMO.XIPCommon.Logging.GMOWCFTraceService));



and Service config need to specify msmq and exactlyOnce=false for non-transactinal queue.



<system.serviceModel>
<services>
<service
name="GMO.XIPCommon.Logging.GMOWCFTraceService" >
<endpoint address="msmq.formatname:DIRECT=OS:.\private$\Logging"
binding="msmqIntegrationBinding"
bindingConfiguration="LoggingProcessorBinding"
contract="GMO.XIPCommon.Logging.IGMOWCFTrace">
</endpoint>
</service>
</services>
<bindings>
<msmqIntegrationBinding>
<binding name="LoggingProcessorBinding" exactlyOnce="false" >
<security mode="None" />
</binding>
</msmqIntegrationBinding>
</bindings>
</system.serviceModel>




WCF client has MSMQ code and optionally WCF Code:



public override void WriteLine(object o)
{
Message msg = new Message();
msg.Body = (GMO.XIPCommon.Logging.GMO_LOG_DataContract)o;
loggingQueue.Send(msg);
}



Note Client Configuration can optionally have WCF serviceModel to hint WCF services start processing. This is not absolutely needed but some of my test showed logging
stuck in MSMQ until a call is made to WCF Services:



<system.serviceModel>
<client>
<endpoint name="LoggingEndpoint"
address="msmq.formatname:DIRECT=OS:.\private$\Logging"
binding="msmqIntegrationBinding"
bindingConfiguration="LoggingBinding"
contract="GMO.XIPCommon.Logging.IGMOWCFTrace">
</endpoint>
</client>

<bindings>
<msmqIntegrationBinding>
<binding name="LoggingBinding" exactlyOnce="false" >
<security mode="None" />
</binding>
</msmqIntegrationBinding>
</bindings>
</system.serviceModel>



In other words, MSMQ integration need both MSMQ Code and WCF client code.


Wednesday, November 12, 2008

Sql Query Notification setup code

  
string cs = "Server=vcgmo;Initial Catalog=AdventureWorks; User Id=sa; password=xxxxxx;";
SqlConnection cn;

SqlDependency.Start(cs);
cn = new SqlConnection(cs);
cn.Open();

SqlDataReader r;
SqlCommand cmd;
SqlDependency sd;
SqlDataAdapter ad;

cmd = new SqlCommand("[dbo].[uspTest]", cn);
sd = new SqlDependency(cmd);
sd.OnChange += new OnChangeEventHandler(sd_OnChange);
r = cmd.ExecuteReader();

SqlDependency.Stop(cs);

void sd_OnChange(object sender, SqlNotificationEventArgs e) { }


Note: To enable SQL Notification, must run

ALTER DATABASE [DatabaeName] SET ENABLE_BROKER;

in the Database

Wednesday, November 5, 2008

Call C++ Open MP from C# code



static OMPCommon.TestCallback cb = new OMPCommon.TestCallback(Test);
static void Main(string[] args)
{
OMPCommon.Helper.UseOMP(cb);
Console.ReadLine();
}
static void Test(int i)
{
Console.WriteLine(i);
Thread.Sleep(5000);
}

// Set VS2008 C++ project Properties -->Configure --> C/C++ Language --> Support OpenMP
#include <omp.h>
#pragma once

using namespace System;

namespace OMPCommon {


public delegate void TestCallback(int i);
public ref class Helper
{
public:
static void UseOMP(TestCallback^ cb)
{
omp_set_num_threads(10);
#pragma omp parallel for
for (int i=0;i<20; i++)
{
cb(i);
}
}
};
}



Convert System.String to bstr



GMOBlotter::GMOBlotter(String^ TraderName, String^ TraderPassword, String^ XIPDBServer)
{
::bstr_t trader, pwd, server;
trader.Attach(static_cast(System::Runtime::InteropServices::Marshal::StringToBSTR(TraderName).ToPointer()));
pwd.Attach(static_cast(System::Runtime::InteropServices::Marshal::StringToBSTR(TraderPassword).ToPointer()));
server.Attach(static_cast(System::Runtime::InteropServices::Marshal::StringToBSTR(XIPDBServer).ToPointer()));
::MxEnumReturnCode ret;
ret=pMxgXOM->Login(trader, pwd, server, L"GMO_INTRADAY",::MxeEncryptionMethodNone);
};

Wednesday, October 15, 2008

VBS for NT services installation


Install/Uninstall by Name:

strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colListOfServices = objWMIService.ExecQuery _
("SELECT * FROM Win32_Service WHERE Name = 'IA DB Logging'")
For Each objService in colListOfServices
objService.StopService()
objService.Delete()
Next

Install by source exe
DIM objShell
set objShell = wscript.createObject("wscript.shell")
iReturn = objShell.Run("C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\installUtil IACalcDaemon.exe")

Friday, October 10, 2008

C++ code for XIP Allocation


#import "C:\Program Files\Macgregor\XIP\Common\XIP\TypeLibs\MxXOM.tlb" no_namespace named_guids
#import "C:\Program Files\Macgregor\XIP\Common\XIP\TypeLibs\Xip.tlb" no_namespace named_guids exclude("_IMxXOMEvents","IMxComponentInfo","MxEnumMsgCode","MxEnumObjectType","MxEnumReturnCode","MxEnumBoolean","MxEnumXOMAction","MxEnumRefreshEventType")
#import "C:\Program Files\Macgregor\XIP\Common\XIP\TypeLibs\MxOrderGenerator.tlb" no_namespace named_guids exclude("_IMxXOMEvents","IMxComponentInfo","MxEnumMsgCode","MxEnumObjectType","MxEnumReturnCode","MxEnumBoolean","MxEnumXOMAction","MxEnumRefreshEventType","MxEnumEncryptionMethod","IMxComponentInfo_701")

IMxgXOMPtr pMxgXOM(__uuidof(MxgXOM));

GMOBlotter::GMOBlotter(String^ TraderName, String^ TraderPassword, String^ XIPDBServer)
{
::bstr_t trader, pwd, server;
trader.Attach(static_cast(System::Runtime::InteropServices::Marshal::StringToBSTR(TraderName).ToPointer()));
pwd.Attach(static_cast(System::Runtime::InteropServices::Marshal::StringToBSTR(TraderPassword).ToPointer()));
server.Attach(static_cast(System::Runtime::InteropServices::Marshal::StringToBSTR(XIPDBServer).ToPointer()));
::MxEnumReturnCode ret;
ret=pMxgXOM->Login(trader, pwd, server, L"GMO_INTRADAY",::MxeEncryptionMethodNone);
};

int GMOBlotter::Recalc(int TickNum)
{
::MxEnumReturnCode ret;
::HRESULT h;
IMxXOMAcctsAllocPtr pAcctsAlloc;
::CoInitialize(NULL);

try
{

IDispatchPtr pDis =pMxgXOM->GetCollection(L"TradeOrders");
IMxXOMOrdersPtr pOrd=NULL;
h=pDis->QueryInterface(::IID_IMxXOMOrders,(void **) &pOrd);
IMxXOMOrder3Ptr pTOrd;
VARIANT* v= new VARIANT();
h=pOrd->Item(TickNum,v);
v->pdispVal->QueryInterface(::IID_IMxXOMOrder2,(void**) &pTOrd);


h=pTOrd->GetAcctsAlloc()->QueryInterface(::IID_IMxXOMAcctsAlloc,(void**) &pAcctsAlloc);

ret=pAcctsAlloc->BeginProcessing();
// ret=pAcctsAlloc->Recalc();
pAcctsAlloc->raw_BeginProcessing(&ret);
h=pAcctsAlloc->raw_Recalc(&ret);
if (ret!=::MxeOK)
String^ error="Error";

}
catch (System::Runtime::InteropServices::COMException^ cex)
{
String^ err="";
return -1;
}
catch (...)
{
String^ err="";
return -1;
}
finally
{
pAcctsAlloc->raw_EndProcessing(::MxeProcessActionSave,&ret);
// ret=pAcctsAlloc->EndProcessing(::MxeProcessActionSave);
}
if (ret!=::MxeOK) return -1;
return 0;
};

Thursday, September 11, 2008

TFS Branching and Merging draft Guideline


Branch and Merge is a core concept in TFS to facilate Source Control and release
management. There are various approach to these topics. But here are brain-dump
while encountering practical issues using TFS ( Team Fundation server).

(1) Agile Development Directory Structure representing Team, products, solutions,
major branch

Trading System
CRD
XIP
GMO.XIP
Branches
2008
2009
Trunk


(2) Each branch represent a weekly release version. and Trunk should not be released.
This will allows us to support different usage of XIP solution for different
business cases and still support common core.
If CMMI are used, then the structure could be based on version number not related to Dates

(3) For non-release related feature (eg. new helper function or bug fixes), a
feature branches should be used for the changes. In other words, Trunk can only be
changed through merge back from branches.

(4) Branching should be off Tip Revision (Latest Version), rather than a label since TFS needs
to duplicated files on branching and we have to use duplicated directory structure, which in
itself already acts like Label.

Wednesday, August 13, 2008

Use reflection to dump properies

 For debugging purposes, we can use the following reflection based code:

public static string DumpOrderBean(OrderBean ob)
{

PropertyInfo[] pi = typeof(OrderBean).GetProperties();
StringBuilder sb= new StringBuilder();
foreach (PropertyInfo p in pi)
{
if (p.Name.IndexOf("Bean")<0)
sb.Append(p.Name +" :"+ p.GetValue(ob, null)+"\r\n");
}
StreamWriter w= new StreamWriter(@"c:\JGBRollTestOB.txt");
w.Write(sb.ToString()); w.Flush();

OrderAllocationBean oa = ob.allocationBeans[0];
PropertyInfo[] pi2 = typeof(OrderAllocationBean).GetProperties();
StringBuilder sb2 = new StringBuilder();
foreach (PropertyInfo p2 in pi2)
{
if (p2.Name.IndexOf("Bean") < 0)
sb2.Append(p2.Name + ":" + p2.GetValue(oa, null) + "\r\n");
}
StreamWriter w2 = new StreamWriter(@"c:\JGBRollTestOAB.txt");
w2.Write(sb2.ToString()); w2.Flush();
return sb.ToString();
}


Friday, August 1, 2008

Constrain SQL like pattern for Commission Rate lookup


SQL Like allow pattern match but normally return multiple rows. If you have one
commision rate for a pattern, carefully specified pattern will allow look up to
return just one value without the ambiguity as shown here:
FSMI% vs. FSMIU%

In general, we need to consider the following:

(1) Clearly define Bloomberg symbol as 2 charaters key and Add GMO prefix to
generate external security id pattern. (GMO_EXT_SEC_ID_PATN_DEF).
In particular, Commission Rate table GMO_BROKER_COMM need to have Foreign key
constraints from GMO_EXT_SEC_ID_PATN_DEF to avoid invalid security.

(2) GMO_BROKER_COMM need to have a trigger constraint to make sure the following
will not return more than one row:
select * from GMO_BROKER_COMM2 where
(EXT_SEC_ID_PATN like @EXT_SEC_ID_PATN or
@EXT_SEC_ID_PATN like EXT_SEC_ID_PATN)

in particular, if we need to have both FSMI% and FSMIU%, we will need to span out
even with duplcation rates:
FSMIH% 2.95
FSMIG% 2.95
FSMIZ% 2.95

FSMIU% 4.95

This will eliminate ambiguity.

(3) We need [BB_SYMBOL] [char](2) NOT NULL to keep space for Bloomberg symbol
and that will avoid some ambiguity like FBC % vs. FBCC%

(4) FBC % vs. FBC%
FB C -- SET50 FUTURES maps to FBC %
F BC -- CORN FUTURE maps to FBC%
we currenlty do not have commission rate for FBC %. But we need to be
careful when enter rates in the future

(5) The following is the SQL used in Mid-Tier:
select * from GMO_BROKER_COMM where @ext_sec_id like EXT_SEC_ID_PATN



Tuesday, July 29, 2008

Runing CRD 8.2.2 against SQL Server 2005 Express


There are some particular considerations when install CRD 8.2.2 against SQL Server 2005 Express:

(1) SQL Server 2005 Express must installed as default instance. No other instance should ever be installed.
(2) Installation works on XP SP2.
(3) Must create TM_DEV user in login first before restore data.bak. And server role should be empty, especially should not have "public" role visible.
(4) Must use SQL Configuration manager to enable Client VIA, TCP/IP, ShareMemeory, NamedPipes.
(5) Create a new Database CRD822 and install into it with "Overwrite Existing DB" option checked.
(6) TM_DEV mapping to PDF_User dbo_owner roles. ( start up server while doing CRD client installation).

Sunday, July 13, 2008

LINQ to Text file through StreamReader Extension method


Text file data feeds come in different format but with common theme: parse a line into an object representation. Here is one example of the object:

public class BrokerDataItem : ILineParser<BrokerDataItem>
{
public string Ticker { get; set;}
public double Price { get; set;}
public long QTY { get; set;}
public string Trader { get; set;}
public DateTime TradeDate { get; set;}
public string TradeType { get; set;}

public BrokerDataItem() { }
public BrokerDataItem Parse(string[] p)
{
return null;
}
public BrokerDataItem Parse(string entireLine) {
string[] p = entireLine.Split(',');
Ticker = p[0].ToString();
Price = Convert.ToDouble(p[1]);
QTY = Convert.ToInt64(p[2]);
Trader = p[3].ToString();
TradeDate = Convert.ToDateTime(p[4]);
TradeType = p[5].ToString();
return this;
}

Note I abstracted parse operation into interface

public interface ILineParser<T>
{
T Parse(string[] p);
T Parse(string entireLine);
}

So that I can create an Extension Method for StreamReader that return the Data Object to LINQ. Consequently, this allows LINQ runs against data object of any source to get the required data elements:

public static class AnyThing
{
public static IEnumerable<T> GetData<T>(this StreamReader sr) where T : ILineParser<T>, new()
{
string L;
while ((L = sr.ReadLine()) != null)
{
T t = new T();
yield return t.Parse(L);
}
}
}


class Program
{
static void Main(string[] args)
{
StreamReader sr = new StreamReader(@"..\..\Data.txt");

var t =
from data in sr.GetData<BrokerDataItem>()
select data;
foreach (BrokerDataItem i in t)
Console.WriteLine(i.Ticker+" " + i.Price.ToString());
Console.ReadLine();
}
}

Here are the data:
FBN U8,134.79, 1000,JIMMYD,7/14/2008,BUYL
FBN U8,444.90, 7832,JIMMYD,7/14/2008,BUYL
FBN U8,4567.9, 1000,JIMMYD,7/14/2008,SELL
FBN U8,581.79, 5634,JIMMYD,7/14/2008,BUYL
FBN U8,724.78, 1212,JIMMYD,7/14/2008,SELL
FBN U8,932.01, 8892,JIMMYD,7/14/2008,SELL
FBN U8,678.88, 3,JIMMYD,7/14/2008,BUYL

Finally, extension method is not required since you can just create an IEnumerable and use it in LINQ.

Friday, July 11, 2008

Data Proection API

DPAPI uses the key from the following location to encrypt/decrypt:

C:\Documents and Settings\All Users\Application Data\Microsoft\Crypto
or

C:\WINDOWS\system32\Microsoft\Protect or Crypto.

These are replaced by SID if DataProtectionScope.LocalMachine is replaced by DataProtectionScope.CurrentUser.
In theory, if data are moved away from the machine, there would no way to decrypt,
even DataProtectionScope.CurrentUser for the same user logged on to a different machine:


byte[] entropyBytes =null;// Encoding.Unicode.GetBytes("GMO");
byte[] pBytes;
private void button1_Click(object sender, EventArgs e)
{
string plainText = this.textBox1.Text;
byte[] plainBytes = Encoding.Unicode.GetBytes(plainText);

pBytes = ProtectedData.Protect(plainBytes, entropyBytes, DataProtectionScope.LocalMachine);
string ps = Convert.ToBase64String(pBytes);
this.textBox2.Text = ps;

}

private void button2_Click(object sender, EventArgs e)
{
byte[] upBytes = ProtectedData.Unprotect(pBytes, entropyBytes, DataProtectionScope.LocalMachine);
this.textBox3.Text = Encoding.Unicode.GetString(upBytes);
}

Monday, June 30, 2008

Using WSE 3.0 X509 Search API to implement RSA Crypto


WSE 3.0 has two functions to retrieve X509 Certificate:

X509Certificate2Collection cert2s = X509Util.FindCertificateBySubjectName(SubjectName, StoreLocation, StoreName.ToString());

X509Certificate2Collection cert2s = X509Util.FindCertificateByKeyIdentifier(ThumbPrint , StoreLocation, StoreName.ToString());

This is much simpler than using COM API or its .Net Wrapper. Using these function, we can write a class encapsulate RSA Crypto with considering of Certification Basic Policy Validation ( such as revocation):


namespace JQD {
public class X509RSAEncryptor
{
#region Encryption and Decryption
public static string[] EncryptUTF8ToBase64(string ClearTextUTF8, X509Certificate2 cert2ForEncryption, X509Certificate2 cert2ForSignning)
{
if (null == cert2ForEncryption)
throw new ApplicationException("null X509 cert for Encryption");
// create Encryption RSA using Public Key only
RSAParameters rsaForEncryptionPublicParam = X509Util.GetKey(cert2 ForEncryption).ExportParameters(false);
RSACryptoServiceProvider rsaForEncryption = new RSACryptoServiceProvider();
rsaForEncryption.ImportParameters(rsaForEncryptionPublicParam);
// generate encrypted Base64 string from clear Text
byte[] clearBytes = Encoding.UTF8.GetBytes(ClearTextUTF8);
byte[] cipherBytes = rsaForEncryption.Encrypt(clearBytes, true);
string cipherTextBase64 = Convert.ToBase64String(cipherBytes);
string signatureTextBase64 = "";
if (null != cert2ForSignning)
{
// create Signning RSA using Private Key
RSAParameters rsaForSignningPrivateParam = X509Util.GetKey(cert2ForSignning).ExportParameters(true);
RSACryptoServiceProvider rsaForSignning = new RSACryptoServiceProvider();
rsaForSignning.ImportParameters(rsaForSignningPrivateParam);
// compute Signature using SHA1
byte[] signature = rsaForSignning.SignData(cipherBytes, SHA1.Create());
signatureTextBase64 = Convert.ToBase64String(signature);
rsaForSignning.Clear();
}

rsaForEncryption.Clear();
// send both Data and its singature as Base64 string
return new string[2] { cipherTextBase64, signatureTextBase64 };
}
public static string DecryptBase64ToUTF8(string[] CipherBase64, X509Certificate2 cert2ForDecryption, X509Certificate2 cert2ForVerifySignning)
{
if (null == cert2ForDecryption)
throw new ApplicationException("null X509 cert for decryption");
byte[] cipherBytes = Convert.FromBase64String(CipherBase64[0]);
if (null != cert2ForVerifySignning)
{
// create Verify Signning RSA using public Key
RSAParameters rsaForVerifySignningPrivateParam = X509Util.GetKey(cert2ForVerifySignning).ExportParameters(false);
RSACryptoServiceProvider rsaForVerifySignning = new RSACryptoServiceProvider();
rsaForVerifySignning.ImportParameters(rsaForVerifySignningPrivateParam);
// Verify signature
byte[] signature = Convert.FromBase64String(CipherBase64[1]);
try
{
if (!rsaForVerifySignning.VerifyData(cipherBytes, SHA1.Create(), signature))
throw new ApplicationException("Data have been tampered.");
}
finally
{
rsaForVerifySignning.Clear();
}
}
// create Decryption RSA using Private Key
RSAParameters rsaForDecryptionPrivateParam = X509Util.GetKey(cert2ForDecryption).ExportParameters(true);
RSACryptoServiceProvider rsaForDecryption = new RSACryptoServiceProvider();
rsaForDecryption.ImportParameters(rsaForDecryptionPrivateParam);
// Decrypt and convert to Clear Text
byte[] clearBytes = rsaForDecryption.Decrypt(cipherBytes, true);
rsaForDecryption.Clear();
return Encoding.UTF8.GetString(clearBytes);
}
#endregion

#region X509 finder
public static X509Certificate2 FindX509Certificate2(string SubjectName, StoreLocation StoreLocation, StoreName StoreName)
{
X509Certificate2Collection cert2s = X509Util.FindCertificateBySubjectName(SubjectName, StoreLocation, StoreName.ToString());
X509Certificate2Collection validCert2s = Validate(cert2s);
if (validCert2s.Count == 0) return null;
return validCert2s[0];
}
public static X509Certificate2 FindX509Certificate2(byte[] ThumbPrint,StoreLocation StoreLocation, StoreName StoreName)
{
X509Certificate2Collection cert2s = X509Util.FindCertificateByKeyIdentifier (ThumbPrint , StoreLocation, StoreName.ToString());
X509Certificate2Collection validCert2s=Validate(cert2s);
if (validCert2s.Count == 0) return null;
return validCert2s[0];
}
private static X509Certificate2Collection Validate(X509Certificate2Collection cert2s)
{
X509Certificate2Collection validCert2s = new X509Certificate2Collection();
foreach (X509Certificate2 cert2 in cert2s)
{
// applies the base policy to that chain, Note that on Win2k3, the basic policy
// check conformance to RFC3280, which include revocation for X509 Cert2.
bool IsConformedToBasicPolicy = cert2.Verify();
// Some other simple checking
bool IsArchived = cert2.Archived;
bool IsExpired = (DateTime.Now > cert2.NotAfter)
bool IsNotActive =( DateTime.Now < cert2.NotBefore);
if (IsConformedToBasicPolicy && !IsArchived && !IsExpired && !IsNotActive)
{
validCert2s.Add(cert2);
}
}
return validCert2s;
}
#endregion
}
}

The usage is also simple as illustrated by the following:

class Program
{
static void Main(string[] args)
{
string msg="This is a secret.";
Console.WriteLine(msg);
X509Certificate2 cert2Enc;
X509Certificate2 cert2Sig;
string subjectName1="CN=idmcertid, OU=Internet Infrastructure, O=\"Blah Blah, Inc.\", L=Boston, S=massachusetts, C=US";
byte[] thumbPrint1=new byte[] { 0xb7, 0x4a, ....., 0x9c, 0x0c };

cert2Enc = X509RSAEncryptor.FindX509Certificate2(subjectName1,StoreLocation.LocalMachine, StoreName.My);
cert2Sig = X509RSAEncryptor.FindX509Certificate2("CN=XYZ Company", StoreLocation.CurrentUser, StoreName.My);
cert2Sig = X509RSAEncryptor.FindX509Certificate2(subjectName1, StoreLocation.CurrentUser, StoreName.My);
string[] cipherBase64 = X509RSAEncryptor.EncryptUTF8ToBase64(msg, cert2Enc, cert2Sig);
Console.WriteLine(cipherBase64[0]);
Console.WriteLine();
Console.WriteLine(cipherBase64[1]);
Console.WriteLine();
X509Certificate2 cert2Dec=X509RSAEncryptor.FindX509Certificate2(subjectName1,StoreLocation.LocalMachine, StoreName.My);
Console.WriteLine(X509RSAEncryptor.DecryptBase64ToUTF8(cipherBase64, cert2Dec, cert2Sig));
Console.ReadLine();
}

Note that when install Private Key, Must check " Mark this key Exportable" to avoid " Key in invalid state" exception. Also remember RSA encryption requires Receiving party to hold private key for decryption and hold public key for verify signning. Sending party hold just the opposite. So Receiveing party only need sending party's public key, and so on. This means it is better to have two computers with two set of good X509 Cert to run the code. If the cert is really invalid as seen in MMC IDE, IsConformedToBasicPolicy will be false.
Finally, There are no need to install WSE 3.0. You only need to have a copy of Microsoft.Web.Services3.dll and add its reference to your project.

Saturday, June 21, 2008

Load CLR runtime into XIP addin unmanaged process

LPWSTR pszVer = L"v2.0.50727";
LPWSTR pszFlavor = L"svr"; // svr, wks
ICorRuntimeHost *pHost =NULL;
mscorlib::_AppDomain *pDefaultDomain = NULL;
IUnknown *pAppDomainPunk = NULL;
STDMETHODIMP CXIPVCAddin::AppStartUp( VARIANT_BOOL* pnComponentInitialized)
{

HRESULT hr =::CorBindToRuntimeEx(pszVer, pszFlavor,
STARTUP_LOADER_OPTIMIZATION_SINGLE_DOMAIN ,
CLSID_CorRuntimeHost, IID_ICorRuntimeHost, (void **)&pHost);
pHost->Start();

hr = pHost->GetDefaultDomain(&pAppDomainPunk);
hr = pAppDomainPunk->QueryInterface(__uuidof(mscorlib::_AppDomain),
(void**) &pDefaultDomain);


JQDXIPEventHandler::IXIPEventHandler *pObj=NULL;
mscorlib::_ObjectHandle *pObjHandle = NULL;

_bstr_t a("JQDXIPEventHandler");
_bstr_t t("JQD.XIPEventHandler");

hr=pDefaultDomain->CreateInstance(a,t,&pObjHandle);

VARIANT v;
VariantInit(&v);
hr = pObjHandle->Unwrap(&v);

hr = v.pdispVal->QueryInterface(__uuidof(JQDXIPEventHandler::XIPEventHandler),
(void**) &pObj);
hr=pObj->OnEvent();


MessageBox(NULL,"AppStartUp with CLR loaded, MFC/ATL","IXIPAddIn Sample",MB_OK);
*pnComponentInitialized=VARIANT_TRUE;
return S_OK;
}

STDMETHODIMP CXIPVCAddin::AppShutDown (VARIANT_BOOL* pnComponentDisconnected)
{
pHost->Stop();

pAppDomainPunk->Release();
pDefaultDomain->Release();
pHost->Release();
//MessageBox(NULL,"AppShutDownB with CLR Cleaned","IXIPAddIn Sample",MB_OK);
*pnComponentDisconnected=VARIANT_TRUE;
return S_OK;
}

STDMETHODIMP CXIPVCAddin::OnEvent (BSTR bstrEventName, IDispatch* pObject, VARIANT vArg)
{

MessageBox(NULL,"OnEvent","IXIPAddIn Sample",MB_OK);
return S_OK;
}

Thursday, June 19, 2008

XIP Addin COM object fail to load .Net code

This could be a general problem, i.e., when a win32 process is loading a COM object, we can get "Class not registered" error, if one of the following is true:
(1) The COM object uses CoCreateInstance to initalized C# comsible .Net class
(2) Teh COM object uses C++ Mixed Managed and unmanaged code feature.

Here are the code snippets:

// C# COM object
#import "C:\Working\JQDXIPCOMCS\Debug\JQDXIPCOMCS.tlb"
STDMETHODIMP CXIPVCAddin::AppStartUp( VARIANT_BOOL* pnComponentInitialized)
{
HRESULT hr = CoInitialize(NULL);
JQDXIPCOMCS::IXIPEventHandlerPtr pEH(__uuidof(JQDXIPCOMCS::XIPEventHandler));


// ATL C++ COM with /clr at project or file level
#import "C:\Working\JQDTestCOM\JQDTestCOM\Debug\JQDTestCOM.tlb"
STDMETHODIMP CXIPVCAddin::AppStartUp( VARIANT_BOOL* pnComponentInitialized)
{
HRESULT hr = CoInitialize(NULL);
JQDTestCOMLib::IClass1Ptr p(__uuidof(JQDTestCOMLib::Class1));

// alternative ATL COM objet initiation
CComPtr pH;
::CoCreateInstance(__uuidof(JQDXIPCOMCS::XIPEventHandler),NULL,CLSCTX_ALL,
__uuidof(JQDXIPCOMCS::IXIPEventHandler), (void**) &pH);

The following are the workaround until this problem can be solved:
HINSTANCE h=ShellExecute(NULL,"open","C:\\XIP_GMO\\OrdAlloc.exe","c:\\MyLog.log","",SW_SHOW);

It turn out that xip.exe.config did not specify CLR runtime version and codebase for registered COM may not point to the right place. We just need to do the folowing:
1) Add <supportedRuntime version="v2.0.50727" /> in xip.exe.config
2) Create a new directory GMOCSharpCOM on app server and set CodeBase of all C# COM object to this directory. e.g. CodeBase file:///X:/GMOCSharpCOM/GMOAllocator.dll

Wednesday, June 11, 2008

T-SQL split function

This is a code based on my goole search
CREATE FUNCTION dbo.fnSplit
(
@string varchar(500),
@delimiter char(1),
@return_index int
)
RETURNS varchar(500)
AS
BEGIN
declare @pos int
declare @piece varchar(500)

if right(rtrim(@string),1) <> @delimiter
set @string = @string + @delimiter

set @pos = patindex('%'+@delimiter+'%' , @string)

declare @i int
set @i =0
while @pos <> 0
begin
set @piece = left(@string, @pos - 1)
if @i=@return_index
return cast(@piece as varchar(500))

set @string = stuff(@string, 1, @pos, '')
set @pos = patindex('%'+@delimiter+'%' , @string)
set @i=@i+1
end

RETURN null
END

Monday, May 26, 2008

Language Binding for WCF REST Messages


WCF in .Net 3.5 support REST on server side using [WebGet]. But there are no SOAP/WSDL proxy auto-gen tool. In fact, REST messages will come off wire through WebClient and we can use DataContractSerializer to bind back to a CLR object.

namespace GMO
{
[DataContract()]
public class Stock
{
[DataMember]
public double Price { get; set; }
[DataMember]
public string Symbol { get; set; }
public override string ToString()
{
return Price.ToString();
}
}

using Data;
[ServiceContract]
public interface IPostTrade
{
[OperationContract]
[WebGet()]
List<object> GetInstrumentList(string tradeID);

[OperationContract]
[WebGet()]
bool HasSettled(string TradeID,string InstID);

[OperationContract]
[WebGet()]
List<Stock> GetStockHoldings(string BlotterID);

}
}


DataContractSerializer ser = new DataContractSerializer(typeof(List<GMO.Data.Stock>));
WebClient c= new WebClient();
Stream r = c.OpenRead(@"http://localhost:49176/PostTrade.svc/GetStockHoldings?blooterID=0");
List<GMO.Data.Stock> list=(List<GMO.Data.Stock>)ser.ReadObject(r);
listBox1.ItemsSource = list;



Exposing CLR object as WCF REST


Use .Net framework 3.5, we can load CLR objects through WebService Host Factory as WCF REST Message endpoint without any configuration.
Note that we only need one .svc file specifiying Factory and Service CLR class. After that we can just add any new method on the fly to that CLR class and copy paste to Web Service for new functionality.

<%@ ServiceHost Language="C#" Debug="true"
Service="GMO.PostTrade"
Factory="System.ServiceModel.Activation.WebServiceHostFactory"
%>

namespace GMO
{
[ServiceContract]
public interface IPostTrade
{
[OperationContract]
[WebGet()]
List<object> GetInstrumentList(string tradeID);

[OperationContract]
[WebGet()]
bool HasSettled(string TradeID,string InstID);

}

public class PostTrade : IPostTrade
{
public List<object> GetInstrumentList(string tradeID)
{
List<Object> list = new List<object>();
for (int i = 0; i < 10; i++)
list.Add("CRD Instrument" + i.ToString() + " for trade ID=" + tradeID);
return list;
}

public bool HasSettled(string TradeID, string InstID)
{
if (InstID=="1" ) return true;
return false;
}


}
}

To access end points added into the CLR class:

http://localhost:49176/PostTrade.svc/GetInstrumentList?TradeID=78
http://localhost:49176/PostTrade.svc/HasSettled?InstID=10
http://localhost:49176/PostTrade.svc/AnyNewMethodAdded?newID=99

Sunday, May 25, 2008

Simple Master-Detail Databinding


In WPF, Listbox can hold IEnumerable while ContentPresneter can display CurrentItem. When both control share the same DataContext, Master detail relationship is established:



public class Stocks : List
{
public Stocks()
{
Add(new Stock("YHOO", 27.90));
Add(new Stock("MSFT", 28.90));
Add(new Stock("GOOG", 179.40));
}
}

public class Stock {
public string Symbol { get; set; }
public double Price { get; set; }
public Stock(string s, double p) {
this.Price = p; this.Symbol = s; }
public override string ToString() { ..}
}


<Window x:Class="MasterDetailWPF.Window1"
xmlns="..."
xmlns:x="..."
...
xmlns:local="clr-namespace:MasterDetailWPF">
<Window.DataContext>
<local:Stocks>
</Window.DataContext>
<Grid>
<ListBox ..
ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="True">

</ListBox>
<ContentPresenter Content="{Binding}" ..>
<ContentPresenter.ContentTemplate>

<DataTemplate>
<TextBox Text="{Binding Path=Symbol, Mode=Default}" />
</DataTemplate>
</ContentPresenter.ContentTemplate>
</ContentPresenter>
</Grid>
</Window>



Wednesday, May 21, 2008

Tilt User Interface for eye-ball



Before WPF, UI is layed out on a flat plane, limiting the number of UI elements. Some information just need eye-ball and therefore can be tilted to save space.
Here is the code to do that using SkewTransform:


<Grid Margin="8,-73,0,0" Name="grid1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150" />
<ColumnDefinition Width="150" />
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<DockPanel Margin="8,190,0,28" Name="viewbox1">

<Image Source="c:\working\1.jpg" Margin="0,0,0,0" Name="image1" Height="163" VerticalAlignment="Top" Width="141" />
<TextBox Height="164" Margin="14,0,16,64" Name="textBox1" VerticalAlignment="Bottom" />

<DockPanel.RenderTransform>
<SkewTransform AngleX="0" AngleY="-40" />
</DockPanel.RenderTransform>
</DockPanel>
<ListBox Grid.Column="1" Margin="0,73,0,29">
<ListBoxItem>1</ListBoxItem>
<ListBoxItem>2</ListBoxItem>
<ListBoxItem>3</ListBoxItem>
</ListBox>
<ListBox Grid.Column="2" Margin="2,75,-2,30">
<ListBoxItem>1
<ListBoxItem>2
<ListBoxItem>3
<ListBox.RenderTransform>
<SkewTransform CenterX="0" CenterY="0" AngleX="0" AngleY="40" />
</ListBox.RenderTransform>
</ListBox>

Collection View


Data should be separated out from UI Elements for data binding purposes. In fact, Sorting, Grouping, selected changed event ( as in IBindingList) are better handled in View ( such as DataView and ListCollectionView). Here is a simple usage of Collection View in WPF:


public class Stock
{
public string Symbol { get; set; }
public double Price { get;set;}
public Stock(string s, double p)
{
this.Price = p;
this.Symbol = s;
}

public override string ToString()
{
return Symbol + " " + Price;
}
}

List<Stock> stocks = new List<Stock>();
stocks.Add(new Stock("YHOO", 27.90));
stocks.Add(new Stock("MSFT", 28.90));
stocks.Add(new Stock("GOOG", 179.40));
ListCollectionView cv = new ListCollectionView(stocks);
cv.SortDescriptions.Add(new SortDescription("Symbol", ListSortDirection.Ascending));
Binding b = new Binding();
b.Source = cv;
this.listBox1.SetBinding(ListBox.ItemsSourceProperty, b);


Monday, May 19, 2008

Control template vs. Data Template

In the following Example, both Control Template and Data Template will fill ListBox using List Data. But Control Template disable ListBox Selection.

<Window.Resources>
<!--<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}"> <TextBlock Text="{Binding Path=Symbol}"></TextBlock> </ControlTemplate>
</Setter.Value>
</Setter>
</Style>-->
<ObjectDataProvider x:Key="Stocks" ObjectType="{x:Type data:Stocks}" />
<DataTemplate x:Key="ShowStock">
<TextBlock Text="{Binding Path=Symbol}">

</DataTemplate>
</Window.Resources>
<Grid Height="182" Width="240"> <Grid.RowDefinitions> <RowDefinition> <RowDefinition> </Grid.RowDefinitions>
<ListBox ItemsSource="{Binding Source={StaticResource Stocks}}" Name="StockList1" Grid.Row="0" ItemTemplate="{Binding Source={StaticResource ShowStock}}" />
<ListBox ItemsSource="{Binding Source={StaticResource Stocks}}" Name="StockList2" Grid.Row="1" />
</Grid>

Use Style to Add Control Template

WPF make is very easy to do "owner-drawl" by Control Template

<Window.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<DockPanel>
<TextBlock TextTrimming="CharacterEllipsis" Width="150" Text="{TemplateBinding Content}" Foreground="Red"/>
<Image Source="c:\working\Test1.jpg" Width="20" Height="20"/>
<DockPanel> </ControlTemplate> </Setter.Value>
</Setter>
</Style>
</Window.Resources> <StackPanel Margin="30">
<ListBox>
<ListBoxItem>Test this /ListBoxItem>
</ListBox>
</StackPanel>