Skip to content
⌘ NSIS Forum Archive

Questions about UAC plugin

52 posts

sledgehammer_999#
Thanks. This is some progress but I still see 3 errors.

RunAs.cpp
uac.cpp
util.cpp
Generating Code...
Microsoft (R) Incremental Linker Version 9.00.30729.01
Copyright (C) Microsoft Corporation. All rights reserved.

/out:RunAs.dll
/dll
/implib:RunAs.lib
kernel32.lib
user32.lib
shell32.lib
advapi32.lib
ole32.lib
/DLL
/OUT:uac.dll
RunAs.obj
uac.obj
util.obj
RunAs.obj : warning LNK4229: invalid directive '/opt:nowin98' encountered; ignored
RunAs.obj : warning LNK4229: invalid directive '/ignore:4078' encountered; ignored
uac.obj : warning LNK4229: invalid directive '/opt:nowin98' encountered; ignored
uac.obj : warning LNK4229: invalid directive '/ignore:4078' encountered; ignored
Creating library RunAs.lib and object RunAs.exp
RunAs.obj : error LNK2019: unresolved external symbol _memset referenced in function "int __stdcall MyRunAsDlgProc(struct HWND__ *,unsigned int,unsigned int,long)" (?MyRunAsDlgProc@@YGHPAUHWND__@@IIJ@Z)
uac.obj : error LNK2001: unresolved external symbol _memset
util.obj : error LNK2001: unresolved external symbol _memset
uac.dll : fatal error LNK1120: 1 unresolved externals
Unfortunately google didn't turn up something useful. Any ideas?

PS: Commmandline used:

cl.exe /O1s /GS- /GR- /EHs-c- /Zl /LD /DUNICODE RunAs.cpp uac.cpp util.cpp /link kernel32.lib user32.lib shell32.lib advapi32.lib ole32.lib /DLL /OUT:uac.dll
Anders#
I uploaded a new version that tries to not use memset. You could also specify /MD or one of the other CRT switches (and remove /Zl) but then the plugin might not work on older versions of Windows.
sledgehammer_999#
I still get one memset error in util.cpp

util.obj : error LNK2019: unresolved external symbol _memset referenced in function "void __stdcall MemSet(void *,unsigned long,unsigned char)" (?MemSet@@YGXPAXKE@Z)
But removing /Zl and using /MD produces a dll. I am going to test it now and probably go to sleep.

Thanks for the help and I hope you'll solve the remaining memset error.
Anders#
Actually, that error is not really possible to solve, the only way around it is to use a pragma to disable optimizations for that function.

This is a bug in the compiler IMHO. What actually happens is that the compiler sees that the MemSet function looks like it can be replaced by a call to memset and so the compiler does exactly that without even checking if the memset function "exists"...
sledgehammer_999#
OK.

So does using /MD have any real disadvantage? My minimum OS req is Windows XP.

And of course I have another problem now that I am able to compile the script.
NSIS reports that function PageFinishRun isn't referenced and it zeroes it out. The funny thing is that I use it in MUI_FINISHPAGE_RUN_FUNCTION.

I might find what is wrong tomorrow when I won't be sleepy...
Anders#
/MD will import from msvcrt*.dll. Which exact dll that is depends on the compiler version. If it is msvcrt.dll then it will work on all versions except Win95 RTM, if it is one with a number in the name then it will only work if the CRT redist. for that exact version is installed on the machine. You can try /MT or one of the other CRT switches...
Afrow UK#
Are you explicitly using memset or ZeroMemory? Something like this can also force the compiler to use memset: char a[32] = "";

If you can't stop the compiler from linking with memset (or you'd rather not) you can include your own memset function (CRTReplica.cpp in LockedList or crt.cpp in inetc has it).

This is a blog post you may like to read if you want to get rid of any MSVCRT dependencies: http://afrowsoft.blogspot.co.uk/2011...ual-c-run.html.

Stu
Anders#
Originally Posted by Afrow UK View Post
If you can't get rid of the memset reference, you can include your own memset function (CRTReplica.cpp in LockedList or crt.cpp in inetc has it).
There is no memset reference, it is the compiler itself that makes the reference internally.

It will turn "void MemSet(char*p,int c,int v) { for(..) .. }" into a call to memset even when compiling with /Zl and no CRT. The compiler just assumes that the CRT is always available.
Afrow UK#
Originally Posted by Anders View Post
There is no memset reference, it is the compiler itself that makes the reference internally.
My first sentence made this quite clear that this is the case and one way to stop it. I have edited the 2nd sentence for clarity.

Originally Posted by Anders View Post
It will turn "void MemSet(char*p,int c,int v) { for(..) .. }" into a call to memset even when compiling with /Zl and no CRT. The compiler just assumes that the CRT is always available.
Not if you use /NODEFAULTLIB.

Stu
sledgehammer_999#
I opened the produced dll in dependency walker and there isn't a reference to msvcrt.dll in the first level of the dependency tree. (compiled with /MD).

I then compiled it using /MT (statically link the runtime). The filesize increased ~2KB. This means that something is used from the runtime, but why doesn't dependcy walker show the dependency of msvcrt in the /MD compiled dll?

Not if you use /NODEFAULTLIB
Tried with /Zl and /NODEFAULTLIB but I get the same error.
sledgehammer_999#
Originally Posted by sledgehammer_999 View Post
I opened the produced dll in dependency walker and there isn't a reference to msvcrt.dll in the first level of the dependency tree. (compiled with /MD).

I then compiled it using /MT (statically link the runtime). The filesize increased ~2KB. This means that something is used from the runtime, but why doesn't dependcy walker show the dependency of msvcrt in the /MD compiled dll?



Tried with /Zl and /NODEFAULTLIB but I get the same error.
And I forgot to mention that dependency walker doesn't show any dependency on any msvcrt<versionumber>.dll either.

I also rechecked the filesize difference. It is a ~4KB difference.
I also attach a screeshot of dependecy walker for the /MD compiled dll.
Anders#
Originally Posted by Afrow UK View Post
My first sentence made this quite clear that this is the case and one way to stop it. I have edited the 2nd sentence for clarity.

Not if you use /NODEFAULTLIB.
/NODEFAULTLIB is a linker flag, how is it going to affect the code generated by the compiler? /Zl should have the same effect.

You cannot include your own memset function either if you are also compiling with /GL.
Anders#
Originally Posted by sledgehammer_999 View Post
I opened the produced dll in dependency walker and there isn't a reference to msvcrt.dll in the first level of the dependency tree. (compiled with /MD).

I then compiled it using /MT (statically link the runtime). The filesize increased ~2KB. This means that something is used from the runtime, but why doesn't dependcy walker show the dependency of msvcrt in the /MD compiled dll?
The compiler might inline the memset call, who knows. Compile with /FAcs and see if there is a memset call and what is generated.

/MT should not increase the filesize (in theory). 😢
Afrow UK#
Originally Posted by Anders View Post
/NODEFAULTLIB is a linker flag, how is it going to affect the code generated by the compiler? /Zl should have the same effect.

You cannot include your own memset function either if you are also compiling with /GL.
LockedList and inetc both use their own memset function instead of the CRT's. This is with /MT, /GL and /Zi. You just have to use /NODEFAULTLIB so it links against your memset instead. Compiled with VS2012 (v110 toolset).

Edit: If you are using Zl (L) for debugging you may as well just link with MSVCRT anyway.

Stu
Anders#
Originally Posted by Afrow UK View Post
LockedList and inetc both use their own memset function instead of the CRT's. This is with /MT, /GL and /Zi. You just have to use /NODEFAULTLIB so it links against your memset instead. Compiled with VS2012 (v110 toolset).
I know that works sometimes and other times it will give you:

...\util.cpp(7) : error C2268: 'memset' is a
compiler predefined library helper. Library helpers are not supported with /GL;
compile object file without /GL.
LINK : fatal error LNK1257: code generation failed
sledgehammer_999#
If I wrap the MemSet function in this:

#pragma optimize("", off)
void WINAPI MemSet(void*pMem,SIZE_T cb,BYTE set)
{
char *p=(char*)pMem;
while (cb-- > 0){*p++=set;}
// return pMem;
}
#pragma optimize("", on)
A dll is produced with the /Zl switch now. And it is the exact same size as the one produced via /MD. (md5sum shows that they have different contents though).

@Anders, so maybe upload a new version with those pragmas?
Anders#
Originally Posted by sledgehammer_999 View Post
@Anders, so maybe upload a new version with those pragmas?
I used a different compiler version when I compiled...
sledgehammer_999#
Would it make sense to wrap the pragma inside ifdef checking the compiler version to the msvc2008 one?

Also I don't think it would hurt if the pragma was used regardless of compiler version...
The uac plugin doesn't need to be overly optimized anyway. We cannot gain much in terms of speed.
nickdollahz#
UAC Plugin: UAC_PageElevation_OnInit Page Skip Issues

I am having issues with the UAC Plugin using UAC_PageElevation_OnInit and UAC_PageElevation_OnGuiInit macros.

If I manually skip pages based off a condition using Abort it doesn't actually skip the page in the admin instance. I figured out a workaround but I'm not even sure why the workaround works. (Workaround is to hit the next button on those pages and then Abort. I commented out the code with the workaround)

I have attached a minimal example.
nickdollahz#
So noticed UAC Plugin is now labeled deprecated.
Curious what other solutions exist?

Although a lot of people aren't using it for the way I am using it. It seems to serve a purpose for MultiUser Installers. https://github.com/Drizin/NsisMultiUser

I did try and mess around with the source code and compile a debug version. I was able to determine that it is some issue with the Auto Page Jump feature. Unfortunately my C++ skills are non-existent but I do want to learn it eventually. So I have gone away from using it and decided to use the regular UAC Macros. Which means I have to manually skip each page in a pre function.

Everything seems to be working fine. Although I would like to be able to Hide the User instance Window after the admin instance has successfully launched. Not able to figure out how to get the HWND of the original instance.

I have attached an example of calling HideWindow before UAC call, but ideally I would like to call ShowWindow on the HWND of the User instance after the admin instance has been launched successfully.
Anders#
The page jump feature was bolted on later in the development and it might have some bugs because it is a slightly hacky way of doing things.

Manually skipping pages in your code is perfectly fine.