<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>KoroIRC Developer Blog</title>
	<atom:link href="http://blog.koroirc.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.koroirc.com</link>
	<description>Thoughts while coding.</description>
	<lastBuildDate>Tue, 06 Jul 2010 13:30:53 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>What to expect from KoroIRC 0.4</title>
		<link>http://blog.koroirc.com/2009/01/what-to-expect-from-koroirc-0-4/</link>
		<comments>http://blog.koroirc.com/2009/01/what-to-expect-from-koroirc-0-4/#comments</comments>
		<pubDate>Thu, 15 Jan 2009 12:07:01 +0000</pubDate>
		<dc:creator>Koro</dc:creator>
				<category><![CDATA[KoroIRC]]></category>

		<guid isPermaLink="false">http://blog.koroirc.com/?p=64</guid>
		<description><![CDATA[Since I started this blog, which was kind of supposed to be the KoroIRC developer blog, I went on many ramblings about random stuff, but never actually took the time to talk about the main subject. This is what I do today.
Changes in this version
Here I will talk a little about what will change and [...]]]></description>
			<content:encoded><![CDATA[<p>Since I started this blog, which was kind of supposed to be the <i>KoroIRC</i> developer blog, I went on many ramblings about random stuff, but never actually took the time to talk about the main subject. This is what I do today.</p>
<h3>Changes in this version</h3>
<p>Here I will talk a little about what will change and what will not.</p>
<h4>Modularity</h4>
<p>In version 0.3, the source code of the main executable contained about three big categories of code:</p>
<ol>
<li><b>User interface code:</b> This is the code that manages the windows, switchbar, pane, all the settings dialogs, etc. Everything you can see or interact with is here.</li>
<li><b>IRC code:</b> This is what manages the actual connections, parses the protocol and notifies the user interface. Also, all CTCP, DCC and Identity management is here.</li>
<li><b>Helper and &#8220;glue&#8221; code:</b>This is all the code that does common tasks. Initialization, custom memory management, string parsing, threads, etc. This part was very big.</li>
</ol>
<p>Of course, all of it was compiled into a giant monolithic executable that has everything embedded in it. Therefore, the goal for this version is to try and make KoroIRC 0.4 more modular.</p>
<p>In order to achieve this goal, the main executable code has been split into many parts. First, all the common code has been made into a new library, <code>kirccore.dll</code>. This also allows the other executables and DLLs to reuse that code too, reducing them in code size. Most of the extraneous functions of KoroIRC are in the process of being moved to plugins (<code>.kpl</code> files), with <code>kircapi.dll</code> as their &#8220;call gate&#8221; into the main executable code. As such, it is possible to have a super minimalist, no-frills KoroIRC installation in only three files:</p>
<ul>
<li><code>KoroIRC.exe</code></li>
<li><code>kirccore.dll</code></li>
<li><code><a href="http://www.korosoft.net/projects/tdemu/">TDEmu.dll</a></code></li>
</ul>
<p>I shall also take the occasion to mention that KoroIRC can be used as a <a href="http://portableapps.com/">portable application</a> since its very birth. The installer is provided merely as a convenience. If KoroIRC finds an INI file in the same folder as itself, it will use it for loading/saving settings.</p>
<h4>Operating system requirements</h4>
<p>In version 0.3, I had three separate builds to maintain: an Unicode build, an ANSI build and an x64 build. This was all magically hidden to the user by the installer, which automatically installed the right one.</p>
<p>Back in 2005, when I started version 0.3, I still knew a bunch of people stuck with old computers, still on Windows 98. So it was only natural to support these old operating systems, since they were still used. However, having to support them often meant a lot of glue code, such as loading stuff with <code>LoadLibrary</code> / <code>GetProcAddress</code> and having an &#8220;alternate code path&#8221; if the functionality was not present. This increased code size and complexity a lot, and limited my choice of APIs to use.</p>
<p>Thankfully, these days everybody uses Windows XP or Windows Vista now, so I think it is safe to remove support for the old operating systems. So version 0.4 will only support Windows 2000 and higher, and the code is being cleaned of old code paths. A good example of this is in the updater code, where I could just stick a call to <code>CheckTokenMembership</code> &mdash; which is only available starting with Windows 2000 &mdash; instead of having to manually loop through the groups in the token.</p>
<h4>User interface changes</h4>
<p>There won&#8217;t be much major user interface changes for this version. But there is one thing worthy of noting. I&#8217;m currently in the process of replacing all message boxes with much more user-friendlier <a href="http://msdn.microsoft.com/en-us/library/bb760441(VS.85).aspx">task dialogs</a> instead. The very cool thing is that <a href="http://www.korosoft.net/projects/tdemu/">it works in Windows 2000 and Windows XP too</a>! And, since I&#8217;m doing that, I&#8217;ve also started using string table resources.</p>
<p>Also, I&#8217;m working hard in order to have High-DPI support. KoroIRC 0.3 only had that partially, which is why the executable wasn&#8217;t marked as &#8220;DPI-aware&#8221; under Windows Vista. I&#8217;m working hard to remove all remaining hardcoded sizes (which are often for bitmaps or icons) and making sure everything scales well no matter the size. Also, this is an area I&#8217;m dogfooding much, as I myself run at 120DPI on my new LCD monitor.</p>
<p>Also, for all those who complained that it was imposible to hide the lower pane, this version won&#8217;t have the possibility to hide it either, sorry. However, know that I heard you and that it is definitely planned for the following version, along with a slew of other user interface changes.</p>
<h4>Tools</h4>
<p>I have also added my own crash reporter. Yeah, I know this reeks of <a href="http://en.wikipedia.org/wiki/Not_Invented_Here">NIH</a>, especially when Microsoft has <a href="http://www.microsoft.com/whdc/maintain/StartWER.mspx">Windows Error Reporting</a>, but there are hard entry conditions on WER, and also my own crash reporting tool allows to collect additional information from the user before sending the dump file.</p>
<p>I have also added a &#8220;Files&#8221; pane as an optional plugin, which is merely an embedding of a shell folder right into the lower pane. It is very useful to be able to drag and drop files to send them to somebody real fast, without having to switch windows.</p>
<p>I plan to redo the user interface of the DCC Information Tool. For those who didn&#8217;t know, every time you receive a file by DCC, KoroIRC stores additional information from the DCC into an alternate data stream of the file. This tool allows you to see that stored information.</p>
<h3>Status</h3>
<p>I have much done, enough to say that KoroIRC 0.4 is already significantly different from version 0.3. However, there is still much work to be done in all areas, so I&#8217;d say it&#8217;s at about 50% done.</p>
<h3>Why is development so slow?</h3>
<p>The short answer is: because I&#8217;m not paid to do it. The long answer is that coding is an activity best done at night, and also needs long times of having nothing to do in order to be properly set in motion.</p>
<p>Thing is, with school and work being much more demanding than before, I simply do not have as much free time as I&#8217;d like to, and when I get some, I don&#8217;t necessarily feel like coding much. Back in 2004, I had whole months free, with nothing better to do than sleeping in the day and coding in the night, and thus KoroIRC 0.2 was born in about four months of concentrated efforts.</p>
<p>Sadly, this is not the case anymore, and sometimes months can pass without me writing a single line of code on KoroIRC. This is why it takes so much time to release new versions now.</p>
<p></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.koroirc.com/2009/01/what-to-expect-from-koroirc-0-4/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>How to bring back regular window captions in Windows Live Messenger 9</title>
		<link>http://blog.koroirc.com/2009/01/how-to-bring-back-regular-window-captions-in-windows-live-messenger-9/</link>
		<comments>http://blog.koroirc.com/2009/01/how-to-bring-back-regular-window-captions-in-windows-live-messenger-9/#comments</comments>
		<pubDate>Wed, 14 Jan 2009 17:27:54 +0000</pubDate>
		<dc:creator>Koro</dc:creator>
				<category><![CDATA[Reverse Engineering]]></category>

		<guid isPermaLink="false">http://blog.koroirc.com/?p=63</guid>
		<description><![CDATA[I hate skinned applications. Hate them, with a burning passion. The only thing I hate more are skinned applications that &#8220;try&#8221; to look native but spectacularly fail on anything else but the default theme.
Now, it ain&#8217;t so bad when applications restrict that to their client area. It is still useless and disrespectful of my settings, [...]]]></description>
			<content:encoded><![CDATA[<p>I hate skinned applications. Hate them, with a burning passion. The only thing I hate more are skinned applications that &#8220;try&#8221; to look native but spectacularly fail on anything else but the default theme.</p>
<p>Now, it ain&#8217;t so bad when applications restrict that to their client area. It is still useless and disrespectful of my settings, but at least it&#8217;s contained. But more and more apps take bolder steps at spitting in the face of my settings — hint: I set them that way <i>for a reason</i>, because I like it that way — and, sadly, Microsoft is no exception to this.</p>
<p>Windows Live Messenger is a big culprit in this case. Up until Wave 3, even though it defaulted to using custom window captions, a simple &#8220;Show the menu bar&#8221; would bring the regular ones back. But, as it seems to be the fashion these days, that possibility was <b>removed</b>. That, and they also now impose ClearType usage, even if you explicitly disabled it. Not that important now, since LCD screens are everywhere, but <a href="/blogdata/old_crt_monitor.jpg">my old CRT monitor</a> only broke 6 months ago.</p>
<p>But if you played a little with WLM9, you notice it reverts to regular window captions in certain cases, like if you maximize a window. A little poking around in WinDbg quickly shows that it&#8217;s just using window regions to do its bidding. That, along with a friend that showed me that under Aero Glass, it actually just lets the window manager do its job and uses regular captions, was more than enough to tip me off that something could be done very easily about this problem.</p>
<p>My first try was to try and block the <code>SetWindowRgn</code> call outright. I basically overwrite the code for that function in the process&#8217; memory with the assembly equivalent of this:</p>
<blockquote><pre>
int HookSetWindowRgn(HWND hWnd, HRGN hRgn, BOOL bRedraw)
{
    if (hRgn)
        DeleteObject(hRgn);
    return 1;
}
</pre>
</blockquote>
<p>There are multiple problems with this approach. First, since WLM hides the whole caption and window borders, it has to handle <code>WM_NCHITTEST</code> in order to allow window resizing from within its client area. Since it also still thinks the caption and borders are hidden, it does not handle these cases, and as such, returns <code>HTBOTTOM</code> when the cursor is on the window caption. Also, the theming system in <code>UxTheme.dll</code> also calls this function &mdash; why it does not call <code>NtUserSetWindowRgn</code> directly is beyond me &mdash; in order to have those round window corners, and this &#8220;fix&#8221; disables that too.</p>
<p>My second and final solution came upon noticing that when WLM itself decides to show these captions, they work properly, and also the pseudo-caption inside the client area disapprears, too. If there was a way to trick WLM into thinking one of the &#8220;show the caption&#8221; conditions is met, it would by itself comply and show it without additional work. I first tried to hook the <code>IsZoomed</code> function directly to make it always return <code>TRUE</code>, but again it caused problems with <code>UxTheme.dll</code>.</p>
<p>I started by looking for calls to <code>SetWindowRgn</code> in all of WLM&#8217;s binaries. One of these files is <code>UxCore.dll</code>. Now, the fun part with exporting C++ classes or functions directly with <code>__declspec(dllexport)</code> is that all the decorated names are kept intact, which is <i>very</i> handy for reverse engineering like this since they contain full parameters and return type information. It did not take much time to find the <code>UXFramelessManager</code> class, which is responsible for hiding or showing the window caption, and handling everything that is associated with it. That class has a method called <code>UpdateFrame</code>, which does the work of determining if a window region needs to be set, and setting or clearing it as needed.</p>
<p>The <code>UpdateFrame</code> method checks that at least one of these three conditions is met:</p>
<ul>
<li>The window is maximized</li>
<li>Aero Glass is enabled</li>
<li>High Contrast Mode is enabled</li>
</ul>
<p>If that is the case, it will set a <code>NULL</code> region for the window and not do any custom handling of the <code>WM_NCHITTEST</code> message. So, I figured, let&#8217;s make it think the window is always maximized! The code that does this check is:</p>
<blockquote><pre>
7033e028  push  dword ptr [esi+8]
7033e02b  shr   eax,13h
7033e02e  and   al,1
7033e030  mov   byte ptr [ebp-1],al
7033e033  call  dword ptr [__imp__IsZoomed@4]
</pre>
</blockquote>
<p>The instruction at <code>7033e028</code> pushes the <code>HWND</code> of the window on the stack. The next three instructions are interleaved code that does something else, probably due to agressive compiler optimization settings, then the call is done at <code>7033e033</code>. So all we need to do is to change the code to just always assume <code>IsZoomed</code> returned <code>TRUE</code>, padding as appropriate with <code>NOP</code>s:</p>
<blockquote><pre>
7033e028  nop
7033e029  nop
7033e02a  nop
7033e02b  shr   eax,13h
7033e02e  and   al,1
7033e030  mov   byte ptr [ebp-1],al
7033e033  mov   eax,1
7033e038  nop
</pre>
</blockquote>
<p>All that was needed was to patch that new stream of instructions at the right file offset in <code>UxCore.dll</code>:</p>
<blockquote><p><code>0003D428 -> 90 90 90 C1 E8 13 24 01 88 45 FF B8 01 00 00 00 90</code></p></blockquote>
<p>Upon starting WLM, I had my window captions indeed:</p>
<p><a href="/blogdata/wlm9_conversation_with_frame.png"><img src="/blogdata/wlm9_conversation_with_frame_preview.png" width="410" height="150" alt="WLM9 conversation window with regular window caption" /></a></p>
<p>(Yes, I went back to Windows Classic, despite my <a href="/2008/08/three-good-black-uxtheme-skins/">claims to the contrary</a>.)</p>
<p>There is still a bug with this though. It it not apparent under Windows Classic, but <code>UxTheme.dll</code> causes problems again, albeit a minor one this time. Basically, <code>UpdateFrame</code> will still call <code>SetWindowRgn</code> on window creation with a <code>NULL</code> region, clearing the one set by <code>UxTheme.dll</code>. This is the code that does it:</p>
<blockquote><pre>
7033e141  push   1
7033e143  push   ebx
7033e144  push   dword ptr [esi+8]
7033e147  call   dword ptr [__imp__SetWindowRgn@12]
</pre>
</blockquote>
<p>Note that <code>EBX</code> is zeroed out at the beginning of the function, so this code is the equivalent of:</p>
<blockquote><pre>
SetWindowRgn(m_hWnd,NULL,TRUE);
</pre>
</blockquote>
<p>All we have to do is to replace that whole code sequence with <code>NOP</code>s again. I won&#8217;t present the code here, but directly the bytes to patch in the file:</p>
<blockquote><p><code>0003D541 -> 90 90 90 90 90 90 90 90 90 90 90 90</code></p></blockquote>
<p>Once this is patched, WLM will have regular window captions, with no glitch (that I found yet). It is sad though, that I had to resort to patching code for such a trivial matter, especially that older versions of WLM allowed this, so they actually had to <b>remove</b> code to make it not-work&#8230;</p>
<p>All code addresses and listings comes from <code>UxCore.dll</code> version 14.0.8050.1202 in the WLM installation directory. Make sure you have that exact same version before patching the file, of course.</p>
<p><b>Update</b>: This also works with <code>UxCore.dll</code> version 14.0.8064.206, as none of the offsets have changed.</p>
<p></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.koroirc.com/2009/01/how-to-bring-back-regular-window-captions-in-windows-live-messenger-9/feed/</wfw:commentRss>
		<slash:comments>24</slash:comments>
		</item>
		<item>
		<title>Getting around the manifest check in the C Runtime DLL</title>
		<link>http://blog.koroirc.com/2008/09/getting-around-the-manifest-check-in-the-c-runtime-dll/</link>
		<comments>http://blog.koroirc.com/2008/09/getting-around-the-manifest-check-in-the-c-runtime-dll/#comments</comments>
		<pubDate>Tue, 23 Sep 2008 20:47:33 +0000</pubDate>
		<dc:creator>Koro</dc:creator>
				<category><![CDATA[Reverse Engineering]]></category>

		<guid isPermaLink="false">http://blog.koroirc.com/?p=62</guid>
		<description><![CDATA[Today&#8217;s article is again about my &#8220;archnemesis&#8221;, the Visual Studio 2005/2008 CRT. As I mentioned in a previous article, this CRT will refuse to load if it&#8217;s not loaded with a manifest, and today I document how it checks that, and then, how to bypass it. This can be very useful, for example, to get [...]]]></description>
			<content:encoded><![CDATA[<p>Today&#8217;s article is again about my &#8220;archnemesis&#8221;, the Visual Studio 2005/2008 CRT. As I mentioned in a <a href="/2008/06/visual-cpp-woes/">previous article</a>, this CRT will refuse to load if it&#8217;s not loaded with a manifest, and today I document how it checks that, and then, how to bypass it. This can be very useful, for example, to get MSVCR80.DLL to load under WINE.</p>
<p>The core of the manifest checking is in the <code>_check_manifest</code> function, which is located in <code>crtlib.c</code> in the CRT source. As the name suggests, this code is only linked in when compiling a DLL version of the CRT.</p>
<p>Here is what the code does:</p>
<ol>
<li>First, it checks for the presence of the <code>FindActCtxSectionStringW</code> function in <code>KERNEL32.DLL</code>. If this step fails (i.e. <code>GetProcAddress</code> returns <code>NULL</code>), then it assumes that the OS it&#8217;s running on does not support Fusion, and returns with success.</li>
<li>Then, it checks if both of <code>MSCOREE.DLL</code> and <code>PGORT90.DLL</code> are loaded in the process&#8217; address space, and if yes, assumes it was loaded for instrumentation and returns success.</li>
<li>It then retrieves the path of where it was loaded and of the <code>system32</code> directory.</li>
<li>When the paths are retrieved, it checks explicitly that it wasn&#8217;t loaded from <code>system32</code>. If it was loaded from there, it immediately returns a failure.</li>
<li>Then, it checks the current activation context with <code>FindActCtxSectionString</code> to check if it was referenced in the manifest. If that isn&#8217;t the case, it returns a failure.</li>
<li>It then makes sure it was loaded from under the <code>WinSxS</code> folder in the Windows directory by doing a string compare of that path and its own path. If that is the case, it returns with success.</li>
<li>This last check happens only if the previous check failed. It will try to find a file called <code>Microsoft.VC80.CRT.manifest</code> (or <code>Microsoft.VC80.DebugCRT.manifest</code> if it&#8217;s the debug version) in the same folder from which it was loaded, and if found, will return success.</li>
<li>If it comes here, it assumes that it was wrongfully loaded and returns a failure.
</li>
</ol>
<p>Note that over the course of these checks, it uses multiple fixed-size string buffers. The one that is used to retrive the path of the Windows and the <code>system32</code> directories is <code>MAX_PATH</code> in size, whereas the others are 8000 characters in size. If any of these buffers overflow at any time, it will just bail out of the checks and return success.</p>
<p>Also, WINE does have an implementation of activation contexts, found <a href="http://source.winehq.org/source/dlls/kernel32/actctx.c">here</a> (<code>KERNEL32</code> wrappers) and <a href="http://source.winehq.org/source/dlls/ntdll/actctx.c">here</a> (actual implementation in <code>NTDLL</code>). Except for some reason, it fails to go grab <code>MSVCR80.DLL</code> from the <code>WinSxS</code> directory, instead returning with status 0xc0000135. It&#8217;s not that the functionality is not there however, as a quick look into WINE&#8217;s source (in <a href="http://source.winehq.org/source/dlls/ntdll/loader.c"><code>loader.c</code></a> to be exact) shows a neat little function called <code>find_actctx_dll</code> that gets called from <code>find_dll_file</code>.</p>
<p>So, now that you understand how it works, the solution to bypass it becomes very simple.</p>
<p>You can take the long route and recompile your own version of the CRT with the <code>_check_manifest</code> function dummyfied. A quick look at some installed apps on my computer shows that a few apps do it. Firefox has its <code>MOZCRT19.DLL</code> and Winamp has <code>NSCRT.DLL</code>, although the latter is an older version of the CRT.</p>
<p>The previous solution is quite complicated for such a simple detail. Also, if you wish to redistribute the DLL with your application, you have to name it something else than <code>MSVCR80.DLL</code>. So you still have to redistribute it even if you got rid of the manifest check.</p>
<p>Follow me here for a <i>much</i> quickier-and-dirtier hack. Basically, you just have to patch 5 bytes in the DLL file to disable the manifest checking. <b>Disclaimer: I don&#8217;t think the EULA allows you to do that, and it would not be a good idea to redistribute those patched DLLs. Do it at your own risk.</b></p>
<p>I have tested with versions 8.0.50727.1433 and 8.0.50727.3053 of <code>MSVCR80.DLL</code> and it worked well. After that, I was able to drop them into my <code>system32</code> directory in a WINE install and they would work flawlessly. So, you need to patch the following bytes at the following file offset:</p>
<blockquote><p><code>00001D76 -> B8 01 00 00 00 C3</code></p></blockquote>
<p>This effectively turns the content of the <code>_check_manifest</code> function into nothing more than a <code>return TRUE</code>.</p>
<p>I hope that this goes to show again that using manifests for the CRT was a <i>really bad</i> idea. It just pushes more people to either statically link to it, compile their own or try to find another way to get over that restriction, all of which are not really beneficial in the long term. It defeats the purpose of DLLs, which was to share code between processes.</p>
<p></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.koroirc.com/2008/09/getting-around-the-manifest-check-in-the-c-runtime-dll/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Trimming executables Part 1: Getting rid of the C runtime</title>
		<link>http://blog.koroirc.com/2008/09/trimming-executables-part-1-getting-rid-of-the-c-runtime/</link>
		<comments>http://blog.koroirc.com/2008/09/trimming-executables-part-1-getting-rid-of-the-c-runtime/#comments</comments>
		<pubDate>Tue, 09 Sep 2008 21:52:20 +0000</pubDate>
		<dc:creator>Koro</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://blog.koroirc.com/?p=32</guid>
		<description><![CDATA[In a previous post I mentioned my problems with the Visual C Runtimes past version 6.0. This post is post 1 of n, with n having a high probability of being 2, on how to trim executable / download size. I will explain how to get rid of the beast that is the CRT, while [...]]]></description>
			<content:encoded><![CDATA[<p>In a <a href="/2008/06/visual-cpp-woes/">previous post</a> I mentioned my problems with the Visual C Runtimes past version 6.0. This post is post 1 of <i>n</i>, with <i>n</i> having a high probability of being 2, on how to trim executable / download size. I will explain how to get rid of the beast that is the CRT, while retaining functionality.</p>
<h3>The simplest way: Don&#8217;t use it altogether</h3>
<p>For a very small project, most of the time, the only reason you actually use the CRT, is because you don&#8217;t know that you can <i>not</i> use it. But you can tell the compiler that you don&#8217;t want it, and here&#8217;s how.</p>
<p>The first thing to do is to turn on the <code>/Zl</code> (omit default library names) compiler option in your project / makefile. I find this cleaner than using the <code>/NODEFAULTLIB</code> linker option, because it only affects the CRT default libraries. Anyway, at this point, you&#8217;ve already done it, the CRT will not be linked anymore in your binary.</p>
<p>But suddenly, your project will not link anymore. One of the first reasons for that is because the CRT inserts its own entry point and the linker expects to find it, but since you have removed the CRT you&#8217;ll have to supply your own versions of these. Hopefully, the names of the entry points don&#8217;t change much, it&#8217;s just a matter of picking the right one:</p>
<blockquote><pre>
// __DllMainCRTStartup@12
extern "C" BOOL WINAPI _DllMainCRTStartup(HINSTANCE, DWORD, LPVOID);
// _WinMainCRTStartup
extern "C" __declspec(noreturn) void __cdecl WinMainCRTStartup(void);
// _mainCRTStartup
extern "C" __declspec(noreturn) void _cdecl mainCRTStartup(void);
</pre>
</blockquote>
<p>You&#8217;ll instantly notice that the <code>WinMain</code> and <code>main</code> entry points are declared with <code>__declspec(noreturn)</code> and have a <code>void</code> return type. That is not totally true. You <i>can</i> return from that function, at least in Windows NT, and <code>BaseProcessStart</code> will happily terminate the thread. But <b>only</b> the thread. That is why I prefer to end these functions with a call to <code>ExitProcess</code> instead.</p>
<p>As for the <code>DllMain</code> entry points, there is a big probability that it won&#8217;t be needed. The CRT absolutely needs it to do some initialization, but if you&#8217;re like me, and try to do as little as possible in this function, you probably just have a call to <code>DisableThreadLibraryCalls</code> and then return <code>TRUE</code>. If that is the case, you can use the <code>/NOENTRY</code> linker option, which will link the DLL with no entry point at all.</p>
<p>Next, you will encounter linking errors because several &#8220;special&#8221; CRT symbols are referenced by code that is added by the compiler. Hopefully, these are easy to weed out:</p>
<table>
<thead>
<tr>
<th>Symbol reference</th>
<th>How to get rid of it</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>___security_cookie</code><br />
<code>@__security_check_cookie@4</code>
</td>
<td>Setting the <code>/GS-</code> compiler option. (VS: set &#8220;Buffer Security Check&#8221; to No)</td>
</tr>
<tr>
<td>
<code>@_RTC_CheckStackVars@8</code><br />
<code>__RTC_CheckEsp</code><br />
<code>__RTC_Shutdown</code><br />
<code>__RTC_InitBase</code>
</td>
<td>Removing all the <code>/RTC<i>xx</i></code> compiler option. (VS: set &#8220;Basic Runtime Checks&#8221; to Default)</td>
</tr>
<tr>
<td>
<code>__chkstk</code>
</td>
<td>Not using more than 4k of stack variables.</td>
</tr>
<tr>
<td>
<code>_memset</code><br />
<code>_memcpy</code>
</td>
<td>Not using the assignment operator to initialize structs inside functions, or to copy between structs.</td>
</tr>
</tbody>
</table>
<p>Note that is you are doing operations on <code>__int64</code>&#8217;s or using structured exception handlers (SEH), you <b>will</b> need the CRT. More on this later.</p>
<p>The last part on getting rid of the CRT is to replace CRT calls to equivalent API calls. I have put together a quick little table mapping the must used functions:</p>
<table>
<thead>
<tr>
<th>CRT function</th>
<th>Win32 API function</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>str<i>xxx</i></code></td>
<td><code>lstr<i>xxx</i></code></td>
</tr>
<tr>
<td><code>sprintf</code></td>
<td><code>wsprintf</code></td>
</tr>
<tr>
<td><code>vsprintf</code></td>
<td><code>wvsprintf</code></td>
</tr>
<tr>
<td><code>malloc</code></td>
<td><code>HeapAlloc</code></td>
</tr>
<tr>
<td><code>realloc</code></td>
<td><code>HeapReAlloc</code></td>
</tr>
<tr>
<td><code>free</code></td>
<td><code>HeapFree</code></td>
</tr>
</tbody>
</table>
<p>I&#8217;m not going to list every function out there, but the point is, for the most simplistic functions of the CRT, there is often a straightforward Win32 API equivalent. When there is not, it is usually simple to code one (such as <code>atol</code>). But, as you can see, as soon as the project grows a little, it becomes quickly unusable in practice.</p>
<p>Also, note that <code>wsprintf</code> and <code>wvsprintf</code> <a href="http://blogs.msdn.com/oldnewthing/archive/2008/03/10/8080067.aspx">do not support floating point</a>.</p>
<h3>The fraught-with-peril way: Use it a little.</h3>
<p>The problem with the CRT is the lengthy initialization code it adds to an EXE, even when linked dynamically. It seems to want to call every <code>KERNEL32</code> API under the sun, even if in the end you will just use it for a string compare or two.</p>
<p>But sometimes you absolutely need to link in some stand-alone code from the CRT, such as the <code>__int64</code> support code (<code>__<i>x</i>llmul</code> and <code>__<i>x</i>lldiv</code>, respectively). One quick way is to skip the initialization code by redirecting the entry point with the <code>/ENTRY</code> linker option. That way, execution starts right to your code, and (in your release build at least) the CRT initialization code won&#8217;t be linked in at all.</p>
<p>I have to take a break and post a disclaimer here: <b>skipping the CRT initialization code is dangerous. Lots of CRT functions, even simples ones as <code>memcpy</code> or <code>strcmp</code>, reference global CRT variables which need to be initialized. Use this at your own risk, and in case of doubt, double-check the CRT source code.</b></p>
<p>This therefore implies that you can&#8217;t really call CRT functions anyway, apart from standalone ones. So the same rules as if you were not using the CRT at all apply, except for the fact that accidentally referencing a CRT symbol will be much harder to spot because it won&#8217;t cause a link error anymore. So, obviously, this is not a way that I often use.</p>
<h3>The safest way: Use another CRT</h3>
<p>This is the method I use for KoroIRC. Basically, this is using another set of header files and library files when compiling the program.</p>
<p>I found that the safest way to do it is not to change VS&#8217;s library and include paths, but rather to build my release binaries using a special script, and build my debug builds using the regular CRT with the <code>/MT</code> compiler option. I don&#8217;t care if my debug binaries weigh 1MB and have tons of dead code in them, as I never ship them.</p>
<p>The trick is to make a little batch file like this:</p>
<blockquote><pre>
@echo off
set INCLUDE=<i>altcrt\include</i>;%INCLUDE%
set LIB=<i>altcrt\lib</i>;%LIB%
devenv <i>solution.sln</i> /rebuild "Release^|Win32" /useenv
</pre>
</blockquote>
<p>Replace <i>altcrt</i> with the proper path to your alternate CRT, run this in a Visual Studio Command Prompt, and let it churn.</p>
<p>I will now finish this post by presenting two alternate CRT&#8217;s you can use.</p>
<h4>Lightweight but undocumented: NTDLL&#8217;s mini-CRT</h4>
<p>A little-known fact is that <code>NTDLL.DLL</code> embeds its own CRT, probably for use by operating system components and native applications. Of course, you won&#8217;t find complex functions such as <code>rand</code> or <code>time</code> but all string functions, and more importantly, SEH support functions, are there. Since it is always loaded in all processes anyway, it costs nothing to use, except Windows 9x compatibility of course.</p>
<p>To use it, you&#8217;ll need the <a href="http://www.microsoft.com/whdc/devtools/ddk/default.mspx">Windows DDK</a>, which includes all the header files and library files needed in order to import from <code>NTDLL</code>. However, in order to be able to use it with PSDK-compiled applications, you will need to extract only the right files, that is, the whole contents of the <code>inc\crt</code> directory and the <code>lib\wxp\i386\ntdll.lib</code> file for x86 or <code>lib\wnet\amd64\ntdll.lib</code> for x64. Then it is only a matter of using them with the little script I presented earlier.</p>
<h4>Harder but safer: Good old MSVCRT</h4>
<p>In order to do that, you will need two things: an old Visual Studio 6.0 CD, and a copy of the <a href="http://www.microsoft.com/downloads/details.aspx?familyid=D8EECD75-1FC4-49E5-BC66-9DA2B03D9B92&#038;displaylang=en">Windows Server 2003 SP1 Platform SDK</a> that was released just before Visual Studio 2005.</p>
<p>On the Visual Studio 6.0 CD, you will be able to extract the VS6 CRT headers from the <code>VC98\INCLUDE</code> directory, and the libraries from the <code>VC98\LIB</code> directory. The only problem is that they are mixed with Platform SDK files, so you&#8217;ll have to pick them one by one. Luckily, I have thown together <a href="/blogdata/vs6crt_x86.txt">this list</a> of what files belong to the CRT.</p>
<p>The Platform SDK release linked above is special because it contailed a prerelease version of the x64 compiler that came with Visual Studio 2005. As such it also contains everything necessary in order to link with Windows x64&#8217;s <code>MSVCRT.DLL</code>. Hopefully, this time, the headers are in their own subdirectory, <code>Include\crt</code>. The libraries are in <code>Lib\amd64</code> and the PDB files are in <code>NoRedist\Win64\AMD64</code>.</p>
<p>With all this in hand, you should be able to link with <code>MSVCRT.DLL</code> on x86 and x64 using the script.</p>
<h3>Conclusion</h3>
<p>With these methods, it is possible to reduce either the executable size or the download size (for not having to redistribute more recent CRTs) for your program. Of course, this only applies if you program mostly in C, because when you start using C++ or worse, the STL, these approaches stop working well.</p>
<p></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.koroirc.com/2008/09/trimming-executables-part-1-getting-rid-of-the-c-runtime/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Three good black UxTheme skins</title>
		<link>http://blog.koroirc.com/2008/08/three-good-black-uxtheme-skins/</link>
		<comments>http://blog.koroirc.com/2008/08/three-good-black-uxtheme-skins/#comments</comments>
		<pubDate>Fri, 01 Aug 2008 22:00:59 +0000</pubDate>
		<dc:creator>Koro</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.koroirc.com/?p=30</guid>
		<description><![CDATA[Since the advent of Windows XP, I&#8217;ve always been a fervent believer that Windows Classic was the only true look for Windows. This was fueled by a few things:

On the graphical side: The skins that are built-in with Windows XP suck, although the silver one is a little less worse than the others. The title [...]]]></description>
			<content:encoded><![CDATA[<p>Since the advent of Windows XP, I&#8217;ve always been a fervent believer that Windows Classic was the only true look for Windows. This was fueled by a few things:</p>
<ol>
<li><b>On the graphical side:</b> The skins that are built-in with Windows XP suck, although the silver one is <i>a little</i> less worse than the others. The title bars are oversized — especially in the days where screen resolutions like 800&#215;600 and 1024&#215;768 were still the norm — and you are stuck with choosing between happy-blue, dull-green or way-too-bright-silver as the only possible colors. Since I like to match my title bar and selection colors with my desktop background, it&#8217;s kind of a bummer. Also, I hate blue. I have a deep, passionated hatred for the color blue, which is even more fueled by the fact that it seems to be the default color <i>everywhere</i>. In fact, the first thing I always did in a fresh Windows install, was to change the blue colors to something else. So the non-ability to change it to say, forest green, was quite annoying. It&#8217;s not like it would have been hard to implement skin colorization, WindowBlinds was doing it already.</li>
<li><b>On the technical side:</b> The whole UxTheme skin system is such a giant patch over Windows, it almost seems like it was written by a third-party and hastily integrated into the Windows code base. It uses a service with a global hook to apply skinning to the non-client area of windows, and applications have to explicitly request the &#8220;new&#8221; common controls in order to get skinned controls. This is quickly visible in the fact that console windows, hard error dialogs and WOW windows are not skinned at all. Also, all pre-XP applications still have the &#8220;old&#8221; controls, which contributes to the overall uglyness. The question is: why on earth couldn&#8217;t they — security and stability issues aside — plug the skinning code right into the window manager over the old code? They had the source code, and therefore the ability to do it, but instead they went the other way all around and added another layer of complexity.</li>
</ol>
<p>But, as time has passed, these points have become pretty much moot. There are now a lot of user-created skins so #1 is not a problem anymore, and almost all applications include a common control manifest so the impact of #2 is quite minimized. Also, computers have gotten much faster since 2001, so the speed impact of drawing a bitmap instead of a solid fill is almost null.</p>
<p>Whilst user-created UxTheme skins have existed for a while, I have only since recently considered even using one because frankly, most of them sucked. They were either oversized, overcolored, had too much details or were blatant rips of Luna.</p>
<p>The first skin I ever used was Royale, although not for long, because it was blue. Not only the title bars, but every control and color had a blue hue. But I liked its glossy look, it was quite a change from Luna&#8217;s &#8220;deflated baloon&#8221; look. The first skin I <i>really</i> used, and fell in love with, was the Zune skin, which was Royale without the blue. It also made me realize that black is a color that fits with every other color, and therefore wallpaper, so I didn&#8217;t mind much not being able to customize it.</p>
<p>After scouring the web a little, I found some other good black UxTheme skins. I therefore make a little list here for future reference:</p>
<ol>
<li><b><a href="http://www.deviantart.com/deviation/89206761/">Watercolor Emico: Black</a> by Gelosea:</b> By far the most beautiful, most usable skin out there. It also comes in flavor of <a href="http://www.deviantart.com/deviation/87650169/">blue</a>, a <a href="http://www.deviantart.com/deviation/88545593/">darker blue</a>, <a href="http://www.deviantart.com/deviation/91448120/">olive green</a> and <a href="http://www.deviantart.com/deviation/89849316/">silver</a>. I use it on all my computers, enough said.<br />
<img src="/blogdata/skin_watercoloremico.png" width="347" height="185" alt="Screenshot" /></li>
<li><b><a href="http://go.microsoft.com/fwlink/?LinkID=75078">Zune Desktop Theme</a> by Microsoft:</b> This one is actually by Microsoft itself and was released as promotion for the Zune. It&#8217;s basically Royale without the blue, but is <b>not</b> Royale Noir, which still had some blue in it. The advantage of this skin is that, being from Microsoft, it&#8217;s signed and therefore needs no UxTheme patch to apply. I use this one at work or in other places where patching UxTheme would be prohibitive.<br />
<img src="/blogdata/skin_zune.png" width="347" height="185" alt="Screenshot" /></li>
<li><b><a href="http://www.deviantart.com/deviation/29511577/">Luna Element</a> by tornado5:</b> I&#8217;d use this one if the two previous ones didn&#8217;t exist. Comes in blue and black.<br />
<img src="/blogdata/skin_lunaelement.png" width="347" height="185" alt="Screenshot" /></li>
</ol>
<p>With these, there&#8217;s no reason to stay in Windows Classic anymore!</p>
<p></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.koroirc.com/2008/08/three-good-black-uxtheme-skins/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Visual C++ woes</title>
		<link>http://blog.koroirc.com/2008/06/visual-cpp-woes/</link>
		<comments>http://blog.koroirc.com/2008/06/visual-cpp-woes/#comments</comments>
		<pubDate>Tue, 17 Jun 2008 19:21:28 +0000</pubDate>
		<dc:creator>Koro</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://blog.koroirc.com/?p=5</guid>
		<description><![CDATA[It seems that with every new version of Visual Studio, Microsoft does something to alienate its users in regard to the C runtime, compiler and/or linker.
Back in the days of Visual Studio 6.0 (still, in my opinion, the best version to have ever existed, despite its age1), things were simple. There were no useless compiler [...]]]></description>
			<content:encoded><![CDATA[<p>It seems that with every new version of Visual Studio, Microsoft does something to alienate its users in regard to the C runtime, compiler and/or linker.</p>
<p>Back in the days of Visual Studio 6.0 (still, in my opinion, the best version to have ever existed, despite its <a href="#p5footer">age<sup>1</sup></a>), things were simple. There were no useless compiler flags to disable in every project, and the C runtime library was <code>MSVCRT.DLL</code>, which was distributed with the operating system. Actually, <a href="http://blogs.msdn.com/oldnewthing/archive/2008/01/11/7065021.aspx">this is not fully the case</a>, but <code>MSVCRT.DLL</code> has always been there due to the strong reliance of operating system components on it. It was therefore very simple to create small applications and to distribute them.</p>
<p>Then came Visual Studio 7.0, a.k.a. Visual Studio .NET 2002. Suddenly, someone somewhere decided that <code>MSVCRT.DLL</code> belonged &#8220;to the operating system&#8221; and not to Visual C++, and that therefore, its C runtime should now reside in a new, separate, redistributable DLL, <code>MSVCR70.DLL</code>. So suddenly, there was no real incentive to compile with <code>/MD</code>, as it would create the need to distribute a ~330k DLL along with the application. Personally, I would have remained with Visual Studio 6.0, but in the latest Platform SDK, which at the time was the then-new Windows XP SP2 Platform SDK, suddenly the format of the <code>.lib</code> files was just slightly incompatible with the aging linker.</p>
<p>I think it was in Visual Studio 7.1, which, by the way, I have never used personally, that the damned <code>/GS</code> compiler flag was introduced. What a better way to inflate code size uselessly than to add a prolog and epilog in every function that checks for a &#8220;security cookie&#8221;? Personally, I never allocate buffers and strings on the stack anyway, and when I do, I very strictly validate their length, so the protection offered by this flag is quite nil to me.</p>
<p>Then, in Visual Studio 8.0 (2005), somebody sure got angered at all the developers that were copying <code>MSVCR7x.DLL</code> around freely, so it was spoken: <em>&#8220;From now on, the C runtime will only be installed by our own installer&#8221;</em>. So, to install <code>MSVCR80.DLL</code> on a system, it&#8217;s not as simple anymore as just including the file in your installer and dumping it in the application&#8217;s directory during installation, you have to have a freaking <em>manifest</em> to even be able to load it! And of course, since this uses Fusion, the files need to be installed into specific subdirectories of the <code>WinSxS</code> directory, and therefore, the only &#8220;installer&#8221; qualified to do it correctly is the <a href="http://www.microsoft.com/downloads/details.aspx?familyid=32bc1bee-a3f9-4c13-9c99-220b62a191ee&amp;displaylang=en">Visual C++ 2005 Reditributable Package</a>, which weighs a whopping 2.6 MB! Quite a lot for what would have been an application of a few hundred kilobytes, now isn&#8217;t it? And to make sure you don&#8217;t <em>ever</em> try to bypass this &#8220;rule&#8221; and copy it in the application&#8217;s directory, the DLL does a check at startup to see if it was loaded &#8220;correctly&#8221;, and, if not, refuses to load.</p>
<p>Now, it isn&#8217;t that bad, I found a workaround to that (which I will explain in a future post), so I got used to that version and grew to like it.</p>
<p>I then recently got Visual Studio 9.0 (2008) and installed it. Not that it was really useful, since I already had the <a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=9BE1FC7F-0542-47F1-88DD-61E3EF88C402&amp;displaylang=en">Windows Vista (February CTP) SDK</a> installed over my Visual Studio 2005 installation, but I installed it just to be using the latest version. Actually, it&#8217;s not so bad, it&#8217;s even an improvement over the previous version. The <code>/DYNAMICBASE</code> and <code>/NXCOMPAT</code> flags are enabled by default (<a href="http://blog.koroirc.com/2008/06/migrating-a-project-from-vs2005-to-vs2008-disables-aslr/">unless you migrate your project from Visual Studio 2005</a>), and the operating system and subsystem version number in the PE headers were finally bumped to being set to 5.0 by default. That last point is also the frustrating point though. It was probably done that way because version 9.0 of the C runtime wouldn&#8217;t run correctly on anything lower than 5.0 anyway, but if you are not using the C runtime at all, there is no reason to set them to 5.0, other than artificially restricting the versions of Windows your program can run on. So, you might say, <em>&#8220;let&#8217;s just tell the linker to set them back to 4.0 then&#8221;</em>. Except, when you try to do that, you get this lovely little error:</p>
<blockquote><p><code>LINK : warning LNK4010: invalid subsystem version number 4.0; default subsystem version assumed</code></p></blockquote>
<p>Yes, you guessed right. The linker <em>won&#8217;t</em> let you set 4.0 as the subsystem version number. It looks quite like an useless restriction put there just to annoy some of us who still support, or just want to code for Windows 9x/NT4.</p>
<p>But as always, something like that isn&#8217;t enough to stop me, I created my own workaround:</p>
<p><a href="http://www.korosoft.net/programs/snapshot/pever.png"><img src='http://www.korosoft.net/programs/snapshot/pever_preview.png'/></a></p>
<p>The fact that an executable linked with Visual Studio 2008, but not using its C runtime, runs fine on Windows NT 4.0 afterwards proves how much of an artificial restriction that is.</p>
<p>The tool is up for download <a href="http://www.korosoft.net/programs/pever.rar">here</a>.</p>
<p><a name="p5footer"></a></p>
<ol>
<li><small>It&#8217;s not so bad once you install <a href="http://www.wndtabs.com/">WndTabs</a> and work around the few bugs in the resouce editor.</small></li>
</ol>
<p></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.koroirc.com/2008/06/visual-cpp-woes/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Migrating a project from VS2005 to VS2008 disables ASLR</title>
		<link>http://blog.koroirc.com/2008/06/migrating-a-project-from-vs2005-to-vs2008-disables-aslr/</link>
		<comments>http://blog.koroirc.com/2008/06/migrating-a-project-from-vs2005-to-vs2008-disables-aslr/#comments</comments>
		<pubDate>Fri, 13 Jun 2008 23:26:19 +0000</pubDate>
		<dc:creator>Koro</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://blog.koroirc.com/?p=4</guid>
		<description><![CDATA[I just spent about an hour trying to figure out why some of KoroIRC&#8217;s binaries did not have the IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE and IMAGE_DLLCHARACTERISTICS_NX_COMPAT flags enabled in their PE header, and some other had them.
Oddly, only the older projects in the solution had this problem, the newer were OK. I spent a while wondering if it might [...]]]></description>
			<content:encoded><![CDATA[<p>I just spent about an hour trying to figure out why some of KoroIRC&#8217;s binaries did not have the <code>IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE</code> and <code>IMAGE_DLLCHARACTERISTICS_NX_COMPAT</code> flags enabled in their PE header, and some other had them.</p>
<p>Oddly, only the <em>older</em> projects in the solution had this problem, the newer were OK. I spent a while wondering if it might have been a linker bug, then I decided to look at the build log. Surprisingly, the affected projects had the <code>/DYNAMICBASE:NO</code> linker switch specified, even though I specified the opposite in the solution-global <code>.vsprops</code> files.</p>
<p>So I decided to take a look directly in the <code>.vsproj</code> files, and lo and behold, in the linker options, the following lines where there:</p>
<blockquote><p><code>RandomizedBaseAddress="1"<br />
DataExecutionPrevention="0"</code></p></blockquote>
<p>Since I <strong>never</strong> add stuff directly to the <code>.vsproj</code> files, because I prefer <code>.vsprops</code> files which allow sharing common settings between projects, then in the migration from VS2005 to VS2008, it must have &#8220;helpfully&#8221; inserted these for me.</p>
<p>To quote Stan from South Park, &#8220;I learned something today&#8230;&#8221;</p>
<p></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.koroirc.com/2008/06/migrating-a-project-from-vs2005-to-vs2008-disables-aslr/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>First post</title>
		<link>http://blog.koroirc.com/2008/06/first-post/</link>
		<comments>http://blog.koroirc.com/2008/06/first-post/#comments</comments>
		<pubDate>Mon, 09 Jun 2008 05:38:32 +0000</pubDate>
		<dc:creator>Koro</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.koroirc.com/?p=3</guid>
		<description><![CDATA[Welcome to the KoroIRC development blog, where you will be able to get information about the development process and other random rantings as well. Stay tuned for more.
]]></description>
			<content:encoded><![CDATA[<p>Welcome to the KoroIRC development blog, where you will be able to get information about the development process and other random rantings as well. Stay tuned for more.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.koroirc.com/2008/06/first-post/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
