I am trying to build a dll that reads a text file to populate a 2d array, then change that array as needed. I'm using a VB GUI to access it. The overall program is a micromouse simulator in which the user is able to customize the wall placement in a 5x5 maze, as well as mouse start position and goal placement, and allow the search algorithm (dll) to solve it. Here's the code inside my dll:
/*testDLL.cpp*/
#include "testDLL.h"
#include <stdio.h>
FILE *maze;
char mazearray[12][12];
void _stdcall wallfunction(int x, int y){
maze = fopen ("C:\Users\Public\Documents\5x5mazedefault.txt", "r");
fread (mazearray, sizeof(mazearray), 1, maze);
fclose(maze);
if (mazearray[x][y] == 'X'){
mazearray[x][y] = ' ';
}
else if (mazearray[x][y] == ' '){
mazearray[x][y] = 'X';
}
}
I want to be able to put in two input variables as the index of the matrix and add or subtract a wall from that location. Whenever I try to call the function from VB, it sends me a message: PInvoke restriction cannot return variants. The function returns nothing, so I don't understand...
Here's the declaration statement inside my VB program:
Private Declare Function wallfunction Lib "C:\Path\Path\testDLL.dll" (ByVal x As Integer, ByVal y As Integer)
I'm aware I'm not going to be able to call the fread function everytime the user wants to change a wall; I'm just trying to get this working once first. Any thoughts?
Change Function to Sub in your Declare statement in VB. This is because your C++ function returns void.
Related
I have the following function from a dll:
aisgdll_setinfo(int dev, set_field_code field, void *data);
I know how to deal with the first two parameters. I have a textbox the user enters data into and the textbox returns a variable of type String^. I somehow need to get the data from that textbox and do something, so that I can write it to this function to the void *data parameter.
You can use this form.
I used the Thread :: Sleep to prevent abuse in processing. While your thread does not change the status of the screen will be updated.
void solve()
{
using namespace System;
using namespace System::Windows::Forms;
using namespace System::Threading;
Thread^ bot_thread = gcnew Thread(gcnew ThreadStart(bot_run));
bot_thread->Start();
PictureBox^ PB_LoadGIF = gcnew PictureBox();
PB_LoadGIF->Visible = true;
while (bot_thread->ThreadState == ThreadState::Running)
{
Thread::Sleep(1000);
PB_LoadGIF->Parent->Refresh();
}
}
After further research online, I have found some solutions to the problems I was having. The functions I was plugging the retrieved values into needed pointers. I think these solutions can be adapted by others for their own purposes. For converting the Visual Studio Text box String^ to char*:
char* iData = (char*)Marshal::StringToHGlobalAnsi(activeBox->Text).ToPointer();
When I needed to get a floating point number from a Text box, I used the following:
int anInteger = (int)((Convert::ToDouble(activeBox->Text))*10);
int *iData = &anInteger;
I'm using C++/CLI and I have a raw HBITMAP called hStrip, I have to display this in a PictureBox, so I found the following function System::Drawing::Image::FromHbitmap, however this takes IntPtr and I wondered if I need to convert my raw HBITMAP to IntPtr before passing it in or if I could get away passing it in like this?
If I need to convert, how should I convert? I haven't really found the conversion this way. I did find it the other way though.
A simple cast gets the job done:
HBITMAP hBmp = NULL;
// Assign hBmp
//...
Bitmap^ bmp = Bitmap::FromHbitmap((IntPtr)hBmp);
DeleteObject(hBmp); // okay to destroy now
I have a dll for 32bit and 64bit and now I want that my exe call the dll from according to solution platform,means when x64 is set then the dll of 64bit will call.For this I declare a function GetPlatform().
Public Function GetPlateform() As String
Dim var1 As String
If (IntPtr.Size = 8) Then
var1 = hellox64
Else
var1 = hello
End If
Return var1
End Function
and when the form load
this var1 is assign to var and finally.
Public Declare Function function1 Lib "var" (ByVal Id As Integer) As Integer
But When I debug the code "DllNotFoundException" is ocuured.
NOTE:The dll is in vc++.
Store your native dlls into subfolders and hint the Library Loader by filling accordingly the PATH process environment variable with the path to the correct version to load.
For instance, given this tree layout...
Your_assembly.dll
|_NativeBinaries
|_x86
|_your_native.dll
|_amd64
|_your_native.dll
...and this code (sorry, C#, no VB.Net :-/ )...
internal static class NativeMethods
{
private const string nativeName = "your_native";
static NativeMethods()
{
string originalAssemblypath = new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath;
string currentArchSubPath = "NativeBinaries/x86";
// Is this a 64 bits process?
if (IntPtr.Size == 8)
{
currentArchSubPath = "NativeBinaries/amd64";
}
string path = Path.Combine(Path.GetDirectoryName(originalAssemblypath), currentArchSubPath);
const string pathEnvVariable = "PATH";
Environment.SetEnvironmentVariable(pathEnvVariable,
String.Format("{0}{1}{2}", path, Path.PathSeparator, Environment.GetEnvironmentVariable(pathEnvVariable)));
}
[DllImport(nativeName)]
public static extern int function1(int param);
[DllImport(nativeName)]
public static extern int function2(int param);
}
...function1 and function2 would be dynamically bound to either the 32 or 64 bits version of the native code, depending on the size of an IntPtr (more on this in this post from Scott Hanselman or this StackOverflow question).
Note 1: This solution is especially useful when both versions of the dll bear the same name or if you're not willing to duplicate every extern references.
Note 2: This has already been successfully implemented in LibGit2Sharp.
No, you cannot dynamically create a reference to the DLL in a lib statement. However, you may (disclaimer: have not tried) be able to create two references and call the appropriate one in your code.
Public Declare Function Function132 Lib "My32BitLib.DLL" Alias "function1" (ByVal Id As Integer) As Integer
Public Declare Function Function164 Lib "My64BitLib.DLL" Alias "function1" (ByVal Id As Integer) As Integer
You will then need to branch on the platform and call the appropriate alias function name (Function132 or Function164) depending on the platform.
We are running on a Windows Client Platform (generally WinXP) in niche industry program that runs in a 640x480 window back to an AS/400 server. To reduce errors I want to watch for when the title bar of the program changes. Then I need to capture the keyboard entries to validate. I'll then make sure each of the entries is valid since the archaic program does no validation. I'll can then do a pop-up then warning the end-user if errors occur and to reduce/eliminate the exception reports.
My question is how can I capture the event of the application title bar change = 'string' that I need? API call? Aiming to do this in VB unless another would be notable cleaner.
WinEvents should work well here. These are lightweight events that get fired when certain UI changes take place - eg names of objects change - which includes Titlebar text changes. One benefit to this type of hook is that you can set it up to deliver the notifications back to your own process, so you don't need to deal with hooking or IPC. (It also works against both 32-bit and 64-bit processes.)
This is easiest to do in plain C/C++; but can be done in .Net (VB, C#) if you add the appropriate [DllImport]'s.
#include <windows.h>
#include <stdio.h>
#define WM_NAMECHANGED WM_APP
HWND g_hwndTarget; // window we're listening to
void CALLBACK WinEventProc(
HWINEVENTHOOK hWinEventHook,
DWORD event,
HWND hwnd,
LONG idObject,
LONG idChild,
DWORD dwEventThread,
DWORD dwmsEventTime
)
{
// Check this is the window we want. Titlebar name changes result in these
// two values (obtained by looking at some titlebar changes with the
// Accessible Event Watcher tool in the Windows SDK)
if(hwnd == g_hwndTarget && idObject == OBJID_WINDOW && idChild == CHILDID_SELF)
{
// Do minimal work here, just hand off event to mainline.
// If you do anything here that has a message loop - eg display a dialog or
// messagebox, you can get reentrancy.
PostThreadMessage(GetCurrentThreadId(), WM_NAMECHANGED, 0, 0);
}
return;
}
void ReportName(HWND hwnd)
{
WCHAR szName[128];
GetWindowText(hwnd, szName, ARRAYSIZE(szName));
wprintf(L"hwnd 0x%08lx has title: %s\n", HandleToLong(hwnd), szName);
}
int main()
{
wprintf(L"Place mouse pointer over window titlebar to report name changes for and hit return...\n");
getchar();
POINT pt;
GetCursorPos(&pt);
g_hwndTarget = WindowFromPoint(pt);
ReportName(g_hwndTarget);
// Note: this doesn't work for console windows, which are managed by CSRSS.EXE. Simplest (though not efficient) workaround for those
// is to use threadId=0 and filter by hwnd in the callback.
DWORD threadId = GetWindowThreadProcessId(g_hwndTarget, NULL);
// This says: call the callback when any UI elements in the specified thread change
// name. _OUTOFCONTEXT means deliver the notifications in this process, don't hook.
HWINEVENTHOOK hook = SetWinEventHook(EVENT_OBJECT_NAMECHANGE, EVENT_OBJECT_NAMECHANGE, NULL, WinEventProc, 0, threadId, WINEVENT_OUTOFCONTEXT);
// TODO: add error checking as appropriate.
wprintf(L"Waiting...\n");
// Thread needs to have a message loop for SetWinEventHook to work for out-of-context messages.
UINT count = 10;
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
if(msg.message == WM_NAMECHANGED)
{
ReportName(g_hwndTarget);
if(--count == 0)
{
break;
}
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWinEvent(hook);
return 0;
}
Things to watch for: you might get false-positives; and if the name changes rapidly, by the time you get the first event, the name may be at the second value, so you may appear to see two events for the second value. Neither of these should be an issue if you're just using this as a trigger to check for a specified value, however.
I am assuming that you do not own the code for the target application. In this case, there's no easy "call me back when the title changes" event. You then have 2 options to do what you need, which I will outline below.
Easy but not airtight
Have your application get the main window of the target application (this should be easy enough) and poll its title every 100msec or so. When you detect a change, act accordingly.
Difficult but correct
Hook into the target application using e.g. a global CBT hook. Once your code runs in their process subclass their main window, causing all window messages to go through your code first. When your code sees a WM_SETTEXT message going to the main window, you can actively notify your "other" application on the spot using your choice of IPC. If all you need to do is just shout "hey!" to your other application, do so with an auto-reset event (it will be easiest). Of course all this points heavily to unmanaged code.
If the easy solution is not good enough and the difficult one is too much, you can try using an automation library like White (I 've never used it, so I can't really say more than that).
I'm trying to embed and then play back a .wav file in a C++/CLI app but all the examples I've seen which use PlaySound are in VB. I can't see how to get froma Stream^ to the LPCSTR which PlaySound requires:
System::IO::Stream^ s = Assembly::GetExecutingAssembly()->GetManifestResourceStream ("Ping.wav");
LPCSTR buf = s->????;
PlaySound(buf, NULL, SND_ASYNC|SND_MEMORY|SND_NOWAIT);
I guess I need some sort of horrible .net memory conversion magic.
Use the System::Media::SoundPlayer class instead. It has a Stream property, assign your "s" variable to it, then call the Play() method.