Every example I can find is in C++, but I'm trying to keep my project in C. Is it even possible to host the CLR in a C program?
If so, can you point me to an example?
As the above comments hint, there is a set of COM APIs for hosting the CLR, and you should be able to call these COM APIs from both C and C++.
As an example, below is a quick piece of (untested) C code that shows how to start up the CLR and execute a static method of a class in a managed assembly (which takes in a string as an argument and returns an integer). The key difference between this code and its C++ counterpart is the definition of COBJMACROS and the use of the <type>_<method> macros (e.g. ICLRRuntimeHost_Start) to call into the CLR-hosting COM interface. (Note that COBJMACROS must be defined prior to #include'ing mscoree.h to make sure these utility macros get defined.)
#include <windows.h>
#define COBJMACROS
#include <mscoree.h>
int main(int argc, char **argv)
{
HRESULT status;
ICLRRuntimeHost *Host;
BOOL Started;
DWORD Result;
Host = NULL;
Started = FALSE;
status = CorBindToRuntimeEx(
NULL,
NULL,
0,
&CLSID_CLRRuntimeHost,
&IID_ICLRRuntimeHost,
(PVOID *)&Host
);
if (FAILED(status)) {
goto cleanup;
}
status = ICLRRuntimeHost_Start(Host);
if (FAILED(status)) {
goto cleanup;
}
Started = TRUE;
status = ICLRRuntimeHost_ExecuteInDefaultAppDomain(
Host,
L"c:\\path\\to\\assembly.dll",
L"MyNamespace.MyClass",
L"MyMethod",
L"some string argument to MyMethod",
&Result
);
if (FAILED(status)) {
goto cleanup;
}
// inspect Result
// ...
cleanup:
if (Started) {
ICLRRuntimeHost_Stop(Host);
}
if (Host != NULL) {
ICLRRuntimeHost_Release(Host);
}
return SUCCEEDED(status) ? 0 : 1;
}
This sample should work with .NET 2.0+, although it looks like .NET 4.0 (not yet released) has deprecated some of these APIs in favor of a new set of APIs for hosting the CLR. (And if you need this to work with .NET 1.x, you need to use ICorRuntimeHost instead of ICLRRuntimeHost.)
Related
I'm coding a UEFI Runtime Driver for Windows which hooks gRT->SetVariable(...)
Hooking seems to work fine but whenever I startup a user-mode application and call SetFirmwareEnvironmentVariable(...) it reults in a Bluescreen saying UNEXCEPTED_KERNEL_MODE_TRAP.
I cannot find any solution for this. Here are a few things iam aware of:
I'm raising TPL
I recalculate and set CRC32
On SetVirtualAddressMap(...) i convert all my pointer
Google didn't help at all. So i really wonder what causes this Bluescreen and how i may proceed to resolve this issue.
What am i missing? Am i doing something wrong?
Here is my code:
ExchangePointerInServiceTable((VOID**)&gST->RuntimeServices->SetVariable,
(VOID*)HookedSetVariable,
(VOID**)&gOriginalSetVariable);
static
EFI_STATUS
ExchangePointerInServiceTable(
IN OUT VOID** AddressToUpdate,
IN VOID* NewPointer,
OUT VOID** OriginalPointer OPTIONAL
)
{
EFI_STATUS status;
EFI_TPL tpl;
ASSERT(*AddressToUpdate != NewPointer);
tpl = gBS->RaiseTPL(TPL_HIGH_LEVEL);
if (OriginalPointer != NULL)
{
*OriginalPointer = *AddressToUpdate;
}
*AddressToUpdate = NewPointer;
gST->Hdr.CRC32 = 0;
status = gBS->CalculateCrc32(&gST->Hdr, gST->Hdr.HeaderSize, &gST->Hdr.CRC32);
ASSERT_EFI_ERROR(status);
gBS->RestoreTPL(tpl);
return status;
}
EFI_STATUS
EFIAPI
HookedSetVariable(
IN CHAR16* VariableName,
IN EFI_GUID* VendorGuid,
IN UINT32 Attributes,
IN UINTN DataSize,
IN VOID* Data
) {
if (StrCmp(VariableName, gStrComVarName) == 0) {
COMMUNICATION_PROTOCOL * comVarPtr = (COMMUNICATION_PROTOCOL*)Data;
switch (comVarPtr->i8OperationId) {
case COMMUNICATION_PROTOCOL_OPERATION_PING:
comVarPtr->i8OperationId = COMMUNICATION_PROTOCOL_PONG;
}
CopyMem(Data, comVarPtr, DataSize);
}
return gOriginalSetVariable(VariableName, VendorGuid, Attributes, DataSize, Data);
}
Edit: While in UEFI, other UEFI Applications correctly call the hooked SetVariable(...) without any further problems.
This may bring it down to the problem only existing after VirtualAddressSpace has been created from the OS.
I want to get the full version number for Windows, just like CMD does:
I ended up with this MS doc that says:
To obtain the full version number for the operating system, call the
GetFileVersionInfo function on one of the system DLLs, such as
Kernel32.dll, then call VerQueryValue to obtain the
\StringFileInfo\\ProductVersion subblock of the file version
information.
So I tried to use those functions with this code:
#include <Windows.h>
#include <wchar.h>
#pragma comment(lib, "Mincore.lib")
int wmain(int argc, wchar_t* argv[])
{
// GetFileVersionInfoW
LPCWSTR fileName = L"C:\\Windows\\System32\\kernel32.dll";
DWORD fileInfoSize;
fileInfoSize = GetFileVersionInfoSizeW(fileName, NULL);
if (fileInfoSize == 0)
{
fwprintf(stderr, L"\nError code: %u\n", GetLastError());
return;
}
// GetFileVersionInfoW
VOID* pFileVerInfo = malloc(fileInfoSize);
if (pFileVerInfo == NULL)
{
fwprintf(stderr, L"Failed allocating!\n");
return;
}
if (!GetFileVersionInfoW(fileName, 0, fileInfoSize, pFileVerInfo))
{
fwprintf(stderr, L"Error code: %u\n", GetLastError());
free(pFileVerInfo);
return;
}
// VerQueryValueW
LPCWSTR subBlock = L"\\StringFileInfo\\\\ProductVersion";
VS_FIXEDFILEINFO * pFileInfo;
UINT pLen = 0;
if (!VerQueryValueW(pFileVerInfo, subBlock, (LPVOID*)& pFileInfo, &pLen))
{
fwprintf(stderr, L"Error code: %u\n", GetLastError());
return;
}
return 0;
}
However, the VerQueryValueW function fails with code 1813 and I have no idea why. I also have no idea how I can show the full version after calling the function.
Can you help me?
L"\\StringFileInfo\\\\ProductVersion" is not correct. There must be a Language ID in the middle. On my Windows 10 installation, a working string is: L"\\StringFileInfo\\040904B0\\ProductVersion". But maybe this would differ on other systems.
As suggested by Jonathan Potter in comments, you could find the ID by querying \\VarFileInfo\\Translation.
Simpler options to achieve the goal include:
Query VS_FIXEDFILEINFO instead of StringFileInfo
Read the OS version from the Windows API instead of querying a random DLL.
How can I catch the timeout exception in a third dll function,I use c language in Windows
I want to catch a timeout Exception while call a thirdly dll function, you know the function takes a long while, and I need it return a value in limited time, if it doesn't return in the time, I will give it a default value.
I have to look for so much infomation about but it doesn't work.
I get the two point:
1.use the alarm function in ,but it only work in Linux,I can't use it in Windows even I use the MinGW standerd GCC complier.
2.use the timeSetEvent function in and the setjmp/longjmp function in ,the three function maybe so closed to take it work.but I use them caused the programe dump,windows pops a DialogMessage say something wrong.
I give the code and the picture like this :
`
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <setjmp.h>
jmp_buf j;
/**
* 时间中断函数
*/
void PASCAL OneMilliSecondProc(UINT wTimerID, UINT msg, DWORD dwUser, DWORD dwl, DWORD dw2) {
printf("Timout!\n");
longjmp(j,1);
}
int longTimeFunction(){
while (1) {
printf("operating...\n");
Sleep(1000);
}
return 0;
}
int main(){
HANDLE hHandle;
UINT wTimerRes_1ms;//定义时间间隔
UINT wAccuracy; //定义分辨率
UINT TimerID_1ms; //定义定时器句柄
wTimerRes_1ms = 5000;
if((TimerID_1ms = timeSetEvent(
wTimerRes_1ms,
wAccuracy,
(LPTIMECALLBACK)OneMilliSecondProc, // 回调函数
(DWORD)(1), // 用户传送到回调函数的数据;
TIME_PERIODIC//周期调用定时处理函数
)) == 0) {
printf("start!!!!!!!!!!!\n");
} else {
printf("end!!!!!!!!!!!\n");
}
int temp = 0;
if(setjmp(j) == 0){
temp = longTimeFunction();
}else{
printf("xxxxxx...\n");
temp = -1;
}
printf("%d\n", temp);
return 0;
}
`
Unlike UNIX signals, timeSetEvent doesn't interrupt a thread, the callback runs in parallel and longjmping across threads is undefined behavior.
Concerning your actual question, this is a bad idea. Such an abortion could leave the library in an inconsistent state.
Instead, try to get the library vendor to offer an API that accepts a timeout, or use another library that already supports it.
Question
In a Windows C application I want to validate a parameter passed into a function to ensure that the specified path exists.*
How do you check if a directory exists on Windows in C?
*I understand that you can get into race conditions where between the time you check for the existance and the time you use the path that it no longer exists, but I can deal with that.
Additional Background
Knowing explicitly that a directory does or does not exist can get tricky when permissions come into play. It's possible that in attempting to determine if the directory exists, the process doesn't have permissions to access the directory or a parent directory. This is OK for my needs. If the directory doesn't exist OR I can't access it, both are treated as an invalid path failure in my application, so I don't need to differentiate. (Virtual) bonus points if your solution provides for this distinction.
Any solution in the C language, C runtime library, or Win32 API is fine, but ideally I'd like to stick to libraries that are commonly loaded (e.g. kernel32, user32, etc.) and avoid solutions that involve loading non-standard libraries (like PathFileExists in Shlwapi.dll). Again, (Virtual) bonus points if your solution is cross-platform.
Related
How can we check if a file Exists or not using Win32 program?
Do something like this:
BOOL DirectoryExists(LPCTSTR szPath)
{
DWORD dwAttrib = GetFileAttributes(szPath);
return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}
The GetFileAttributes() method is included in Kernel32.dll.
Here's a totally platform-agnostic solution (using the standard C library)
Edit: For this to compile in Linux, replace <io.h> with <unistd.h> and _access with access. For a real platform agnostic solution, use the Boost FileSystem library.
#include <io.h> // For access().
#include <sys/types.h> // For stat().
#include <sys/stat.h> // For stat().
bool DirectoryExists( const char* absolutePath ){
if( _access( absolutePath, 0 ) == 0 ){
struct stat status;
stat( absolutePath, &status );
return (status.st_mode & S_IFDIR) != 0;
}
return false;
}
A Windows-specific implementation that supports both MBCS and UNICODE builds:
#include <io.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <tchar.h>
BOOL directory_exists( LPCTSTR absolutePath )
{
if( _taccess_s( absolutePath, 0 ) == 0 )
{
struct _stat status;
_tstat( absolutePath, &status );
return (status.st_mode & S_IFDIR) != 0;
}
return FALSE;
}
If linking to the Shell Lightweight API (shlwapi.dll) is ok for you, you can use the PathIsDirectory function.
Another option is the shell function PathFileExists()
PathFileExists() documentation
This function "Determines whether a path to a file system object such as a file or directory is valid."
So, this question is full of edge cases. A real answer would be like this:
BOOL DirectoryExists(LPCTSTR szPath, BOOL *exists)
{
*exists = FALSE;
size_t szLen = _tcslen(szPath);
if (szLen > 0 && szPath[szLen - 1] == '\\') --szLen;
HANDLE heap = GetProcessHeap();
LPCTSTR szPath2 = HeapAlloc(heap, 0, (szlen + 3) * sizeof(TCHAR));
if (!szPath2) return FALSE;
CopyMemory(szPath2, szPath, szLen * sizeof(TCHAR));
szPath2[szLen] = '\\';
szPath2[szLen + 1] = '.';
szPath2[szLen + 2] = 0;
DWORD dwAttrib = GetFileAttributes(szPath2);
HeapFree(heap, 0, szPath2);
if (dwAttrib != INVALID_FILE_ATTRIBUTES) {
*exists = TRUE; /* no point checking FILE_ATTRIBUTE_DIRECTORY on "." */
return TRUE;
}
/*
* If we get anything other than ERROR_PATH_NOT_FOUND then something's wrong.
* Could be hardware IO, lack of permissions, a symbolic link pointing to somewhere
* you don't have access, etc.
*/
return GetLastError() != ERROR_PATH_NOT_FOUND;
}
The correct result of DirectoryExists is tri-state. There are three cases and you need to handle all of them. Either it exists, it doesn't exist, or you were unable to check. I've lost data in production because a SAN returned NO to the check function and then let me create something clobbering it on the very next line of code. Don't make the same mistake Microsoft did when designing the File.Exists() API in C#.
However I see a lot of checks that are supliferous. Don't write thinks like if (directory doesn't exist) CreateDirectory(); just write CreateDirectory() if (GetLastError() != 0 && GetLastError() != ERROR_ALREADY_EXISTS. Or the converse with RemoveDirectory(); just remove it and check for either no error or path not found.
I have a pure C application that issues IOCTL calls to my adapter driver and displays info ,this is however compiled using Visual Developer Studio 5(non-managed code) ... I need to get some info however from my adapter using WMI .... My googling efforts show that i would need to write a C++ Application using COM to achieve any form of communication with wMI or a C# with .NET app
a) Is that really the case? NO work around for my C application?
b) If above is true,what are the minimum level changes that i would need to do my project/wp /workspace settings?
Thanks
Som
You can invoke COM from C. The syntax is somewhat less friendly than that of C++, but it works. COM was initially designed to work from either C or C++, and native C language support is included in COM and WMI header files. It will be long though... your program will be responsible for allocating all the necessary objects, checking for error conditions from each and every COM call, and for releasing the objects it instantiated.
When using documentation written with C++ in mind, convert COM calls of the form:
pSomething->Method(arg1, ...); // C++
to:
pSomething->lpVtbl->Method(pSomething, arg1, ...); // C
Below is the shortest piece of C code I could get to actually pull some information from WMI. If successful, it should list the processors on your computer, along with their clock frequency in MHz. The program takes care of disposing resources it allocates, but it does no error checking whatsoever (you should look at those hr values before continuing each step).
This is a visual studio 2008 "Win32 Console Application" with the main file renamed to a .c extension, and the extra stdafx files removed. To get the program to link, make sure to include wbemuuid.lib in the project properties, under Configuration Properties/Linker/Input/Additional Dependencies. It ran successfully on my Vista box.
#define _WIN32_WINNT 0x0400
#define _WIN32_DCOM
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <wbemidl.h>
void _tmain(int argc, _TCHAR* argv[])
{
// result code from COM calls
HRESULT hr = 0;
// COM interface pointers
IWbemLocator *locator = NULL;
IWbemServices *services = NULL;
IEnumWbemClassObject *results = NULL;
// BSTR strings we'll use (http://msdn.microsoft.com/en-us/library/ms221069.aspx)
BSTR resource = SysAllocString(L"ROOT\\CIMV2");
BSTR language = SysAllocString(L"WQL");
BSTR query = SysAllocString(L"SELECT * FROM Win32_Processor");
// initialize COM
hr = CoInitializeEx(0, COINIT_MULTITHREADED);
hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
// connect to WMI
hr = CoCreateInstance(&CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, &IID_IWbemLocator, (LPVOID *) &locator);
hr = locator->lpVtbl->ConnectServer(locator, resource, NULL, NULL, NULL, 0, NULL, NULL, &services);
// issue a WMI query
hr = services->lpVtbl->ExecQuery(services, language, query, WBEM_FLAG_BIDIRECTIONAL, NULL, &results);
// list the query results
if (results != NULL) {
IWbemClassObject *result = NULL;
ULONG returnedCount = 0;
// enumerate the retrieved objects
while((hr = results->lpVtbl->Next(results, WBEM_INFINITE, 1, &result, &returnedCount)) == S_OK) {
VARIANT name;
VARIANT speed;
// obtain the desired properties of the next result and print them out
hr = result->lpVtbl->Get(result, L"Name", 0, &name, 0, 0);
hr = result->lpVtbl->Get(result, L"MaxClockSpeed", 0, &speed, 0, 0);
wprintf(L"%s, %dMHz\r\n", name.bstrVal, speed.intVal);
// release the current result object
result->lpVtbl->Release(result);
}
}
// release WMI COM interfaces
results->lpVtbl->Release(results);
services->lpVtbl->Release(services);
locator->lpVtbl->Release(locator);
// unwind everything else we've allocated
CoUninitialize();
SysFreeString(query);
SysFreeString(language);
SysFreeString(resource);
}
Another option, if you want to keep the impact to your existing C application low, is to write a DLL that internally can use C++ and COM wrapper classes to query the desired WMI information.
This DLL can provide a plain C interface to adapt to your application. Thats the way I would go for.