Hacker News new | ask | show | jobs
by clarge1120 1092 days ago
Thanks for including this example. It helps me understand what you mean.

ChatGPT is not really equipped to do this level of code design because there are too many steps for it to handle at once. It can handle your instructions if it could first write a detailed design spec, then write code and unit tests, then run them, read the compiler output, and iteratively make changes.

IOW, this would require a purpose-built solution which uses ChatGPT's underlying engine to take your list of requirements and turn them into built and tested code.

1 comments

> ChatGPT is not really equipped to do this level of code design because there are too many steps for it to handle at once

There's no code design going on here. My solution was literally just going through like 100 StackOverflow answers & Microsoft's god-awful documentation to get the 50 lines of code that does what I need it to do.

In fact, this is precisely what I'd hope ChatGPT would be good for. Most of my final code is simply copy-pasted from SO/example repos/official docs. He's the correct function (comments added by me so I'll know wtf this is meant to do when I look at it again in 3 months).

    fn get_context_path() -> Result<String, Error> {
        unsafe {
            // Init COM libraries in this thread
            CoInitializeEx(Some(ptr::null()), COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE)?;

            // CabinetWClass is the Explorer window class
            let class = s!("CabinetWClass");
            let topmost_explorer = FindWindowA(class, None);
            let foreground_window = GetForegroundWindow();

            // Breadcrumbs IFF topmost window is an explorer window
            if topmost_explorer == foreground_window {
                let windows: IShellWindows = CoCreateInstance(&ShellWindows, None, CLSCTX_LOCAL_SERVER)?;
                let unk_enum = windows._NewEnum()?;
                let enum_variant: IEnumVARIANT = unk_enum.cast::<IEnumVARIANT>()?;

                // Iterate through all IShellWindows
                loop {
                    let mut fetched = 0;
                    let mut var: [VARIANT; 1] = [VARIANT::default(); 1];
                    let hr = enum_variant.Next(&mut var, &mut fetched);

                    // No more windows?
                    if hr == S_FALSE || fetched == 0 {
                        break;
                    }

                    // Not an IDispatch interface?
                    if var[0].Anonymous.Anonymous.vt != VT_DISPATCH {
                        continue;
                    }

                    // We should be able to turn an IShellWindow into an IShellBrowser
                    let shell_browser: IShellBrowser = IUnknown_QueryService(
                        var[0]
                            .Anonymous
                            .Anonymous
                            .Anonymous
                            .pdispVal
                            .as_ref()
                            .unwrap(),
                        &SID_STopLevelBrowser,
                    )?;
                    let shell_window = shell_browser.GetWindow()?;

                    // NOTE: The window we're matching with is actually the shell's parent
                    // Given that windows can be tabbed, we want to make sure the parent is the top
                    if GetParent(shell_window) == topmost_explorer {
                        let shell_view = shell_browser.QueryActiveShellView()?;

                        // Do some COM finagling, including a QueryInterface cast,
                        // until we get the folder path we're looking at
                        let folder_view: IFolderView = shell_view.cast::<IFolderView>()?;
                        let folder: IPersistFolder2 = folder_view.GetFolder::<IPersistFolder2>()?;
                        let curr_folder = folder.GetCurFolder()?;

                        // NOTE: This fails on non SYSPATH paths (e.g. "Home" or "Recent")
                        let path = SHGetNameFromIDList(curr_folder, SIGDN_FILESYSPATH)?;
                        let result = path.to_string()?;

                        // To figure out what path we're on (e.g. what tab is active), we try to match the
                        // parent title with the folder
                        // FIXME: Unless using full paths as titles, we can have ambiguities here
                        let mut title: [u16; 512] = [0; 512];
                        let len = GetWindowTextW(topmost_explorer, &mut title);
                        let title = String::from_utf16_lossy(&title[..len as usize]);

                        // We found the proper tab (child)
                        if result.contains(&title) {
                            // Cleanup COM & return path result
                            CoUninitialize();
                            return Ok(result);
                        // Must be another one (or something went wrong)
                        } else {
                            continue;
                        }
                    }
                }
            }
            // Cleanup COM & fallback to blank string
            CoUninitialize();
            return Ok(String::from(""));
        }
    }
I've added the statement "let's think through the problem step by step" after your instructions. Here's GPT-4's answer. I don't know Rust so let me know if this is a better answer:

---

Sure, let's break down the problem:

1. Identify the topmost window: We can use the `winapi` crate in Rust to interact with the Windows API. The function `GetForegroundWindow` can be used to get a handle to the topmost window.

2. Check if the window is a Windows Explorer window: We can use the `GetClassNameW` function to get the class name of the window. If the window is a Windows Explorer window, the class name should be `CabinetWClass`.

3. Get the path of the active folder in the Windows Explorer window: This is a bit more complex. We can use the `SHGetPathFromIDListW` function from the Shell API to get the path from an item ID list. However, getting the item ID list for the active folder in a Windows Explorer window is not straightforward. We might need to use COM interfaces like `IShellWindows` to get the `IWebBrowserApp` for the window, and then use `IWebBrowserApp::LocationURL` to get the URL of the active folder.

4. Return the path as a string or a blank string: This is straightforward. We just need to convert the path to a string and return it, or return a blank string if the window is not a Windows Explorer window.

Here is a skeleton of the function in Rust:

  ```rust
  extern crate winapi;

  use std::ptr;
  use std::ffi::OsString;
  use std::os::windows::ffi::OsStringExt;
  use winapi::um::winuser::{GetForegroundWindow, 
  GetClassNameW};
  use winapi::um::shellapi::SHGetPathFromIDListW;
  use winapi::shared::minwindef::MAX_PATH;

  fn get_active_folder_path() -> String {
      // Get the topmost window
      let hwnd = unsafe { GetForegroundWindow() };

      // Get the class name of the window
      let mut class_name = vec![0u16; MAX_PATH + 1];
      unsafe {
          GetClassNameW(hwnd, class_name.as_mut_ptr(), class_name.len() as i32);
      }

    // Convert the class name to a string
    let class_name = OsString::from_wide(&class_name)
          .to_string_lossy()
          .into_owned();

      // Check if the window is a Windows Explorer window
      if class_name.starts_with("CabinetWClass") {
          // TODO: Get the item ID list for the active folder in the Windows Explorer window
          // TODO: Use SHGetPathFromIDListW to get the path from the item ID list
          // TODO: Convert the path to a string and return it
      }

      // If the window is not a Windows Explorer window, return a blank string
      "".to_string()
  }
  ```
Please note that this is a skeleton of the function and it's not complete. The part to get the item ID list for the active folder in a Windows Explorer window and get the path from the item ID list is complex and requires using COM interfaces, which is not straightforward in Rust. You might need to use a crate like `winrt` to interact with COM interfaces in Rust.

---