July 6, 2007 by possemeeg
I’m wrapping a legacy lib for use in a .NET envirment.
Usefull: An Overview of Managed/Unmanaged Code Interoperability
Firstly, I tried to wrap the lib api with COM and use that from my C# app. With speed and efficiecency a priority, this was unacceptable. It involves callbacks (legacy lib) or events (COM) – the big slowdown happened in the call from the COM to it’s connection point (C#).
The way forward is a managed/unmanaged C++ project. All legacy objects are held as pointers to classes that wrap them. A thin wrapper, one managed class for one legacy class. Wrap the pointer in a nice template base class taking a type for the wrapped. Have a pointer expose method that throws an exception if the wrapped pointer is null. Ensure IDisposable is derived from and the ~ClassName, and !ClassName methods are both implemented (finalize and Dispose methods). In the dispose, clean up the unmanaged pointer.
Callbacks from the native? How to: Marshal Callbacks and Delegates Using C++ Interop. It’s very important you don’t try this if the legacy callback expected is not __stdcall. It will mess up the stack when you leave the callback. This was my problem. So, I created a class to set up the callback. The legacy function that sets of the callback takes a callback and a void * as data. For the callback I passed a normal callback function of my own, for the void * I passed a __stdcall callback as set up in the article. When the normal callback gets called, I simple use the given void * as a pointer to a __stdcall callback and call that. One thing about the article, gcnew GetTheAnswerDelegate, can be called passing an object as the first parameter, and a method as the second. Getting your callback into an instance of a class.
Strings: How to: Convert System::String to wchar_t* or char*. A nice wrapper class can’t be resisted.
If COM is the required for some other reasons: Don’t forget “oleautomation” attribute on your non-IDispatch interfaces (in your IDL).
This is a handy way to bind COM enums to a WPF control in XAML. (Note the requirement of the loc namespace to point to where your COMTypes class is). One can use System.Enum.Parse to get the selected enum value back from the combo box.
XAML:
<Window.Resources>
<ObjectDataProvider MethodName="GetMyCOMEnums
ObjectType="{x:Type loc:COMTypes}" x:Key="MyComEnums">
</ObjectDataProvider>
</Window.Resources>
<ComboBox Height="26" Margin="400,29,0,0" Name="m_type" VerticalAlignment="Top" HorizontalAlignment="Left" Width="121" ItemsSource="{Binding Source={StaticResource MyComEnums}}" />
A class in your project:
public class COMTypes
{
public static Array GetMyCOMEnums()
{
return Enum.GetValues(typeof(MyCOMLib.MyEnumType));
}
}
Posted in .NET, C++, COM | 2 Comments »
June 24, 2007 by possemeeg
Alpha version of PMG Connect 2.0. Apart from the visual changes and millions of little changes, the internals have been gutted and put back together in preparation for the new file system features (which are also partially in). Note that, it no longer tries to write to the install directory when launching a Remote Desktop session (noteably a vista problem).
Posted in PMG Connect | Leave a Comment »
June 24, 2007 by possemeeg
After WPF, spending time with NM_CUSTOMDRAW seemed like running somewhere, when one could catch a bus. Someday, we may even do it’s like for pleasure.
My problem: I couldn’t get the separators to draw on my owner draw toolbar. Apparently, the NM_CUSTOMDRAW doesn’t send a CDDS_ITEMPOSTPAINT for separators. So, the way to do it is draw your separator over the top once drawing is complete. Process the CDDS_POSTPAINT with something like this:
CDCHandle dc(__HDR.hdc);
CDC compatDC;
compatDC.CreateCompatibleDC(dc);TBBUTTON button;
for (int i=0;i < ButtonCount();++i)
{
Toolbar().GetButton(i,&button);
if(button.fsStyle&BTNS_SEP)
{
CRect sepRc;
Toolbar().GetRect(button.idCommand,&sepRc);
extra::GDIBitmapObjectSelect leftBmpSel(compatDC,m_sep.Bmp());
dc.BitBlt(sepRc.left,sepRc.top,m_sep.Size().cx,
m_sep.Size().cy,compatDC,0,0,SRCCOPY);
}
}
return CDRF_SKIPDEFAULT;
Don’t forget to return CDRF_NOTIFYPOSTPAINT in response to a CDDS_PREPAINT. (And NOTIFYITEMDRAW if you want to draw the items.) Also, each separator must be added with a unique command Id otherwise GetRect will always just get the first.
Posted in C++ | Leave a Comment »
June 23, 2007 by possemeeg
I wanted to replace a const int with a lazily evalueated int. It had to be lazy evaluated as all that was needed to calculate it was not available when the class is instanciated but was available before the int was needed. I didn’t want to change the code that uses the int. So, I made this class:
template <class T>
class CLazyValue
{
public:
CLazyValue() : m_gotOffArse(false) {}
operator T&() {return (m_gotOffArse ? m_value :
(m_gotOffArse=true,GetOffArse(m_value),m_value));}
private:
bool m_gotOffArse;
T m_value;
virtual void GetOffArse(T &val) = 0;
};
To use it, just derive and fill in GetOffArse. Example:
class CTopOffset : public extra::CLazyValue
{
public:
CTopOffset(CToolbarDrawerTabStyle &drawer) : m_drawer(drawer) {}
private:
CToolbarDrawerTabStyle &m_drawer;
virtual void GetOffArse(int &val);
}TAB_TOP_OFFSET;
Note the name of my const. The int can be calculated from the m_drawer. The great thing is, CLazyValue can be used whenever lazy evaluation is required. I fear this may be rather obvious but it looks good.
Posted in C++ | Leave a Comment »
June 23, 2007 by possemeeg
After about 16 years of writing C++ on Windows I’m sure there’s been many an occasion with the need to test if a file exists. Today, I discovered a new way to check!
bool FileExists(const extra::tstring &file)
{
OFSTRUCT of = {sizeof(of)};
return (OpenFile(CT2CA(file.c_str()),&of,OF_EXIST)!=HFILE_ERROR);
}
Where an extra::tstring is declared such (part of my library of code):
typedef std::basic_string<TCHAR>tstring;
Apparently it closes the handle (see docs), but I still get nervous ignoring a handle like that. The downside (handle anxieties aside) is that this OpenFile function, which I don’t recall ever using before, does not have a Unicode version (hence the need for CT2CA).
Posted in C++ | Leave a Comment »
June 22, 2007 by possemeeg
The C++ STL for_each is very useful. This C# equivalent is even better:
void Method()
{
// assuming string[] strings;
Action stringAction = delegate(string stringParam)
{
// do stuff with stringParam and whatever else available in Method()
};
Array.ForEach(strings,stringAction);
}
See other ForEaches too.
Posted in .NET | Leave a Comment »
June 21, 2007 by possemeeg
Interesting: Glass Bead tutorial. My attempt:

Then try say a 300 x 75 strip. Use brushes:
Brush 1: Solid #121212
Brush 2: Gradient#445282 Offset 0%, #29314D Offset 53%, #12131D Offset 95%
Brush 3: Gradient #393F4D Offset 0%, #4A5367 Offset 33%, #5F6A87″ Offset 98%, #626C88″ Offset 100%
Use brush 1 to solid fill lowest layer. On new layer, create a selection on bottom 28.57 % of image and use brush 2 from bottom to top. On third layer, select the top 48.57 % of the image and use brush 3 from bottom to top. Set opacity to 80% or slightly less. You have a nice glass bead thing.

Try edit the colours to your desired shade by going to each one (bottom solid and each step on the gradients) and movng the second colour slider up and down on the photoshop colour picker.

The next release of pmgconnect is bound to have glass bead somewhere.
Posted in Graphics and Photoshop | Leave a Comment »
June 21, 2007 by possemeeg
Situation: Web server that sends out mail. Configured with SMTP service for this purpose.
Problem 1: Some of emails being relayed by the local SMTP service were failing with “550 not local host gmail.com, not a gateway” (where gmail.com is the domain of the mail in this example). This was domain specific.
Problem 2: Some relay SMTP servers were refusing to take mail with a “greylist” warning. (They would work on subsequent tries).
Firstly, I made sure the “from” domain had valid ANAME Records. No result.
Then, I made sure the MX records of the “from” domain corresponded to the SMTP server. My logic was that the destination SMTP server was checking the MX record for the domain and failing when none in the list corresponded with the IP address that was trying to send it mail. No result. But I did get incoming mail on my pmgconnect.com and pmgconnect.co.uk domains to route through my web server (downside I had to open up POP3 port in the firewall).
Then I investigated and found that the SMTP server was getting a different MX record for the domain (in this case gmail.com) than any this MX record lookup tool gave me. As I was writing an email to the dedicated server host to tell them that something was fishy with their DNS lookup, I decided to check their site for the correct settings…
Yes, all this because I had the wrong DNS settings on my network connection. Probably in an email from the hosting company that I ignored. Well, it all works now.
I’ll watch the “greylist” problem but I suspect the MX record of the sending server may be responsible. Not sure. Could be because the emails being sent had no “from” as they were automaticlly forwarded error reports. Not only will I be getting far less of them, but thier destination domain pmgconnect.com, is now the local server so they just sit and wait for my POP3 pickup.
Posted in Network and Ops | Leave a Comment »
June 21, 2007 by possemeeg
Platform: Vista using VS 2005.
What You Need To Know About One-Way Calls, Callbacks, And Events
The downloadable sample shows different senarios including a good example of the publisher subscriber patten.
For the samples: SQL Server is needed. Windows Vista features to turn on: IIS (including IIS Metabase and IIS 6 configuration compatibility in IIS 6 management compatibility), WCF Microsoft .NET 3 Windows Comunication Foundation HTTP Activation and WCF Microsoft .NET 3 Windows Comunication Foundation Non-HTTP Activation.
Posted in .NET | Leave a Comment »
June 20, 2007 by possemeeg
This is assuming your COM object is a dual interface object (implements IDispatch).
1) Create a text file with a .js extension (eg: test.js)
2) Load the file into Visual Studio.
3) Put the following line at the top:
var arbiObj = new ActiveXObject("ArbiCOM.ArbiClassProx");
where “ArbiCOM.ArbiClassProx” is the prog id of your COM object.
4) VS will have intelisense (bellow type “arbiObj.” and your methods will be listed.
5) Go wild calling the methods. Example:
var arbiObj = new ActiveXObject("ArbiCOM.ArbiClassProx");
var ret="arbiObj.DoSomeStuff(20);<br">WScript.Echo("DoSomeStuff(20) returns " + ret);
ret = arbiObj.DoSomeStuff(19);
WScript.Echo("DoSomeStuff(19) returns " + ret);
6) To “run” your script. Just double click in explorer.
Posted in C++ | Leave a Comment »