What to do when FreeLibrary API call fails? - c

Question
I have a third-party DLL that throws an unhandled exception when attempting to unload it from my native C application. This results in the call to FreeLibrary failing, and the module remaining loaded in my process.
Are there any options to forceably unload the library?
What do you do when the FreeLibrary calls?
Additional Background
When using load-time dynamic linking this is annoying enough, but ultimately the application gets torn down by the OS. The problem comes when using run-time dynamic linking. I load up this DLL, use it, and then in some instances I need to unload it from my process's virtual address space and then continue running. When I call FreeLibrary on the third-party library, it does some cleanup work (i.e. in DllMain when DLL_PROCESS_DETACH is called). While it's doing it's cleanup, it causes an exception to be thrown which it doesn't handle, and bubbles up as an unhandled exception to FreeLibrary. This results in the call failing and the module remaining loaded.
I've put a ticket in with the vendor so hopefully I can get a fix which will allow this specific library to unload successfully. In case I don't however, and for the general case of this issue, I'm curious as to what the options are.

If you are after only unloading dll from the memory you can use
UnmapViewOfFile
providing bases address of your loaded dll as an argument.
Example:
HINSTANCE hInst = LoadLibrary( "path_to_dll" );
if( !FreeLibrary( hInst ) )
{
fprintf( stderr, "Couldn't unload library. Error Code: %02X\n. Attempting to unmap...", GetLastError() );
if( !UnmapViewOfFile( hInst ) )
{
fprintf( stderr, "Couldn't unmap the file! Error Code: %02X\n", GetLastError( ) );
}
}
Or if it's a library that you didn't explicitly load (e.g. a library dependency that was loaded by a library that you loaded) and you don't have the handle, then use GetModuleHandle:
HINSTANCE hInst = GetModuleHandle( "dllname_you_didn't_load" );
if( hInst != NULL )
{
if( !UnmapViewOfFile( hInst ) )
{
fprintf( stderr, "Couldn't unmap the file! Error Code: %02X\n", GetLastError( ) );
}
}

I think there is only one possible solution - interop with dll through dedicated thread. So in time you need to unload dll you just exit (or may be kill) that thread and all associated with it resources will be freed. In this case you are not guaranteed about memory leaks, but I suggest this solution as temporary, till 3d party fixes bugs in dll

This is probably not the issue you're experience, but in case it is:
When using linker support for run-time dynamic linking, don't forget to use the /Delay:Unload argument.

Related

change file descriptor without re-initializing the handle of uv_poll_t type

I have an application project running on Linux environment, which includes libuv and another third-party library, the third-party library provides APIs for starting a TCP connection to remote server (say xxx_connect()) and getting file descriptor of the active connection (say xxx_get_socket()) . So far I managed to get valid file descriptor from xxx_get_socket() after xxx_connect() completed successfully, and initialize uv_poll_t handle with that file descriptor in my program.
Currently I am working on reconnecting function, after reconnecting the same server (by running xxx_connect() again), xxx_get_socket() returns different file descriptor, that means it is necessary to update io_watcher.fd member of a uv_poll_t handle to receive data in the new active connection.
AFAIK uv_poll_init() internally invokes uv__io_check_fd() , uv__nonblock() and uv__io_init() , it seems possible to modify io_watcher.fd of a uv_poll_t handle without closing the handle and then initializing it again (see sample code below), which has extra latency. However I'm not sure if it is safe to do so, I don't know whether io_watcher.fd member of a uv_poll_t handle is referenced elsewhere in libuv (e.g. uv_run()) which makes thing more complex. Is my approach feasible or should I re-initialize the uv_poll_t handle in such case ? Appreciate any feedback.
Possible approach , simplified sample code :
int uv_poll_change_fd( uv_poll_t *handle, int new_fd ) {
if (uv__fd_exists(handle->loop, new_fd))
// ..... some code ....
err = uv__io_check_fd(handle->loop, new_fd);
if(err)
// ..... some code ....
err = uv__nonblock(new_fd, 1);
// ..... some code ....
handle->io_watcher.fd = new_fd;
}

SHFileOperation: randomly raises exceptions when deleting files

I am using SHFileOperation() to delete directories from a specific path. It is done in multiple threads and the directory that's deleted is always different.
From time to time, it throws exceptions:
Exception thrown at 0x00007FF8AF5D9D2A (ntdll.dll) in del.exe:
0xC0000008: An invalid handle was specified
and this one:
Exception thrown at 0x00007FF8ACC90A36 (shell32.dll) in del.exe:
0xC0000005: Access violation reading location 0x0000000000000001.
modules:
shell32.dll 00007FF8ACBD0000-00007FF8AE0D8000
ntdll.dll 00007FF8AF530000-00007FF8AF701000
This is the code:
SHFILEOPSTRUCTW tFileOptions = { 0 };
/* Initialize the file options structure for the deletion process */
tFileOptions.pFrom = pwstrPath;
tFileOptions.wFunc = FO_DELETE;
tFileOptions.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
/* Execute the deletions with the Shell operation */
iResult = SHFileOperationW(&tFileOptions);
if (0 != iResult)
{
printf("WTF\n");
goto lbl_cleanup;
}
SHChangeNotify(SHCNE_RMDIR, SHCNF_PATHW, pwstrPath, NULL);
The pwstrPath has a double null terminator at the end.
What can be the reason for these exceptions?
EDIT
Stack trace:
from stack trace (even without pdb symbols - with it will be much more better ) visible that exception not inside windows shell itself but in third party product - dragext64.dll (this is not native windows image) wich is implement Copy Hook Handler - i advise uninstall this or disable via registry key
HKEY_CLASSES_ROOT
Directory
shellex
CopyHookHandlers
MyCopyHandler
(Default) = {MyCopyHandler CLSID GUID}
and test after this. think exceptions must go away.
also look like some another shell extensions have bugs here - search in google SHELL32_CallFileCopyHooks. for example bug TortoiseGit.dll - note here in stack trace shell32.dll!SHELL32_CallFileCopyHooks()
so all this bugs inside implementation of ICopyHook::CopyCallback method

How to properly get contents of DLL file for PE parsing?

I'm trying to get the RVA of a function in kernel32.dll which means I need to use the offsets to find different structures in the file until I can get the IMAGE_EXPORT_DIRECTORY structure. However I know a lot of methods and ways of getting the contents of files interpret and leave certain characters and stuff out which would make this a nearly impossible task. So I want to know the best way to go about getting the contents of a dll file to copy into a character array.
Update: For anyone interested I created a function for mapping the dll into memory.
void* GetFileImage(char path[])
{
HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
if(hFile == INVALID_HANDLE_VALUE){return NULL;}
HANDLE file_map = CreateFileMapping(hFile, NULL, PAGE_READONLY|SEC_IMAGE, 0, 0, "KernelMap");
if(file_map == INVALID_HANDLE_VALUE){return NULL;}
LPVOID file_image = MapViewOfFile(file_map, FILE_MAP_READ, 0, 0, 0);
if(file_image == 0){return NULL;}
return file_image;
}
There are multiple ways. Not that many multiple, though.
1.If you are trying to parse a system loaded file such as kernel32.dll which are loaded into memory on system startup, you can directly use GetModuleHandle to grab the loaded base address and start parsing through PE (assuming you are familiar with the PE structure and static/delay loading of dlls and its exports).
2.If the dll you are trying to parse is not one of the system loaded, you can load them using LoadLibrary, which will return you the loaded base address, thus enabling you to parse the PE.
3.You can also do CreatFileMapping/MapViewOfFile to map the dll in your own virtual memory to parse.
The msdn article suggested by #David Thomas will be of great help:: Peering Inside the PE

CustomAction succeeds on development computer, fails on deployment computer

I'm creating a WiX installer to install a program which connects to a database. To help with this, I've created a C dll which checks to see if a certain instance of SQL exists on a server:
extern "C" UINT __stdcall DBConTest(MSIHANDLE hInstaller)
{
FILE *fp;
fp = fopen("dbcontestdll.txt", "w");
_ConnectionPtr pCon;
int iErrCode;
HRESULT hr;
UINT rc;
//init COM
fwprintf(fp, L"entering dbcontest\n");
if(FAILED(hr = CoInitializeEx(NULL,tagCOINIT::COINIT_APARTMENTTHREADED)))
return ERROR_INVALID_DATA;
fwprintf(fp,L"did coinit\n");
if(FAILED(hr = pCon.CreateInstance(__uuidof(Connection))))
return ERROR_INVALID_DATA;
fwprintf(fp,L"created instance of connection\n");
TCHAR constr[1024];
DWORD constrlen = sizeof(constr);
rc=MsiGetProperty(hInstaller,TEXT("DBCONNECTIONSTRING"), constr, &constrlen);
fwprintf(fp, L"dbconstring is: %s\n", constr);
TCHAR serverstr[1024];
DWORD serverstrlen = sizeof(serverstr);
rc = MsiGetProperty(hInstaller,TEXT("SQLINSTANCE"),serverstr,&serverstrlen);
fwprintf(fp, L"SQLINSTANCE is: %sl\n",serverstr);
TCHAR finalconstr[2048];
swprintf(finalconstr,L"%s; Data Source=%s;",constr,serverstr);
try{
hr = pCon->Open(finalconstr,TEXT(""),TEXT(""),adConnectUnspecified);
}
catch(_com_error ce){
fwprintf(fp, L"%s\n", msg);
::MessageBox(NULL,msg,NULL,NULL);
CoUninitialize();
MsiSetProperty(hInstaller,TEXT("DBCONNECTIONVALID"),TEXT("0"));
return ERROR_SUCCESS;
}
if(FAILED(hr)){
MsiSetProperty(hInstaller,TEXT("DBCONNECTIONVALID"),TEXT("0"));
return ERROR_SUCCESS;
}
pCon->Close();
CoUninitialize();
MsiSetProperty(hInstaller,TEXT("DBCONNECTIONVALID"),TEXT("1"));
::MessageBox(NULL,TEXT("Successfully connected to the database!"),NULL,NULL);
fwprintf(fp, L"leaving...\n");
fclose(fp);
return ERROR_SUCCESS;
}
Now, when I build this function into a dll and add it to my WiX project, this code works on my development machine (specifically, the installation successfully finishes and the file "dbcontestdll.txt" exists and has the correct data in it)--but, when I run it on a "fresh install" machine, the installation fails with exit code 2896 and the "dbcontestdll.txt" is not created.
Are there prerequisites to using C-based dlls in a Windows Installer, such as the C++ redistributable?
You probably don't want to get yourself into the situation where you have to bootstrap C++ redists just to run a Custom Action. Have you tried using the File | New | C++ Custom Action probject that comes with WiX? You can use that to stub out your CA and then copy and paste your code into it. That should give you all the compiler and linker settings that you need to avoid this problem.
For custom actions, I highly recommend statically linking to the C run time. The custom aciton DLL ends up a little bigger but you'll have one less dependency on files outside the custom action.
Yes you probably need the visual c runtime. Dependency Walker might assist finding the required dlls.
Look at this example how to use a Bootstrapper. This way you can install the runtime before the msi will be run. I use the following bootstrapper line:
<BootstrapperFile Include="Microsoft.Visual.C++.9.0.x86">
<ProductName>Visual C++ 2008 Runtime Libraries (x86)</ProductName>
</BootstrapperFile>
This package is normally stored in the C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bootstrapper\Packages\vcredist_x86 directory.
I had this problem also. I had an MFC DLL that was dynamically linking by default, and I forgot to include MSVCR100.DLL in the package. Of course it worked fine on the development machine, it even worked on most customers' machines, but it failed on an old Vista PC. I switched to statically linked.

How can I make the printer work in C in MS VC++ Express edition?

I am using VC++ 2008 express edition for C. When I try to run this:
/* Demonstrates printer output. */
#include <stdio.h>
main()
{
float f = 2.0134;
fprintf(stdprn, "This message is printed.\n\n");
fprintf(stdprn, "And now some numbers:\n\n");
fprintf(stdprn, "The square of %f is %f.", f, f*f);
/* Send a form feed */
fprintf(stdprn, "\f");
}
I get four of these errors: error C2065: 'stdprn' : undeclared identifier.
On this forum, they wrote that it works to define the printer as follows:
FILE *printer;
printer = fopen("PRN", "w");
EDIT
It builds with a warning that fopen is unsafe. When it runs the error appears:
Debug Assertion fails.
File: f:\dd\vctools\crt_bld\self_x86\crt\src\fprintf.c
Line: 55
Expression: (str != NULL)
The stdprn stream was an extension provided by Borland compilers - as far as I know, MS have never supported it. Regarding the use of fopen to open the printer device, I don't think this will work with any recent versions of Windows, but a couple of things to try:
use PRN: as the name instead of PRN (note the colon)
try opening the specific device using (for example) LPT1: (once again, note the colon). This will of course not work if you don't have a printer attached.
don't depend on a printer dialog coming up - you are not really using the WIndows printing system when you take this approach (and so it probably won't solve your problem, but is worth a try).
I do not have a printer attached, but I do have the Microsoft XPS document writer installed, s it shoulod at least bring up the standard Windows Print dialog from which one can choose the printer.
No. It wouldn't bring up a dialogue. This is because you are flushing data out to a file. And not going through the circuitous Win32 API.
The print doesn't work because the data is not proper PDL -- something that the printer could understand. For the print to work fine, you need to push in a PDL file, with language specific constructs. This varies from printer to printer, a PS printer will need you to push in a PostScript snippet, a PCL -- a PCL command-set and in case of MXDW you will have to write up XML based page description markup and create a zip file (with all resources embedded in it) i.e. an XPS file to get proper printout.
The PDL constructs are important because otherwise the printer doesn't know where to put the data, which color to print it on, what orientation to use, how many copies to print and so on and so forth.
Edit: I am curious why you are doing this. I understand portability is probably something you are trying to address. But apart from that, I'd like to know, there may be better alternatives available. Win32 Print Subsytem APIs are something that you ought to lookup if you are trying to print programmatically on Windows with any degree of fidelity.
Edit#2:
EDIT It builds with a warning that fopen is unsafe.
This is because MS suggests you use the safer versions nowadays fopen_s . See Security Enhancements in the CRT.
When it runs the error appears:
Debug Assertion fails. File: f:\dd\vctools\crt_bld\self_x86\crt\src\fprintf.c Line: 55
Expression: (str != NULL)
This is because fopen (whose return value you do not check) returns a NULL pointer. The file open failed. Also, if it did succeed a matching fclose call is called for.
There's no such thing as stdprn in ANSI C, it was a nonstandard extension provided by some compilers many years ago.
Today to print you have to use the specific APIs provided on your platform; to print on Windows you have to use the printing APIs to manage the printing of the document and obtain a DC to the printer and the GDI APIs to perform the actual drawing on the DC.
On UNIX-like OSes, instead, usually CUPS is used.
You can substitute the printer using this command with net use, see here on the MSDN kb
NET USE LPT1 \\server_name\printer_name
There is an excellent chapter on printing in DOS using the BIOS, ok, its a bit antiquated but interesting to read purely for nostalgic sake.
Onto your problem, you may need to use CreateFile to open the LPT1 port, see here for an example, I have it duplicated it here, for your benefit.
HANDLE hFile;
hFile = CreateFile("LPT1", GENERIC_WRITE, 0,NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
// handle error
}
OVERLAPPED ov = {};
ov.hEvent = CreateEvent(0, false, false, 0);
char szData[] = "1234567890";
DWORD p;
if (!WriteFile(hFile,szData, 10, &p, &ov))
{
if (GetLastError() != ERROR_IO_PENDING)
{
// handle error
}
}
// Wait for write op to complete (maximum 3 second)
DWORD dwWait = WaitForSingleObject(ov.hEvent, 3000);
if (dwWait == WAIT_TIMEOUT)
{
// it took more than 3 seconds
} else if (dwWait == WAIT_OBJECT_0)
{
// the write op completed,
// call GetOverlappedResult(...)
}
CloseHandle(ov.hEvent);
CloseHandle(hFile);
But if you insist on opening the LPT1 port directly, error checking is omitted...
FILE *prn = fopen("lpt1", "w");
fprintf(prn, "Hello World\n\f");
fclose(prn);
Hope this helps,
Best regards,
Tom.

Resources