hi @danielroure2267
Your idea is "feasible" using user32.dll and kernel32.dll by locating the “Loads” window among the active applications.
However, all these copy and paste operations are not native to the Autodesk API but instead rely on Windows level functions.
You won’t find assistance for this here, you’ll need to look for guidance on other forums.
Video tutorial of the PasteCells method
For once, here’s a method to copy loads (using the GetLoads method) to the clipboard and paste them into the active load table according to the per-cell mode.
Naturally, this approach can be applied to any other type of table as well.
public static void PasteFromClipboardIntoActiveWindow() { var r = new RobotApplication();
string tbName = "Loads", wName = $"Autodesk Robot Structural Analysis Professional 20{r.Version} - [{tbName}]";
foreach (var method in Enum.GetValues<WindowMngr.PasteMethod>()) {
var tb = r.Project.ViewMngr.CreateTable(I_TT_LOADS, I_TDT_DEFAULT); tb.Window.Caption = tbName;
WriteLine(WindowMngr.Paste(wName, method) ? "TEST PASSED" : "TEST FAILED");
tb.Window.SendMessage(0x10, 0, 0);
}
}
The GetLoads method is shown here in a hard-coded form, but it can also be generated by other methods in your programs (mass calculation, sorting, selection, etc.).
using System.Text;
using System.Runtime.InteropServices;
using static System.Console;
internal class WindowMngr {
[DllImport("user32.dll", SetLastError = true)] private static extern bool CloseClipboard();
[DllImport("user32.dll", SetLastError = true)] private static extern bool EmptyClipboard();
[DllImport("user32.dll", SetLastError = true)] private static extern bool OpenClipboard(IntPtr hWndNewOwner);
[DllImport("kernel32.dll", SetLastError = true)] private static extern bool GlobalUnlock(IntPtr hMem);
[DllImport("user32.dll", SetLastError = true)] private static extern IntPtr SetClipboardData(uint uFormat, IntPtr hMem);
[DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr GlobalAlloc(uint uFlags, UIntPtr dwBytes);
[DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr GlobalLock(IntPtr hMem);
[DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr GlobalFree(IntPtr hMem);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindow(string? lpClassName, string lpWindowName);
[DllImport("user32.dll")] private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")] private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")] private static extern bool IsIconic(IntPtr hWnd);
[DllImport("user32.dll")] private static extern bool IsWindow(IntPtr hWnd);
[DllImport("user32.dll")] private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")] private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, IntPtr dwExtraInfo);
[DllImport("user32.dll")] private static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
[DllImport("user32.dll")][return: MarshalAs(UnmanagedType.Bool)] private static extern bool BringWindowToTop(IntPtr hWnd);
private const uint CF_UNICODETEXT = 13, GMEM_MOVEABLE = 0x0002, KEYEVENTF_KEYUP = 0x0002;
private const byte VK_CONTROL = 0x11, VK_V = 0x56, VK_RETURN = 0x0D, VK_LEFT = 0x25, VK_DOWN = 0x28, VK_ESCAPE = 0x1B;
private const int SW_RESTORE = 9;
private static IntPtr _targetHwnd = IntPtr.Zero;
private static bool SendKeyCombination(byte keyCode, int delay = 50) {
if (!EnsureTargetWindowActive()) return false;
keybd_event(VK_CONTROL, 0, 0, IntPtr.Zero);
keybd_event(keyCode, 0, 0, IntPtr.Zero); Thread.Sleep(20);
keybd_event(keyCode, 0, KEYEVENTF_KEYUP, IntPtr.Zero);
keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, IntPtr.Zero); Thread.Sleep(delay);
return true;
}
private static bool PressKey(byte keyCode, int delay = 50) {
if (!EnsureTargetWindowActive()) return false;
keybd_event(keyCode, 0, 0, IntPtr.Zero); Thread.Sleep(20);
keybd_event(keyCode, 0, KEYEVENTF_KEYUP, IntPtr.Zero); Thread.Sleep(delay);
return true;
}
private static bool CtrlDown(int delay = 50) => SendKeyCombination(VK_DOWN, delay);
private static bool CtrlLeft(int delay = 50) => SendKeyCombination(VK_LEFT, delay);
private static bool SendPaste(int delay = 50) => SendKeyCombination(VK_V, delay);
private static bool PressEscape(int delay = 50) => PressKey(VK_ESCAPE, delay);
public static string[] GetLoads() {
return [
"1;nodal force;1;0.0;0.0;2500.00;0.0;0.0;0.0;0.0;0.0;0.0;load 1",
"1;uniform load;1;0.0;0.0;2000.00;global;projected;relative;0.0;0.0;0.0;0.0;0.0;load 2",
"1;trapezoidal load (2p);1;0.0;0.0;0.0;1500.00;1.00;0.0;0.0;500.00;global;not project.;relative;0.0;0.0;0.0;load 3",
"1;bar force;1;0.0;0.0;1750.00;0.0;0.0;0.0;0.40;global;relative;0.0;0.0;0.0;0.0;0.0;No node;load 4",
"1;thermal load;1;0.0;0.0;30.00;load 5",
"1;imp. displacement;1;0.0;0.0;0.01;0.0;0.0;0.0;load 6"
];
}
public static bool SetClipboardText(string text) {
const int maxAttempts = 5, retryDelay = 250; int attempt = 0;
while (attempt < maxAttempts) { attempt++;
if (OpenClipboard(IntPtr.Zero)) {
try { EmptyClipboard();
byte[] bytes = Encoding.Unicode.GetBytes(text + '\0');
IntPtr hGlobal = GlobalAlloc(GMEM_MOVEABLE, (UIntPtr)bytes.Length);
if (hGlobal == IntPtr.Zero) return false;
IntPtr pGlobal = GlobalLock(hGlobal);
Marshal.Copy(bytes, 0, pGlobal, bytes.Length); GlobalUnlock(hGlobal);
if (SetClipboardData(CF_UNICODETEXT, hGlobal) == IntPtr.Zero) {
WriteLine("Failed to set clipboard data"); GlobalFree(hGlobal); return false;
}
return true;
} finally { CloseClipboard(); }
} else { Thread.Sleep(retryDelay * attempt); }
}
WriteLine("Cannot open clipboard after multiple attempts"); return false;
}
public enum PasteMethod { ByCell, ByLine, EntireTable }
public static bool Paste(string windowName, PasteMethod method = EntireTable) => Paste(windowName, GetLoads(), method);
public static bool Paste(string windowName, string[] datas, PasteMethod method = EntireTable) {
_targetHwnd = FindWindow(null, windowName);
if (_targetHwnd == IntPtr.Zero) { WriteLine($"Window '{windowName}' not found"); return false; }
Thread.Sleep(500); if (!CtrlDown() || !CtrlLeft() || !PressEscape()) return false;
return method switch {
ByCell => PasteCells(datas), ByLine => PasteLines(datas), EntireTable => PasteTable(datas),
_ => PasteTable(datas)
};
}
private static bool EnsureTargetWindowActive() {
if (_targetHwnd == IntPtr.Zero) { WriteLine("No target window specified"); return false; }
if (!IsWindow(_targetHwnd)) { WriteLine("Target window handle is no longer valid"); return false; }
if (GetForegroundWindow() == _targetHwnd) return true;
if (IsIconic(_targetHwnd)) ShowWindow(_targetHwnd, SW_RESTORE);
foreach (var (method, delay) in new (Func<bool>, int)[] {
(() => SetForegroundWindow(_targetHwnd), 80),
(() => { BringWindowToTop(_targetHwnd); return true; }, 80),
(() => { SwitchToThisWindow(_targetHwnd, true); return true; }, 100)}) {
method(); Thread.Sleep(delay); if (GetForegroundWindow() == _targetHwnd) return true;
}
WriteLine("Warning: unable to bring target window to foreground"); return false;
}
public static bool Write(string Text) {
if (!EnsureTargetWindowActive()) return false;
if (!SetClipboardText(Text)) { WriteLine("Failed to set clipboard"); return false; }
Thread.Sleep(250);
for (int i = 0; i < 2; i++) { if (SendPaste()) { Thread.Sleep(125); return true; } Thread.Sleep(100); }
WriteLine("Paste operation failed"); return false;
}
}
public static bool PasteCells(string[] datas) {
for (int lineIndex = 0; lineIndex < datas.Length; lineIndex++) {
string[] cells = datas[lineIndex].Split(';');
for (int idx = 0; idx < cells.Length; idx++) if (!Write(cells[idx]) || !PressKey(VK_RETURN)) return false;
if (lineIndex < datas.Length - 1) if (!CtrlLeft() || !PressKey(VK_DOWN)) return false;
}
WriteLine("\nAll cells pasted successfully"); return true;
}
To ensure safe and correct use:
These functions are provided as an example for pasting a data table into a pre-configured load table. Windows keyboard emulation, the system clipboard, and Robot event handling operate asynchronously. The key sequences and timings used here are calibrated for a general demonstration context. The provided code may require adjustments to timings, batch sizes, or navigation keys. Therefore, it is recommended to use this code only if you fully understand how these sequences interact with the Windows message loop and the asynchronous clipboard, and can adapt it to your hardware and projects. Incorrect settings may result in incomplete copies, misaligned pastes, or unpredictable behavior.
Best Regards
Stéphane Kapetanovic
Did you find this post helpful? If it gave you one or more solutions,
don't forget to click the Accept Solution button and leave a < like !
