August 14, 2016

Open/create directory

To open an existing directory, use CreateFile() with the FILE_FLAG_BACKUP_SEMANTICS attribute:

To create directory:

  1. If you don't need to create intermediate directories, use CreateDirectory():

  2. Otherwise, use SHCreateDirectoryEx().

    In Visual C++ 6.0, you'll have to use LoadLibrary() and GetProcAddress() with shell32.dll; as a procedure name, specify either SHCreateDirectoryExW() or SHCreateDirectoryExA(), not just SHCreateDirectoryEx().

ATL Service registration failure: CO_E_WRONG_SERVER_IDENTITY

CO_E_WRONG_SERVER_IDENTITY (0x80004015, "The class is configured to run as a security ID different from the caller") returned from a registration function (IRunningObjectTable::Register()) can be the result of the following issues:

  1. Incorrect service registration settings. Find the key named HKEY_CLASSES_ROOT\AppID\{<service_app_GUID>}, delete the value named LocalService (if there is one), and add the value named RunAs (type REG_SZ, value Interactive User).
  2. Wrong service GUID (if you've changed it, which is a bad idea in general). Ensure that the following data ('@' means the default value)

    [HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\{yourServiceGuid}]
    @="yourServiceName"
    

    matches these data:

    [HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\yourServiceName.exe]
    @="yourServiceName.Application"
    "AppId"="{yourServiceGuid}"
    

    Sometimes, the default value can be "(value not set)", but the GUID should match.

  3. Wrong service executable name. Check the registry entry for your service AppID (search in the HKEY_CLASSES_ROOT hive using part of your service executable name):

    HKEY_CLASSES_ROOT\AppID\<executable_name>.EXE
    

    Suppose our service executable is named SomeService100ud.exe but in the registry we see the following entry instead:

    HKEY_CLASSES_ROOT\AppID\SomeService.EXE
    

    In this case, check the registrar script files (.rgs) of your service project. Probably the executable name in these scripts is incorrect.

ATL services: turning off error dialogs

To prevent error dialogs from appearing when the Release version of your ATL service fails, add the following code to WinMain():

Alternatively, you can suppress the Windows Error Reporting UI for all programs by creating/setting the registry value

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting
DontShowUI (REG_DWORD) = 1

WARNING: the registry location should be of the correct bitness (64- or 32-bit).

It's also a good idea to set filter for unhandled exceptions:

wglMakeCurrent(): 0xc0070006 error

Don't use a global window's handle to initialize your window DC like shown below. The problem is, WM_CREATE will be sent before your global variable will be initialized ‒ i.e. before returning from CreateWindowW(). Thus, the global variable will be NULL at the moment when window DC is created.

Note that both GetDC() and wglCreateContext() will return non-NULL handles. The problem will become apparent on calling wglMakeCurrent() ‒ it will fail with 0xc0070006, where 6 means "invalid handle".

To deal with this, note that the window procedure has a window handle which you can use. Instead of the global window handle variable, pass the window procedure's hWnd argument to your OpenGL initialization function.

Code demonstrating the problem:

June 22, 2014

Creating host-only network in a corporate environment: Oracle VirtualBox

Suppose we have to create a host-based network (i.e. a network where a host machine and all virtual machines will be visible to each other but won't "see" the external network) on a host machine that is already connected to a corporate network. To do this without disrupting the existing network settings, you can use the Oracle VirtualBox DHCP server.

For example, your machine has an IP address 192.168.0.22 in the corporate network. You can choose some other private IP address range for your virtual network ‒ say, 172.16.x.x. This will allow you to quickly distinguish the virtual network IP addresses from your corporate network ones.

To illustrate the concept, consider a small network consisting of your host and two virtual machines (Windows 7 in our example). The IP addresses can be arranged like this:

  • 172.16.0.0 ‒ DHCP server. As mentioned above, we'll use the VirtualBox DHCP server.
  • 172.16.0.1 ‒ your host machine. Of course, this IP address will be used by the Virtualbox network adapter, not your Ethernet adapter for Local Area Connection.
  • 172.16.0.2 ‒ the first virtual machine.
  • 172.16.0.3 ‒ the second virtual machine.

Assuming you have already created two Windows virtual machines, let's begin.

First, we'll change VirtualBox DHCP server settings and your host IP address in the virtual network. Open the File menu, then Preferences. In the "VirtualBox ‒ Settings" dialog box, select Network. In the "Host-only Networks" tab, click on the VirtualBox Host-Only Ethernet Adapter and press the "Edit host-only network" button on the right:

In the Adapter tab, change the IPv4 Address to 172.16.0.1 (your host IP address):

In the DHCP Server tab, fill in the Enable Server checkbox and change the settings like this:

  • Server Address: 172.16.0.0
  • Lower Address Bound: 172.16.0.2
  • Upper Address Bound: 172.16.0.254

After you press OK, your firewall can prompt you that new network is detected. You can select the option named like "I am at HOME":

Now select your first virtual machine and change its network settings. In the Network setting, select the Adapter 1 tab and do the following:

  • Fill in the Enable Network Adapter checkbox;
  • In the "Attached to:" drop-down list, select "Host-only Adapter";
  • Expand the Advanced settings and ensure that the "Cable Connected" checkbox is filled in.

Start the first virtual machine. Once inside, press Start, go to Control Panel → Network and Internet → Network and Sharing Center → Change adapter settings. You should see the Local Area Connection icon; right-click on it and select Properties. In the properties dialog, select "Internet Protocol Version 4 (TCP/IPv4)" and press the Properties button. In the General tab, select "Use the following IP address:" and fill in the fields like this:

  • IP address: 172.16.0.2
  • The Subnet mask field should be filled in automatically; otherwise, enter 255.255.0.0
  • Set the default gateway to your VirtualBox DHCP Server address (172.16.0.0 in our example)

You can leave the DNS server settings empty.

Your virtual machine will likely to prompt you to choose the network location. Once again, you can select "Home network":

To check your new settings, run Windows Command Prompt inside your virtual machine and try to ping your host:

> ping -a 172.16.0.1

If the ping fails, check all your steps once again.

Finally, run Windows Command Prompt on your host machine and try to ping your first virtual machine:

> ping -a 172.16.0.2

If all is OK, change the second virtual machine in a way similar to the first one. Don't forget to change the IPv4 address as appropriate (for our example, to 172.16.0.3).

March 14, 2013

Creating process in another session: CreateProcessAsUser

In this example, an interactive process is created by a Windows service.

Before calling CreateProcessAsUser, you need to set the session ID by SetTokenInformation with TokenSessionId. And this call requires the Act As Part Of the Operating System privilege (SE_TCB_NAME, SeTcbPrivilege).

To simplify the code, suppose we have an ID of the running process (dwProcessId) as well as the name of its executable (sImageName). Also, the environment block, the priority required, and the command line are ignored.

March 13, 2013

Using AdjustTokenPrivileges to change several privileges at once

In this example (Windows 7, VS 2010), three privileges are changed for the current process:
  • SeBackupPrivilege is enabled;
  • SeDebugPrivilege is removed;
  • SeCreatePagefilePrivilege is disabled.