Showing posts with label Win32. Show all posts
Showing posts with label Win32. Show all posts

Thursday, July 21, 2022

Sizes of Windows integral types

While developing WinSafe, it’s very common to convert the Windows integral data types to their Rust equivalent. Care must be taken, however, when it comes to pointer size, which varies according to the architecture. Since WinSafe is aimed to both 32 and 64-bit Windows, I must pay attention.

For reference, below is the table I’m using to figure out the sizes:

Signed C Signed Rust Unsigned C Unsigned Rust 32-bit 64-bit
CHAR
 
 
i8 UCHAR
BYTE
BOOLEAN
u8 8 bit (1 byte)
SHORT
 
 
i16 USHORT
WCHAR
WORD
u16 16 bit (2 byte)
BOOL
INT
LONG
 
i32  
UINT
ULONG
DWORD
u32 32 bit (4 byte)
INT_PTR
LONG_PTR
LPARAM
 
isize UINT_PTR
ULONG_PTR
WPARAM
SIZE_T
usize 32 bit (4 byte) 64 bit (8 byte)
LARGE_INTEGER
LONG64
LONGLONG
 
 
i64 ULARGE_INTEGER
ULONG64
ULONGLONG
DWORD64
DWORDLONG
QWORD
u64 64 bit (8 byte)

The table above is an extension of this one.

Monday, May 23, 2022

Cross-compiling Rust in Windows

After making a lot of confusion with Rust cross-compiling, I finally managed to compile WinSafe x32 programs in my Windows x64. The root of the misunderstanding is that, in order to cross compile, you must have the following installed:

  • MSVC build tools;
  • Rust toolchain;
  • Rust target.

Toolchain relevant commands:

rustup toolchain list
rustup toolchain install stable-i686-pc-windows-msvc
rustup toolchain uninstall stable-i686-pc-windows-msvc

Target relevant commands:

rustup target list | grep installed
rustup target add i686-pc-windows-msvc --toolchain stable
rustup target remove i686-pc-windows-msvc

To verify if you program has any linker issues, build and run:

rustup run stable-i686-pc-windows-msvc cargo run
rustup run stable-x86_64-pc-windows-msvc cargo run

Then finally the program can be built for release with:

RUSTFLAGS='-C target-feature=+crt-static' cargo build --release --target i686-pc-windows-msvc
RUSTFLAGS='-C target-feature=+crt-static' cargo build --release --target x86_64-pc-windows-msvc

I only found all that stuff after posting a question on StackOverflow and receiving this comment. The documentation was completely absent in providing any useful information.

Monday, May 9, 2022

Taking a screenshot in Windows with Go

I’ve tried to code a Windows screenshot utility before, following the example of the official Windows documentation I found it tricky though, so I just gave up at the time.

This Monday morning, after receiving a request to implement GetDIBits in WinSafe, I tried to implement it Windigo first. To my surprise, it went incredibly smooth. Go’s defer mechanism is much to praise.

Here’s the whole code

package main

import (
	"runtime"
	"unsafe"

	"github.com/rodrigocfd/windigo/win"
	"github.com/rodrigocfd/windigo/win/co"
)

func main() {
	runtime.LockOSThread()

	cxScreen := win.GetSystemMetrics(co.SM_CXSCREEN)
	cyScreen := win.GetSystemMetrics(co.SM_CYSCREEN)

	hdcScreen := win.HWND(0).GetDC()
	defer win.HWND(0).ReleaseDC(hdcScreen)

	hBmp := hdcScreen.CreateCompatibleBitmap(cxScreen, cyScreen)
	defer hBmp.DeleteObject()

	hdcMem := hdcScreen.CreateCompatibleDC()
	defer hdcMem.DeleteDC()

	hBmpOld := hdcMem.SelectObjectBitmap(hBmp)
	defer hdcMem.SelectObjectBitmap(hBmpOld)

	hdcMem.BitBlt(
		win.POINT{X: 0, Y: 0},
		win.SIZE{Cx: cxScreen, Cy: cyScreen},
		hdcScreen,
		win.POINT{X: 0, Y: 0},
		co.ROP_SRCCOPY,
	)

	bi := win.BITMAPINFO{
		BmiHeader: win.BITMAPINFOHEADER{
			BiWidth:       cxScreen,
			BiHeight:      cyScreen,
			BiPlanes:      1,
			BiBitCount:    32,
			BiCompression: co.BI_RGB,
		},
	}
	bi.BmiHeader.SetBiSize()

	bmpObj := win.BITMAP{}
	hBmp.GetObject(&bmpObj)
	bmpSize := bmpObj.CalcBitmapSize(bi.BmiHeader.BiBitCount)

	rawMem := win.GlobalAlloc(co.GMEM_FIXED|co.GMEM_ZEROINIT, bmpSize)
	defer rawMem.GlobalFree()

	bmpSlice := rawMem.GlobalLock(bmpSize)
	defer rawMem.GlobalUnlock()

	hdcScreen.GetDIBits(hBmp, 0, int(cyScreen), bmpSlice, &bi, co.DIB_RGB_COLORS)

	bfh := win.BITMAPFILEHEADER{}
	bfh.SetBfType()
	bfh.SetBfOffBits(uint32(unsafe.Sizeof(bfh) + unsafe.Sizeof(bi.BmiHeader)))
	bfh.SetBfSize(bfh.BfOffBits() + uint32(bmpSize))

	fo, _ := win.FileOpen("C:\\Temp\\foo.bmp", co.FILE_OPEN_RW_OPEN_OR_CREATE)
	defer fo.Close()

	fo.Write(bfh.Serialize())
	fo.Write(bi.BmiHeader.Serialize())
	fo.Write(bmpSlice)

	println("Done")
}

For reference, this example is now on GetDIBits documentation.

Thursday, May 13, 2021

The ghastly button focus

During my 20 years or so writing Win32 programs, I always relied on SetFocus to focus a control. However, I always noticed a weird behavior on push buttons regarding the BS_DEFPUSHBUTTON style, which was never right. In fact, I remember one of the past WinLamb incarnations which I implemented some trick involving changing the button style when setting the focus.

Anyway, now I found out how to properly set the focus on a control, and it does not involve SetFocus, but rather the WM_NEXTDLGCTL message:

SendMessage(hParent, WM_NEXTDLGCTL, (WPARAM)hButton, MAKELPARAM(TRUE, 0));

And the push button magically sets its own style correctly.

Monday, June 15, 2020

Embedding rc files into Go Win32 executables

When building Go executables in Windows, the Go toolchain recognizes *.syso files and automatically embeds then into the *.exe – this allows the embedding of resources scripts, which can contain icon and manifest, among other resources. Visual C++ resource compiler, however, only generate *.res files.

I’ve seen people using rsrc tool to add manifest files to executables. The problem is that this tool doesn’t really compile a resource file, nor it converts *.res into *.syso.

Turns out resource file compilation can be done with windres tool, from MinGW package. Since I already have the whole Visual C++ stuff, I didn’t want to install all the package, which is rather big, and I already have MinGW terminal from Git. Fortunately, windres works standalone, the only requisite is that gcc is in the same directory. And we can download both.

Portable MinGW tools can be downloaded from here:

From both packages, extract gcc and windres and save them somewhere else. All the rest can be deleted.

Compile the *.rc file into *.res with Visual C++ Developer Power Shell for VS 2019:

rc /r my-resource.rc

Then, on MinGW prompt, convert *.res into *.syso:

windres -i my-resource.res -o my-resource.syso

Now place my-resource.syso in the same directory of your main.go, and that’s it. For some weird reason, when debugging in VSCode, the program icon may appear wrong, but it will show fine in release builds, which are the ones that really matter:

go build -ldflags "-s -w -H=windowsgui"

Ideally windres would be used to compile the *.rc directly into *.syso, but to do so it needs the Win32 headers from MinGW, which are not present – you’ll get an error. Probably there’s a way to point Visual C++ headers directory to windres, but by now I’m satisfied using windres tool just to convert the *.res.

Thursday, February 7, 2019

A very simple, raw Win32 WinLamb program

Months ago I noticed that WinLamb was missing a simple, introductory example. I never really had time to write and publish one. Until today.

Click lines is a very simple program, inspired by Charles Petzold, which draws lines upon mouse clicks. Just this. It’s intended to be a very simple showcase of WinLamb, showing how to create raw windows, raw custom controls, and handling messages. I usually use dialog boxes on my real-world programs, but for this one I really kept it bare-bones, with no dialogs.

I hope it can be useful to anyone interested in WinLamb.

Sunday, October 21, 2018

SRTEd 1.3.1, minor release

This week I released a new SRTEd version 1.3.1, with has minor, but many usability improvements. Also, it’s built with latest version of WinLamb, my very own personal raw Win32 library, which I use for everything.

I was planning a bigger release for SRTEd, with more advanced features, but since my time is pretty short these days, I just released a version where it is now, with the UI improvements. It’s already more than a year since the last version, time flies. One notable difference is the absence of a 32-bit executable, which was not included because it was firing false positives for malware, something completely absurd. To avoid the hassle, I opted to keep only the 64-bit version.

SRTEd can be downloaded from CNET.

Tuesday, April 4, 2017

After 4 years, SRTEd 1.3.0

So finally I released a new version of SRTEd, my own subtitles editor. Honestly, in these four years I didn’t see a better subtitle editor, I still think it’s the most user-friendly editor out there.

The interface didn’t improve much, but there are many bugfixes and minor UI adjusts. It took so long because I entirely rewrote it using my new Win32 library, which I expect to release as open source soon, together with an article explaining what it is and how to take the best out of it.

It can be downloaded from CNET or Softpedia.

Sunday, May 1, 2016

Git .gitignore file to Visual C++ 2015 Update 2

After upgrading my Visual C++ 2015 from Update 1 to Update 2, I noticed that a new file appeared in the root directory of the projects I was opening. The file was always named ProjectName.VC.db. Indeed according to the release notes, a new SQLite-based database engine is now being used by default, and that’s the file where the database is stored. The old file, named ProjectName.sdf is now unused and can be safely deleted.

The change also demanded an update on my .gitignore files to also ignore this new database file, and here it goes:
Debug/
Release/
*.aps
*.db
*.ffs_db
*.ncb
*.opensdf
*.rar
*.sdf
*.suo
*.user
*.VC.opendb
TODO.txt
If you import and old .vssettings file, however, the option to use the new SQLite-based database can be rolled back to the old .sdf files. To manually change it, go to: Tools → Options → Text Editor → C/C++ → Advanced → Browsing/Navigation → Enable New Database Engine. Set it to “true”.

Wednesday, March 23, 2016

Disabling C++ exceptions in Visual Studio 2015

When using the STL with Visual Studio 2015 – and older versions, probably –, C++ exceptions are enabled by default. To view the options specified below, first add at least one CPP file to your project.

The first thing to change on the project settings is under C/C++ code generation, enable C++ exceptions: set this to “no”.

Then, on the project settings, C/C++ preprocessor, to each configuration and platform individually, add the following preprocessor definition:
_HAS_EXCEPTIONS=0
This way you’ll be able to use the STL without the C++ exception handling mechanism.

Friday, March 15, 2013

The best SRT editor for subtitles

After a couple months of work, it has just been published on CNet’s Download.com my newest program: SRTEd, a visual and portable editor to SRT files for Windows.

Basically, I decided to write this program because I had to edit some subtitles a while ago, in SRT format, and the available editors were quite tedious and painful to use. I somewhat got this insight of a more visual editor, and some time later I began writing it. The most important thing to “get the feel” is the use of the keyboard arrow keys to sync the subs. Left/right arrows move them, and when holding Shift key, change the duration. This makes the sync incredibly easy to do, visual.



Technically, the program is pure C-like C++ (that’s how I define my own C++ style) and native Win32, so it’s really light and fast. To video playback, it uses DirectX infrastructure. Moreover, SRTEd uses my own Win32 object-oriented library, which I plan to release as open source some day.

Here’s a getting started video:



CNet download link: SRTEd - SRT Subtitles Editor.

Update: I just received an e-mail from Softpedia, they published SRTEd on their site too.

Thursday, February 14, 2013

Reading version from EXE and DLL files

Here’s a C++ and Win32 class to read version information from the resource section within EXE and DLL Windows binaries. The key functions are GetFileVersionInfo and VerQueryValue. The object will provide public pointers to the strings; these pointers should not be deleted, since they point straight into the allocated data block. If version information can’t be read – for example, if it’s a file with no version information – the load method will simply return false.

There’s room for more improvements, like tighter error checking, but it’s pretty usable:
#include <Windows.h>
#pragma comment(lib, "Version.lib")

class VersionInfo {
public:
	const wchar_t *pComments, *pCompanyName, *pLegalCopyright, *pProductVersion;

	VersionInfo() : _data(NULL),
		pComments(NULL), pCompanyName(NULL),
		pLegalCopyright(NULL), pProductVersion(NULL) { }

	~VersionInfo() {
		if(_data) free(_data);
	}

	bool load(const wchar_t *path) {
		DWORD szVer = 0;
		if(!(szVer = GetFileVersionInfoSize(path, &szVer)))
			return false;
		_data = (BYTE*)malloc(sizeof(BYTE) * szVer);
		if(!GetFileVersionInfo(path, 0, szVer, _data))
			return false;

		UINT len = 0;
		VerQueryValue(_data, L"\\StringFileInfo\\040904b0\\Comments",
			(void**)&pComments, &len);
		VerQueryValue(_data, L"\\StringFileInfo\\040904b0\\CompanyName",
			(void**)&pCompanyName, &len);
		VerQueryValue(_data, L"\\StringFileInfo\\040904b0\\LegalCopyright",
			(void**)&pLegalCopyright, &len);
		VerQueryValue(_data, L"\\StringFileInfo\\040904b0\\ProductVersion",
			(void**)&pProductVersion, &len);
		return true;
	}

private:
	BYTE *_data;
};
Usage example:
{
	VersionInfo vi;
	if(vi.load(L"C:\\Program.exe")) {
		OutputDebugString(vi.pProductVersion);
		OutputDebugString(vi.pComments);
	}
}
Can’t be simpler than that.

Sunday, December 2, 2012

Automation for C++ COM pointers

This week I was working on a C++ program which used a lot of COM pointers. I remembered I’ve seen an automation class somewhere, and after some searching I found it, it’s Microsoft’s ComPtr template class. Although I liked the concept, it had too much fuss to me, so I was displeased in using it.

Oh well, here we go again: I wrote my own COM pointer automation class. Here it goes the full code of it, which I now share with the world:
#pragma once
#include <Windows.h>
#include <ObjBase.h>

template<typename T> class ComPtr {
public:
	ComPtr()                    : _ptr(NULL) { }
	ComPtr(const ComPtr& other) : _ptr(NULL) { operator=(other); }
	~ComPtr()                   { this->release(); }
	ComPtr& operator=(const ComPtr& other) {
		if(this != &other) {
			this->~ComPtr();
			_ptr = other._ptr;
			if(_ptr) _ptr->AddRef();
		}
		return *this;
	}
	void release() {
		if(_ptr) {
			_ptr->Release();
			_ptr = NULL;
		}
	}
	bool coCreateInstance(REFCLSID rclsid) {
		return _ptr ? false :
			SUCCEEDED(::CoCreateInstance(rclsid, 0, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&_ptr)));
	}
	bool coCreateInstance(REFCLSID rclsid, REFIID riid) {
		return _ptr ? false :
			SUCCEEDED(::CoCreateInstance(rclsid, 0, CLSCTX_INPROC_SERVER, riid, (void**)&_ptr));
	}
	template<typename COM_INTERFACE> bool queryInterface(REFIID riid, COM_INTERFACE **comPtr) {
		return !_ptr ? false :
			SUCCEEDED(_ptr->QueryInterface(riid, (void**)comPtr));
	}
	bool isNull() const { return _ptr == NULL; }
	T&   operator*()    { return *_ptr; }
	T*   operator->()   { return _ptr; }
	T**  operator&()    { return &_ptr; }
	operator T*() const { return _ptr; }
private:
	T *_ptr;
};
Basically, by using this class I don’t have to worry about calling the Release method. Most interestingly, I added two shorhand methods to ease my life, coCreateInstance and queryInterface. Here are an example illustrating the use of the ComPtr class, along with the cited methods:
{
	ComPtr<IGraphBuilder> graph;
	if(!graph.coCreateInstance(CLSID_FilterGraph))
		OutputDebugString(L"Failed!");

	ComPtr<IMediaControl> mediaCtrl;
	if(!graph.queryInterface(IID_IMediaControl, &mediaCtrl))
		OutputDebugString(L"Failed!");

	graph->RenderFile(L"foo.avi", NULL); // sweet!
}
If you’re wondering about the usefulness of this ComPtr class, try to write the code above without it.

Sunday, May 13, 2012

FLAC and LAME frontend

I use the FLAC and LAME command line tools, and I’ve tried many FLAC and LAME frontends. And I disliked all them. One day I decided to write my own, with a parallel multithreaded handling of the files, so all the files are converted at once, taking advantage of multicore CPUs.

Today I’ve just published it as open source on GitHub. It’s pure C and Win32. I hope it can be useful to someone – not only the program itself, but also my C programming techniques. It can be found at rodrigocfd/flac-lame-gui.

Saturday, May 12, 2012

My first program on GitHub

That’s a simple C Win32 program to shrink down padding bytes from ID3v2 tags on MP3 files. Maybe the most important thing, I think it showcases my style of C programming, and I’m glad to share it with the world. I hope it can be useful to someone someday.

It can be browsed at rodrigocfd/id3-padding-remover.

Wednesday, March 21, 2012

Finding memory leaks in Win32

I’ve just discovered an interesting function to aid the Win32 programmer in finding eventual memory leaks in debugging mode, and with a very straightforward use: _CrtDumpMemoryLeaks.

The function compares the current memory state with the one at the program start, and if any unnalocated memory block is found, it returns TRUE and prints some debug information on the output window. So, to use it effectively, without false positives, one must call it when all objects are out of scope. Here’s an example:
#include <crtdbg.h>
#include <string>
int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
{
	std::wstring name = L"abcdef";
	_CrtDumpMemoryLeaks(); // will accuse a leak!
	return 0;
}
In the code above, there will be a false positive, because the string object didn’t go out of scope yet, therefore its destructor wasn’t called so far, so there’s still memory allocated. But this would rather lead to our expectations:
#include <crtdbg.h>
#include <string>
int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
{
	{
		std::wstring name = L"abcdef";
	}
	_CrtDumpMemoryLeaks(); // no leaks!
	return 0;
}
Now, since the string was declared within the scope of the nested block, its destructor will be called when the nested block ends, and no memory will remain allocated after it. This way, _CrtDumpMemoryLeaks will correctly report no leaks; indeed, nothing will be printed to the output window.

And the function is removed when _DEBUG is not defined, so you don’t need to worry about it on your release builds.

I particularly found it useful to use the _CrtDumpMemoryLeaks call inside an _ASSERT macro, so that when a memory leak is found, a huge popup will honk right in my face, in addition to the debug messages. So I actually proceed like this:
_ASSERT(!_CrtDumpMemoryLeaks());

Tuesday, March 6, 2012

Load Explorer file extension icon in Win32

When programming with C and Win32, sometimes you need to load an icon, as displayed on Windows Explorer, relative to a file extension. For example, you need to load the Explorer icon associated to the “txt” file extension.

Here is a quick function I use to do it:
HICON ExplorerIcon(const wchar_t *fileExtension)
{
	wchar_t extens[10];
	SHFILEINFO shfi = { 0 };

	lstrcpy(extens, L"*.");
	lstrcat(extens, fileExtension);
	SHGetFileInfo(extens, FILE_ATTRIBUTE_NORMAL, &shfi, sizeof(shfi),
		SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES);
	SHGetFileInfo(extens, FILE_ATTRIBUTE_NORMAL, &shfi, sizeof(shfi),
		SHGFI_ICON | SHGFI_SMALLICON | SHGFI_SYSICONINDEX | SHGFI_USEFILEATTRIBUTES);

	return shfi.hIcon; // use DestroyIcon() on this handle
}

// Usage example:
HICON hIconTxt = ExplorerIcon(L"txt");
Remember to release the HICON handle by calling DestroyIcon after using it, or you’ll have a resource leak.

Friday, February 17, 2012

Optimization settings for Visual C++ 2008

These are the optimization settings I use on Visual C++ 2008. These settings are set to the release builds, on the project settings window, and they complement the default release settings.
  • C/C++
    • General
      • Debug Information Format: Disabled
    • Code Generation
      • Enable String Pooling: Yes
      • Enable C++ Exceptions: No
      • Runtime Library: Multi-threaded (/MT)
      • Enable Enhanced Instruction Set: Streaming SIMD Extensions 2 (/arch:SSE2)
  • Linker
    • Debugging
      • Generate Debug Info: No

On debug builds I don’t change the settings much: I just disable the C++ exceptions, and enable the SSE2 and the string pooling.

Wednesday, September 21, 2011

A sprintf with automatic memory allocation

Personally, I’m a sprintf lover. Not only in C, but in any program language that implements it. I use sprintf all the time, it’s extremely simple, clean and quick.

The sprintf version found on the C standard library requires a previously allocated memory space, where the formatted string will be placed after the operation. However, there are many times where you don’t know how long the result string can be, or you simply don’t want to waste space with a “worst case scenario” allocation. I used to face this a lot. There’s a GNU extension called asprintf, which you can use on Linux, but it doesn’t return the pointer, it returns the number of bytes – although it’s fine, it’s not exactly what I wanted.

So I decided to write my own version of a sprintf function which automatically finds out how much space is needed, allocates the memory and then returns the pointer, with the formatted string. Then I just have to free the pointer after use.

In order to accomplish this task, I used some least known functionalities from the C standard library, so it may be interesting to you to study how I did the job, so the technique can be applied when you need. Also, I found out that some of them behave differently on Linux and Win32. The idea is simple, though: find out how much memory is needed; allocate the memory; call sprintf; return the pointer. After all, I ended up with a valuable and handly function to work with.

This is the Linux version:
char* allocfmt(const char *fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);
	int len = vsnprintf(0, 0, fmt, ap);
	va_end(ap);

	va_start(ap, fmt);
	char *retbuf = malloc(sizeof(char) * (len + 1));
	vsprintf(retbuf, fmt, ap);
	va_end(ap);
	return retbuf;
}
And this is the Unicode-ready Win32 version:
#include <tchar.h>
#include <windows.h>
LPTSTR allocfmt(LPCTSTR fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);
	int len = _vsctprintf(fmt, ap);
	TCHAR *retbuf = malloc(sizeof(TCHAR) * (len + 1));
	_vsntprintf(retbuf, len, fmt, ap);
	va_end(ap);

	*(retbuf + len) = 0;
	return retbuf;
}

Wednesday, September 14, 2011

Fast, in-place C string trim

I want to share with the world this code for a fast trim function in C which is part of my personal library, and that I use quite often. It performs both left and right trim as an in-place operation, changing the original string. The return value is the same pointer that was passed as argument.

This is the version I use on Linux:
char* trim(char *s)
{
	char *pRun = s;
	while(*pRun == ' ') ++pRun;
	if(pRun != s)
	memmove(s, pRun, (strlen(pRun) + 1) * sizeof(char));
	pRun = s + strlen(s) - 1;
	while(*pRun == ' ') --pRun;
	*(++pRun) = 0;
	return s;
}
And this is the version I use on Win32, which is Unicode-ready:
LPTSTR trim(LPTSTR s)
{
	TCHAR *pRun = s;
	while(*pRun == TEXT(' ')) ++pRun;
	if(pRun != s)
	memmove(s, pRun, (lstrlen(pRun) + 1) * sizeof(TCHAR));
	pRun = s + lstrlen(s) - 1;
	while(*pRun == TEXT(' ')) --pRun;
	*(++pRun) = 0;
	return s;
}