Replacing a .NET dll - vb.net

I have a dll which is installed with the initial installation of my app (via an msi file). The dll contains a user key and this is 'demo' for the initial installation. When a user buys a licence he is provided with another dll which contains his name. The second dll is simply the first, rebuilt with a different name so it is the same GUID and file name.
This works fine on my win7 test machine, I can replace the dll in my apps dir and it runs correctly. I have recently provided a user dll to a new client but the replace method doesn't seem to work. He is quite IT literate so I think he is following the emailed instruction (replace the userdata.dll in your app directory with the attached) it does not seem to change the dll. He is using Win8(pro).
I had thought of sending him an Inno setup to copy the user dll into the app dir, Flags:ignorereversion regserver sharedfile
Can anyone suggest a solution or an explanation?
Later...
I have now sent him an Inno setup for the updated dll and this works. If I used the second dll method (a good idea) I would still need to have the user install it.

Rather than replacing the original .dll, why not provide a second .dll with the customer's specific info? The 2nd .dll will unlock features in the original .dll.
For instance, in your original .dll you might check for Customer.dll:
if(TryLoadAssembly("Customer.dll", out assembly)) {
if(Validate(assembly)){
IsUnlocked = true;
}
}
Further recommendations (and untested samples) - have Customer.dll contain a single object implementing an interface:
class Customer : IToken {
GUID Guid {get;}
// other fields
}
To validate:
bool Validate(Assembly assembly){
Type type = assembly.GetType("Customer");
IToken customerToken = (IToken)Activator.CreateInstance(type);
// check some properties
return customerToken.Guid == application.Guid;
}

You say it doesn't appear to be replacing the DLL. Is it UAC redirecting his filecopy into local storage?
If this is the case then the easiest way to deal with it would be to either
1) supply a batch file that can do the file copy, along with instructions to launch the batch file by right clicking on it anc choosing "run as administrator".
2) supply an executable that can do the file copy. You can either include instructions to run the exe as an administrator like the batch file, or you can include a manifest with the application to instruct windows that the file needs to execute as an administrator.
A last option, which might be worth while for troubleshooting would be to get the user to turn off UAC and try the file copy again. If that works then this user will be happy and you know what the problem is and can find an elegant solution for future customers.
I've just looked on my Win 8 laptop and the option for UAC is in Control Panel - User Accounts - User Accounts - Change user account control settings. This will give a slider which can be slid all the way to the bottom to turn off UAC.
(User Accounts really is listed twice.)

Related

how to use different profile for dev and production in office vsto add-in development

When we dev/test our add-in, we need to request request http://dev.xx.com. and after release, in production we need to change the url to http://prod.xx.com.
How can we do this?
===
I'm new to vsto development and c#. I looked config file(in fact Settings.settings) way. But in fact i don't want the users to "config" it. It't better if I can build out two different versions in one click ervery time, and give one to testers and another to the end user.
When I devloping server-side springboot applications, I use 3 different config file and one single jar. And give the different config file and same sigle jar to different persons. This way at least we can confirm that the applicaiton (jar) is the same for test and deploy.
But the "Settings.settings" seems binded to the "solution" in vs. The pre processor seems not good enough, seems that it binded to the "solution" too. I have to change it in the "Properties" every time before I build the project? Or I need to create more "Solutions"?
Maybe I did't look that deep enough, I will keep looking
=== SOLVED
We finaly solved (partly) using Conditional compilation
#if DEBUG
const string baseUrl = "192.168.20.101:8001/api";
#endif
#if (!DEBUG)
const string baseUrl = "xxx.com/api";
#endif
one small issue is that we need to distribute debug package to our test team.

CoCreateInstance CLSID_IConverterSession fails with Office 2016

I'm using IConverterSession to create mail items from mhtm files. This works fine with Outlook Versions < 2016. With Office 2016, IConverterSession cannot be created.
If you are running C2R (click-to-run) version of Outlook 2016, all registry keys are virtualized - see the registry keys below (%s needs to be replaced by the Outlook version, e.g. 16.0). Since the COM system does not look there, you will need to implement your own version of CoCreateInstance that reads the default value from the key to figure out the dll file name, then calls LoadLibrary / GetProcAddress("DllGetClassObject") / DllGetClassObject(..., IID_IClassFactory, ...) / IClassFactory.CreateInstance.
SOFTWARE\Microsoft\Office\%s.0\ClickToRun\REGISTRY\MACHINE\Software\Classes\CLSID\%s\InprocServer32
SOFTWARE\Microsoft\Office\%s.0\ClickToRun\REGISTRY\MACHINE\Software\Classes\Wow6432Node\CLSID\%s\InprocServer32
SOFTWARE\Microsoft\Office\ClickToRun\REGISTRY\MACHINE\Software\Classes\CLSID\%s\InprocServer32
SOFTWARE\Microsoft\Office\ClickToRun\REGISTRY\MACHINE\Software\Classes\Wow6432Node\CLSID\%s\InprocServer32
Instead of implementing CoCreateInstance() on your own, you have to enable registry redirection to enable C2R (click-to-run) virtualization of Outlook which is using detours to redirect the call to RegOpenKey(). After enabling that redirection just use the normal CoCreateInstance().
The reason why implementing CoCreateInstance() on your own doesn't work is, that the converter will also call CoCreateInstance() internally and that will fail like your original call because it doesn't find the CLSID in the normal hive of the registry.
I found out the code myself by looking on the jitv.dll exports. The parameters may be wrong, but as a first start it was working without a crash. To find out the parameters I have to debug an Office application and look at the disassembly (or any volunteers?).
Here the experimental code that worked for me :
HMODULE jitv = ::LoadLibrary(TEXT("jitv.dll"));
if (jitv) {
FARPROC efv = ::GetProcAddress(jitv, "EnableFullVirtualization");
if(efv)
efv();
// call CoCreateInstance(guid::CLSID_IConverterSession)
// and do your work
}
if (jitv)
FreeLibrary(jitv);
There are some other exports in the jitv.dll whose names are mostly selfexplanary:
"APIExportForDetours"
"DisableVirtualizationOnThread"
"EnableVirtualizationOnThread"
"IsCurrentThreadVirtualized"
Thanks to this posting by nickekallen which mentioned that dll and brought me to that idea.

How to pass arguments to an application that is already running?

I have an application written in VB.NET and I have a file association that will trigger a specific function if opened from that file type.
The only thing is that If the application is already open and a user clicks on an associated file, it opens another instance of the application.
Basically, I would like to have the currently running instance of the application handle any incoming arguments from a double click on an associated file. Here is some pseudo-code to help understand.
if(application.isAlreadyRunning){
application.doSomething(filePath);
}
else{
proceed normally...
}
I've looked into mutexes, and they allow me to ensure that only one instance of the app is running, but then I need to pass the filename to the currently running instance.
Thanks!
P.S. I forgot to mention that I am using ClickOnce to deploy the app and AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData to retrieve the "arguments"

Write to file as Different User

I am trying to write to a file that my local user account does not have access to, how can I open and write to the file as an administrator?
You need to launch another process that has admin rights. To do that call ShellExecute with 'runas' as the second parameter (this will open a User Account Control dialog). That executable may be separate or may be the same one that is calling ShellExecute.
You might want to look at PSEXEC from Microsoft, it allows you to execute files in elevated mode, and as a different user if desired.
You didn't say how the file is opened for writing, but PSEXEC can be used in conjunction in batch/vbs file to execute another batch/vbs/exe.
A good wrapper class for impersonation in a using block is what I have used with success before:
using (new Impersonation(domain, username, password))
{
// <code that executes under different user context>
}
The Using statement is great for code readability as seen in this example and to ensure that the object used is properly disposed when the final } character is reached (running out of scope). Apparently there is no guarantee of garbage collection though (see first answer).
Two different sources for such a wrapper class:
This stackoverflow solution features good readability and usability.
Here is similar code from CodeProject: A small C# Class for impersonating a User.
See MSDN for more on the Using statement.

My application fails to create MAPI/Messaging profile properly using MAPI subsystem

I have an application which creates a MAPI profile to send mails/messages. The profile is getting created properly on Outlook2007 environment, but it is not getting created properly on Outlook2007 SP2 environment. Both the source code and "exchange environment to which MAPI/outlook profile" are same. The profile is created using MAPI subsystem.
Description about the application: The application is a windows service-based application. The service executes a COM application. The COM application spawns a new thread to create a new profile and sends a sample message.
Actual problem: During the profile creation, the call to the ConfigureMsgService function (that belongs to IMsgServiceAdmin) is not working properly even though it returns S_OK. The value for the 5th parameter "lpProps" of ConfigureMsgService function is given below.
// First, the mailbox name.
ZeroMemory(&rgval[0], sizeof(SPropValue) );
rgval[0].ulPropTag = PR_PROFILE_UNRESOLVED_NAME;
rgval[0].Value.lpszA = szMailbox;
// Next, the server name.
ZeroMemory(&rgval[1], sizeof(SPropValue) );
rgval[1].ulPropTag = PR_PROFILE_UNRESOLVED_SERVER;
rgval[1].Value.lpszA = szServer;
// For NT Services, need to do this to keep MAPI from
// displaying dialog boxes.
ZeroMemory(&rgval[2], sizeof(SPropValue) );
rgval[2].ulPropTag = PR_CONVERSION_PROHIBITED; //As the com application is executed by the NT service, this parameter is specified.
rgval[2].Value.b = TRUE;
Also note, prior to ConfigureMsgService function call, all the other MAPI calls such as MAPIInitialize, MAPIAdminProfiles, CreateProfile, AdminServices, CreateMsgService, GetMsgServiceTable etc are succeeded.
My question, the same code was working properly with Outlook 2007 environment, but it failed in Outlook 2007 SP2 environment.
Please note,
1. when the same code is executed from a stand-alone application, it worked fine.
2. The code didn't work properly if the service is executed as a Local System account or as a network service account.
What could be the problem? Am I missing some thing.
Is there any work-around is available?
Thanks in advance
Saravanan
Your problem is in #2 of your note:
Please note, 1. when the same code is
executed from a stand-alone
application, it worked fine. 2. The
code didn't work properly if the
service is executed as a Local System
account or as a network service
account.
MAPI profiles are stored in the current user's hive* in the registry (HKEY_CURRENT_USER and HKEY_USERS{user SID}). The system accounts (LocalSystem and NetworkService) don't present a user hive which MAPI needs to write the profile information.
The easiest fix is to have your service run under a user account which has been granted the Log On As Service right. Depending on how your COM app is run as (in proc vs out of proc) you may be able to have it run as a specific user instead of a system account.
*Hive is the term used for the different sections of the registry. Here we're just dealing with the user's own section of the registry.
Thanks for your reply.
I tried your idea, but it doesn't worked. I spoke to Microsoft in this case, they have provided a fix for this issue(http://support.microsoft.com/kb/972363), it fixed it.
Saravanan