0

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?

user2338150
  • 479
  • 5
  • 14
  • 1
    When regsvr32 fails does it set the errorlevel to a number greater than zero? If so you can do something like this: `IF ERRORLEVEL 1 regasm "%%A"`. – Squashman Nov 06 '18 at 14:41
  • Yeah, it's basically correct. What if there are native dlls also? Wouldn't be a problem though. I wanted, if there were some tools in msdev already, that I could use or exploit.:) – user2338150 Nov 06 '18 at 14:57
  • Are the file extensions different between them? If so use the command modifier to check the file extension? `IF /I "%~x1"==".dll" regsvr32 "%1"`. Not sure why you are using a `FOR /F` command to parse the command line argument. You certainly do not need to do that. And if you are going to use the `FOR` command then you just need the `FOR` command by itself. You don't need to use the `/F` or the options. – Squashman Nov 06 '18 at 15:02
  • Ah, my bad. This is expected to take newline separated filenames in a file as input. The reason the '/F' switch is there is from having lingered from another batch file that I was trying to edit. I understand, this one here, would try to break up line into tokens, here only 1. So, you're correct that it is redundant. Please excuse me this one time. I'm relatively less experienced on scripting side. I'll try to get better – user2338150 Nov 06 '18 at 15:18
  • If you are reading a file then yes you need to use a `FOR /F`. Your question is confusing as you state you have a bunch of files in a folder. So I assumed you were just passing a single dll file to the batch file. – Squashman Nov 06 '18 at 15:25
  • 1
    If you can tell me where on my computer I might find a normal dll and a .NET dll, I could probably code something to figure out which is which. – Squashman Nov 06 '18 at 15:26
  • Hi, sorry I was gone for a while. For .NET dll, say you could pick for instance: "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\Microsoft.CSharp.dll". For native dll, say: "C:\Windows\System32\ole32.dll". – user2338150 Nov 07 '18 at 16:39

1 Answers1

1

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
Michael Gunter
  • 12,528
  • 1
  • 24
  • 58
  • 2
    Yes, your last code is what I was referring to in my first comment above. You could also use a batch file to figure out if it is a normal com or a .net based on PE being in the header. We have some examples of this on DosTips.com. Just trying to find that thread over there. – Squashman Nov 06 '18 at 19:31
  • 1
    Thank you for the answers. I think I would go with Squashman's solution. It's really simple. I did learn about corflags.exe. This was what I was looking for. I see, that it can identify and modify CLR header. Might want to use it in future. – user2338150 Nov 07 '18 at 16:48
  • Cool. That solution is probably what I would do, too. @Squashman : Is [this](https://www.dostips.com/forum/viewtopic.php?t=5826) the link you were looking for? OP, you could maybe use something like this, but personally, I think it's pretty ugly. – Michael Gunter Nov 07 '18 at 21:12