SharePoint fails to load a C++ DLL on Windows 2008 - c#

I have a SharePoint DLL that does some licensing things and as part of the code it uses an external C++ DLL to get the serial number of the hardisk.
When I run this application on Windows Server 2003 it works fine, but on Windows Server 2008 the whole site (loaded on load) crashes and resets continually. This is not Windows Server 2008 R2 and is the same in 64 or 32 bits.
If I put a Debugger.Break before the DLL execution then I see the code get to the point of the break and then never come back into the DLL again. I do get some debug assertion warnings from within the function, again only in Windows Server 2008, but I'm not sure this is related.
I created a console application that runs the C# DLL, which in turn loads the C++ DLL, and this works perfectly on Windows Server 2008 (although it does show the assertion errors, but I have suppressed these now).
The assertion errors are not in my code but within ICtypes.c, and not something I can debug.
If I put a breakpoint in the DLL it is never hit and the compiler says:
"step in: Stepping over non user code"
If I try to debug into the DLL using Visual Studio.
I have tried wrapping the code used to call the DLL in:
SPSecurity.RunWithElevatedPrivileges(delegate()
But this also does not help.
I have the source code for this DLL so that is not a problem.
If I delete the DLL from the directory I get an error about a missing DLL. If I replace it, back to no error or warning just a complete failure.
If I replace this code with a hardcoded string the whole application works fine.
Any advice would be much appreciated, I can't understand why it works as a console application, yet not when run by SharePoint. This is with the same user account, on the same machine...
This is the code used to call the DLL:
[DllImport("idDll.dll", EntryPoint = "GetMachineId", SetLastError = true)]
extern static string GetComponentId([MarshalAs(UnmanagedType.LPStr)]String s);
public static string GetComponentId()
{
Debugger.Break();
if (_machine == string.Empty)
{
string temp = "";
id= ComponentId.GetComponentId(temp);
}
return id;
}

This could be security related:
An important point is that it works in a console app.
In a console app RunWithElevatedPrivileges has no effect since it emulates the app pool user for your worker process, a user that should have no special rights on the box itself.
In contrast a console app runs in context of the logged in user.
Try emulating a user with rights like when you run the console application specified here (with Undo() inside try/finally mind you!). When obtaining the token you can create an SPUserToken and establish site context using the SPSite constructor that takes a GUID and a SPUserToken
Theres several examples out there documenting this approach, here for example.
EDIT: oh and the reason it worked on 2003 could be that your app pool account had way too many rights ;-)

Why not use WMI to get the serial number of hard disk, thus avoids execution of unmanaged code. See this sample How to Retrieve the REAL Hard Drive Serial Number

That non-deterministic crashing behavior is often seen with memory overwrites/corruption; sometimes it matters (crash), sometimes you get lucky.
You might want to check into getting a crash dump and analyze it with WindDbg. Since you have the source you could re-build it with the various stack, heap memory protection and warning systems enabled (depending on your compiler) and see what you get.

I'd find out if it is a User Account Control related problem, you can try to disable it.
2003 doesn't have UAC.
Your app pool account might not have the right to retrieve this information?

In visual studio, go into the properties of your executable assembly, and under the debug tab, check the enable debugging unmanaged code option.
If the method your are importing belongs to a class, you need to add the mangled C++ name (e.g. 2#MyClass#MyMethod?zii) as an entry point to the DllImport attribute (run depends on the native DLL to get it).
You do not need C++ for that: http://www.codeproject.com/KB/cs/hard_disk_serialno.aspx

If i put a breakpoint in the DLL it is
never hit and the compiler says :
"step in: Stepping over non user code"
That's the debugger, not the compiler, and if you configured it properly it wouldn't do that. Look for the options calls "Use native debugging" and "Just my code". The first one should be on and the second one off.

This problem may happen due to one of the problems listed below.
the web part may not have the right permissions to call the DLL or
you may not have set the appropriate trust level for your SharePoint site.
For the permission you can use impersonation and for the trust level below site can help you.
http://msdn.microsoft.com/en-us/library/dd583158(office.11).aspx

I made a new C++ DLL from scratch which works fine when referenced as a console application on Windows Server 2003 and Windows Server 2008, but as soon as I reference it from the DLL in SharePoint the same things happens and it won't run.
It does find the DLL, but I think it has no permissions to execute it, even if I put it into the My Documents section and reference it directly!

Related

PDB file and error handling?

We have a windows form application running across different customers, when they get errors we log into a database & using that stack information that is logged, we correct the issue.
However there are issues that occur only in production, the stack shows for example
CalculateTotals(method name) :NullReferenceException: Object reference not set to instance of an object.
The CalculateTotals is a method name, that has lots of sub-method calls & more lines, i am not able to get the exact line # of the code where it fails.
My application's PDB file is not sent to customers (when they do installation),
how do i keep a copy of that .PDB file (may be in a remote location and
not make it part of installation) and use that to
debug the errors & get the exact line?
You can include the pdb-files in release if you want to, but you can also use IntelliTrace to debug data from production in Visual Studio.
In short, IntelliTrace:
IntelliTrace plays a role similar to that of a black box in a plane. It keeps track of important points in your programs execution and allow you to play back what happened at those points at a later time.
Have a look at these blog posts:
Running IntelliTrace on Applications in Production
IntelliTrace - what and how.
And of course, you can search the web and find more about IntelliTrace.
You will only get line number info in the exception's stack trace when the CLR can find the PDB file at runtime. You are making this difficult by wanting to do this from a remote location but it is not impossible. The underlying API that the CLR uses is DIA (Debug Interface Access) which in turn uses the Debug API.
You'd have to setup the machine the same way you'd setup a debug session to have the debugger use a symbol server. Requirements are that you first setup a symbol server that can be accessed across the Internet, similar to the Microsoft Symbol Server. Then set the _NT_SYMBOL_PATH environment to reference that server. The core MSDN Library page that describes this is here. Beware that this is not easy to troubleshoot if it doesn't work.
An entirely different approach is that you create a minidump from the crashed process. You'll need to pinvoke MiniDumpWriteDump(). Beware that a good minidump for a .NET process is not very mini, you'll need the plumbing to have enough storage and somehow get it to your machine.

C# application says "No" when executed

I have developed a small-ish C# console application (TextMatcher.exe) on my local development machine and now need to deploy it to the live environment. It references another class library which I developed which has generic functions, which I intend to use and improve in future console applications.
Ultimately this specific application will be executed from within an SSIS package, but for now I'm just trying to run it from cmd.
I kid you not that this is the actual output from the program:
E:/TextMatcher>TextMatcher.exe
No
E:/TextMatcher>
The computer literally says "No" and gives no further information. I have not included, anywhere in the program, to output the word "No", on any failure or otherwise.
Of course, it runs fine locally. I made sure I included the dll of the utility class library too. I have read other questions (here, here) about how to deploy console apps correctly, and have followed the advice.
NB: This is also proving to be quite hard to Google because of the use of the word "No" being fundamental to the problem...
EDIT - It seems to be working now... I simply copied over the files again from my local machine to the remote machine... I am trying to get it to break again so that I can figure out what on Earth happened, and until I do, I will not accept an answer so that people could maybe shed some more light onto it. Either way it is quite baffling.
There's a chance that someone has modified the Image File Execution Options registry setting on the server to launch a debugger automatically.
In short, examine the registry key HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\currentversion\image file execution options and see if there's an entry that matches the name of your executable.
Check whether you have installed the necessary Framework components,
i.e. the suiting Dot net framework. Application with 4.0 and installed 3.5
can cause very strange behaviour.
Try writing a very simple window application and start it on the deployment machine
(this will give you probably more help what is missing).
Check whether the needed Dlls (that you developed, e.g. your class library) are reachable for the console application. And check whether the right version of your Dll is matched!
Check the plattform settings in your console application. Do they match with
the machine where you want to run your application? (win64 and win32 mismatch)
If all of those do not help, try inspecting your executable on the deployment machine
for example with depends.net, checkasm, or similar.
Does your production environment have AppLocker running? I don't know if its output can be customized to output "No" on a command line. Applocker comes to my mind because you can use it to restrict a system to run only signed executables. If your Textmatcher executable is unsigned, it may get shut down immediately. If you have the ability, I'd be curious to see if signing your binary changes the behavior.

Environment.SpecialFolder.CommonDocuments

When I execute this statement:
string folderPath =
Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments);
folderPath is set to C:\ProgramData.
When I execute this statement in the Immediate Window:
Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments);
C:\Users\Public\Documents is displayed (which is what I expected).
Any thoughts on the difference?
UPDATE 7/6/12:
I’m getting different results in different classes in the same exe.
I have one class that lives in a library, and one that’s linked directly into the app.
The library class returns “C:\ProgramData”.
The linked code returns “C:\Users\Public\Documents”.
Further, the library code returns “C:\ProgramData” for both
“Environment.SpecialFolder.CommonDocuments” and
“Environment.SpecialFolder.ApplicationData”.
The linked code returns “C:\Users\Public\Documents” for “Environment.SpecialFolder.CommonDocuments” and "C:\Users\Me\AppData\Roaming" for “Environment.SpecialFolder.ApplicationData”.
I’m baffled.
This could happen if your program is 64-bit. Since Visual Studio is 32-bit, when you execute Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments); in the Immediate Window, it looks up the Windows 32 hive, whereas your program would look up the 64 hive. And it is possible that the CommonDocuments folder has been moved, which would only be registered in the 64 hive.
This is a Windows bug as defined here
EDIT Your update says that it is happening in two classes within the same EXE. Since a process can only be 32-bit or 64-bit (not both), this would indicate the above bug does not apply to you (assuming normal comms between the assemblies, not COM with a wrapper for example). Are you able to work it into a suitable test that you can post?
As a quick confirmation, it might also be worthwhile including the following code in each to be doubly sure they are both running in the same process:
Console.WriteLine("{0} Process {1} is {2}bit", GetType().ToString(), System.Diagnostics.Process.GetCurrentProcess().Id, IntPtr.Size * 8);
C:\Users\Public\Documents is the right path:
Per Machine “Documents”
“Document” type files that users create/open/close/save in the application that are used across users. These are usually template or public documents.
Example: MyTemplate.dot
Windows 7: C:\Users\Public
Vista: %SystemDrive%\Users\Public
XP: %ALLUSERSPROFILE%\Documents
Environment Variable: Vista/Win7: %PUBLIC% Note: Does not exist on XP
Known Folder ID: FOLDERID_PublicDocuments
System.Environment.SpecialFolder: System.Environment.SpecialFolder.CommonDocuments
CSIDL: CSIDL_COMMON_DOCUMENTS
It’s obvious after looking at all these locations that where you store your files can be challenging if you are targeting multiple OS versions. The best guidance is to use API’s to find the special folder path. API’s will return the appropriate location for the target OS.
source: http://blogs.msdn.com/b/patricka/archive/2010/03/18/where-should-i-store-my-data-and-configuration-files-if-i-target-multiple-os-versions.aspx

Cannot create ADODB.Connection with complicated programming chain

Ok so this is a really complicated problem, I will try my best to explain.
We have a c++ application which communicates with Sql Connection like so:
CoCreateInstance(_T("ADODB.Connection"))
This works fine.
We recently made all of our backend code into a Com Object. If I write a Vb program to load our Com Object and do some database operations everything works fine, CoCreateInstance(_T("ADODB.Connection"))
still works.
We use fitnesse for testing so I wrote a fixture that:
1) Takes a string of vb code input into an html page.
2) compiles the vb code
3) runs the vb code that uses our Com Object.
* fitnesse is a java application so the code path travels through Java as well.
Now when any operation touches the database the Com Object hits an exception. Uses message boxes, and removing code I narrowed the problem down to this line of code:
CoCreateInstance(_T("ADODB.Connection"))
normally the return code is 0, but with this chain of code calling code I get the return code: 800401F3 which says that it cannot find the object to load.
I am pulling my hair out trying to figure out whats going on. Any bit of insight would be greatly appreciated.
It is telling you that it cannot find the ProgId in the registry. That's not very healthy, it is a pretty standard component on any Windows install. Verify this, fire up regedit.exe and navigate to HKLM\Software\Classes\ADODB.Connection
If that is missing then you need to install the dbase providers on that machine. Download the MDAC 2.8 installer from Microsoft and run it. If it is not missing then you have a more mysterious problem, perhaps something to do with this being a 64-bit operating system. Look in HKLM\Software\Wow6432Node then. Get additional diagnostics by using the SysInternals' ProcMon tool to see what it is poking at in the registry.
As an alternative, you don't say whether your com "object" is a .dll. If it is, then make sure it is either "self-registering" or you'll need to run this at the command prompt.
regsvr32 myobject.dll
If it's an exe with COM objects, register the objects by running the program with the "/RegServer" command line option like this:
myobject.exe /RegServer
HTH

Windows seems to lose track of .NET application

We have a .NET application that we distribute to our users via an MSI installer package. We have C++ applications that run each morning to see if the user's copy of the application is out of date, and if so, we pull down the new MSI and install it. If the application is running, we need to take it down so we can perform the update.
Our problem is that every once in a while it seems like windows "loses" our application. It will not report that the process is running - though it is. It will allow us to overwrite, or even delete, the in-use executable file without taking down the application.
Maybe this is something that is common -- but we can't figure out what is going on! Does anyone have any insight into this situation?
It seems like a temporary copy of our application is getting created, and the program is getting ran from that. But if that is the case, why doesn't it happen all the time?
EDIT:
In our program, We are using the "EnumProcesses" function from the Platform SDK, PSAPI.dll, to enumerate all of the running processes.
Could it be that either the script or the application runs as a 64-bit program, and the other as a 32-bit program? If so, then on 64-bit machines the update check could be looking in the wrong location for an existing application and thus reporting it as missing?
What mechanism are you using to check to see if the process is running or not?
Try using something like process explorer to see what path the executable image is loaded from - it should be listed in the modules section.

Categories

Resources