I am working on Amibroker C# plugin project. Amibroker SDK is written in C++ but, I am using a C# plugin which does exactly what Amibroker C++ does C# Plugin link
Everything in C# plugin works just fine except one function which is written in c++ this way:
PLUGINAPI struct RecentInfo* GetRecentInfo(LPCTSTR ticker)
{
//Process & return RecentInfo* (RecentInfo is a structure)
}
In C# standard plugin it has been converted this way
public RecentInfo GetRecentInfo(string ticker)
{
//Process & Return RecentInfo
}
Unfortunately, Amibroker application crashes with this wrong conversion. So I did try to convert it my way to get Amibroker App working, but failed multiple times
This is what i have tried so far:
Attemp 1:
unsafe public RecentInfo* GetRecentInfo(string ticker)
{
//Process & Return RecentInfo* (RecentInfo structure is declared as unsafe)
}
Impact:
Amibroker app does not load
Attemp 2:
public IntPtr GetRecentInfo(string ticker)
{
//Process & Return Pointer using Marshal.StructureToPtr
}
Impact:
Amibroker app does not load
Attemp 3:
public void GetRecentInfo(string ticker)
{
//Useless becoz no return type
}
Impact:
Amibroker loads & does call function correctly but how do return a structure pointer
So, I am scratching my head to find out the exact conversion of C++ function in C#
If it is fully written in c# then , this is pretty well ,think there is problem in implementation not in calling
public RecentInfo GetRecentInfo(string ticker)
{
RecentInfo rc;
//Process & Return RecentInfo
return rc;
}
or this , (you can use ref too)
public void GetRecentInfo(string ticker,out RecentInfo rc )
{
rc=new RecentInfo();
....process
return ;
}
Related
I have two project, say named CPPDLLProject and CSharpProject.
Here in CPPDLLProject, there are few dllexport functions which can be called from CSharpProject and that calling is working fine.
But here I want to call CSharpProject's functions from CPPDLLProject so that can propagate data from C++ DLL to C# project.
Just for more explanation, Would like to add below code example.
Below is the function in the C++ DLL from which would like to call C# functions.
void __stdcall CPPDLLApp::PumpMessageData(int aCode, int aType)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
if (aCode == PUMP_UPDATE_MSG && aData != NULL)
{
switch (aType)
{
case MSG_ADD:
{
// Call the C# function to send the added msg to C# project
GetCPPDLLAppMsg("MSG added");
break;
}
case MSG_DELETE:
{
// Call the C# function to send the deleted msg to C# project
GetCPPDLLAppMsg("MSG deleted");
break;
}
case MSG_UPDATE:
{
// Call the C# function to send the updated msg to C# project
GetCPPDLLAppMsg("MSG updated");
break;
}
}
}
if (aCode == PUMP_STOP_MSG)
{
// Call the C# function to send the stop msg to C# project
break;
}
if (aCode == PUMP_START_MSG)
{
// Call the C# function to send the start msg to C# project
break;
}
}
Below is the C# project's function.
public void GetCPPDLLAppMsg(string aMessage)
{
Console.WriteLine(aMessage);
}
Please suggest how to achieve this goal.
I have done few googling but no luck.
My question might not be clear but any kind of help is appreciated.
I don't really understand your question, but you can use a intermediate dll and the following C++ method:
void *p = (void *)wglGetProcAddress(name);
if (p == 0 ||
(p == (void*)0x1) || (p == (void*)0x2) || (p == (void*)0x3) ||
(p == (void*)-1))
{
HMODULE module = LoadLibraryA("dllname.dll");
p = (void *)GetProcAddress(module, name);
}
name = name of the function
dllname = name of your dll
with this you will be able to load a dll and get the function pointer to wichever function you need, but you may need to compile a C# dll to use this, you can make a bridge or something
I am using Visual Studio 2017. I added two projects in a solution. One project is in C# with WPF. The other is in VC++ with ATL.
From C#, I call a function in the VC++ project, which sets low level mouse hook. A part of the code in the low level mouse proc is as follows:
MSLLHOOKSTRUCT stMouse = *(MSLLHOOKSTRUCT*)(lParam);
POINT pt = stMouse.pt;
IAccessible* pAcc;
VARIANT varChild;
HRESULT hr = AccessibleObjectFromPoint(pt, &pAcc, &varChild);
VARIANT varRole;
hr = pAcc->get_accRole(varChild, &varRole);
When I test by clicking on a check box under View tab in MS Word 2013, then I get the role as client for WM_LBUTTONDOWN and WM_LBUTTONUP messages. But I should get the role as check box.
I checked with Inspect.exe that comes with Windows 10 SDK. Inspect.exe shows role correctly as check box. Inspect.exe has two options - one to see UI Automation properties and the other to see MSAA properties. I am seeing the MSAA properties.
How can I get the correct role? What method deos Inspect.exe uses?
Microsoft Active Accessibility / MSAA (based on the IAccessible interface) is a legacy API. You should now use Windows Automation. UIA is based on COM, and uses interfaces, the most important one being IUIAutomationElement. Inspect.exe uses UIA or MSAA.
Note .NET is compatible with UIA and WPF can expose its UI Elements to UIA pretty easily, through the AutomationPeer class and UIElement.OnCreateAutomationPeer Method method. WPF provides a default implementation that can be tweaked if needed.
Here is a similar example to yours in C++, using the UIA API, instead of MSAA (we could write the same using C#):
#include "stdafx.h" // needs <uiautomation.h>
class CCoInitialize { // https://blogs.msdn.microsoft.com/oldnewthing/20040520-00/?p=39243
public:
CCoInitialize() : m_hr(CoInitialize(NULL)) { }
~CCoInitialize() { if (SUCCEEDED(m_hr)) CoUninitialize(); }
operator HRESULT() const { return m_hr; }
HRESULT m_hr;
};
// this is a poor-man COM object class
class CHandler : public IUIAutomationEventHandler
{
public:
HRESULT QueryInterface(REFIID riid, LPVOID * ppv)
{
if (!ppv) return E_INVALIDARG;
*ppv = NULL;
if (riid == IID_IUnknown || riid == IID_IUIAutomationEventHandler)
{
*ppv = this;
return NOERROR;
}
return E_NOINTERFACE;
}
ULONG AddRef() { return 1; }
ULONG Release() { return 1; }
// this will be called by UIA
HRESULT HandleAutomationEvent(IUIAutomationElement *sender, EVENTID eventId)
{
wprintf(L"Event id: %u\n", eventId);
return S_OK;
}
};
int main()
{
CCoInitialize init;
// this sample uses Visual Studio's ATL smart pointers, but it's not mandatory at all
CComPtr<IUIAutomation> uia;
if (SUCCEEDED(uia.CoCreateInstance(CLSID_CUIAutomation)))
{
// get mouse pos now
POINT pt;
GetCursorPos(&pt);
// find what type of "control" was under the mouse
CComPtr<IUIAutomationElement> element;
if (SUCCEEDED(uia->ElementFromPoint(pt, &element)))
{
CComBSTR type;
element->get_CurrentLocalizedControlType(&type);
wprintf(L"type at %u,%u: %s\n", pt.x, pt.y, type.m_str);
}
// get root
CComPtr<IUIAutomationElement> root;
if (SUCCEEDED(uia->GetRootElement(&root)))
{
// add a handler that will trigger every time you open any window on the desktop
// in the real world, you'll need to delete this pointer to avoid memory leaks of course
CHandler *pHandler = new CHandler();
if (SUCCEEDED(uia->AddAutomationEventHandler(UIA_Window_WindowOpenedEventId, root, TreeScope::TreeScope_Children, NULL, pHandler)))
{
// since this is a console app, we need to run the Windows message loop otherwise, you'll never get any UIA events
// for this sample, just press CTRL-C to stop the program. in the real world, you'll need to get out properly
// if you have a standard windows app, the loop will be already there
while (TRUE)
{
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
}
}
return 0;
}
I support an old VS 2010 C++ Video Application. This application calls Video Integrators that are written in C# 2015 (and older versions as well). We have run into a unique issue that I have pinpointed to being the transfer of a camera list from the Integrator to the Video App, where the string of data is truncated at exactly 5087 characters. (resulting in only 88 of the 134 cameras being loaded into the Video Application) I am not strong at C++ at all, so I'm not entirely certain what other options I have for data objects and definition. I totally presume the issue is on the C++ side, because I can see the complete outgoing list of cameras in the C# Integrator code. (but maybe I'm mistaken)
//Video Application code (c++ 2010)
deviceLibrary.h file
//get setting extended
typedef TCHAR* (*DI_GETSETTINGEX)(HWND hParentWnd, int nParameter,LPARAM lParam);
#define DI_GETSETTINGEX_ENTRY "GetSettingEx"
class CDeviceLibrary : public CCameraWindow
{
public:
DI_GETSETTINGEX m_pGetSettingEx;
};
deviceLibrary.cpp
CDeviceLibrary::CDeviceLibrary(int nId,LPCTSTR pszName,LPCTSTR pszView,HINSTANCE hLib,HWND hWnd,LPCTSTR pszLibrary,LPCTSTR pszPropertiesString)
{
m_pGetSettingEx = (DI_GETSETTINGEX)GetProcAddress(m_hLib,DI_GETSETTINGEX_ENTRY);
}
CString CDeviceLibrary::GetSetting(int nSetting,LPARAM lParam)
{
if(m_pGetSettingEx)
return m_pGetSettingEx(AfxGetMainWnd()->m_hWnd,nSetting,lParam);
else if(m_pGetSetting)
return m_pGetSetting(nSetting,lParam);
return _T("");
}
ConfigureServers.cpp
void CConfigurationServers::LoadCameras()
{
//RIGHT HERE! THE VALUE OF strCameras only contains 5087 characters in it, when it is supposed to contain over 7000
CString strCameras = GetSetting(ParameterGetCameraList,(LPARAM)(LPCTSTR)strParameters);
}
Video Integrator Code Base (C# 2010, .NET 4.0)
public virtual String GetLibrarySetting(int Parameter,int lParam)
{
return GetCameraList(Marshal.PtrToStringAnsi((IntPtr)lParam));
}
virtual public String GetCameraList()
{
String CameraList = "";
try
{
if(!Connected)
Connect();
if(DeviceList.Count > 0)
{
List<BaseCamera>.Enumerator Cameras = DeviceList.GetEnumerator();
while(Cameras.MoveNext())
{
BaseCamera Camera = Cameras.Current;
int FeatureFlags = (int)CameraFlags.FLAG_PTZ_SUPPORT | (Camera.PTZ?(int)CameraFlags.FLAG_PTZ:0) |
(int)CameraFlags.FLAG_AUDIO_SUPPORT | (Camera.AudioIn?(int)CameraFlags.FLAG_AUDIO:0) |
(int)CameraFlags.FLAG_MIKE_SUPPORT |
(Camera.RecordNotSupported ? (int)CameraFlags.FLAG_NO_RECORD_SUPPORT | (int)CameraFlags.FLAG_NO_RECORD : 0);
CameraList += String.Format("{0};{1};{2}\n", Camera.Title.Length > 0 ? Camera.Title : Camera.Name, Camera.CameraId, FeatureFlags);
}
}
}
catch(Exception e)
{
LogException(e.Message);
}
return CameraList;
}
I am not the original creator of either of these applications. If you ask me a "why did you do...." question, I have no idea what the answer is. If any of you know of a solution that can seamlessly replace this solution, and retrieve me the full string I am looking for, wonderful. If you see the reason why I only a subset of the original list of characters is being received into the Video App, please let me know why. Thanks!
NOTE: I have stripped out hundreds of lines of code in this post. The code base is massive.
Sample text being passed, and how it is being truncated at the C++ property:
C001-P100--1-SeeTec (Peliquin);4611967493405284623;2293760
C001-P100--SeeTec (Peliquin);4611967493405284639;2293760
C002-P100--1-SeeTec (Peliquin);4611967493405284632;2293760
C002-P100--SeeTec (Peliquin);4611967493405284646;2293760
C003-P100--1-SeeTec (Peliquin);4611967493405284660;2293760
C003-P100--SeeTec (Peli"
Arg... as it turns out, C++ cannot (at least in our app) directly call a C# application. It needs an app in the middle to do some sort of conversion between the two languages. I tracked down a tiny c++ application in our system that is referenced by the program that makes the two languages talk to each other, which had the following code in it:
wchar_t* ConvertToCharW(String^ Input)
{
static wchar_t ch[5001]=L""; //TODO: make dynamic so no String^ length limit
try
{
ch[0] = ch[5000] = '\0';
// Pin memory so GC can't move it while native function is called
pin_ptr<const wchar_t> wch = PtrToStringChars(Input);
wcscpy_s(ch,5000,wch);
}
catch(...)
{
}
return ch;
}
And there is my 5000 character limit. Since I have no idea how to make it dynamic in C++, I changed it to 20000.
I am trying out released VS 2013 Update 2 and building a sample Universal Application.
I have created a user control and on both MainPages added GridViews (on Windows Phone and Windows 8).
I want to change some things via code when app is running on Windows Phone.
Is there a way to do something like:
if(<deviceType> == "WindowsPhone")
{
}
else
{
}
Normally when building your app, you can use preprocessor directives. When building app for windows phone, VS as default defines WINDOWS_PHONE_APP (take a look at Project Properties -> Build -> Conditional compilation symbols). Therefore anywhere in your code you can put such a statement:
#if WINDOWS_PHONE_APP
// do when this is compiled as Windows Phone App
#else
// not for windows phoen
#endif
More information you can get at MSDN.
I would advise to use this approach, hence in most cases you know exactly when you will use specific code for Phone (ARM) or other platform. Of course if you need you can define more symbols for specific build configurations/platforms.
Remarks: Since W10, where you need to check the platform in Run-Time, then you can use ApiInformation class and check if specific type exists in the api. For example like this:
if (ApiInformation.IsApiContractPresent("Windows.Phone.PhoneContract", 1))
// do code for mobile
else
// do code for other
That's what worked for me in Universal Windows (Windows 10) project
public static Platform DetectPlatform()
{
bool isHardwareButtonsAPIPresent =
ApiInformation.IsTypePresent("Windows.Phone.UI.Input.HardwareButtons");
if (isHardwareButtonsAPIPresent)
{
return Platform.WindowsPhone;
}
else
{
return Platform.Windows;
}
}
If you want an in-code method of determining the current device, you could try this:
public Windows.Foundation.Metadata.Platform DetectPlatform()
{
try
{
//Calls an unsupported API.
Windows.Networking.BackgroundTransfer.BackgroundDownloader.RequestUncontrainedDownloadsAsync(null);
}
catch (NotImplementedException)
{
//The API isn't supported on Windows Phone. Thus, the current platform is Windows Phone.
return Windows.Foundation.Metadata.Platform.WindowsPhone;
}
catch(Exception)
{
//Otherwise, this is Windows (desktop/RT).
return Windows.Foundation.Metadata.Platform.Windows;
}
}
Source: https://gist.github.com/Amrykid/2fd65ae1815a928fe753
OR you can do this
Add this to
App.Xaml.Cs
public static bool IsMobile
{
get
{
var qualifiers = Windows.ApplicationModel.Resources.Core.ResourceContext.GetForCurrentView().QualifierValues;
return (qualifiers.ContainsKey("DeviceFamily") && qualifiers["DeviceFamily"] == "Mobile");
}
}
From GitHub
public static class DeviceTypeHelper
{
public static DeviceFormFactorType GetDeviceFormFactorType()
{
switch (AnalyticsInfo.VersionInfo.DeviceFamily)
{
case "Windows.Mobile":
return DeviceFormFactorType.Phone;
case "Windows.Desktop":
return UIViewSettings.GetForCurrentView().UserInteractionMode == UserInteractionMode.Mouse
? DeviceFormFactorType.Desktop
: DeviceFormFactorType.Tablet;
case "Windows.Universal":
return DeviceFormFactorType.IoT;
case "Windows.Team":
return DeviceFormFactorType.SurfaceHub;
default:
return DeviceFormFactorType.Other;
}
}
}
public enum DeviceFormFactorType
{
Phone,
Desktop,
Tablet,
IoT,
SurfaceHub,
Other
}
https://gist.githubusercontent.com/wagonli/40d8a31bd0d6f0dd7a5d/raw/f6175de5fcad40cc257edc3748c0e349495d17f6/DeviceTypeHelper.cs
It's a workaround
//PC customization
if(ApiInformation.IsTypePresent("Windows.UI.ViewManagement.ApplicationView"))
{
}
//Mobile customization
if(ApiInformation.IsTypePresent("Windows.UI.ViewManagement.StatusBar"))
{
}
I am trying to host CLR in my native Win32 C++ application.
CLR loading works okay, but when i try to execute a method in the assembly, then ExecuteInDefaultAppDomain returns 0x8013101B, and bails out.
Here is the code snippet:
// Managed Code
namespace ManagedLibrary
{
public class LibraryBootstrapper
{
static LibraryBootstrapper()
{
MessageBox.Show("Static LibraryBootsrapper");
}
public LibraryBootstrapper()
{
}
public static int Initialize(String str)
{
MessageBox.Show("Hi " + str + ", Library Bootsrapped");
return 0;
}
}
// Native Code
int tmain()
{
// Bind to the runtime.
ICLRRuntimeHost *pClrHost = NULL;
HRESULT hrCorBind = CorBindToRuntimeEx(
NULL, // Load the latest CLR version available
L"wks", // Workstation GC ("wks" or "svr" overrides)
0, // No flags needed
CLSID_CLRRuntimeHost,
IID_ICLRRuntimeHost,
(PVOID*)&pClrHost);
// Now, start the CLR.
HRESULT hrStart = pClrHost->Start();
DWORD result = 0;
// Load an assembly and execute a method in it.
HRESULT hrExecute = pClrHost->ExecuteInDefaultAppDomain(L"C:\\KIRAN\\Workspaces\\VS 2010\\HostCLR\\ManagedLibrary\\bin\\Debug\\ManagedLibrary.dll", L"ManagedLibrary.LibraryBootstrapper", L"Initialize", L"Kiran", &result);
//HRESULT hrStop = pClrHost->Stop();
return;
}
I figured it out!
The problem was that the versions of .NET frame that was being referenced by native and managed projects were different. Syncing that up worked.
And, btw, the error code 0x8013101B, corresponds to COR_E_NEWER_RUNTIME (see corerror.h), which helped me figure out the problem.
The error codes are explained here: http://blogs.msdn.com/b/yizhang/archive/2010/12/17/interpreting-hresults-returned-from-net-clr-0x8013xxxx.aspx