Converting generic OopFactory.X12 structures to typed counterparts

OopFactory.X12 can parse EDI messages into segments and loops. However despite typed segments and loops exist, the parser does not generate them in the object model.  The unit test only use them when generating EDI messages.

The typed segments and loops are aggregative objects that do not contain their own data members besides the contained untyped objects. Which means if I replace the contained object with the generic one from the parser via .Net reflection, then I can access the object model in a typed way. So I created this in a static class

public static void SetFieldValue(this object obj, string name, object Value)
             // Set the flags so that private and public fields from instances will be found
             var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
             var field = obj.GetType().GetField(name, bindingFlags);
             field.SetValue(obj, Value);
public static T AsTypedSegment<T>(this OopFactory.X12.Parsing.Model.Segment segment)
             where T: OopFactory.X12.Parsing.Model.TypedSegment,new()

             if (segment == null) return null;
             T result = new T();
             result.SetFieldValue(“_segment”, segment);
             return result;
         public static T AsTypedLoop<T>(this OopFactory.X12.Parsing.Model.Loop loop)
             where T : OopFactory.X12.Parsing.Model.TypedLoop, new()

             if (loop == null) return null;
             T result = new T();
             result.SetFieldValue(“_loop”, loop);
             return result;

Then I use them to convert the generic segments and loops from the parser to typed ones. The example is for parsing a 835 file, for other types the loop numbers and segments may be different.

string fileText = System.IO.File.ReadAllText(fileName);
List<Interchange> envelopes = parser.ParseMultiple(fileText);
if (envelopes.Count == 0) return null;

var isa = envelopes[0];

var gs = isa.FunctionGroups.ElementAt(0);

var st = gs.Transactions[0];

var payerLoops = st.Loops.Where(l => l.Specification.LoopId.Equals(“1000A”));

var payerLoop = payerLoops.FirstOrDefault();
var payerName = payerLoop.AsTypedLoop<TypedLoopN1>().N102_Name;

var payerIdSegment = payerLoop.Segments
                     .Where(s => s.SegmentId.Equals(“REF”)
                         && s.GetElement(1).Equals(“2U”)).FirstOrDefault();
if (payerIdSegment != null)
          var payerId = payerIdSegment.AsTypedSegment<TypedSegmentREF>().REF02_ReferenceId;

var paymentLoops = st.Loops.Where(l => l.Specification.LoopId.Equals(“2000”));

foreach (var paymentLoop in paymentLoops)

        var claimPaymentInformationLoops = paymentLoop.Loops.
                         Where(l => l.Specification.LoopId.Equals(“2100”));

       foreach (var claimPaymentInformationLoop in claimPaymentInformationLoops)
                var mrnSegment = claimPaymentInformationLoop.Segments.Where
                           (s => s.SegmentId.Equals(“REF”) && s.GetElement(1).Equals(“EA”)).FirstOrDefault()
                  if (mrnSegment != null)
                             var patientMrn = mrnSegment.REF02_ReferenceId;

The library is written for 837, thus many types used in 835 like loop 2000 and segment CLP are not defined.

Posted in Uncategorized | Leave a comment

How To Determine When a Page Is Done Printing in WebBrowser Control

Note this post is originally written in 2012. It was lost when moving my web site from Windows Live Spaces to WordPress. I found a dead link to my web site on Stackoverflow and found an archive from So here it is the old article, with dead link updated of course.

The printing from a WebBrowser control can be customized by using custom headers and footers (, archived from or replacing the default print template. However, using such techniques conflicts with the PRINT_WAITFORCOMPLETION flag, which is used for synchronous printing.

Since Internet Explorer 6.0, the WebBrowser control raises the DWebBrowserEvents2::PrintTemplateTeardown event when a print template has been destroyed. If the printing involves a custom print template, this is a good indicator of print completion. You can create a event handler function in your application for this event to determin if a the WebBrowser control is finished printing a Web page.


The WebBrowser control launches another thread which hosts another MSHTML document which renders to the printer. When this thread is finished, if a custom print template is involved, the WebBrowser control destroys the print template and raises PrintTemplateTeardown event. This indicates that the WebBrowser control has completed printing the Web page.

If the default print template and the customization of headers and footers are desired, load the template from the source of IExplorer.exe, and use it as a custom template.

To translate the asynchronous printing to synchronous, a message loop need to be created (better if use with a timeout handler) .

BOOL PrintTemplateTeardownFired=FALSE;
//launch printing……
//loop until PrintTemplateTeardown is set to TRUE in the PrintTemplateTeardown event handler
MSG msg;
while (!PrintTemplateTeardownFired&&GetMessage(&msg, NULL, 0, 0) > 0)


Posted in Uncategorized | Leave a comment

Troubleshooting a memory leak

Got called into a memory leak troubleshooting. The application was leaking memory at 1mb per second. In memory profiler, most of the growing memory are used by byte[] and RuntimeMethodHandle (growing at around a million per minute). Initially I thought it is a disposing problem, but the memory occupied by disposable objects does not increase over time.

Looking at the RuntimeMethodHandle instances, I found that it is closely associated with DynamicResolver, whose instance count grows in a much smaller but steady rate. This leads me to kissdodog’s post Windbg + .Net .NET Memory Profiler 排查内存泄露 but kissdodog only located the problem but didn’t give a cause (some coworker got the blame and fixed it).

Then I want to see if there’s any GDI leak and added handle columns to task manager, surprisingly there’s a handle leak growing at 1/2 per second, but then there is no memory map in the code. Under Process Explorer’s handle view,  the leaking handles are revealed as user tokens, which is even more puzzling because the code doesn’t deal with windows logins. But at least this gives me some clear indicator to divide and conquer.

By commenting out portions of code (more like a human binary search) and watching Task Manager religiously, I found the issue is caused by creating XslCompiledTransform in a loop, something KB316775 cited as a design limitation that the dynamic assemblies can’t be unloaded. Obviously this isn’t fixed even in .Net 4.8. The KB was no longer published by Microsoft and I had to read it off a mirror.

Once the problem is located the fix is easy, making those XslCompiledTransform objects singleton solved the issue.

Posted in Uncategorized | Leave a comment

Icepocalypse 2021 冰狱 2021

this is my dairy about the winter storm occurred in Feb 2021.


Feb 13 Sat. 27-30F. Stockpile food (glad I did it). Heard ice building on roads, so instead I shopped on foot. Almost fell because of invisible ice.

2月13日周六 –3-1度。储粮(幸好我这么做了)。听说路上在结冰所以我走路去买菜。还是有看不见的冰,差点摔倒。

Feb 14 Sun. 12-30F Stay home. Freeze warning, keep water dropping. Listened to police radio for a while and heard nothing but crashes. Person is bleeding on Colorado Hills… that is why we advise everyone (to stay off road)…. several vehicles… we need a tow at…. some of the ten fours sound like sigh and two person exchanging (insurance) info was almost a relief. It snowed the night and sounded like raining cats and dogs.

2月14日周日 –11–1度。宅。冰冻警报,保持水龙头滴水。收听了一下警察的通话,基本上都是车祸。科罗拉多丘有人流血。这就是为什么我们建议所有人(不上路)——多辆车——我们这里需要拖车——很多10-4(警用代码,意即收到)听起来像叹气。两个人交换(保险)信息几乎是好消息。晚上下雪的声音听起来像冰雹。

Feb 15 Mon 10-27F. Snow. Wake up by UPS beeps. Turned it off and woke up again by chilling. Realized the power outage could last for a while, announced my unavailability to coworkers. Then saw this outside

2月15日周一 –13–5度。下雪。被不间断电源吵醒。关掉之后回笼觉,又被冻醒。意识到停电可能会很久,通知同事我一时半会不能上班。然后看到外面是这样


Went out for some warm food. Big mistake. 4-10 inches of snow and sometimes step on curbs. Wandering dogs. HEB and everything else closed. No cell signals most of the way. Good that almost nobody is driving and for the rest they drive really slow. And snow blindness is a thing.



Power briefly went back for about an hour after 3pm. but that is just enough for cooking and charging power banks.



Feb 16 Tue 6-25F. Cloudy. Room temperature dropped so much that my dog was crying. So took her to the warmest place in the room.

2月16日周二 –13–4度。多云。室温降到狗狗都在哭了,所以把她移动到房间里最温暖的地方。


and dress her with a cut rice bag



Power back again after 3pm for 40 minutes. Cooked and charged.


Started refreshing ERCOT web site. The 60KMW goal was never reached, only briefly touched 50KMW.

开始刷德州电力可靠委员会(ERCOT )网站。60吉瓦的恢复目标当天没达到,仅仅短暂地达到了50吉瓦

Feb 17 Wed. 23-32F. Snow. From the ERCOT report, the grid almost crashed in the morning with almost no margin between generation and load. Generation picked up in the afternoon to 55KMW but power didn’t come back at all today. Did some cleanup, help neighbor and got helped by a neighbor with a hammer.



Pipe started to burst everywhere and I lost water today.


Feb 18 Thu. 19-32F. Snow. Slept up early yesterday and woke up at 1am. Then saw this:



Brightest night in years.


Power went back on around 2 am. The ERCOT price map is almost green now, with a small deep blue spot indicating negative power prices near Houston. But without water I can no longer cook. Decided to get some water from HEB. My car was actually frozen up like this



So I decided to take a bus which is running for the first time since Monday. The trees along the way are down by the snowstorm:



They looked like this in the summer



On the way there was a pond



I wonder where the ducks went. And this was the pond in the summer



At HEB there’s a long line… and thick ice.



Someone actually fell and one helping on the left almost fell too when running over.



Got in after an hour of waiting in line. Unfortunately there was no waster or milk on the shelf. Settled for some juice and soymilk.


Icicle fell off and scared a bus rider. But it is a good sign that ice was melting.


My apartment offered its pool water for toilet use. Nice for them.


ERCOT reports 60KMW generation for the first time and the price map is sky blue, means everything normal again.


Posted in Uncategorized | Leave a comment



用了Process Monitor跟踪了一下,发现每次切换中英文的时候,微软拼音都会在%appdata%\Microsoft\InputMethod\Chs下面创建一个名字为UDPXXXX(这里XXXX是16进制数字).tmp的文件,我这个目录下有六万五千多个这样的文件。从命名风格来看,很明显是在调用GetTempFileName,而这个函数有65535个文件的限制,不删除文件的话,第65536次调用会失败,应该是微软拼音没有处理好调用这个函数失败的情况,也没有删除临时文件的代码,就卡住了。


del %appdata%\Microsoft\InputMethod\Chs\*.tmp /q



Posted in Uncategorized | Leave a comment

Today’s fake email of the day

Today’s fake email of the day

Hi Dear,

How are you doing hope you are fine and OK?

I was just going through the Internet search when I found your email address


So you care about an article titled “
Trap CtrlAltDel; Hide Application in Task List on Win2000/XP” in 2020 and downloaded its source code, but still don’t know my name?

Also when I read the message header (it is called view source in hotmail or view original in gmail)
From: Lisa Williams
X-Mailer: WebService/1.1.16718 YMailNodin Mozilla/5.0 (Windows NT 6.1; rv:81.0) Gecko/20100101 Firefox/81.0
Content-Length: 572
X-IncomingHeaderCount: 14
To: Undisclosed recipients:;

So this is a bulk mail, I am BCCed. Kinda strange to do for a letter that express love interest. But Kudos to keep your Firefox version up to date! Although the scammer can lie here too if wanted to just like everywhere else, there is nothing really beneficial to say you mailed it from Microsoft Outlook Express.

Also in the mail header:

Received-SPF: SoftFail ( domain of transitioning discourages use of as permitted sender)

I wonder why…

Posted in Uncategorized | Leave a comment

Finding the right ruby version

I am installing eHMP on Centos 7. Centos 7 has ruby 2.0 out of box, thus the install

chef-client -o workstation –config ~/Projects/vistacore/.chef/knife.rb

fails with

rb-notify version 0.10.0 needs Ruby 2.2.2 or newer

Following the instructions at I got ruby 2.7 installed. However

sudo chef-client -o workstation –config ~/Projects/vistacore/.chef/knife.rb

fails with the same error.


ruby –version

shows that rvm has no effect on sudo. I am still running the script against Ruby 2.0

Supposedly I can sudo and install rvm there, but rvm complained and suggested me to use rvmsudo instead. Then I tried it, rvmsudo doesn’t carry over my environment, even $HOME, thus the script still fails.

After searching for awhile I found a walkaround

rvmsudo bash -c “HOME=$HOME; exec bash” chef-client -o workstation –config ~/Projects/vistacore/.chef/knife.rb

This gets the home directory passed to the script, now the script is complaining

STDERR: ERROR:  While executing gem … (OptionParser::InvalidOption) invalid option: –no-rdoc

The script was pretty old, I know. I have no time to fix the script, so I need to downgrade the ruby version. After testing for each version I settled for 2.3.

rvm install 2.3

rvm use 2.3 –default

sudo gem update –system 2.3

Now the script runs successfully.

Posted in eHMP | Tagged | Leave a comment

Fix sphinxcontrib-googleanalytics on Sphinx 1.8

The Google Analytics extension from

python -m pip install  sphinxcontrib-googleanalytics

does not work on Sphinx 1.8. When I run it, I get the following error

Could not import extension sphinxcontrib.googleanalytics (exception: cannot import name ‘ExtensionError’ from ‘sphinx.application’ (c:\python37\lib\site-packages\sphinx\

Fix is to change C:\Python37\Lib\site-packages\sphinxcontrib\ Line 4


from sphinx.application import ExtensionError


from sphinx.errors import ExtensionError

After that I get another warning

WARNING: extension ‘sphinxcontrib.googleanalytics’ returned an unsupported object from its setup() function; it should return None or a metadata dictionary

Fix is to change the last line from

return app


return {‘version’: ‘0.1’}

Posted in Uncategorized | Leave a comment

Blinking wifi icon and black screen on Surface 2

This is the second time I run into this problem after a Windows Update. First time was halfway through last year’s Microsoft MVP Summit and I had to Remote Desktop to my home machine with a spare android tablet and Bluetooth keyboard/mouse to get access to Windows apps.  Good that the summit wifi was amazing but a Surface 2 with touch cover was way easier to carry around than the combination of tablet/keyboard/mouse.

I got around the problem by manually uninstalling  KB3033055 with dism remove package in recovery console command prompt and hide the update afterwards. But recently I got the black screen with blinking wifi icon, again after installing a bunch of Windows Updates.  So it probably has multiple causes.

Anyway this is my way to get update working as of July 2018:

1 factory reset

2 go through initial setup (wifi, microsoft account etc)

3 search for update, this would take a while

4 uncheck everything, only install the 2015 firmware update.

5 turn wifi off, reboot.

6 download kb2919355, KB3173424, KB3172614 and KB3097667 on another machine (you need the ARM edition of those updates, not x86 or x64 so the file names should contain arm) to a usb drive.

7 install in the order of kb2919355, KB3173424, KB3172614 and KB3097667 from usb drive, reboot

8 turn wifi back on and search for updates.

9 install remaining updates and reboot

Microsoft says August 14, 2018—KB4343898 (Monthly Rollup) fixes an issue with KB3033055 which has the same syndrome. Not sure if this has anything to do with KB3097667. Hopefully this is the end of black screen with blinking wifi icon for Surface owners.

Posted in Uncategorized | Leave a comment


用户AcmeContracted安装masm32失败,所以想知道是否能集成masm64到Visual Studio 2017中


安装完之后创建个C++的Win32命令项目,然后在解决方案浏览器里选中项目节点,右键,选择Build Dependencies->Build Customisations,在弹出的对话框里选中masm,然后选择OK。这会使得你的项目里的新asm文件使用ml或者ml64编译(具体使用哪个取决于你的项目当前编译配置是32位还是64位)。

另外VS里面新建文件的选择里没有asm文件的模板,随便选个纯文本格式(.h,cpp,.txt,.html都行)的来替代,建完了把扩展名改成asm,然后在解决方案浏览器里右键点文件打开文件属性对话框,把项目类型改成Microsoft Macro Assembler。确定之后这个文件就会用masm来编译了,可以重新打开文件属性对话框检查编译时使用的命令行。


Posted in Uncategorized | Leave a comment