.netbatch-filecomregsvr32regasm

Distinguish COM dll from .NET assembly in batch files


I have a bunch of dlls in a folder, which are either COM dlls, or .NET assemblies. Now, I'm using something like this below to register the binaries:

@echo off

set argCount=0
for %%x in (%*) do (
   set /A argCount+=1
)
if not %argCount% == 1 (
    echo Usage:
    echo   %0 ^<filename^>
    echo Example:
    echo   %0 path\to\the\file.ext
    goto end
)

for /F "tokens=*" %%A in (%1) do (
    echo Registering %%A ...
    regsvr32 "%%A"
)

:end

The issue here is that although for COM dlls, it works fine, but for .NET assemblies it fails. As a workaround, I could replace the regsvr32 with regasm and run it again. This would, in the second run register the .NET assemblies. I was wondering, if there was a way the batch file might be able to distinguish between the two cases here. I understand, COM dlls must have the PE or COFF header while .NET assemblies would not (?). Looking at MSDN, I see ImageHlp API which might have something for this. Is there an easier way to achieve the same?


Solution

  • I'm fairly certain there is nothing you can do with raw batch script to detect this. (Or if you can figure out a way, it's going to be incredibly ugly.) But you can do this a number of other ways.

    Here's one option: Use corflags.exe, which ships with the Windows SDK. To find a copy on your system, try something like attrib /s C:\corflags.exe. To use it, try something like this:

    corflags.exe your.dll
    if %ERRORLEVEL% equ 0 goto :IS_DOT_NET
    goto :IS_NOT_DOT_NET
    

    Alternatively, you could write your own program that looks for the existence of a DllRegisterServer entry point in the DLL, which .NET DLLs do not have. It would only take a handful of lines of code in any language to do this check. Here's the C++:

    // returns:
    //   1 if the dll can be used with regsvr32
    //   0 if the dll cannot be used with regsvr32
    //  -1 if the dll cannot be loaded
    int main(int argc, LPCSTR* argv)
    {
        if (argc != 2)
            return -1;
        HMODULE hModule = LoadLibraryA(argv[1]);
        if (!hModule)
            return -1;
        FARPROC dllRegisterServer = GetProcAddress(hModule, "DllRegisterServer");
        FreeLibrary(hModule);
        if (dllRegisterServer)
            return 1;
        return 0;
    }
    

    Of course, this is half of what regsvr32.exe already does, so you could just do something like:

    regsvr32.exe /s your.dll
    if %errorlevel% neq 0 regasm.exe your.dll